首页  >  文章  >  web前端  >  放大缩小画布中的粘着点

放大缩小画布中的粘着点

WBOY
WBOY原创
2024-07-18 05:56:57908浏览

使用粘点进行放大缩小是我们在 Figma 等设计或构建工具上遇到的常规用例。在这篇博客中,我将介绍一个通过 javascript、HTML 和 CSS 处理它的基本算法。

演示

示范

代码一步一步

1。创建一个容器和一个可扩展项目

<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;
}

在此示例中,我使用 div 作为类为“scalable-child”的可扩展项目,其容器是类为“parent”的 div。
请注意某些属性:

  • 上、左:0 是默认位置

  • Pointer-event:none,因为我们会将事件添加到父级,如果pointer-event !== none,算法将失败。

  • Transform-origin:左上,以坐标原点计算位置

2。添加滚轮事件监听

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

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

我们将使用 WheelEvent 来处理放大、缩小和移动子项

注意:此示例仅针对触控板进行演示。您还需要处理热键(Ctrl +、Ctr -)或鼠标的事件。

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`,
  });
};

首先,我们有 isZooming 变量来检查是否缩放或移动子元素。

然后我们计算子元素的新位置和比例。左、上和比例被用作温度变量。

现在该将算法重点放在 2 个计算函数上:

3。缩放计算

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,
  };
};

缩放时,wheelEvent 将返回 deltaY 作为比例,我们可以用它来计算 newScale

  • deltaY > 0 =>缩小

  • deltaY 放大
    detalScale = e.deltaY * oldScale * 0.01 控制缩放速度

让我们看下图来更多地了解如何计算 newLeft 和 newTop 变量:

Image description
当鼠标位于 A 点时开始放大子项。这时,我们可以得到一些值:

  • e.offsetX:鼠标到父级左边缘之间的距离

  • e.offsetY:鼠标到父级上边缘之间的距离

  • left:当前孩子的左样式值

  • top:当前孩子的顶级样式值

子级从比例缩放到比例'比例,A点转到A'。
因此,为了使 A 点具有粘性(与父点),我们需要计算 deltaX 和 deltaY,然后以精确的 px 移动子点恢复。

detalX = x’ - x
= x * (比例’ / 比例) - x
= x * (比例’ / 比例 - 1)
= (e.offsetX - 左) * (scale’/scale - 1)

detalY = y’ - y
= y * (比例’ / 比例) - y
= y * (尺度' / 尺度 - 1)
= (e.offsetY - 顶部) * (scale’/scale - 1)

newLeft = 左 - detalX
newTop = 顶部 - detalY

4。搬家计算

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

在移动事件中,我们只需要计算 newLeft 和 newTop 值。我们还 *2 每个增量值来提高速度。

这就是我们需要处理的一切。我希望它有帮助。感谢您的观看!
您可以在此处查看完整的源代码。

以上是放大缩小画布中的粘着点的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn