From 9d6f3337784717c7db222edbcf12950a8401edb8 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Sun, 16 Jun 2024 14:16:34 +0300 Subject: [PATCH] Resize images (local only) --- client/default.css | 7 ++++ client/index.js | 2 ++ client/webgl_geometry.js | 64 ++++++++++++++++++++++++++++++++++-- client/webgl_listeners.js | 68 +++++++++++++++++++++++++++++++++++---- 4 files changed, 132 insertions(+), 9 deletions(-) diff --git a/client/default.css b/client/default.css index 8960f8e..03b1632 100644 --- a/client/default.css +++ b/client/default.css @@ -51,6 +51,13 @@ canvas.picker { cursor: url('icons/picker.svg') 0 19, crosshair; } +canvas.resize-topleft { + cursor: nwse-resize; +} + +canvas.resize-topright { + cursor: nesw-resize; +} /* canvas.movemode { cursor: grab; diff --git a/client/index.js b/client/index.js index 58d0663..064afd5 100644 --- a/client/index.js +++ b/client/index.js @@ -179,6 +179,8 @@ async function main() { 'zoomdown': false, 'moving_image': null, + 'scaling_image': null, + 'scaling_corner': null, 'current_strokes': {}, diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js index c2876b9..49e0c06 100644 --- a/client/webgl_geometry.js +++ b/client/webgl_geometry.js @@ -216,7 +216,9 @@ function add_image(context, image_id, bitmap, p) { gl.bindTexture(gl.TEXTURE_2D, entry.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + 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_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } @@ -225,13 +227,44 @@ function move_image(context, image, dx, dy) { consol.error('wtf is this'); } +function scale_image(context, image, corner, canvasp) { + let new_width, new_height; + + const old_x2 = image.at.x + image.width; + const old_y2 = image.at.y + image.height; + + if (corner === 0) { + image.at.x = canvasp.x; + image.at.y = canvasp.y; + new_width = old_x2 - image.at.x; + new_height = old_y2 - image.at.y; + } else if (corner === 1) { + image.at.y = canvasp.y; + new_width = canvasp.x - image.at.x; + new_height = old_y2 - image.at.y; + } else if (corner === 2) { + new_width = canvasp.x - image.at.x; + new_height = canvasp.y - image.at.y; + } else if (corner === 3) { + image.at.x = canvasp.x; + new_width = old_x2 - image.at.x; + new_height = canvasp.y - image.at.y; + } + + image.width = new_width; + image.height = new_height; +} + function image_at(context, x, y) { for (const image of context.images) { const at = image.at; const w = image.width; const h = image.height; - if (at.x <= x && x <= at.x + w && at.y <= y && y <= at.y + h) { + const in_x = (at.x <= x && x <= at.x + w) || (at.x + w <= x && x <= at.x); + const in_y = (at.y <= y && y <= at.y + h) || (at.y + h <= y && y <= at.y); + + if (in_x && in_y) { return image; } } @@ -239,6 +272,33 @@ function image_at(context, x, y) { return null; } +function image_corner(state, image, canvasp) { + const sp = canvas_to_screen(state, canvasp); + const at = canvas_to_screen(state, image.at); + const w = image.width * state.canvas.zoom; + const h = image.height * state.canvas.zoom; + + const width = 8; + + if (at.x - width <= sp.x && sp.x <= at.x + width && at.y - width <= sp.y && sp.y <= at.y + width) { + return 0; + } + + if (at.x + w - width <= sp.x && sp.x <= at.x + w + width && at.y - width <= sp.y && sp.y <= at.y + width) { + return 1; + } + + if (at.x + w - width <= sp.x && sp.x <= at.x + w + width && at.y + h - width <= sp.y && sp.y <= at.y + h + width) { + return 2; + } + + if (at.x - width <= sp.x && sp.x <= at.x + width && at.y + h - width <= sp.y && sp.y <= at.y + h + width) { + return 3; + } + + return null; +} + function geometry_gen_circle(cx, cy, r, n) { const step = 2 * Math.PI / n; const result = []; diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js index d595485..f755c65 100644 --- a/client/webgl_listeners.js +++ b/client/webgl_listeners.js @@ -217,13 +217,37 @@ function mousedown(e, state, context) { } else if (state.tools.active === 'eraser') { state.erasing = true; } else if (state.tools.active === 'pointer') { - const image_event = image_at(context, canvasp.x, canvasp.y); + state.scaling_image = null; + + if (context.active_image !== null) { + // Resize image? + const image = get_image(context, context.active_image); + corner = image_corner(state, image, canvasp); + if (corner !== null) { + state.scaling_image = image.key; + state.scaling_corner = corner; + + document.querySelector('canvas').classList.remove('resize-topleft'); + document.querySelector('canvas').classList.remove('resize-topright'); + + if (corner === 0 || corner === 2) { + document.querySelector('canvas').classList.add('resize-topleft'); + } else if (corner === 1 || corner === 3) { + document.querySelector('canvas').classList.add('resize-topright'); + } + } + } - if (image_event) { - context.active_image = image_event.key; - state.moving_image = image_event.key; - } else { - context.active_image = null; + 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; + } else { + context.active_image = null; + } } schedule_draw(state, context); @@ -250,7 +274,25 @@ function mousemove(e, state, context) { const screenp = {'x': window.devicePixelRatio * e.clientX, 'y': window.devicePixelRatio * e.clientY}; 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); + const corner = image_corner(state, image, canvasp); + + if (state.scaling_corner === null) { + document.querySelector('canvas').classList.remove('resize-topleft'); + document.querySelector('canvas').classList.remove('resize-topright'); + + if (corner === 0 || corner === 2) { + document.querySelector('canvas').classList.add('resize-topleft'); + } else if (corner === 1 || corner === 3) { + document.querySelector('canvas').classList.add('resize-topright'); + } + } + } + } + if (state.me in state.players) { const me = state.players[state.me]; const width = Math.max(me.width * state.canvas.zoom, 2.0); @@ -308,6 +350,12 @@ function mousemove(e, state, context) { do_draw = true; } + if (state.scaling_image) { + const image = get_image(context, state.scaling_image); + scale_image(context, image, state.scaling_corner, canvasp); + do_draw = true; + } + if (state.moving_image) { const image = get_image(context, state.moving_image); @@ -371,6 +419,12 @@ function mouseup(e, state, context) { return; } + if (state.scaling_image) { + state.scaling_image = null; + state.scaling_corner = null; + return; + } + if (state.moving || e.button === 1) { state.moving = false; context.canvas.classList.remove('moving');