前段時間因為參與專案涉密,所以一直沒有更新部落格,有些博友給我私信或者留言要部分博文的原始碼,因為我的電腦更換,demo的原始碼沒有備份 所以無法提供。大家可針對具體問題問我,有空我定會回覆的。另外轉發文章請說明出處,謝謝關注!
之前有多篇博文介紹了d3力導向圖的繪製過程的一些問題,現在由於效能和UI的要求,要升級d3版本。因為v3版本現在使用的不多了,網上可找的資料不多且擴充性不好,因此花了點時間做了版本升級。
效果展示
初始化佈局
this.force = d3.forceSimulation(nodes)
.force('link', d3.forceLink(links).id(d => d.id).strength(0.6).distance(Math.floor(height / 4)))
.force('charge', d3.forceManyBody().strength(-500).distanceMin(50).distanceMax(400))
.force('center', d3.forceCenter())
.force('collision', d3.forceCollide().radius(50))
.velocityDecay(0.5)
基礎的配置,中文api裡說的很清楚,d3-force
容器建立
let circles = null; // circle元素集合
let lines = null; // line元素集合
let gContainer = null; // 所有元素容器
let gCircle = null; // circle元素容器
let gLine = null; // line元素容器
let svg = null;
......
svg = d3.select('#svgForce')
.append('svg')
.attr('class', 'svg__container')
.attr('viewBox', [-width / 2, -height / 2, width, height])
// g容器,存放其他元素
gContainer = svg
.append('g')
.attr('class', 'force__container')
.attr('transform', 'translate(' + 10 + ',' + 10 + ')');
// 容器
gLine = gContainer.append('g').attr('class', 'force__line');
gCircle = gContainer.append('g').attr('class', 'force__circle');
容器建立,區分線和節點,便於維護和處理
Zoom縮放(僅附上關鍵程式碼,不可貼上賦值直接實現哦~)
// zoom縮放
let zoom = d3.zoom()
.scaleExtent([0.5, 5])
.on('zoom', this.zoomed);
// 滑鼠放大縮小
zoomed () {
const transform = d3.event.transform;
d3.selectAll('.force__container').attr('transform', transform);
}
....
svg.call(zoom)
Drag拖拽
// 拖拽
let drag = d3.drag()
.on('start', d => {
if (!d3.event.active) this.force.alphaTarget(0.8).restart(); // 當alpha為0 設定值讓其動起來
d.fx = d.x;
d.fy = d.y;
})
.on('drag', d => {
d.fx = d3.event.x;
d.fy = d3.event.y;
d.drag = true;
this.force.force('center', null) // 允許隨意拖動
})
.on('end', d => {
if (!d3.event.active) this.force.alphaTarget(0); // 靜下來
})
circles = gCircle.selectAll('g')
.data(that.nodes, d => `circle${d.id}`)
.join('g')
.call(drag)
- d.fx 和 d.fy 表示設定拖拽固定的節點位置,如果想結束拽動後固定,需要在end中 刪除2個值~
- 拖拽函式:
start
,drag
和end
- 設定
this.force.force('center', null)
是讓節點隨著拖動的位置隨意飄動,不然你拽不走它的,它會被center的向心力吸引的
模擬tick
this.force.on('tick', () => {
circles.attr('transform', d => `translate(${d.x},${d.y})`);
lines.selectAll('path')
.attr('d', d => that.linkTick(d))
linkTick
是直線平行線的繪製方法,上篇博文有寫,d3力導圖繪製節點間多條關係平行線的方法
小結
本文主要寫了下佈局,拖拽,縮放一些基礎方法的改變和使用。下篇將說一些最近調研的一些新玩意,包括文字加底色,線條加底色的方法。