Skip to content

Collaborative Painter

Video Lecture

Collaborative Painter Collaborative Painter

Description

A basic collaborative painting example.

<>

./src/server/server.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { createServer } from 'http'
import { Server } from 'socket.io'
import * as express from 'express'
import * as path from 'path'

const port = 3000

const app = express()
app.use(express.static(path.join(__dirname, '../client')))

const server = createServer(app)

const io = new Server(server)

io.on('connection', (socket) => {
  socket.on('draw', (message) => {
    socket.broadcast.emit('draw', message)
  })
})

server.listen(port, () => {
  console.log('Server listening on port ' + port)
})

./src/client/client.ts

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
import { io } from 'socket.io-client'

const socket = io()

socket.on('draw', (message) => {
  prevX = message[0]
  prevY = message[1]
  currX = message[2]
  currY = message[3]
  color = message[4]
  draw()
})

let prevX = 0,
  currX = 0,
  prevY = 0,
  currY = 0

let color = 'black'
const thickness = 10

const canvas = document.getElementById('canvas') as HTMLCanvasElement
canvas.width = window.innerWidth
canvas.height = window.innerHeight

const ctx = canvas.getContext('2d') as CanvasRenderingContext2D

window.addEventListener('resize', function () {
  if (window.innerWidth > 0 && window.innerHeight > 0) {
    const data = ctx.getImageData(0, 0, window.innerWidth, window.innerHeight)
    canvas.width = window.innerWidth
    canvas.height = window.innerHeight
    ctx.putImageData(data, 0, 0)
  }
})

const greenButton = document.getElementById('greenButton') as HTMLDivElement
greenButton.addEventListener('click', () => {
  color = 'green'
})
const blueButton = document.getElementById('blueButton') as HTMLDivElement
blueButton.addEventListener('click', () => {
  color = 'blue'
})
const redButton = document.getElementById('redButton') as HTMLDivElement
redButton.addEventListener('click', () => {
  color = 'red'
})
const yellowButton = document.getElementById('yellowButton') as HTMLDivElement
yellowButton.addEventListener('click', () => {
  color = 'yellow'
})
const orangeButton = document.getElementById('orangeButton') as HTMLDivElement
orangeButton.addEventListener('click', () => {
  color = 'orange'
})
const blackButton = document.getElementById('blackButton') as HTMLDivElement
blackButton.addEventListener('click', () => {
  color = 'black'
})
const whiteButton = document.getElementById('whiteButton') as HTMLDivElement
whiteButton.addEventListener('click', () => {
  color = 'white'
})
const resetButton = document.getElementById('resetButton') as HTMLButtonElement
resetButton.addEventListener('click', () => {
  reset()
})

canvas.addEventListener('mousemove', (e) => {
  if (e.buttons) {
    prevX = currX
    prevY = currY
    currX = e.clientX - canvas.getBoundingClientRect().left
    currY = e.clientY - canvas.getBoundingClientRect().top
    draw()

    socket.emit('draw', [prevX, prevY, currX, currY, color])
  }
})
canvas.addEventListener('mousedown', (e) => {
  currX = e.clientX - canvas.getBoundingClientRect().left
  currY = e.clientY - canvas.getBoundingClientRect().top
})
canvas.addEventListener('mouseenter', (e) => {
  currX = e.clientX - canvas.getBoundingClientRect().left
  currY = e.clientY - canvas.getBoundingClientRect().top
})

function draw() {
  ctx.beginPath()
  ctx.moveTo(prevX, prevY)
  ctx.lineTo(currX, currY)
  ctx.strokeStyle = color
  ctx.lineWidth = thickness
  ctx.stroke()
  ctx.closePath()
}

function reset() {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
}

./dist/client/index.html

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>
      Colab Painter : Socket.IO TypeScript Tutorials by Sean Bradley :
      https://sbcode.net/tssock/
    </title>
    <style>
      body {
        overflow: hidden;
        margin: 0px;
      }

      #canvas {
        width: 100%;
        height: 100%;
      }

      #greenButton {
        background: green;
        position: absolute;
        left: 0px;
        width: 80px;
        height: 40px;
      }

      #blueButton {
        background: blue;
        position: absolute;
        left: 80px;
        width: 80px;
        height: 40px;
      }

      #redButton {
        background: red;
        position: absolute;
        left: 160px;
        width: 80px;
        height: 40px;
      }

      #yellowButton {
        background: yellow;
        position: absolute;
        left: 240px;
        width: 80px;
        height: 40px;
      }

      #orangeButton {
        background: orange;
        position: absolute;
        left: 320px;
        width: 80px;
        height: 40px;
      }

      #blackButton {
        background: black;
        position: absolute;
        left: 400px;
        width: 80px;
        height: 40px;
      }

      #whiteButton {
        background: white;
        position: absolute;
        left: 480px;
        width: 78px;
        height: 38px;
        border: 1px solid black;
      }

      #resetButton {
        position: absolute;
        left: 560px;
        width: 78px;
        height: 40px;
        border-radius: 0;
      }
    </style>
  </head>
  <body>
    <canvas
      id="canvas"
      width="628"
      height="400"
      style="position: absolute; top: 40px; border: 5px solid"
    ></canvas>
    <div id="greenButton"></div>
    <div id="blueButton"></div>
    <div id="redButton"></div>
    <div id="yellowButton"></div>
    <div id="orangeButton"></div>
    <div id="blackButton"></div>
    <div id="whiteButton"></div>
    <input id="resetButton" type="button" value="Reset" />
    <script type="module" src="bundle.js"></script>
  </body>
</html>