diff --git a/client/client_recv.js b/client/client_recv.js index c64541a..c2a9c61 100644 --- a/client/client_recv.js +++ b/client/client_recv.js @@ -392,13 +392,12 @@ function handle_event(state, context, event, options = {}) { // Already moved due to local prediction if (event.user_id !== state.me) { const image_id = event.image_id; - const image_event = find_image(state, image_id); + const image = get_image(context, image_id); - if (image_event) { + if (image) { // if (config.debug_print) console.debug('move image', image_id, 'to', image_event.x, image_event.y); - image_event.x = event.x; - image_event.y = event.y; - move_image(context, image_event); + image.at.x = event.x; + image.at.y = event.y; need_draw = true; } } diff --git a/client/cursor.js b/client/cursor.js deleted file mode 100644 index cfe31ce..0000000 --- a/client/cursor.js +++ /dev/null @@ -1,327 +0,0 @@ -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); - - // Scroll wheel (mouse button 3) - if (e.button === 1) { - // storage.state.moving = true; - // storage.state.mousedown = true; - return; - } - - // Right mouse button - if (e.button === 2) { - const image_hit = image_at(x, y); - activate_image(image_hit); - e.preventDefault(); - return; - } - - // Left mouse button - if (e.button === 0) { - const image_hit = image_at(context, x, y); - - if (elements.active_image !== null && image_hit !== null) { - const image_id = image_hit.getAttribute('data-image-id'); - const image_position = storage.images[image_id]; - storage.state.moving_image = true; - storage.moving_image_original_x = image_position.x; - storage.moving_image_original_y = image_position.y; - 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; - - if (storage.tools.active === 'pencil') { - const predraw = predraw_event(x, y); - storage.current_stroke.push(predraw); - fire_event(predraw); - } else if (storage.tools.active === 'ruler') { - storage.ruler_origin.x = x; - storage.ruler_origin.y = y; - } - } -} - -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) { - if (storage.tools.active === 'pencil') { - 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.tools.active === 'eraser') { - const erased = strokes_intersect_line(last_x, last_y, x, y); - storage.erased.push(...erased); - - if (erased.length > 0) { - for (const other_event of storage.events) { - for (const stroke_id of erased) { - if (stroke_id === other_event.stroke_id) { - if (!other_event.deleted) { - other_event.deleted = true; - const stats = stroke_stats(other_event.points, storage.cursor.width); - redraw_region(stats.bbox); - } - } - } - } - } - } else if (storage.tools.active === 'ruler') { - const old_ruler = [ - {'x': storage.ruler_origin.x, 'y': storage.ruler_origin.y}, - {'x': last_x, 'y': last_y} - ]; - - const stats = stroke_stats(old_ruler, storage.cursor.width); - const bbox = stats.bbox; - - storage.ctx1.clearRect(bbox.xmin, bbox.ymin, bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin); - - storage.ctx1.beginPath(); - - storage.ctx1.moveTo(storage.ruler_origin.x, storage.ruler_origin.y); - storage.ctx1.lineTo(x, y); - - storage.ctx1.stroke(); - } else { - console.error('fuck'); - } - } 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]; - // Store delta instead of new position for easy undo - const event = image_move_event(image_id, position.x - storage.moving_image_original_x, position.y - storage.moving_image_original_y); - await queue_event(event); - storage.moving_image_original_x = null; - storage.moving_image_original_y = null; - 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) { - if (storage.tools.active === 'pencil') { - const event = stroke_event(); - storage.current_stroke = []; - await queue_event(event); - } else if (storage.tools.active === 'eraser') { - const events = eraser_events(); - storage.erased = []; - if (events.length > 0) { - for (const event of events) { - await queue_event(event); - } - } - } else if (storage.tools.active === 'ruler') { - const event = ruler_event(storage.cursor.x, storage.cursor.y); - await queue_event(event); - } else { - console.error('fuck'); - } - - storage.state.drawing = false; - - 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) { - undo(); - return; - } -} - -function on_keyup(e) { - if (e.code === 'Space' && storage.state.moving) { - storage.state.moving = false; - storage.state.spacedown = false; - } -} - -function on_leave(e) { - // TODO: broken when "moving" - if (storage.state.moving) { - storage.state.moving = false; - storage.state.holding = false; - return; - } -} - -function on_resize(e) { - const width = window.innerWidth; - const height = window.innerHeight; - -elements.canvas0.width = elements.canvas1.width = width; - elements.canvas0.height = elements.canvas1.height = height; - - storage.ctx1.lineJoin = storage.ctx1.lineCap = storage.ctx0.lineJoin = storage.ctx0.lineCap = 'round'; - storage.ctx1.lineWidth = storage.ctx0.lineWidth = storage.cursor.width; - - redraw_region({'xmin': 0, 'xmax': width, 'ymin': 0, 'ymax': width}); - // 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) { - return; - - 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); -} diff --git a/client/index.js b/client/index.js index 064afd5..f3f0bcf 100644 --- a/client/index.js +++ b/client/index.js @@ -177,9 +177,10 @@ async function main() { 'colorpicking': false, 'zooming': false, 'zoomdown': false, + 'imagemoving': false, + 'imagescaling': false, - 'moving_image': null, - 'scaling_image': null, + 'active_image': null, 'scaling_corner': null, 'current_strokes': {}, @@ -271,7 +272,6 @@ async function main() { 'bgcolor': {'r': 1.0, 'g': 1.0, 'b': 1.0}, 'gpu_timer_ext': null, - 'active_image': null, 'last_frame_ts': 0, 'last_frame_dt': 0, }; diff --git a/client/webgl_draw.js b/client/webgl_draw.js index 62cddb7..b7dafd4 100644 --- a/client/webgl_draw.js +++ b/client/webgl_draw.js @@ -236,7 +236,7 @@ async function draw(state, context, animate, ts) { gl.drawArrays(gl.TRIANGLES, offset, 6); // Highlight active image - if (entry.key === context.active_image) { + if (entry.key === state.active_image) { gl.uniform1i(locations['u_solid'], 1); gl.uniform4f(locations['u_color'], 0.133 * 0.5, 0.545 * 0.5, 0.902 * 0.5, 0.5); gl.drawArrays(gl.TRIANGLES, offset, 6); @@ -361,8 +361,8 @@ async function draw(state, context, animate, ts) { } // HUD: resize handles, etc - if (context.active_image !== null) { - const handles = geometry_generate_handles(state, context, context.active_image); + if (state.active_image !== null) { + const handles = geometry_generate_handles(state, context, state.active_image); const ui_segments = 7 * 4 - 1; // each square = 4, each line = 1, square->line = 1, line->square = 1 gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_instance']); diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js index 49e0c06..ee6598c 100644 --- a/client/webgl_geometry.js +++ b/client/webgl_geometry.js @@ -218,7 +218,7 @@ function add_image(context, image_id, bitmap, p) { gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap); gl.generateMipmap(gl.TEXTURE_2D); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js index f755c65..1386755 100644 --- a/client/webgl_listeners.js +++ b/client/webgl_listeners.js @@ -209,7 +209,7 @@ function mousedown(e, state, context) { geometry_add_point(state, context, state.me, canvasp); state.drawing = true; - context.active_image = null; + state.active_image = null; schedule_draw(state, context); } else if (state.tools.active === 'ruler') { @@ -217,14 +217,17 @@ function mousedown(e, state, context) { } else if (state.tools.active === 'eraser') { state.erasing = true; } else if (state.tools.active === 'pointer') { - state.scaling_image = null; + state.imagescaling = false; + state.imagemoving = false; - if (context.active_image !== null) { - // Resize image? - const image = get_image(context, context.active_image); - corner = image_corner(state, image, canvasp); + if (state.active_image !== null) { + // Check for resize first, because it supports + // clicking slightly outside of the image + const image = get_image(context, state.active_image); + const corner = image_corner(state, image, canvasp); if (corner !== null) { - state.scaling_image = image.key; + // Resize + state.imagescaling = true; state.scaling_corner = corner; document.querySelector('canvas').classList.remove('resize-topleft'); @@ -238,15 +241,15 @@ function mousedown(e, state, context) { } } - if (state.scaling_image === null) { - // Select/move image? - const image_event = image_at(context, canvasp.x, canvasp.y); - - if (image_event) { - context.active_image = image_event.key; - state.moving_image = image_event.key; + // Only do picking logic if we haven't started imagescaling already + if (!state.imagescaling) { + const image = image_at(context, canvasp.x, canvasp.y); + if (image !== null) { + state.active_image = image.key; + // Allow immediately moving + state.imagemoving = true; } else { - context.active_image = null; + state.active_image = null; } } @@ -276,8 +279,8 @@ function mousemove(e, state, context) { const canvasp = screen_to_canvas(state, screenp); if (state.tools.active === 'pointer') { - if (context.active_image !== null) { - const image = get_image(context, context.active_image); + if (state.active_image !== null) { + const image = get_image(context, state.active_image); const corner = image_corner(state, image, canvasp); if (state.scaling_corner === null) { @@ -350,14 +353,14 @@ function mousemove(e, state, context) { do_draw = true; } - if (state.scaling_image) { - const image = get_image(context, state.scaling_image); + if (state.imagescaling) { + const image = get_image(context, state.active_image); scale_image(context, image, state.scaling_corner, canvasp); do_draw = true; } - if (state.moving_image) { - const image = get_image(context, state.moving_image); + if (state.imagemoving) { + const image = get_image(context, state.active_image); if (image !== null) { const dx = e.movementX / state.canvas.zoom; @@ -366,8 +369,6 @@ function mousemove(e, state, context) { image.at.x += dx; image.at.y += dy; - //move_image(context, state.moving_image); - do_draw = true; } } @@ -412,15 +413,16 @@ function mouseup(e, state, context) { return; } - if (state.moving_image) { + if (state.imagemoving) { + state.imagemoving = false; + const image = get_image(context, state.active_image); + queue_event(state, image_move_event(state.active_image, image.at.x, image.at.y)); schedule_draw(state, context); - //queue_event(state, image_move_event(context.active_image, state.moving_image.x, state.moving_image.y)); - state.moving_image = null; return; } - if (state.scaling_image) { - state.scaling_image = null; + if (state.imagescaling) { + state.imagescaling = false; state.scaling_corner = null; return; }