Its the middle of the term as we know it…

….and I feel fine.

Test it out here: ppc7138.itp.io:3000

After many hours alone, I succumbed to need for help. I sent the up signal and it was answered by none other than the prolific CODING LAB. Partners in help David Currie and Wasif Hyder on two different occasions helped to correct my course and teach me how to change the errors I had made. 

The idea for this project remains the same as last week, a tool for relaxation allowing multiple users to control the output. The interactions have strict confines in order to keep chaos from taking over, this is supposed to be a relaxation tool after all. 

Users can control the x and y location of an ellipse that is drawn to the canvas. Along with x and y, users can control color, stroke, direction and starting degree of rotation, framerate, and an adjustment variable called “rep”. There are two viewing options inset and full-width as well as the ability to reset the canvas to clear the current drawings.

The heart of the code is really this little block right here:

function drawShape(shapeData) {

  if (shapeData.shape1) {
    ellipseMode(CENTER);
    push();
    strokeWeight(shapeData.strk1);
    stroke(shapeData.col1, 100, 100, 50);
    rotate(shapeData.x1 / shapeData.deg1);
    ellipse(shapeData.x1, shapeData.y1, shapeData.x1, shapeData.y1);
    pop();

    shapeData.x1 = shapeData.x1 + shapeData.rep * 0.2;
    shapeData.y1 = shapeData.y1 + shapeData.rep2 * 0.2;
    shapeData.y1 = shapeData.y1;
    if (shapeData.x1 > width + 50) {
      shapeData.x1 = 0;
      shapeData.y1 = 0;
    }
  }

 

I was only able to test it with 3 or 4 users at a time, so I’m not sure how many users at a time this will support. There is a lot of data coming through the pipe here. I’m sure there is a better way of doing it, like only sending data when a change is made but I wasn’t able to figure out how to do that right now. 

Have fun with it, relax, and let me know if anything breaks.



Two users, one in green-yellow, the other in red.
Two users after some time has past with many changes being made over the course of the draw loop.

sketch.js

let myShape = {
  x1: 1,
  y1: 1,
  col1: 10,
  strk1: 1,
  frmRt: 10,
  shape1: false,
  deg1: 0.33,
  rep: 2, 
  rep2: 1,
}

let otherShapes = {}
let otherShapeIds = []

let socket 

function setup() {
  socket = io.connect();

  socket.on('otherShapes', (data) => {
    
    otherShapes[data.id] = data;
  })
  socket.on('removeuser', (id) => {
    delete otherShapes[id];
  })

  createCanvas(400, 400);
  background(0, 0, 0);
  angleMode(DEGREES);
  colorMode(HSB, 360, 100, 100, 100);
  create_ui();

}

function draw() {


  frameRate(myShape.frmRt);
  slider_value('Rep', myShape.rep);
  slider_value('Rep2', myShape.rep2);
  slider_value('frmRt', myShape.frmRt);
  slider_value('x1', myShape.x1);
  slider_value('y1', myShape.y1);
  noFill();
  translate(width / 2, height / 2);
  drawShape(myShape);

  sendData(myShape);

  let shapes = Object.values(otherShapes)
  for(let i = 0; i < shapes.length; i++){
    drawOtherShapes(shapes[i].id);
  }


}


function sendData(shapeData) {

  socket.emit('otherShapes', shapeData);
}

function drawShape(shapeData) {

  if (shapeData.shape1) {
    ellipseMode(CENTER);
    push();
    strokeWeight(shapeData.strk1);
    stroke(shapeData.col1, 100, 100, 50);
    rotate(shapeData.x1 / shapeData.deg1);
    ellipse(shapeData.x1, shapeData.y1, shapeData.x1, shapeData.y1);
    pop();

    shapeData.x1 = shapeData.x1 + shapeData.rep * 0.2;
    shapeData.y1 = shapeData.y1 + shapeData.rep2 * 0.2;
    shapeData.y1 = shapeData.y1;
    if (shapeData.x1 > width + 50) {
      shapeData.x1 = 0;
      shapeData.y1 = 0;
    }
  }
}

function drawOtherShapes(id) {

  if (otherShapes[id].shape1) {
    ellipseMode(CENTER);
    push();
    strokeWeight(otherShapes[id].strk1);
    stroke(otherShapes[id].col1, 100, 100, 50);
    rotate(otherShapes[id].x1 / otherShapes[id].deg1);
    ellipse(otherShapes[id].x1, otherShapes[id].y1, otherShapes[id].x1, otherShapes[id].y1);
    pop();

    // otherShapes[id].x1 = otherShapes[id].x1 + otherShapes[id].rep;
    // otherShapes[id].y1 = otherShapes[id].y1 + otherShapes[id].rep;
  }
}

index.js (server)

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);

app.use('/', express.static('public'));

io.on('connection', (socket) => {
    console.log('a user connected');

    socket.on('otherShapes', (data) => {
        console.log('message: ' + JSON.stringify(data, null, 2)); // Stringify prints object as json string
        data.id = socket.id;
        socket.broadcast.emit('otherShapes', data);
      });

    socket.on('disconnect', () => {
      console.log('user disconnected');
      socket.broadcast.emit('removeuser', socket.id);
    });
  });

server.listen(3000, () => {
  console.log('listening on *:3000');
});

 

ui.js

function create_ui() {
  createP();
  {
    let a_button = createButton('resize-full');
    a_button.mousePressed(function() {
      resizeCanvas(windowWidth, windowHeight);
      background(0, 0, 0);
    });
  } {
    let a_button = createButton('resize-inset');
    a_button.mousePressed(function() {
      resizeCanvas(400, 400);
      background(0, 0, 0);
    });
  } {
    let a_button = createButton('reset');
    a_button.mousePressed(function() {
      fill(0);
      rect(-windowWidth / 2, -windowHeight / 2, windowWidth, windowHeight);
    });
    createP();
  } {
    let a_check = createCheckbox('Shape', myShape.shape1);
    a_check.style('font-size', '25px');
    a_check.style('color:cyan');
    a_check.changed(function() {
      myShape.shape1 = this.checked();
    });
    createP();
  } {
    let a_span = createSpan('Rep:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(1, 10, myShape.rep, 0.25);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.rep = a_slider.value();
    });
  } {
    let a_span = createSpan('Rep2:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(1, 10, myShape.rep2, 0.25);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.rep2 = a_slider.value();
    });
  }

  {
    let a_span = createSpan('frmRt:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(2, 30, myShape.frmRt);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.frmRt = a_slider.value();
    });
  }

  //   X1,Y1

 {
    let a_span = createSpan('x:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(1, 100, myShape.x1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.x1 = a_slider.value();
    });
  } {
    let a_span = createSpan('y:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(1, 100, myShape.y1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.y1 = a_slider.value();
    });
    createP();
  } {
    let a_span = createSpan('Degrees:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(-0.99, 0.99, myShape.deg1, 0.01);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.deg1 = a_slider.value();
    });
  } {
    let a_span = createSpan('color:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 360, myShape.col1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.col1 = a_slider.value();
    });
  } {
    let a_span = createSpan('stroke:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(1, 5, myShape.strk1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      myShape.strk1 = a_slider.value();
    });
    createP();
  }
}

function slider_value(label, num) {
  let elm = select('#' + label);
  num = round(num, 2);
}

style.css

html, body {
  background-color: black;
  margin: 0;
  padding: 0;
}
canvas {
  display: block;
}

index.html

<!DOCTYPE html><html lang="en"><head>
    <script type="text/javascript" src="/socket.io/socket.io.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js" integrity="sha512-NxocnqsXP3zm0Xb42zqVMvjQIktKEpTIbCXXyhBPxqGZHqhcOXHs4pXI/GoZ8lE+2NJONRifuBpi9DxC58L0Lw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <meta charset="utf-8">
</head>
<body>
    <script src="sketch.js"></script>
    <script src="ui.js"></script>
</body></html>