Browse Source

Correct Ctrl+Z with image support

master
A.Olokhtonov 2 years ago
parent
commit
2b01730749
  1. 12
      client/cursor.js
  2. 6
      client/default.css
  3. 24
      client/draw.js
  4. 3
      client/index.html
  5. 3
      client/index.js
  6. 44
      client/recv.js

12
client/cursor.js

@ -1,6 +1,5 @@
function on_down(e) { function on_down(e) {
if (e.button === 1) { if (e.button === 1) {
elements.cursor.classList.add('dhide');
elements.canvas0.classList.add('moving'); elements.canvas0.classList.add('moving');
storage.state.moving = true; storage.state.moving = true;
storage.state.mousedown = true; storage.state.mousedown = true;
@ -76,7 +75,6 @@ async function on_up(e) {
if (storage.state.moving && (e.button === 1 || e.button === 0)) { if (storage.state.moving && (e.button === 1 || e.button === 0)) {
storage.state.mousedown = false; storage.state.mousedown = false;
if (!storage.state.spacedown) { if (!storage.state.spacedown) {
elements.cursor.classList.remove('dhide');
elements.canvas0.classList.remove('moving'); elements.canvas0.classList.remove('moving');
storage.state.moving = false; storage.state.moving = false;
return; return;
@ -94,16 +92,21 @@ async function on_up(e) {
function on_keydown(e) { function on_keydown(e) {
if (e.code === 'Space' && !storage.state.drawing) { if (e.code === 'Space' && !storage.state.drawing) {
elements.cursor.classList.add('dhide');
elements.canvas0.classList.add('moving'); elements.canvas0.classList.add('moving');
storage.state.moving = true; storage.state.moving = true;
storage.state.spacedown = true; storage.state.spacedown = true;
return;
}
if (e.code === 'KeyZ' && e.ctrlKey) {
const event = undo_event();
queue_event(event);
return;
} }
} }
function on_keyup(e) { function on_keyup(e) {
if (e.code === 'Space' && storage.state.moving) { if (e.code === 'Space' && storage.state.moving) {
elements.cursor.classList.remove('dhide');
elements.canvas0.classList.remove('moving'); elements.canvas0.classList.remove('moving');
storage.state.moving = false; storage.state.moving = false;
storage.state.spacedown = false; storage.state.spacedown = false;
@ -112,7 +115,6 @@ function on_keyup(e) {
function on_leave(e) { function on_leave(e) {
if (storage.state.moving) { if (storage.state.moving) {
elements.cursor.classList.remove('dhide');
elements.canvas0.classList.remove('moving'); elements.canvas0.classList.remove('moving');
storage.state.moving = false; storage.state.moving = false;
storage.state.holding = false; storage.state.holding = false;

6
client/default.css

@ -13,6 +13,12 @@ html, body {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
opacity: 1;
transition: opacity .2s;
}
.canvas.white {
opacity: 0;
} }
.canvas.moving { .canvas.moving {

24
client/draw.js

@ -38,4 +38,28 @@ function predraw_user(user_id, event) {
storage.ctx1.stroke(); storage.ctx1.stroke();
storage.predraw[user_id].push({ 'x': event.x, 'y': event.y }); storage.predraw[user_id].push({ 'x': event.x, 'y': event.y });
}
function redraw_region(bbox) {
storage.ctx0.save();
storage.ctx0.clearRect(bbox.xmin, bbox.ymin, bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin);
storage.ctx0.beginPath();
storage.ctx0.rect(bbox.xmin, bbox.ymin, bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin);
storage.ctx0.clip();
for (const event of storage.events) {
if (event.type === EVENT.STROKE && !event.deleted) {
if (stroke_intersects_region(event.points, bbox)) {
draw_stroke(event);
}
} else if (event.type === EVENT.IMAGE && !event.deleted) {
const image_bbox = bitmap_bbox(event);
if (rectangles_intersect(image_bbox, bbox)) {
storage.ctx0.drawImage(event.bitmap, image_bbox.xmin, image_bbox.ymin);
}
}
}
storage.ctx0.restore();
} }

3
client/index.html

@ -14,8 +14,7 @@
<script type="text/javascript" src="draw.js"></script> <script type="text/javascript" src="draw.js"></script>
</head> </head>
<body> <body>
<div class="cursor" id="cursor"></div> <canvas class="canvas white" id="canvas0"></canvas>
<canvas class="canvas" id="canvas0"></canvas>
<canvas class="canvas" id="canvas1"></canvas> <canvas class="canvas" id="canvas1"></canvas>
</body> </body>
</html> </html>

3
client/index.js

@ -141,9 +141,6 @@ function main() {
elements.canvas0 = document.getElementById('canvas0'); elements.canvas0 = document.getElementById('canvas0');
elements.canvas1 = document.getElementById('canvas1'); 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.offset_x = window.scrollX; storage.canvas.offset_x = window.scrollX;
storage.canvas.offset_y = window.scrollY; storage.canvas.offset_y = window.scrollY;

44
client/recv.js

@ -86,23 +86,18 @@ function des_event(d) {
return event; return event;
} }
function redraw_region(bbox) { function bitmap_bbox(event) {
storage.ctx0.save(); const x = (event.x <= storage.canvas.width ? event.x : event.x - 65536);
storage.ctx0.clearRect(bbox.xmin, bbox.ymin, bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin); const y = (event.y <= storage.canvas.height ? event.y : event.y - 65536);
storage.ctx0.beginPath(); const bbox = {
storage.ctx0.rect(bbox.xmin, bbox.ymin, bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin); 'xmin': x,
storage.ctx0.clip(); 'xmax': x + event.bitmap.width,
'ymin': y,
for (const event of storage.events) { 'ymax': y + event.bitmap.height
if (event.type === EVENT.STROKE && !event.deleted) { };
if (stroke_intersects_region(event.points, bbox)) {
draw_stroke(event);
}
}
}
storage.ctx0.restore(); return bbox;
} }
async function handle_event(event) { async function handle_event(event) {
@ -123,11 +118,17 @@ async function handle_event(event) {
case EVENT.UNDO: { case EVENT.UNDO: {
for (let i = storage.events.length - 1; i >=0; --i) { for (let i = storage.events.length - 1; i >=0; --i) {
const other_event = storage.events[i]; const other_event = storage.events[i];
if (other_event.type === EVENT.STROKE && other_event.user_id === event.user_id && !other_event.deleted) { if (other_event.type === EVENT.STROKE && other_event.user_id === event.user_id && !other_event.deleted) {
other_event.deleted = true; other_event.deleted = true;
const stats = stroke_stats(other_event.points, storage.cursor.width); const stats = stroke_stats(other_event.points, storage.cursor.width);
redraw_region(stats.bbox); redraw_region(stats.bbox);
break; break;
} else if (other_event.type === EVENT.IMAGE && other_event.user_id === event.user_id && !other_event.deleted) {
other_event.deleted = true;
const bbox = bitmap_bbox(other_event);
redraw_region(bbox);
break;
} }
} }
@ -139,11 +140,11 @@ async function handle_event(event) {
const blob = await r.blob(); const blob = await r.blob();
const bitmap = await createImageBitmap(blob); const bitmap = await createImageBitmap(blob);
event.bitmap = bitmap;
const x = (event.x <= storage.canvas.width ? event.x : event.x - 65536); const bbox = bitmap_bbox(event);
const y = (event.y <= storage.canvas.height ? event.y : event.y - 65536); storage.ctx0.drawImage(bitmap, bbox.xmin, bbox.ymin);
storage.ctx0.drawImage(bitmap, x, y);
break; break;
} }
@ -176,7 +177,6 @@ async function handle_message(d) {
console.debug('init in'); console.debug('init in');
} }
const event_count = des_u32(d); const event_count = des_u32(d);
console.debug(`${event_count} events in init`); console.debug(`${event_count} events in init`);
@ -184,10 +184,12 @@ async function handle_message(d) {
for (let i = 0; i < event_count; ++i) { for (let i = 0; i < event_count; ++i) {
const event = des_event(d); const event = des_event(d);
handle_event(event); await handle_event(event);
storage.events.push(event); storage.events.push(event);
} }
elements.canvas0.classList.remove('white');
send_ack(event_count); send_ack(event_count);
sync_queue(); sync_queue();

Loading…
Cancel
Save