Fix zoom button animation and improve performance

- Fixed viewport jump to 0,0 by preventing click event from being passed as focal point
- Added smooth animation to zoom buttons and keyboard shortcuts (animatedZoomView)
- Doubled zoom step from 0.1 to 0.2 for faster zooming
- Optimized animation performance by only updating transforms during animation frames
- Fixed undefined variable issue (vis/gridScale -> eventLayer/outer)
- Full redraw only happens once at end of animation, eliminating jarring experience
pan-zoom
dimitrieh 2025-09-30 14:12:51 +02:00 committed by Nick O'Leary
parent 324ca52516
commit 95b750060f
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 19 additions and 10 deletions

View File

@ -7,7 +7,7 @@ RED.view.zoomConstants = {
MAX_ZOOM: 2.0,
// Zoom step for keyboard/button controls
ZOOM_STEP: 0.1,
ZOOM_STEP: 0.2,
// Animation settings
DEFAULT_ZOOM_DURATION: 125, // ms, faster animation

View File

@ -763,11 +763,11 @@ RED.view = (function() {
'</span>')
})
$("#red-ui-view-zoom-out").on("click", zoomOut);
$("#red-ui-view-zoom-out").on("click", function() { zoomOut(); });
RED.popover.tooltip($("#red-ui-view-zoom-out"),RED._('actions.zoom-out'),'core:zoom-out');
$("#red-ui-view-zoom-zero").on("click", zoomZero);
RED.popover.tooltip($("#red-ui-view-zoom-zero"),RED._('actions.zoom-reset'),'core:zoom-reset');
$("#red-ui-view-zoom-in").on("click", zoomIn);
$("#red-ui-view-zoom-in").on("click", function() { zoomIn(); });
RED.popover.tooltip($("#red-ui-view-zoom-in"),RED._('actions.zoom-in'),'core:zoom-in');
$("#red-ui-view-zoom-fit").on("click", zoomToFitAll);
RED.popover.tooltip($("#red-ui-view-zoom-fit"),RED._('actions.zoom-fit'),'core:zoom-fit');
@ -2847,16 +2847,16 @@ RED.view = (function() {
function zoomIn(focalPoint) {
if (scaleFactor < RED.view.zoomConstants.MAX_ZOOM) {
zoomView(scaleFactor + RED.view.zoomConstants.ZOOM_STEP, focalPoint);
animatedZoomView(scaleFactor + RED.view.zoomConstants.ZOOM_STEP, focalPoint);
}
}
function zoomOut(focalPoint) {
var minZoom = calculateMinZoom();
if (scaleFactor > minZoom) {
zoomView(Math.max(scaleFactor - RED.view.zoomConstants.ZOOM_STEP, minZoom), focalPoint);
animatedZoomView(Math.max(scaleFactor - RED.view.zoomConstants.ZOOM_STEP, minZoom), focalPoint);
}
}
function zoomZero() { zoomView(1); }
function zoomZero() { animatedZoomView(1); }
function zoomToFitAll() {
// Get all nodes in active workspace
@ -2931,9 +2931,11 @@ RED.view = (function() {
function zoomView(factor, focalPoint) {
console.log('=== ZOOM VIEW CALLED ===', 'factor:', factor, 'focalPoint:', focalPoint);
// Early return if scale factor isn't actually changing
// This prevents focal point shifts when at zoom limits
if (Math.abs(scaleFactor - factor) < 0.001) {
console.log('Zoom view SKIPPED - already at target zoom');
return;
}
@ -2960,8 +2962,10 @@ RED.view = (function() {
chart.scrollTop(center[1] * scaleFactor - focalPoint[1]);
} else {
// Keep viewport center on the same workspace coordinates
chart.scrollLeft(center[0] * scaleFactor - screenSize[0]/2);
chart.scrollTop(center[1] * scaleFactor - screenSize[1]/2);
var newScrollLeft = center[0] * scaleFactor - screenSize[0]/2;
var newScrollTop = center[1] * scaleFactor - screenSize[1]/2;
chart.scrollLeft(newScrollLeft);
chart.scrollTop(newScrollTop);
}
RED.view.navigator.resize();
@ -3041,13 +3045,18 @@ RED.view = (function() {
chart.scrollLeft(newScrollPos[0]);
chart.scrollTop(newScrollPos[1]);
// During animation, only update the scale transform, not the full redraw
// This is much more performant with many nodes
eventLayer.attr("transform", "scale(" + scaleFactor + ")");
outer.attr("width", space_width * scaleFactor).attr("height", space_height * scaleFactor);
RED.view.navigator.resize();
redraw();
},
onEnd: function() {
cancelInProgressAnimation = null;
// Ensure scaleFactor is exactly the target to prevent precision issues
scaleFactor = targetFactor;
// Full redraw at the end to ensure everything is correct
redraw();
if (RED.settings.get("editor.view.view-store-zoom")) {
RED.settings.setLocal('zoom-level', targetFactor.toFixed(1));
}