用D3.js进行图谱展示时连接线长度随节点大小动态变化的实现方式
問題起源:?用d3.js實現(xiàn)前端知識圖譜的展示,開始跟著視頻做了一個基本功能,但是節(jié)點的大小不能調整,于是做了一個大小調整的功能,即選中一個標簽,然后再選擇大小,從而實現(xiàn)讓節(jié)點根據(jù)類型的不同來變化,然后自己就嘗試做了一下,基本實現(xiàn)了選擇大小的功能,但是新的問題隨之而來,發(fā)現(xiàn)節(jié)點變大之后連接線很短,節(jié)點變小之后,連接線上的箭頭又距離節(jié)點很遠,原因在于原來節(jié)點間的連線是根據(jù)節(jié)點的圓心來連接的,箭頭的位置是按照一個固定的半徑大小進行偏移的,然后現(xiàn)在的節(jié)點的半徑是用戶可以隨意調節(jié)的大小,所以設置一個固定的偏移量自然不能隨著節(jié)點半徑的變化而變化了。
知道了問題所在,就來解決問題,開始一個直觀的思路是,讓箭頭的偏移量可以跟隨半徑的大小而變化,因為節(jié)點的半徑的改變就是用的這個思路,獲取到所有節(jié)點,然后遍歷每一個,判斷這個節(jié)點的類型是否有對應的用戶自定義量,如果有的話就用用戶自定義的,沒有就用默認的。但是問題是,箭頭的實現(xiàn)方式和節(jié)點的實現(xiàn)方式不同,節(jié)點的實現(xiàn)方式是每個節(jié)點是一個獨立的個體,然后用<g>包著可以遍歷每一個,但是箭頭是用了兩個<marker>就像模具,每個路徑引用這個模具,每個模具都是一模一樣的。所以沒有辦法遍歷每一個箭頭,而且箭頭偏移量和節(jié)點的類型之間也沒有關聯(lián),即使能夠遍歷也無法根據(jù)節(jié)點類型來動態(tài)調節(jié)偏移量。
后來在neo4j browser的前端代碼中找到了靈感,它在實現(xiàn)邊連線的時候,是用path在目的節(jié)點的與源節(jié)點的切點位置畫了一個箭頭,而不是用的圓心位置然后進行箭頭的偏移,所以就想到通過調整連線的起始位置,不讓path從圓心指向圓心的,而是連接兩個圓最接近的兩個點,這樣是不是就解決問題了,這樣問題的解決思路就從改變箭頭的偏移量變?yōu)楦淖冞B線的盡頭的位置,運動是相對的嘛,你不動,我就動。
有了這個思路,實現(xiàn)起來就比較容易了,用到的就是初中的幾何知識了。下面是代碼演示:
//給出源節(jié)點和目標節(jié)點,返回目標節(jié)點的邊上距離源節(jié)點最近的點的坐標getCoord(source, target) {//根據(jù)目標節(jié)點的類型,計算路徑的長度,讓路徑指向目標節(jié)點的邊,而不是圓心let r = 30;if (this.nodeSizeList.has(target.type)) {r = this.nodeSizeList.get(target.type);}let scale =r /Math.sqrt(Math.pow(target.y - source.y, 2) + Math.pow(target.x - source.x, 2));let targetX = target.x - scale * (target.x - source.x);let targetY = target.y - scale * (target.y - source.y);return targetX + " " + targetY;}最后是在實現(xiàn)上的幾個問題:
改變節(jié)點大小后,路徑的長度沒有更新
這是因為最后沒有觸發(fā)力導向圖的更新,這個需要最后restart()一下當目標節(jié)點在源節(jié)點左側的時候路徑離節(jié)點很遠,而目標節(jié)點在源節(jié)點右側的時候有看不到箭頭(實際上是因為箭頭的底部靠近了連線的終點。示意圖如下:
引發(fā)左右bug不一致的原因是源于路徑繪制時的一個問題:因為d3的機制,文字只會呈現(xiàn)在路徑的上方,所以當路徑是從右至左的時候,文字就會倒立起來,看起來奇怪,所以為了解決這個問題,因為路徑是從源節(jié)點指向目的節(jié)點的,所有目的節(jié)點出現(xiàn)在源節(jié)點的左邊,這個時候就會出現(xiàn)文字倒立的現(xiàn)象,這個時候就逆向思維讓目的節(jié)點指向源節(jié)點,這行路徑還是保持了自右至左,所以目的節(jié)點出現(xiàn)在源節(jié)點左側和右側的路徑繪制是不同的。
先說左側的bug,左側的路徑距離節(jié)點遠了,說明減多了,對于正常的情況,也就是目標節(jié)點在源節(jié)點右側的時候,是通過計算目標節(jié)點端應該縮短多少,因為箭頭是附在目標節(jié)點端的。但是對于目標節(jié)點出現(xiàn)在源節(jié)點左側的時候,這個時候我們將目標節(jié)點和源節(jié)點調換身份,左側的目標節(jié)點變?yōu)樵垂?jié)點,右側的源節(jié)點變?yōu)槟繕斯?jié)點,此時箭頭是附在“源節(jié)點”這一端的,所以應該縮短“源節(jié)點”端的長度,但是縮短的比例開始的時候是按目標端的半徑算的,所以開始的時候按目標端的比例去縮短源節(jié)點端就導致不匹配,驢唇對不上馬嘴。所以只計算一端的思路是滿足不了我們的需求的,所以就用一個函數(shù)來單獨計算坐標,分別計算兩端的坐標而不是只計算一端。
右側的bug,不是因為這個原因,右側path的計算是正確的,但是因為上圖示意的那個問題,所以讓箭頭偏移一個箭頭的位置,這樣就能露出來了
組件的地址如下,如果有需要的同學可以watch:
https://github.com/lzzlzz/Knowledge_grap
?
?
總結
以上是生活随笔為你收集整理的用D3.js进行图谱展示时连接线长度随节点大小动态变化的实现方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 9.0 rom定制化系列
- 下一篇: 凡科网JS逆向后跳出的滑块验证(base