使用粘点进行放大缩小是我们在 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 变量:
当鼠标位于 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中文网其他相关文章!