问题描述
下面的片段旨在模拟从 Web 服务中定期检索数据集(可能会更改)并将该数据合并到 d3 力导向图中。我将旧模拟节点对面的每个节点的位置和速度复制到新节点列表中,但是,每次重新启动模拟时,不紧靠 SVG 边界的节点都会略微向中心脉冲的图表。
如何避免这种影响?
function nodes() {
let nodes = {};
for (let ii = 0; ii <= 10; ii++) {
nodes[`${ii}`] = {
id: ii
};
}
return nodes;
}
function links(nodes) {
let links = {};
for (var a in Object.keys(nodes)) {
for (var b in Object.keys(nodes)) {
links[`${nodes[a].id}-${nodes[b].id}`] = {
id: `${nodes[a].id}-${nodes[b].id}`,source: `${nodes[a].id}`,target: `${nodes[b].id}`
};
}
}
return links;
}
let display = d3.selectAll("div");
var displaySize = display.node().getBoundingClientRect();
let r = 3;
let svg = display.append("svg");
let g = svg.append("g");
let node = g.selectAll("circle");
let link = g.selectAll("line");
function ticked() {
node.attr("cx",d => d.x)
.attr("cy",d => d.y);
link.attr("x1",d => d.source.x)
.attr("x2",d => d.target.x)
.attr("y1",d => d.source.y)
.attr("y2",d => d.target.y);
}
let simulation = d3.forceSimulation()
.force("charge",d3.forceManyBody().strength(-100))
.force("center",d3.forceCenter(displaySize.width / 2,displaySize.height / 2).strength(0.01))
.force("link",d3.forceLink()
.id(d => d.id)
.distance(5).strength(0.01))
.force("limit",d3.forceLimit()
.x0(r).y0(r).x1(displaySize.width - r).y1(displaySize.height - r))
.alphaMin(0.5)
.on("tick",ticked)
.on("end",update)
.stop();
let localNodes = {};
let localLinks = {};
function update() {
simulation.alpha(1).restart();
let nextNodes = nodes();
let nextLinks = links(nextNodes);
for (var ii in nextNodes) {
if (ii in localNodes) {
nextNodes[ii].vx = localNodes[ii].vx;
nextNodes[ii].vy = localNodes[ii].vy;
nextNodes[ii].x = localNodes[ii].x;
nextNodes[ii].y = localNodes[ii].y;
}
}
for (var ii in nextLinks) {
nextLinks[ii].target = nextNodes[nextLinks[ii].target];
nextLinks[ii].source = nextNodes[nextLinks[ii].source];
}
localNodes = nextNodes;
localLinks = nextLinks;
node = g.selectAll("circle")
.data(Object.values(localNodes),d => d.id)
.join("circle")
.attr("r",r);
link = g.selectAll("line")
.data(Object.values(localLinks),d => d.id)
.join("line");
simulation.nodes(Object.values(localNodes))
.force("link").links(Object.values(localLinks));
}
update();
simulation.alpha(1).restart();
circle {
stroke: #000;
fill: #000;
}
line {
stroke-width: 2px;
stroke: #000;
}
div {
position: relative;
width: 100%;
height: 90vh;
}
svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://unpkg.com/d3-force-limit@1.1.7/dist/d3-force-limit.min.js"></script>
<div></div>
解决方法
减少simulation.alpha() 值似乎减少了恒定脉冲。它仍然有运动,但比你原来的要少。这是你想要的吗?
function nodes() {
let nodes = {};
for (let ii = 0; ii <= 10; ii++) {
nodes[`${ii}`] = {
id: ii
};
}
return nodes;
}
function links(nodes) {
let links = {};
for (var a in Object.keys(nodes)) {
for (var b in Object.keys(nodes)) {
links[`${nodes[a].id}-${nodes[b].id}`] = {
id: `${nodes[a].id}-${nodes[b].id}`,source: `${nodes[a].id}`,target: `${nodes[b].id}`
};
}
}
return links;
}
let display = d3.selectAll("div");
var displaySize = display.node().getBoundingClientRect();
let r = 3;
let svg = display.append("svg");
let g = svg.append("g");
let node = g.selectAll("circle");
let link = g.selectAll("line");
function ticked() {
node.attr("cx",d => d.x)
.attr("cy",d => d.y);
link.attr("x1",d => d.source.x)
.attr("x2",d => d.target.x)
.attr("y1",d => d.source.y)
.attr("y2",d => d.target.y);
}
let simulation = d3.forceSimulation()
.force("charge",d3.forceManyBody().strength(-100))
.force("center",d3.forceCenter(displaySize.width / 2,displaySize.height / 2).strength(0.01))
.force("link",d3.forceLink()
.id(d => d.id)
.distance(5).strength(0.01))
.force("limit",d3.forceLimit()
.x0(r).y0(r).x1(displaySize.width - r).y1(displaySize.height - r))
.alphaMin(0.5)
.on("tick",ticked)
.on("end",update)
.stop();
let localNodes = {};
let localLinks = {};
function update() {
simulation.alpha(0.5).restart();
let nextNodes = nodes();
let nextLinks = links(nextNodes);
for (var ii in nextNodes) {
if (ii in localNodes) {
nextNodes[ii].vx = localNodes[ii].vx;
nextNodes[ii].vy = localNodes[ii].vy;
nextNodes[ii].x = localNodes[ii].x;
nextNodes[ii].y = localNodes[ii].y;
}
}
for (var ii in nextLinks) {
nextLinks[ii].target = nextNodes[nextLinks[ii].target];
nextLinks[ii].source = nextNodes[nextLinks[ii].source];
}
localNodes = nextNodes;
localLinks = nextLinks;
node = g.selectAll("circle")
.data(Object.values(localNodes),d => d.id)
.join("circle")
.attr("r",r);
link = g.selectAll("line")
.data(Object.values(localLinks),d => d.id)
.join("line");
simulation.nodes(Object.values(localNodes))
.force("link").links(Object.values(localLinks));
}
update();
simulation.alpha(0.5).restart();
circle {
stroke: #000;
fill: #000;
}
line {
stroke-width: 2px;
stroke: #000;
}
div {
position: relative;
width: 100%;
height: 90vh;
}
svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://unpkg.com/d3-force-limit@1.1.7/dist/d3-force-limit.min.js"></script>
<div></div>
减少更多会进一步减少图表的动能。您可以调整它,直到找到您喜欢的值。
function nodes() {
let nodes = {};
for (let ii = 0; ii <= 10; ii++) {
nodes[`${ii}`] = {
id: ii
};
}
return nodes;
}
function links(nodes) {
let links = {};
for (var a in Object.keys(nodes)) {
for (var b in Object.keys(nodes)) {
links[`${nodes[a].id}-${nodes[b].id}`] = {
id: `${nodes[a].id}-${nodes[b].id}`,update)
.stop();
let localNodes = {};
let localLinks = {};
function update() {
simulation.alpha(0.1).restart();
let nextNodes = nodes();
let nextLinks = links(nextNodes);
for (var ii in nextNodes) {
if (ii in localNodes) {
nextNodes[ii].vx = localNodes[ii].vx;
nextNodes[ii].vy = localNodes[ii].vy;
nextNodes[ii].x = localNodes[ii].x;
nextNodes[ii].y = localNodes[ii].y;
}
}
for (var ii in nextLinks) {
nextLinks[ii].target = nextNodes[nextLinks[ii].target];
nextLinks[ii].source = nextNodes[nextLinks[ii].source];
}
localNodes = nextNodes;
localLinks = nextLinks;
node = g.selectAll("circle")
.data(Object.values(localNodes),d => d.id)
.join("line");
simulation.nodes(Object.values(localNodes))
.force("link").links(Object.values(localLinks));
}
update();
simulation.alpha(0.1).restart();
circle {
stroke: #000;
fill: #000;
}
line {
stroke-width: 2px;
stroke: #000;
}
div {
position: relative;
width: 100%;
height: 90vh;
}
svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://unpkg.com/d3-force-limit@1.1.7/dist/d3-force-limit.min.js"></script>
<div></div>