本文主要实现了动力图中:
节点的显示;
节点与节点之间关系的连接,以及对应的关系类型的显示;
节点的拖拽;
图谱的缩放
1.先上效果:
2. 以下是完整的代码部分:
<template>
<div ref="chart" className="ggraph"></div>
</template>
<script>
import * as d3 from 'd3';
export default {
data() {
return {
nodes: [
{id: 1, name: '刘备', type: '皇上'},
{id: 2, name: '关羽', type: '将军'},
{id: 3, name: '张飞', type: '将军'},
{id: 4, name: '诸葛亮', type: '丞相'},
{id: 5, name: '小兵1', type: '士兵'},
{id: 6, name: '小兵2', type: '士兵'},
],
links: [
{source: 1, target: 2, relate: '将军'},
{source: 1, target: 3, relate: '将军'},
{source: 1, target: 4, relate: '丞相'},
{source: 2, target: 5, relate: '下属'},
{source: 2, target: 6, relate: '下属'},
{source: 3, target: 5, relate: '下属'},
]
};
},
mounted() {
this.drawChart();
},
methods: {
drawChart() {
const data = {
nodes: this.nodes,
links: this.links
};
const width = 600;
const height = 400;
// 创建SVG容器
const svg = d3.select(this.$refs.chart)
.append('svg')
.attr('width', width)
.attr('height', height);
const g = svg.append('g'); // 将 g 元素放在 svg 元素内部
// 创建力导向图模拟器
const simulation = d3.forceSimulation(data.nodes)
.force('link', d3.forceLink(data.links).id(d => d.id).distance(100))
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2));
// 创建边
const link = g.selectAll('line')
.data(data.links)
.enter()
.append('line')
.attr('stroke', '#999')
.attr('stroke-width', 2)
//创建节点
const node = g.selectAll('.node')
.data(data.nodes)
.enter()
.append('g')
.attr('class', 'node')
.style('fill', 'black');
node.append('circle')
.attr('r', 18)
.attr('fill', 'steelblue')
.style('fill', 'blue')
.call(d3.drag() //节点拖拽
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended));
//节点上面显示文字
node.append('text')
.text(d => d.name)
.attr('text-anchor', 'middle')
.attr('dy', 4)
.attr('font-size', d => Math.min(2 * d.radius, 20))
.attr('fill', 'black')
.style('pointer-events', 'none');
// 连线文字
const linkText = g.selectAll('.linktext')
.data(data.links)
.enter()
.append('text')
.attr('class', 'linktext')
.style('fill', 'black')
.style('font-size', 8)
.style('text-anchor', 'middle')
.text(d => d.relate)
.style('pointer-events', 'none');
// 缩放
svg.call(d3.zoom().on("zoom", function (event) {
g.attr("transform", event.transform);
}));
// 监听力导向图模拟器的tick事件,更新节点和边的位置
simulation
.on('tick', () => {
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
node.attr('transform', d => `translate(${d.x},${d.y})`);
// 更新连线文字的位置
linkText
.attr('x', d => (d.source.x + d.target.x) / 2)
.attr('y', d => (d.source.y + d.target.y) / 2);
});
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.5).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
}
}
};
</script>
<style>
svg {
background-color: #d1e9ff;
}
</style>
标签:vue,const,attr,js,source,data,d3,target
From: https://blog.csdn.net/m0_54479027/article/details/140440995