「AntV」x6 框選新增右鍵選單

2023-08-23 06:00:41

今天在群裡有個小夥伴提出了這麼個問題:如何在框選完成後給框選的區域新增一個右鍵選單的功能,我看到了這個問題後也是有點懵,心裡想著怎麼還有這個需求,直接快捷鍵刪除不是更好嗎,誰知這位小夥伴也是這麼寫的,奈何客戶要新增右鍵選單的功能,所以說,客戶最大。既然人家都提出這個需求呢,那就說明大概率情況下是可以做的,只是看自己想不想做了,下面我先來分析下我的思路,僅供參考,不過這個方案應該是能解決大部分的業務場景了

問題分析

  1. 框選完成?那就監聽框選完成的事件,這個官方是有對應的事件的
  2. 框選完成才會觸發右鍵?也就是說不框選是不能觸發右鍵事件的
  3. 即使前面兩個步驟都解決了,那我這個選單座標怎麼確定?第一個想到是框選的時候會有左右的邊界,就像如圖這樣,我是否可以根據這兩個邊界節點的座標去動態計算?第二個方法就是不加右鍵的功能,直接在框選的容器的右上角新增一個dom,把操作按鈕放在這裡面,通過滑鼠劃入來控制顯示和隱藏

  1. 但是從全域性的角度分析了下,發現第三個步驟複雜度有點大,不是說不能實現,而是沒有必要這麼做;就像你去跑800米,正常情況下我們都是貼著最內道跑,而你非要在最外道跑。而且沒有新增右鍵這個操作,不就滿足不了需求了嗎。
  2. 經過一輪分析後,決定還是來玩玩dom操作,因為只有dom是一直不變的,變的只是顯示隱藏而已,從理論上來說,我們是可以獲取到框選這個容器的dom範例的,然後再根據這個dom範例去觸發右鍵的事件,然後我在這個右鍵裡面新增我的業務操作不就行了嗎?開幹吧!

解決方法

步驟1

這裡為了保險起見,我給框選外掛的設定項新增了一個自定義的class類名,我可以根據我這個唯一的class去獲取框選的容器

步驟二

開始玩dom,先獲取到我自定義的這個class,然後再根據這個父級去獲取真正的框選容器(框選容器的class需要自行開啟瀏覽器的f12去找哈)

// 我自定義的class
const parent = document.getElementsByClassName('cu-selected-container')[0];
// 框選的容器
const selectInner = parent.getElementsByClassName('x6-widget-selection-inner')[0];
// 列印下看是個啥
console.log('seleeeee >>>', selectInner);

沒錯了,我獲取到了,看下圖

步驟三

經過前面兩個步驟的處理,步驟三就輕鬆多了,步驟三主要做的事情就是監聽框選完成的事件,看過官網的小夥伴都知道,官方大大給我們提供的事件還是挺多的事件,那小夥伴在這裡可能就犯嘀咕了,我到底該用哪個呢?其實吧,我覺得這裡用哪個事件更多取決你的業務場景,我這裡為了節約時間,就直接使用selection:changed這個事件了。
:::warning
Tip:如果你框選的節點個數是0的話需要特殊處理下,不然控制檯會報框選的容器不存在,我這裡是根據selected的長度進行判斷,不滿足條件直接提前返回
:::

graph.on('selection:changed', ({ selected }) => {
  if (selected.length === 0) return;
  const parent = document.getElementsByClassName('cu-selected-container')[0];
  const selectInner = parent.getElementsByClassName('x6-widget-selection-inner')[0];
  selectInner.style.pointerEvents = 'unset';
  console.log('seleeeee >>>', selectInner);
 selectInner.addEventListener('contextmenu', event => {
    event.preventDefault();
    alert(1);
  });
});

最後再看下效果吧,選單的內容後面我再更新吧……

步驟四

原以為到第三個步驟就結束了,沒想到還有個問題,就是我一直去框選,但是這期間我不去觸發右擊事件,直到最後我再右鍵,這時你再去點選alert的確定按鈕會發現完全關不掉,我想著完了完了,是不是進入死迴圈了?於是我就多實驗了幾次,發現這個alert的次數是和我框選的次數是有關聯的,於是就在想是哪裡除了問題,經過一番排查後發現是事件的問題,好像是每次框選完後沒有清空掉dom,於是我就從事件這裡下手解決,決定在觸發右鍵選單之前先移除一下右鍵的事件(排他法,不管你有沒有,先清空再說),果然問題得到了完美的解決


const handleContextMenu = event => {
  event.preventDefault();
  alert(1);
};
graph.on('selection:changed', ({ selected }) => {
  if (selected.length === 0) return;
  const parent = document.getElementsByClassName('cu-selected-container')[0];
  const selectInner = parent.getElementsByClassName('x6-widget-selection-inner')[0];
  selectInner.style.pointerEvents = 'unset';
  console.log('seleeeee >>>', selectInner);
  selectInner.removeEventListener('contextmenu', handleContextMenu);
  selectInner.addEventListener('contextmenu', handleContextMenu);
});

總結

問題分析很關鍵,程式碼只是個工具,具體怎麼走還是要我們自己去制定,所以在這一行待的時間久了,你會發現分析問題和關鍵時刻解決問題的能力是有多重要。順便講一下這個小功能我也是趁著下班前15分鐘搞出來的,如果我直接跳過分析問題的步驟,我估計到節後也不一定能想到解決方案。好了,這個小問題的總結就到這吧,有空再更新選單座標的問題的解決思路吧。