I'm implementing a pan-zoom functionality in JavaScript where users can pan and zoom an iframe. The implementation works well when the zoom level is above 0.5 (50%), but when zooming out below 0.5, the panning movement overshoots - meaning the content moves too far relative to the mouse movement.
Here's my current implementation for updating the panning position:
let translateX = 0;
let translateY = 0;
let scale = 100;
let isPanning = false;
let lastMouseX = 0;
let lastMouseY = 0;
function updatePanning(x, y) {
if (!isPanning) return;
const scaleValue = scale / 100; // scale is in percentage (e.g., 50 means 0.5)
const deltaX = x - lastMouseX;
const deltaY = y - lastMouseY;
// This works fine when scaleValue > 0.5, but overshoots when scaleValue < 0.5
translateX = translateX + deltaX / scaleValue;
translateY = translateY + deltaY / scaleValue;
lastMouseX = x;
lastMouseY = y;
applyTransform();
}
function applyTransform() {
const scaleValue = scale / 100;
wrapper.style.transform = `scale(${scaleValue}) translate(${translateX}px, ${translateY}px)`;
}
I'm using the CSS transform property with scale and translate. The panning calculation divides the mouse movement delta by the current scale to compensate for the scaling effect.
Why does this approach work correctly at scales above 0.5 but cause overshooting at lower scales? Is there a different formula I should be using for the coordinate transformation at very low zoom levels?
I've created a demo here: Use scrool to zoom and left mouse click to pan / or here
Any insights on how to make panning consistent across all zoom levels would be greatly appreciated.
I'm implementing a pan-zoom functionality in JavaScript where users can pan and zoom an iframe. The implementation works well when the zoom level is above 0.5 (50%), but when zooming out below 0.5, the panning movement overshoots - meaning the content moves too far relative to the mouse movement.
Here's my current implementation for updating the panning position:
let translateX = 0;
let translateY = 0;
let scale = 100;
let isPanning = false;
let lastMouseX = 0;
let lastMouseY = 0;
function updatePanning(x, y) {
if (!isPanning) return;
const scaleValue = scale / 100; // scale is in percentage (e.g., 50 means 0.5)
const deltaX = x - lastMouseX;
const deltaY = y - lastMouseY;
// This works fine when scaleValue > 0.5, but overshoots when scaleValue < 0.5
translateX = translateX + deltaX / scaleValue;
translateY = translateY + deltaY / scaleValue;
lastMouseX = x;
lastMouseY = y;
applyTransform();
}
function applyTransform() {
const scaleValue = scale / 100;
wrapper.style.transform = `scale(${scaleValue}) translate(${translateX}px, ${translateY}px)`;
}
I'm using the CSS transform property with scale and translate. The panning calculation divides the mouse movement delta by the current scale to compensate for the scaling effect.
Why does this approach work correctly at scales above 0.5 but cause overshooting at lower scales? Is there a different formula I should be using for the coordinate transformation at very low zoom levels?
I've created a demo here: Use scrool to zoom and left mouse click to pan https://jsfiddle/wgkptxsn/ or here https://codepen.io/wisegorilla/pen/WbNKeOR
Any insights on how to make panning consistent across all zoom levels would be greatly appreciated.
Share Improve this question asked Mar 24 at 23:59 Islam MohamedIslam Mohamed 911 silver badge11 bronze badges2 Answers
Reset to default 0Why does this approach work correctly at scales above 0.5 but cause overshooting at lower scales? Is there a different formula I should be using for the coordinate transformation at very low zoom levels?
That's because you're dividing the deltaX
and deltaY
by scaleValue
(where scaleValue is the scale expressed as a fraction). It means that as the scale decreases, the effective translation amount increases. It also overshooting because the translation exaggerated when zoomed out.
So you need to calculate the new translation based on the mouse movement. Update the mouse positions and apply the transformation. You can do it by changing your current code below..
From(current code)
// Changed from multiplication to division to account for scale inversion
translateX = translateX + deltaX / scaleValue;
translateY = translateY + deltaY / scaleValue;
lastMouseX = x;
lastMouseY = y;
applyTransform();
To(new code)
// Use raw deltas for translation
translateX += deltaX;
translateY += deltaY;
// Update mouse positions
lastMouseX = x;
lastMouseY = y;
// Then, apply the transformation
applyTransform();
Playground
Assume that
x = 400;
y = 200;
Scale = 40% //0.4
Then
const deltaX = x - lastMouseX;
Means
const deltaX = 400 - 0; //400
Which consequently means that:
translateX = translateX + deltaX / scaleValue;
Will render the result:
translateX = 0 + (400 / 0.4);
Which is
translateX = 0 + 1000; //1000
But if you change the scale to be 80% (higher than 50), so we have:
translateX = 0 + (400 / 0.8);
Which is
translateX = 0 + 500; //500
So, the lower the scale (i.e fraction) the bigger the translate value, and vice versa.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744223573a4563899.html
评论列表(0条)