diff --git a/client/default.css b/client/default.css index 0fcfa4b..c23c499 100644 --- a/client/default.css +++ b/client/default.css @@ -47,6 +47,7 @@ canvas.picker { cursor: url('icons/picker.svg') 0 19, crosshair; } +/* canvas.movemode { cursor: grab; } @@ -58,7 +59,7 @@ canvas.movemode.moving { canvas.mousemoving { cursor: move; } - +*/ .brush-dom { position: absolute; pointer-events: none; diff --git a/client/index.js b/client/index.js index 6b23fe6..0115db1 100644 --- a/client/index.js +++ b/client/index.js @@ -13,9 +13,9 @@ const config = { second_finger_timeout: 500, buffer_first_touchmoves: 5, debug_print: false, - zoom_delta: 0.15, - min_zoom_level: -75, - max_zoom_level: 20, + zoom_delta: 0.05, + min_zoom_level: -150, + max_zoom_level: 40, initial_offline_timeout: 1000, default_color: 0x00, default_width: 8, @@ -28,6 +28,7 @@ const config = { bvh_fullnode_depth: 5, pattern_fadeout_min: 0.3, pattern_fadeout_max: 0.75, + min_pressure: 50, benchmark: { zoom_level: -75, offset: { x: 425, y: -1195 }, @@ -171,6 +172,8 @@ async function main() { 'drawing': false, 'spacedown': false, 'colorpicking': false, + 'zooming': false, + 'zoomdown': false, 'moving_image': null, diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js index 8af79df..c4c0578 100644 --- a/client/webgl_geometry.js +++ b/client/webgl_geometry.js @@ -151,19 +151,14 @@ function recompute_dynamic_data(state, context) { context.dynamic_stroke_count = total_strokes; } -let _head = null; - -function geometry_add_point(state, context, player_id, point) { +function geometry_add_point(state, context, player_id, point, is_pen) { if (!state.online) return; - const points = state.players[player_id].points; + const player = state.players[player_id]; + const points = player.points; - if (false && points.length === 1) { - // Fix up pressure of first point to get rid of ugly spike bit - const first_point = points[0]; - if (first_point.pressure === 0) { - first_point.pressure = point.pressure; - } + if (point.pressure < config.min_pressure) { + point.pressure = config.min_pressure; } if (points.length > 0) { @@ -172,18 +167,22 @@ function geometry_add_point(state, context, player_id, point) { const streamline = 0.5; const t = 0.15 + (1 - streamline) * 0.85 const smooth_pressure = exponential_smoothing(points, point, 3); + points.push({ - 'x': _head.x * t + point.x * (1 - t), - 'y': _head.y * t + point.y * (1 - t), - 'pressure': _head.pressure * t + smooth_pressure * (1 - t), + 'x': player.dynamic_head.x * t + point.x * (1 - t), + 'y': player.dynamic_head.y * t + point.y * (1 - t), + 'pressure': is_pen ? player.dynamic_head.pressure * t + smooth_pressure * (1 - t) : point.pressure, }); - point.pressure = smooth_pressure; + + if (is_pen) { + point.pressure = smooth_pressure; + } } else { state.players[player_id].points.push(point); } recompute_dynamic_data(state, context); - _head = point; + player.dynamic_head = point; } function geometry_clear_player(state, context, player_id) { diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js index dfe4a3f..b00910c 100644 --- a/client/webgl_listeners.js +++ b/client/webgl_listeners.js @@ -145,6 +145,8 @@ function keydown(e, state, context) { enter_picker_mode(state, context); } else if (e.code === 'KeyD') { document.querySelector('.debug-window').classList.toggle('dhide'); + } else if (e.code === 'KeyZ') { + state.zoomdown = true; } } @@ -155,6 +157,8 @@ function keyup(e, state, context) { context.canvas.classList.remove('movemode'); } else if (e.code === 'ControlLeft' || e.code === 'ControlRight') { exit_picker_mode(state); + } else if (e.code === 'KeyZ') { + state.zoomdown = false; } } @@ -181,6 +185,12 @@ function mousedown(e, state, context) { return; } + if (state.zoomdown) { + state.zooming = true; + state.canvas.zoom_screenp = screenp; + return; + } + if (state.colorpicking) { const color_u32 = color_to_u32(state.color_picked.substring(1)); state.players[state.me].color = color_u32; @@ -264,6 +274,30 @@ function mousemove(e, state, context) { update_color_picker_color(state, context, canvasp); } + if (state.zooming) { + const zooming_in = e.movementY > 0; + const zooming_out = e.movementY < 0; + + let zoom_level = null; + + if (zooming_in) { + zoom_level = state.canvas.zoom_level + 1 + } else if (zooming_out) { + zoom_level = state.canvas.zoom_level - 1; + } else { + return; + } + + if (zoom_level < config.min_zoom_level || zoom_level > config.max_zoom_level) { + return; + } + + const dz = (zoom_level > 0 ? config.zoom_delta : -config.zoom_delta); + state.canvas.zoom_level = zoom_level; + state.canvas.target_zoom = Math.pow(1.0 + dz, Math.abs(zoom_level)) + + do_draw = true; + } if (state.moving) { state.canvas.offset.x += e.movementX; @@ -288,7 +322,7 @@ function mousemove(e, state, context) { if (state.drawing) { canvasp.pressure = Math.ceil(e.pressure * 255); - geometry_add_point(state, context, state.me, canvasp); + geometry_add_point(state, context, state.me, canvasp, e.pointerType === "pen"); fire_event(state, predraw_event(canvasp.x, canvasp.y)); do_draw = true; } @@ -321,6 +355,11 @@ function mouseup(e, state, context) { return; } + if (state.zooming) { + state.zooming = false; + return; + } + if (state.moving_image) { schedule_draw(state, context); queue_event(state, image_move_event(context.active_image, state.moving_image.x, state.moving_image.y)); @@ -395,7 +434,7 @@ function update_cursor(state) { function wheel(e, state, context) { const screenp = {'x': window.devicePixelRatio * e.clientX, 'y': window.devicePixelRatio * e.clientY}; const zooming_in = e.deltaY < 0; - const zoom_level = zooming_in ? state.canvas.zoom_level + 1 : state.canvas.zoom_level - 1; + const zoom_level = zooming_in ? state.canvas.zoom_level + 2 : state.canvas.zoom_level - 2; if (zoom_level < config.min_zoom_level || zoom_level > config.max_zoom_level) { return;