【发布时间】:2020-04-18 09:37:13
【问题描述】:
我找到了一个很好的 FD Graph 脚本,可以交互式地添加和删除节点,用 D3 v3 编写。 (见http://bl.ocks.org/tgk/6068367)。我试图将它移植到 v5,但它不起作用。我构建了以下脚本来比较两个版本。我找到的任何示例,只需切换链接数据(请参阅https://bl.ocks.org/colbenkharrl/21b3808492b93a21de841bc5ceac4e47),而不是节点数据。
谁能帮忙?
D3版本切换请看代码第34行!
<!DOCTYPE html>
<meta charset="utf-8">
<style>
html {
background-color: black;
}
svg {
background-color: white;
}
rect {
fill: none;
pointer-events: all;
}
.node {
fill: #000;
}
.cursor {
fill: none;
stroke: brown;
pointer-events: none;
}
.link {
stroke: #999;
}
</style>
<body>
<script>
let version = 5;
let loader = 'document.write("<' + 'script src=\\"https://d3js.org/d3.v' + version + '.min.js\\"></' +
'script>' +
'");';
eval(loader);
</script>
<script>
!(function () {
'use strict';
// - - - - - - - - - -
// 1. Global declaration
// - - - - - - - - - -
let
fill, simulation, svg, nodes, links, node, link, cursor,
i = false,
canvas = {},
dataset = {};
// Starting with an empty dataset
dataset.nodes = [{}];
dataset.links = [{}];
canvas = {
width: 800,
height: 400
};
// - - - - - - - - - -
// 2. Functions
// - - - - - - - - - -
// 2.1. Eventhandler functions
// - - - - - - - - - -
function onCanvasMousemove() {
cursor
.attr("transform", "translate(" + d3.mouse(this) + ")");
}
function onCanvasMousedown() {
let point = d3.mouse(this),
node = {
x: point[0],
y: point[1]
},
n = nodes.push(node);
// add links to any nearby nodes
nodes
.forEach(function (target) {
let x = target.x - node.x,
y = target.y - node.y;
if (Math.sqrt(x * x + y * y) < 30) {
links.push({
source: node,
target: target
});
}
});
restartSimulation();
}
function onNodeMousedown(d, i) {
nodes.splice(i, 1);
links = links.filter(function (l) {
return l.source !==
d && l.target !== d;
});
d3.event.stopPropagation();
restartSimulation();
}
function onTicked() {
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;
});
node
.attr("cx", function (d) {
if (i === false) {
console.log(typeof node);
console.log(typeof d);
i = true;
}
return d.x;
}).attr("cy", function (d) {
return d.y;
});
}
// - - - - - - - - - -
// 2.2 Setter functions
// - - - - - - - - - -
function setSvg() {
svg = d3.select("body")
.append("svg")
.attr("width", canvas.width)
.attr("height", canvas.height)
.on("mousemove", onCanvasMousemove)
.on("mousedown", onCanvasMousedown);
svg.append("rect")
.attr("width", canvas.width)
.attr("height", canvas.height);
}
function setCursor() {
// create the cursor
cursor = svg.append("circle")
.attr("r", 30)
.attr("transform", "translate(-100,-100)")
.attr("class", "cursor");
}
function setColorScheme() {
switch (version) {
case 3:
fill = d3.scale.category20();
break;
case 5:
d3.scaleOrdinal(d3.schemeCategory10);
break;
}
}
/** Create the force direction graph
*/
function setSimulation() {
switch (version) {
case 3:
simulation = d3.layout
.force()
.size([canvas.width, canvas.height])
.nodes(dataset.nodes) // ! data, initialize with a single node
.linkDistance(30)
.charge(-60)
.on("tick", onTicked);
break;
case 4:
case 5:
simulation = d3.forceSimulation()
.nodes(dataset.nodes)
.force('link', d3.forceLink().distance(30))
.force('charge',
d3.forceManyBody()
.strength(-60))
.force('center', d3.forceCenter(canvas.width / 2, canvas.height / 2))
.on('tick', onTicked);
break;
}
restartSimulation();
}
function restartSimulation() {
// - - - - - - - - - -
// NODES
// - - - - - - - - - -
switch (version) {
case 3:
node = svg.selectAll('.node');
nodes = simulation.nodes();
node = node.data(nodes);
node.exit().remove();
node.enter()
.insert("circle", ".cursor")
.attr("class", "node")
.attr("r", 5)
.on("mousedown", onNodeMousedown);
break;
case 4:
case 5:
node = svg.selectAll('.node');
nodes = simulation.nodes();
node = node.data(nodes);
node.exit().remove();
node.enter()
.insert("circle", ".cursor")
.attr("class", "node")
.attr("r", 5)
.merge(node)
.on("mousedown", onNodeMousedown);
break;
}
// - - - - - - - - - -
// LINKS
// - - - - - - - - - -
switch (version) {
case 3:
link = svg.selectAll('.link');
links = simulation.links();
link = link.data(links);
link.exit().remove();
link.enter()
.insert("line", ".node")
.attr("class", "link")
break;
case 4:
case 5:
links = svg.selectAll('.link')
link = link.data(links);
link.exit().remove();
link.enter()
.append("line", ".node")
.attr("class", "link")
.merge(link);
break;
}
switch (version) {
case
3:
simulation.start();
break;
case 5:
simulation.alphaTarget(0.3).restart();
break;
}
}
// - - - - - - - - - -
// 2.3 Control functions
// - - - - - - - - - -
function main() {
setSvg();
setSimulation();
setCursor();
setColorScheme();
}
function init() {
main();
};
// - - - - - - - - - -
// 3. Main control
// - - - - - - - - - -
window.addEventListener('load', init);
// - - - - - - - - - -
}())
</script>
【问题讨论】:
-
你好。你可以为你的问题创建一个 JS Fiddle/Codepen/Blockbuilder.org/Observable 示例吗?
-
你会在这里找到一个代码笔:codepen.io/zenbox/pen/wvBqxep。请参阅 HTML 的第 4 行以更改 D3 版本。
标签: d3.js force-layout