How to integrate P5JS with Flask-SocketIO


flask

P5Js is an implementation of processing.org’s library in JavaSript. It can be thought of as a canvas management library. Integrating such a library with a common backend like Flask unlocks amazing opportunities. Canvas is even better if sockets.io is involved for real-time events. This post shows how to integrate these 3 libraries using flask-socketio.

Main codes

Github Repo

Server:

from shopyo.api.module import ModuleHelp

from flask_socketio import SocketIO, join_room, leave_room, emit

from init import socketio

mhelp = ModuleHelp(__file__, __name__)
globals()[mhelp.blueprint_str] = mhelp.blueprint
module_blueprint = globals()[mhelp.blueprint_str]


@module_blueprint.route("/")
def index():
    return mhelp.render('index.html')


@socketio.on('mouse')# , namespace='/chat')
def mouse(data, methods=['GET', 'POST']):
    # print(data)
    emit('mouse', data, broadcast=True)

Client

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Websockets drawing app</title>
  <link rel="stylesheet" type="text/css" href="styles.css" />
  <script src="https://cdn.socket.io/4.4.1/socket.io.min.js" integrity="sha384-fKnu0iswBIqkjxrhQCTZ7qlLHOFEgNkRmK2vaO/LbTZSXdJfAu6ewRBdwHPhBo/H" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>
  <script type="text/javascript">


 let socket
let color = '#FFF'
let strokeWidth = 4

function setup() {
  // Creating canvas
  const cv = createCanvas(1000, 1000)
  cv.position(600, 100)
  cv.background(0)

  // Start the socket connection
  socket = io.connect('http://127.0.0.1:5000')

  // Callback function
  socket.on('mouse', data => {
    // console.log('received ' + data.color+ ' '+data.x)
    stroke(data.color)
    strokeWeight(data.strokeWidth)
    line(data.x, data.y, data.px, data.py)
  })

  // Getting our buttons and the holder through the p5.js dom
  const color_picker = select('#pickcolor')
  const color_btn = select('#color-btn')
  const color_holder = select('#color-holder')

  const stroke_width_picker = select('#stroke-width-picker')
  const stroke_btn = select('#stroke-btn')

  // Adding a mousePressed listener to the button
  color_btn.mousePressed(() => {
    // Checking if the input is a valid hex color
    if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(color_picker.value())) {
      color = color_picker.value()
      color_holder.style('background-color', color)
    }
    else {console.log('Enter a valid hex value')}
  })

  // Adding a mousePressed listener to the button
  stroke_btn.mousePressed(() => {
    const width = parseInt(stroke_width_picker.value())
    if (width > 0) strokeWidth = width
  })
}

function mouseDragged() {
  // Draw
  stroke(color)
  strokeWeight(strokeWidth)
  line(mouseX, mouseY, pmouseX, pmouseY)

  // Send the mouse coordinates
  sendmouse(mouseX, mouseY, pmouseX, pmouseY)
}

// Sending data to the socket
function sendmouse(x, y, pX, pY) {
  const data = {
    x: x,
    y: y,
    px: pX,
    py: pY,
    color: color,
    strokeWidth: strokeWidth,
  }

  socket.emit('mouse', data)
}
  </script>
  <style type="text/css">
    input.call-picker {
  border: 1px solid #AAA;
  color: #666;
  text-transform: uppercase;
  float: left;
  outline: none;
  padding: 10px;
  text-transform: uppercase;
  width: 85px;
}

.color-picker {
  width: 130px;
  background: #F3F3F3;
  height: 81px;
  padding: 5px;
  border: 5px solid #fff;
  box-shadow: 0px 0px 3px 1px #DDD;
  position: absolute;
  top: 61px;
  left: 2px;
}

.color-holder {
  background: #fff;
  cursor: pointer;
  border: 1px solid #AAA;
  width: 40px;
  height: 36px;
  float: left;
  margin-left: 5px;
}

input.stroke_width_picker {
  border: 1px solid #AAA;
  color: #666;
  text-transform: uppercase;
  float: left;
  outline: none;
  padding: 10px;
  text-transform: uppercase;
  width: 85px;
}

p {
  margin-top: 2rem;
  margin-bottom: 2rem;
}
button {
  margin-left: 1rem;
}
  </style>
</head>

<body>
  <p>Choose color (# hex)</p>
  <input type="text" name="custom_color" placeholder="#FFFFFF" id="pickcolor" class="call-picker" />
  <div id="color-holder" class="color-holder call-picker"></div>
  <button id="color-btn">Change color</button>
  <br />
  <p>Choose stroke width</p>
  <input type="text" name="stroke_width" placeholder="4" id="stroke-width-picker" class="stroke_width_picker" />
  <button id="stroke-btn">Change stroke width</button>
</body>
</html>

Free Flask Course