首頁  >  文章  >  web前端  >  放大縮小畫布中的黏著點

放大縮小畫布中的黏著點

WBOY
WBOY原創
2024-07-18 05:56:57786瀏覽

使用黏點進行放大縮小是我們在 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 變數:

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