function on_down(e) { const x = Math.round((e.clientX + storage.canvas.offset_x) / storage.canvas.zoom); const y = Math.round((e.clientY + storage.canvas.offset_y) / storage.canvas.zoom); if (e.button === 1) { storage.state.moving = true; storage.state.mousedown = true; return; } if (e.button === 2) { const image_hit = image_at(x, y); activate_image(image_hit); e.preventDefault(); return; } if (e.button === 0) { const image_hit = image_at(x, y); if (elements.active_image !== null && image_hit !== null) { storage.state.moving_image = true; return; } if (storage.state.moving) { storage.state.mousedown = true; return; } storage.state.drawing = true; if (storage.ctx1.lineWidth !== storage.cursor.width) { storage.ctx1.lineWidth = storage.cursor.width; } storage.cursor.x = x; storage.cursor.y = y; const predraw = predraw_event(x, y); storage.current_stroke.push(predraw); fire_event(predraw); } } function on_move(e) { const last_x = storage.cursor.x; const last_y = storage.cursor.y; const x = storage.cursor.x = Math.max(Math.round((e.clientX + storage.canvas.offset_x) / storage.canvas.zoom), 0); const y = storage.cursor.y = Math.max(Math.round((e.clientY + storage.canvas.offset_y) / storage.canvas.zoom), 0); const old_offset_x = storage.canvas.offset_x; const old_offset_y = storage.canvas.offset_y; if (elements.active_image && storage.state.moving_image) { const dx = Math.round(e.movementX / storage.canvas.zoom); const dy = Math.round(e.movementY / storage.canvas.zoom); const image_id = elements.active_image.getAttribute('data-image-id'); const ix = storage.images[image_id].x += dx; const iy = storage.images[image_id].y += dy; elements.active_image.style.transform = `translate(${ix}px, ${iy}px)`; return; } if (storage.state.drawing) { const width = storage.cursor.width; storage.ctx1.beginPath(); storage.ctx1.moveTo(last_x, last_y); storage.ctx1.lineTo(x, y); storage.ctx1.stroke(); const predraw = predraw_event(x, y); storage.current_stroke.push(predraw); fire_event(predraw); } else if (storage.state.moving && storage.state.mousedown) { storage.canvas.offset_x -= e.movementX; storage.canvas.offset_y -= e.movementY; if (storage.canvas.offset_x !== old_offset_x || storage.canvas.offset_y !== old_offset_y) { move_canvas(); } // if (storage.canvas.offset_x > storage.canvas.max_scroll_x) storage.canvas.offset_x = storage.canvas.max_scroll_x; // if (storage.canvas.offset_x < 0) storage.canvas.offset_x = 0; // if (storage.canvas.offset_y > storage.canvas.max_scroll_y) storage.canvas.offset_y = storage.canvas.max_scroll_y; // if (storage.canvas.offset_y < 0) storage.canvas.offset_y = 0; } e.preventDefault(); } async function on_up(e) { if (storage.state.moving_image && e.button === 0) { storage.state.moving_image = false; const image_id = elements.active_image.getAttribute('data-image-id'); const position = storage.images[image_id]; const event = image_move_event(image_id, position.x, position.y); await queue_event(event); return; } if (storage.state.moving && (e.button === 1 || e.button === 0)) { storage.state.mousedown = false; if (!storage.state.spacedown) { storage.state.moving = false; return; } } if (storage.state.drawing && e.button === 0) { storage.state.drawing = false; const event = stroke_event(); storage.current_stroke = []; await queue_event(event); return; } } function on_keydown(e) { if (e.code === 'Space' && !storage.state.drawing) { storage.state.moving = true; storage.state.spacedown = true; return; } if (e.code === 'KeyZ' && e.ctrlKey) { const event = undo_event(); queue_event(event); return; } } function on_keyup(e) { if (e.code === 'Space' && storage.state.moving) { storage.state.moving = false; storage.state.spacedown = false; } } function on_leave(e) { if (storage.state.moving) { storage.state.moving = false; storage.state.holding = false; return; } } function on_resize(e) { storage.canvas.max_scroll_x = storage.canvas.width - window.innerWidth; storage.canvas.max_scroll_y = storage.canvas.height - window.innerHeight; } async function on_drop(e) { e.preventDefault(); const file = e.dataTransfer.files[0]; const bitmap = await createImageBitmap(file); const x = storage.cursor.x - Math.round(bitmap.width / 2); const y = storage.cursor.y - Math.round(bitmap.height / 2); // storage.ctx0.drawImage(bitmap, x, y); const form_data = new FormData(); form_data.append('file', file); const resp = await fetch(`/api/image?deskId=${storage.desk_id}`, { method: 'post', body: form_data, }) if (resp.ok) { const image_id = await resp.text(); const event = image_event(image_id, x, y); await queue_event(event); } return false; } function on_wheel(e) { const x = Math.round((e.clientX + storage.canvas.offset_x) / storage.canvas.zoom); const y = Math.round((e.clientY + storage.canvas.offset_y) / storage.canvas.zoom); const dz = (e.deltaY < 0 ? 0.1 : -0.1); storage.canvas.zoom += dz; if (storage.canvas.zoom > storage.max_zoom) { storage.canvas.zoom = storage.max_zoom; return; } if (storage.canvas.zoom < storage.min_zoom) { storage.canvas.zoom = storage.min_zoom; return; } const zoom_offset_x = Math.round(dz * x); const zoom_offset_y = Math.round(dz * y); storage.canvas.offset_x += zoom_offset_x; storage.canvas.offset_y += zoom_offset_y; move_canvas(); } function cancel(e) { e.preventDefault(); return false; } function update_brush() { elements.brush_preview.classList.remove('dhide'); const color = elements.brush_color.value; const width = elements.brush_width.value; storage.cursor.color = color; storage.cursor.width = width; const x = Math.round(storage.cursor.x - width / 2); const y = Math.round(storage.cursor.y - width / 2); elements.brush_preview.style.transform = `translate(${x}px, ${y}px)`; elements.brush_preview.style.width = width + 'px'; elements.brush_preview.style.height = width + 'px'; elements.brush_preview.style.background = color; if (storage.timers.brush_preview) { clearTimeout(storage.timers.brush_preview); } storage.timers.brush_preview = setTimeout(() => { elements.brush_preview.classList.add('dhide'); }, 1000); }