javascript - CSS transform: Pan overshoots when scale is below 0.5 but works fine above 0.5 - Stack Overflow

I'm implementing a pan-zoom functionality in JavaScript where users can pan and zoom an iframe. Th

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 badges
Add a comment  | 

2 Answers 2

Reset to default 0

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?

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条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信