Zoom-in zoom-out a sticky point in canvas

Zoom-in zoom-out with stick point is a regular use case we meet on design or builder tools such as Figma. In this blog, I will present a basic algorithm to handle it by javascript, HTML and CSS.

Demo

Demonstration

Code step-by-ste…


This content originally appeared on DEV Community and was authored by Dung Nguyen Thi Thuy

Zoom-in zoom-out with stick point is a regular use case we meet on design or builder tools such as Figma. In this blog, I will present a basic algorithm to handle it by javascript, HTML and CSS.

Demo

Demonstration

Code step-by-step

1. Create a container and a scalable item

<div id="app">
      <div class="parent">
        <div class="scalable-child"></div>
      </div>
</div>
.scalable-child {
  width: 300px;
  height: 300px;
  position: relative;
  top: 0;
  left: 0;
  pointer-events: none;
  transform-origin: left top;
  background-image: url('https://cdn4.vectorstock.com/i/1000x1000/17/58/caro-pattern-background-vector-2261758.jpg');
  background-size: contain;
}
.parent {
  position: relative;
  background-color: white;
  width: 100vw;
  height: 100vh;
}

In this example, I use an div as a scalable item with class “scalable-child” and its container is a div with class “parent”.
Please note for some properties:

  • Top, left: 0 is the default position

  • Pointer-event: none, because we will add event to parent, if pointer-event !== none the algorithm will be failed.

  • Transform-origin: left top, that makes coordinate origin to calculate the position

2. Add wheel event listener

const parent = document.querySelector('.parent');
const child = document.querySelector('.scalable-child');

parent.addEventListener('wheel', wheelEventHandler, {
  passive: false,
  capture: true,
});

We will use WheelEvent to handle zoom-in, zoom-out, and moving child

Note: this example demonstrates only for the trackpad. You need to handle events for hotkeys such as (Ctrl +, Ctr -) or mouse as well.

let left = 0;
let top = 0;
let scale = 1;

const wheelEventHandler = (e) => {
  e.preventDefault();
  // Handle zoom with touch pad and hot key.
  const isZooming = e.ctrlKey || e.metaKey;
  let newValues = {};
  if (isZooming) {
    newValues = calculateOnZooming(e, scale, left, top);
  } else {
    newValues = calculateOnMoving(e, scale, left, top);
  }

  left = newValues.newLeft;
  top = newValues.newTop;
  scale = newValues.newScale;

  Object.assign(child.style, {
    transform: `scale(${scale})`,
    left: `${left}px`,
    top: `${top}px`,
  });
};

Firstly, we have isZooming variable to check if zooming or moving the child element.

Then we calculate the new position and scale for the child element. Left, top, and scale are being used as temperate variables.

And it’s time to focus the algorithm on 2 calculate functions:

3. Calculate on Zooming

const calculateOnZooming = (e, oldScale, oldLeft, oldTop) => {
  let newScale = oldScale - e.deltaY * oldScale * 0.01;
  newScale = Math.max(newScale, 0.1);
  const newLeft = oldLeft - (e.offsetX - oldLeft) * (newScale / scale - 1);
  const newTop = oldTop - (e.offsetY - oldTop) * (newScale / scale - 1);
  return {
    newScale,
    newLeft,
    newTop,
  };
};

On zooming, wheelEvent will return the deltaY as a scale ratio and we can use it to calculate newScale

  • deltaY > 0 => zoom-out

  • deltaY < 0 => zoom-in
    The detalScale = e.deltaY * oldScale * 0.01 to control scaling speed

Let’s see the below image to more understand how to calculate the newLeft and newTop variables:

Image description
Start zooming-in child when mouse is in A point. At that time, we can get some values:

  • e.offsetX: distance between mouse to parent’s left edge

  • e.offsetY: distance between mouse to parent’s top edge

  • left: current child’s left style value

  • top: current child’s top style value

Child is scaled from scale ratio to scale’ ratio, and point A go to A’.
So to make A point sticky (with parent), we need to calculate deltaX and deltaY then move child revert with exactly px.

detalX = x’ - x
= x * (scale’ / scale) - x
= x * (scale’ / scale - 1)
= (e.offsetX - left) * (scale’ / scale - 1)

detalY = y’ - y
= y * (scale’ / scale) - y
= y * (scale’ / scale - 1)
= (e.offsetY - top) * (scale’ / scale - 1)

newLeft = left - detalX
newTop = top - detalY

4. Calculate on Moving

const calculateOnMoving = (e, oldScale, oldLeft, oldTop) => {
  return {
    newLeft: oldLeft - e.deltaX * 2,
    newTop: oldTop - e.deltaY * 2,
    newScale: oldScale,
  };
};

On moving event, we need to calculate only newLeft and newTop values. And we *2 each delta value to increase speed as well.

That’s all we need to handle. I hope it’s helpful. Thank you for watching!
You can view the full source code here.


This content originally appeared on DEV Community and was authored by Dung Nguyen Thi Thuy


Print Share Comment Cite Upload Translate Updates
APA

Dung Nguyen Thi Thuy | Sciencx (2024-06-24T14:45:15+00:00) Zoom-in zoom-out a sticky point in canvas. Retrieved from https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/

MLA
" » Zoom-in zoom-out a sticky point in canvas." Dung Nguyen Thi Thuy | Sciencx - Monday June 24, 2024, https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/
HARVARD
Dung Nguyen Thi Thuy | Sciencx Monday June 24, 2024 » Zoom-in zoom-out a sticky point in canvas., viewed ,<https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/>
VANCOUVER
Dung Nguyen Thi Thuy | Sciencx - » Zoom-in zoom-out a sticky point in canvas. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/
CHICAGO
" » Zoom-in zoom-out a sticky point in canvas." Dung Nguyen Thi Thuy | Sciencx - Accessed . https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/
IEEE
" » Zoom-in zoom-out a sticky point in canvas." Dung Nguyen Thi Thuy | Sciencx [Online]. Available: https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/. [Accessed: ]
rf:citation
» Zoom-in zoom-out a sticky point in canvas | Dung Nguyen Thi Thuy | Sciencx | https://www.scien.cx/2024/06/24/zoom-in-zoom-out-a-sticky-point-in-canvas/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.