<!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>Document</title>
<style>
.nodes g {
cursor: move;
}
.link-text text {
font-size: 14px;
fill: #000;
fill-opacity: 0;
}
.nodes text {
font-weight: 700;
}
.links {
stroke: #fff;
}
.links line {
stroke: #ddd;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width=1000;
var height=1000;
const data = {
nodes : [{name: "杭州",value:1193},
{name: "宁波",value:940.4},
{name: "绍兴",value:527.1},
{name: "嘉兴",value:540.1},
{name: "温州",value:957.3},
{name: "台州",value:662.3},
{name: "金华",value:705.1},
{name: "丽水",value:250.7},
{name: "衢州",value:227.6},
{name: "湖州",value:336.8},
{name: "舟山",value:115.8}
],
edges: [
// value越小距离越近
{source:0,target:9,relation:"杭湖线",value:200},{source:0,target:3,relation:"杭嘉线",value:200},
{source:0,target:2,relation:"杭绍线",value:200},{source:0,target:6,relation:"杭金线",value:200},
{source:0,target:8,relation:"杭衢线",value:200},{source:2,target:1,relation:"绍甬线",value:200},
{source:1,target:10,relation:"甬舟线",value:200},{source:8,target:7,relation:"衢丽线",value:200},
{source:2,target:5,relation:"绍台线",value:200},{source:2,target:6,relation:"绍金线",value:200},
{source:7,target:4,relation:"丽温线",value:200},{source:5,target:4,relation:"台温线",value:200}
]
}
//定义svg
var svg = d3.select('body')
.append('svg')
.attr("width",width)
.attr("height",height)
// 构建力导向图
let simulation = d3.forceSimulation(data.nodes)
// .force('collision',d3.forceCollide(function(d,i){
// return d.value/10;
// })
// .strength(0.9)
// .iterations(1)
.force('charge', d3.forceManyBody())
.force('link', d3
.forceLink()
.id(function(d,i){
return i;
})
.links(data.edges)
.distance(function(d){//每一边的长度
return d.value;
}))
// .force('x', d3.forceX(width / 2))
// .force('y', d3.forceY(height / 2))
.force('center', d3.forceCenter(width / 2, height / 2))
.on('tick', ticked)
//构建颜色比例尺
let z = d3.scaleOrdinal(d3.schemeCategory20)
//连接线
let link = svg.append('g')
.attr('class', 'links')
.selectAll('line')
.data(data.edges)
.enter()
.append('line')
//连接线上的文字
let linkText = svg.append('g')
.attr('class', 'link-text')
.selectAll('text')
.data(data.edges)
.enter()
.append('text')
.text(function(d) {
return d.relation
})
//画圆圈和上面的文字
let node = svg.append('g') // 画圆圈和文字
.attr('class', 'nodes')
.selectAll('g')
.data(data.nodes)
.enter()
.append('g')
.on('mouseover',function(d,i){
//显示连接线上的文字
linkText.style('fill-opacity', function(edges) {
if (edges.source === d || edges.target === d) {
return 1
}
})
//连线加粗
link.style('stroke-width', function(edges) {
if (edges.source === d || edges.target === d) {
return '2px'
}
})
.style('stroke', function(edges) {
if (edges.source === d || edges.target === d) {
return '#000'
}
})
})
.on('mouseout', function(d, i) {
//隐去连接线上的文字
linkText.style('fill-opacity', function(edges) {
if (edges.source === d || edges.target === d) {
return 0
}
})
//连接线减粗
link.style('stroke-width', function(edges) {
if (edges.source === d || edges.target === d) {
return '1px'
}
})
.style('stroke', function(edges) {
if (edges.source === d || edges.target === d) {
return '#ddd'
}
})
})
.call(
d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended)
)
//画节点
node.append('circle')
.attr("r", function(d,i){
return d.value/10;
})
.attr('fill', function(d, i) {
return z(i)
})
//节点上的文字
node.append('text')
.attr('fill', "black")
.attr('y', -20)
.attr('dy', '.71em')
.text(function(d) {
return d.name
})
function ticked() {
// 力导向图变化函数,让力学图不断更新
link
.attr('x1', function(d) {
return d.source.x
})
.attr('y1', function(d) {
return d.source.y
})
.attr('x2', function(d) {
return d.target.x
})
.attr('y2', function(d) {
return d.target.y
})
linkText
.attr('x', function(d) {
return (d.source.x + d.target.x) / 2
})
.attr('y', function(d) {
return (d.source.y + d.target.y) / 2
})
node.attr('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')'
})
}
//拖拽事件初始化函数
function dragstarted(d) {
if (!d3.event.active) {
simulation.alphaTarget(.2).restart()//衰减函数,使节点慢慢开始拖拽
}
d.fx = d.x
d.fy = d.y
}
function dragged(d) {
d.fx = d3.event.x
d.fy = d3.event.y
}
function dragended(d) {
if (!d3.event.active) {
simulation.alphaTarget(0)
}
d.fx = null
d.fy = null
}
</script>
</body>
</html>