D3.js官网
一个小小的练习效果
效果图
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
svg{
border:1px solid #000;
}
</style>
</head>
<body>
<script>
// 定义画布大小
const width = 600;
const height = 600;
// 创建画布
const svg = d3
.select("body")
.append("svg")
.attr("id", "svg")
.attr("width", width)
.attr("height", height);
// .attr('border',"1px solid #000")
// 节点数据
const nodes = [{
index: 0,
name: "张三",
"fx": "225",
"fy": "225",
type: 'circle',
},
{
index: 1,
name: "李四",
"fx": "300",
"fy": "400",
type: 'circle',
},
{
type: 'circle',
name: "王二",
"fx": "300",
"fy": "100"
},
{
type: 'circle',
name: "小李",
"fx": "400",
"fy": "100"
},
{
type: 'circle',
name: "陈二",
"fx": "200",
"fy": "100"
},
{
name: "某人",
"fx": "300",
"fy": "200"
},
{
type: 'circle',
name: "小二",
"fx": "200",
"fy": "500"
},
{
type: 'diamond',
name: "郭靖",
"fx": "100",
"fy": "200"
}
];
// 节点关系 source 和 target 不能变
const links = [{
source: 0,
target: 1,
relation: "关系1"
},
{
source: 0,
target: 2,
relation: "关系2"
},
{
source: 0,
target: 3,
relation: "关系3"
},
{
source: 0,
target: 4,
relation: "关系4"
},
{
source: 0,
target: 5,
relation: "关系5"
},
{
source: 0,
target: 6,
relation: "关系6"
},
{
source: 0,
target: 7,
relation: "关系7"
}
];
// 随机颜色
const color = d3.scaleOrdinal(d3.schemeCategory10);
// 新建一个力导向图
let simulation = d3
.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-200)) // 电荷力 相互之间的作用力
.force("center", d3.forceCenter(width / 2, height / 2)) // 用指定的x坐标和y坐标创建一个居中力
.force("link", d3.forceLink(links).distance(200)) //
.on("tick", ticked);
let xy = simulation.find(50, 10)
// 画线
function drawLine() {
let lines = svg
.append("g")
.selectAll(".force-line")
.data(links)
.enter()
.append("line")
.attr("class", "line")
.attr("stroke", "#999")
.attr("stroke-width", "1px");
return lines;
}
let lines = drawLine();
// 画节点节点盒子
function drawCircle() {
let nodeGroups = svg
.append("g")
.attr("class", "nodes-box")
.selectAll(".force-node")
.data(nodes)
.enter()
.append("g")
.attr("class", "force-node")
.call(
d3.drag().on("start", started).on("drag", dragged).on("end", ended)
);
nodeGroups.select(function(d) {
console.log(d)
});
// 生成不同需求的图元
const even = nodeGroups.filter((d, i) => i % 2 == 0)
const sven = nodeGroups.filter((d, i) => i % 2 !== 0)
even
.append("circle")
.attr("class", "force-circle")
.attr("r", 20)
.style("fill", function(d, i) {
return color(i);
});
sven
.append("rect") //添加一个矩形
.attr("x", -25)
.attr("y", -25)
.attr("width", 50)
.attr("height", 50)
// .attr("fill","red")
.style("fill", function(d, i) {
return color(i);
});
nodeGroups
.append("text")
.attr("class", "force-text")
.attr("dy", ".33em")
.attr("font-size", "12px")
.attr("text-anchor", "middle")
.style("fill", "#eee")
.text(function(d) {
return d.name;
});
return nodeGroups;
}
let nodesCircle = drawCircle();
function ticked() {
lines
.attr("x1", (d) => {
return d.source.x;
})
.attr("y1", (d) => {
return d.source.y;
})
.attr("x2", (d) => {
return d.target.x;
})
.attr("y2", (d) => {
return d.target.y;
});
nodesCircle.attr("transform", function(d) {
// d.fx=d.x;d.fy=d.y; 固定位置
return "translate(" + d.fx + ", " + d.fy + ")";
});
}
// 拖拽
function started(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function ended(event) {
if (!event.active) simulation.alphaTarget(0);
// event.subject.fx = null;
// event.subject.fy = null;
}
// 创建一个缩放 ===========
var zoom = d3.zoom()
.scaleExtent([0.1 ,10])
.on('start',()=>{
console.log('start')
svg.style('cursor','pointer')
})
.on('zoom',(e)=>{
console.log(e)
svg.selectAll('g').attr('transform','translate('+ e.transform.x+','+e.transform.y +') scale('+ e.transform.k + ')')
// svg.selectAll('g').attr('transform','translate('+ e.transform.x+','+e.transform.y +') scale('+ e.transform.k + ')')
})
.on('end',()=>{
svg.style('cursor','default')
})
console.log(zoom)
svg.call(zoom).call(zoom.transform , d3.zoomIdentity.scale(1))
</script>
</body>
</html>