使用黏點進行放大縮小是我們在 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 變數來檢查是否縮放或移動子元素。
然後我們計算子元素的新位置和比例。 Left、top 和scale 被用作溫度變數。
現在該將演算法重點放在 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中文網其他相關文章!