let ws = null; let ls = window.localStorage; document.addEventListener('DOMContentLoaded', main); const EVENT = Object.freeze({ PREDRAW: 10, STROKE: 20, UNDO: 30, REDO: 31, }); const MESSAGE = Object.freeze({ INIT: 100, SYN: 101, ACK: 102, FULL: 103, FIRE: 104, JOIN: 105, }); const config = { ws_url: 'wss://desk.local/ws/', sync_timeout: 1000, ws_reconnect_timeout: 2000, }; const storage = { 'state': { 'drawing': false, 'moving': false, }, 'predraw': {}, 'timers': {}, 'me': {}, 'sn': 0, // what WE think SERVER SN is (we tell this to the server, it uses to decide how much stuff to SYN to us) 'server_lsn': 0, // what SERVER said LSN is (used to decide how much stuff to SYN) 'lsn': 0, // what actual LSN is (can't just use length of local queue because it gets cleared) 'queue': [], // to server 'events': [], // from server 'current_stroke': [], 'desk_id': 123, 'canvas': { 'width': 2000, 'height': 2000, 'offset_x': 0, 'offset_y': 0, }, 'cursor': { 'width': 8, 'x': 0, 'y': 0, } }; const elements = { 'cursor': null, 'canvas0': null, 'canvas1': null, }; function event_size(event) { let size = 1 + 1; // type + padding switch (event.type) { case EVENT.PREDRAW: { size += 2 * 2; break; } case EVENT.STROKE: { size += 2 + event.points.length * 2 * 2; // u16 (count) + count * (u16, u16) points break; } case EVENT.UNDO: case EVENT.REDO: { break; } default: { console.error('fuck'); process.exit(1); } } return size; } function predraw_event(x, y) { return { 'type': EVENT.PREDRAW, 'x': x, 'y': y }; } function stroke_event() { return { 'type': EVENT.STROKE, 'points': storage.current_stroke, }; } function undo_event() { return { 'type': EVENT.UNDO }; } function redo_event() { return { 'type': EVENT.REDO }; } function main() { const url = new URL(window.location.href); const parts = url.pathname.split('/'); storage.desk_id = parts.length > 0 ? parts[parts.length - 1] : 0; ws_connect(); elements.canvas0 = document.getElementById('canvas0'); elements.canvas1 = document.getElementById('canvas1'); elements.cursor = document.getElementById('cursor'); elements.cursor.style.width = storage.cursor.width + 'px'; elements.cursor.style.height = storage.cursor.width + 'px'; storage.canvas.rect = elements.canvas0.getBoundingClientRect(); storage.ctx0 = elements.canvas0.getContext('2d'); storage.ctx1 = elements.canvas1.getContext('2d'); storage.ctx1.canvas.width = storage.ctx0.canvas.width = storage.canvas.width; storage.ctx1.canvas.height = storage.ctx0.canvas.height = storage.canvas.height; storage.ctx1.lineJoin = storage.ctx1.lineCap = storage.ctx0.lineJoin = storage.ctx0.lineCap = 'round'; storage.ctx1.lineWidth = storage.ctx0.lineWidth = storage.cursor.width; window.addEventListener('pointerdown', on_down) window.addEventListener('pointermove', on_move) window.addEventListener('pointerup', on_up); window.addEventListener('pointercancel', on_up); window.addEventListener('touchstart', (e) => e.preventDefault()); window.addEventListener('keydown', on_keydown); window.addEventListener('keyup', on_keyup); // window.addEventListener('pointerleave', on_leave); }