前段时间因为参与项目涉密,所以一直没有更新博客,有些博友给我私信或者留言要部分博文的源码,因为我的电脑更换,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力导图绘制节点间多条关系平行线的方法
小结
本文主要写了下布局,拖拽,缩放一些基础方法的改变和使用。下篇将说一些最近调研的一些新玩意,包括文字加底色,线条加底色的方法。