mirror of https://github.com/node-red/node-red.git
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 experiencepan-zoom
parent
324ca52516
commit
95b750060f
|
|
@ -7,7 +7,7 @@ RED.view.zoomConstants = {
|
||||||
MAX_ZOOM: 2.0,
|
MAX_ZOOM: 2.0,
|
||||||
|
|
||||||
// Zoom step for keyboard/button controls
|
// Zoom step for keyboard/button controls
|
||||||
ZOOM_STEP: 0.1,
|
ZOOM_STEP: 0.2,
|
||||||
|
|
||||||
// Animation settings
|
// Animation settings
|
||||||
DEFAULT_ZOOM_DURATION: 125, // ms, faster animation
|
DEFAULT_ZOOM_DURATION: 125, // ms, faster animation
|
||||||
|
|
|
||||||
|
|
@ -763,11 +763,11 @@ RED.view = (function() {
|
||||||
'</span>')
|
'</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.popover.tooltip($("#red-ui-view-zoom-out"),RED._('actions.zoom-out'),'core:zoom-out');
|
||||||
$("#red-ui-view-zoom-zero").on("click", zoomZero);
|
$("#red-ui-view-zoom-zero").on("click", zoomZero);
|
||||||
RED.popover.tooltip($("#red-ui-view-zoom-zero"),RED._('actions.zoom-reset'),'core:zoom-reset');
|
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.popover.tooltip($("#red-ui-view-zoom-in"),RED._('actions.zoom-in'),'core:zoom-in');
|
||||||
$("#red-ui-view-zoom-fit").on("click", zoomToFitAll);
|
$("#red-ui-view-zoom-fit").on("click", zoomToFitAll);
|
||||||
RED.popover.tooltip($("#red-ui-view-zoom-fit"),RED._('actions.zoom-fit'),'core:zoom-fit');
|
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) {
|
function zoomIn(focalPoint) {
|
||||||
if (scaleFactor < RED.view.zoomConstants.MAX_ZOOM) {
|
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) {
|
function zoomOut(focalPoint) {
|
||||||
var minZoom = calculateMinZoom();
|
var minZoom = calculateMinZoom();
|
||||||
if (scaleFactor > minZoom) {
|
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() {
|
function zoomToFitAll() {
|
||||||
// Get all nodes in active workspace
|
// Get all nodes in active workspace
|
||||||
|
|
@ -2931,9 +2931,11 @@ RED.view = (function() {
|
||||||
|
|
||||||
|
|
||||||
function zoomView(factor, focalPoint) {
|
function zoomView(factor, focalPoint) {
|
||||||
|
console.log('=== ZOOM VIEW CALLED ===', 'factor:', factor, 'focalPoint:', focalPoint);
|
||||||
// Early return if scale factor isn't actually changing
|
// Early return if scale factor isn't actually changing
|
||||||
// This prevents focal point shifts when at zoom limits
|
// This prevents focal point shifts when at zoom limits
|
||||||
if (Math.abs(scaleFactor - factor) < 0.001) {
|
if (Math.abs(scaleFactor - factor) < 0.001) {
|
||||||
|
console.log('Zoom view SKIPPED - already at target zoom');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2960,8 +2962,10 @@ RED.view = (function() {
|
||||||
chart.scrollTop(center[1] * scaleFactor - focalPoint[1]);
|
chart.scrollTop(center[1] * scaleFactor - focalPoint[1]);
|
||||||
} else {
|
} else {
|
||||||
// Keep viewport center on the same workspace coordinates
|
// Keep viewport center on the same workspace coordinates
|
||||||
chart.scrollLeft(center[0] * scaleFactor - screenSize[0]/2);
|
var newScrollLeft = center[0] * scaleFactor - screenSize[0]/2;
|
||||||
chart.scrollTop(center[1] * scaleFactor - screenSize[1]/2);
|
var newScrollTop = center[1] * scaleFactor - screenSize[1]/2;
|
||||||
|
chart.scrollLeft(newScrollLeft);
|
||||||
|
chart.scrollTop(newScrollTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.view.navigator.resize();
|
RED.view.navigator.resize();
|
||||||
|
|
@ -3041,13 +3045,18 @@ RED.view = (function() {
|
||||||
chart.scrollLeft(newScrollPos[0]);
|
chart.scrollLeft(newScrollPos[0]);
|
||||||
chart.scrollTop(newScrollPos[1]);
|
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();
|
RED.view.navigator.resize();
|
||||||
redraw();
|
|
||||||
},
|
},
|
||||||
onEnd: function() {
|
onEnd: function() {
|
||||||
cancelInProgressAnimation = null;
|
cancelInProgressAnimation = null;
|
||||||
// Ensure scaleFactor is exactly the target to prevent precision issues
|
// Ensure scaleFactor is exactly the target to prevent precision issues
|
||||||
scaleFactor = targetFactor;
|
scaleFactor = targetFactor;
|
||||||
|
// Full redraw at the end to ensure everything is correct
|
||||||
|
redraw();
|
||||||
if (RED.settings.get("editor.view.view-store-zoom")) {
|
if (RED.settings.get("editor.view.view-store-zoom")) {
|
||||||
RED.settings.setLocal('zoom-level', targetFactor.toFixed(1));
|
RED.settings.setLocal('zoom-level', targetFactor.toFixed(1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue