日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

拓展阅读 —— G6 坐标系深度解析

發布時間:2024/5/7 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 拓展阅读 —— G6 坐标系深度解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在 G6 中,實例化圖時指定 container 字段指定了畫布 <Canvas></Canvas> 標簽的父容器。而 DOM 的坐標與真正繪制圖形時的坐標并不是同一套坐標系,這可能會使得如下場景中用戶指定坐標時產生困惑:

  • 在畫布上放置一個 position: absolute 的 DOM 元素,如 tooltip、 menu 等時:
    • 在鼠標點擊畫布上的位置放置;
    • 鼠標點擊節點時,在節點位置。
      上面問題在 graph 縮放、平移后更加凸顯。下面,我們將深度解析這些坐標之間的關系。

三個坐標系

首先,我們要知道 G6 中有三個坐標系:clientX/clientY、canvasX/canvasY、pointX/pointY。

clientX/clientY

相對于瀏覽器的坐標系,原點位于瀏覽器內容范圍的左上角(坐標系位置不隨滾動條變化)。如下兩圖中的 y 軸上頁面滾動(y-scroll)位置不同,但 clientX/clientY 坐標系的原點都在左上角。因而 Container DOM 的左上角的 clientX/clientY 不同,左圖 Container DOM 的左上角坐標為(100, 1000),右圖 Container DOM 的左上角坐標為(100, 200)。

canvasX/canvasY

Container DOM 的自身坐標系。假設示例化圖時設定 width 與 height 分別是 550 與 500:

const Graph = new G6.Graph({container: 'container',width: 550,height: 500 })

則下圖 Container DOM 的寬高即為 550*500。canvasX/canvsY 的原點在 Container DOM 的左上角,Container DOM 右下角的 canvasX/canvasY 坐標為(550,500)。

pointX/pointY

以上兩種坐標系均可理解為 DOM 相關的坐標,其取值均為整數。而在真正繪制圖形時,圖形是根據 pointX/pointY 定位的,即節點的 (x, y) 等都是與pointX/pointY 坐標系相對應的。圖的縮放、平移其實是整個 pointX/pointY 坐標系的縮放和平移。

三個坐標系的關系

上面描述比較抽象。下面我們通過具體例子,進一步了解三種坐標系的關系。

下面所有圖中,灰色的坐標系表示 clientX/clientY,藍色坐標系表示 canvasX/canvasY,紅色坐標系表示 pointX/pointY。灰、藍、紅色的虛線以及數字均是相應坐標系的標注。

圖無變換

下圖展示了當圖沒有縮放和平移,也就是說其變換矩陣 matrix 為單位矩陣時,三個坐標系的關系。可以看到 canvasX/canvasY 與 pointX/pointY 兩個坐標系是完全重合的,坐標軸尺度、原點位置完全一致。如下圖中樹圖根節點(黑點標注的)位置,其 canvasX/canvasY 和 pointX/pointY 坐標值是一樣的。而 clientX/clientY 的原點在瀏覽器內容左上角,黑點的 clientX/clientY 則需要加上 Container DOM 的左邊距和上邊距。

圖 1:圖無變換時的三種坐標系。

圖縮放

當圖被縮放:以 pointX/pointY 坐標系的原點為縮放中心,放大為原來的兩倍,即圖的變換矩陣 matrix 為:

matrix = 2 0 00 2 00 0 1

很容易想到,大部分圖可能會超出 Container DOM。

事實上,在縮放時,是在縮放 pointX/pointY 的整個坐標系。由于這個例子中縮放中心是 pointX/pointY 坐標系的原點,縮放兩倍即是 pointX/pointY 的 x 軸、y 軸的尺度變為原來的兩倍。打個比方,我們把 pointX/pointY 的 x 軸、y 軸看作兩根繩子,繩子上每隔 1cm 有標記 1、2、3、……這些標記就是 pointX/pointY 的坐標值,我們分別拽住繩子的一端,把它們分別沿正方向拉長一倍,那么相鄰標記之間的距離變成了 2cm 。

canvasX/canvasY 和 clientX/clientY 坐標系不隨圖的變換而變化。換句話說,在這種情況下,canvasX/canvasY 的 (90, 0) 對應的 pointX/pointY 坐標為 (45, 0) ,canvasX/canvasY 的 (0, 250) 對應的 pointX/pointY 坐標為 (0, 125) 。而 clientX/clientY 仍然是 canvasX/canvasY 加上 Container DOM 的左/上邊距。

圖 2:圖縮放變換時的三種坐標系。

可以看到上圖中,圖 1 中的樹圖根節點位置(黑點 A)的 canvasX/canvasY 和 clientX/clientY 坐標不變,仍然分別是 (90, 250) 和 (290, 350)。但由于 pointX/pointY 的坐標軸尺度發生了變化,所以它的 pointX/pointY 變為了 (45, 125)。而現在的根節點(黑點 B 標記)的繪制坐標不變,pointX/pointY 仍然是 (90, 250),但黑點 B 對應的 canvasX/canvasY 和 clientX/clientY 分別變為了 (180, 500),(380, 600)。

圖縮放 + 平移

當圖在上一節的基礎上再進行平移:把圖的左上角移動到 (50, 50) 的位置,即圖的變換矩陣 matrix 為:

matrix = 2 0 00 2 050 50 1

很容易想到,大部分圖可能會超出 Container DOM 且左上角為出現留白。

和上一節縮放相似,平移圖其實是在平移 pointX/pointY 的整個坐標系。打個比方,我們把 pointX/pointY 的 x 軸、y 軸看作兩根繩子,兩根繩子一起向右平移 50,向下平移 50。

canvasX/canvasY 和 clientX/clientY 坐標系不隨圖的變換而變化。換句話說,在這種情況下,canvasX/canvasY 的 (90, 0) 對應的 pointX/pointY 坐標為 ((90-50)/2=20, 0) ,canvasX/canvasY 的 (0, 250) 對應的 pointX/pointY 坐標為 (0, (250-50)/2=100) 。而 clientX/clientY 仍然是 canvasX/canvasY 加上 Container DOM 的左/上邊距。

圖 3:圖縮放+平移變換時的三種坐標系。

可以看到上圖中,圖 1 中的樹圖根節點位置(黑點 A)的 canvasX/canvasY 和 clientX/clientY 坐標不變,仍然分別是 (90, 250) 和 (290, 350)。但由于 pointX/pointY 的坐標軸尺度、原點發生了變化,所以它的 pointX/pointY 變為了 (20, 100)。而現在的根節點(黑點 B 標記)的繪制坐標不變,pointX/pointY 仍然是 (90, 250),但黑點 B 對應的 canvasX/canvasY 和 clientX/clientY 分別變為了 (230, 550),(430, 650)。

使用 API 進行轉換

了解了三種坐標系的含義后,我們有時需要通過相互轉換使用。首先,在 G6 的事件中,event 會包含當前鼠標操作位置的三種坐標值,它們的變量名與上述三種坐標系對應關系如下:

  • event.x, event.y => pointX/pointY;
  • event.canvasX, event.canvasY => canvasX/canvasY;
  • event.clientX, event.clientY => clientX/clientY。

可以發現后兩者的名字是直接對應的,我們只需要注意 event 中的 x 和 y 對應的是 pointX/pointY 坐標系即可。

getCanvasByPoint

將 pointX/pointY 坐標系的坐標值轉換為 canvasX/canvasY 的坐標值。

getPointByCanvas

將 canvasX/canvasY 坐標系的坐標值轉換為 pointX/pointY 的坐標值。

getClientByPoint

將 pointX/pointY 坐標系的坐標值轉換為 clientX/clientY 的坐標值。

getPointByClient

將 clientX/clientY 坐標系的坐標值轉換為 pointX/pointY 的坐標值。

可以發現 G6 的上述四個 API 都是圍繞 point,通過上面四個 API 可以進行組合從而使得 clientX/clientY 與 canvasX/canvasY 進行轉換:

  • clientX/clientY 轉 canvasX/canvasY:
const point = graph.getPointByClient(clientX, clientY) const canvasXY = graph.getCanvasByPoint(point.x, point.y);
  • canvasX/canvasY 轉 clientX/clientY:
const point = graph.getPointByCanvas(canvasX, canvasY) const clientXY = graph.getClientByPoint(point.x, point.y);

使用三種坐標系

本文開始時,我們提到了如下場景需要我們使用三種坐標系:

在畫布上放置一個 position: absolute 的懸浮 DOM 元素,如 tooltip、 menu 等時:

  • 在鼠標點擊畫布上的位置放置;
  • 鼠標點擊節點時,在節點位置。

如果使用了錯誤的坐標系來給定懸浮 DOM 元素的位置,將會出現偏移,在圖有縮放、平移等變化時,偏移更加嚴重。
在了解如何使用坐標系給懸浮 DOM 定位前,我們先定義一個懸浮 DOM 元素:

const floatDOM = createDom(`<div id="test-dom" style="position: absolute; background: #f00; height: 100px; width: 200px">floating dom</div>`);

不論上述哪一種情況,我們都推薦兩種掛載這個懸浮 DOM 的方式:

  • 方法一:掛載在 body 上:
document.body.appendChild(floatDOM);
  • 方法二:掛載在 Container DOM 上,即與 canvas 標簽同一父容器:
const container = document.getElementById('container') // 假設 Container DOM 的 id 為 container container.appendChild(floatDOM);

懸浮 DOM 掛載在 body 上

眾所周知,position: absolute 的 DOM 元素相對于父容器定位。若我們把懸浮 DOM 掛載在 body 上,它的父容器是 body,我們可以使用 clientX/clientY 來指定它的 left/top:

  • 在點擊畫布的位置上放置 DOM:
graph.on('canvas:click', event => {floatDOM.style.left = event.clientX;floatDOM.style.top = event.clientY; });
  • 在某個節點的位置上放置 DOM:
const node = graph.getNodes()[0]; const { x, y } = node.getModel(); // 獲得該節點的位置,對應 pointX/pointY 坐標 const clientXY = graph.getClientByPoint(x, y); floatDOM.style.left = clientXY.x; floatDOM.style.top = clientXY.y;

懸浮 DOM 掛載在 Container DOM 上

若我們把懸浮 DOM 掛載在 Container DOM 上,它的父容器是 Container DOM,我們可以使用 canvasX/canvasY 來指定它的 marginLeft/marginTop:

  • 在點擊畫布的位置上放置 DOM:
graph.on('canvas:click', event => {floatDOM.style.marginLeft = event.canvasX;floatDOM.style.marginTop = event.canvasY; });
  • 在某個節點的位置上放置 DOM:
const node = graph.getNodes()[0]; const { x, y } = node.getModel(); // 獲得該節點的位置,對應 pointX/pointY 坐標 const canvasXY = graph.getCanvasByPoint(x, y); floatDOM.style.marginLeft = canvasXY.x; floatDOM.style.marginTop = canvasXY.y; 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的拓展阅读 —— G6 坐标系深度解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。