问题描述
我无法在React应用程序中为节点链接图的强制布局实现更新模式。据我了解,该模式为join,exit,update,enter
,但显然我没有正确实现它。以下是指向沙盒的链接,其中包含一个复制问题的最小示例:https://codesandbox.io/s/sharp-moser-ubizi?file=/src/Chart.jsx:0-4867一些链接消失了,但是没有新节点进入,也没有节点退出。
基本上,每三秒钟,我要交换数据源并使用适当的节点链接更新svg。
这里是Chart Wrapper,它允许我在React应用程序中编写纯d3:
import React,{ useEffect,useRef,useState } from 'react';
import data from "./products";
import data2 from "./products2";
import Chart from './Chart';
import * as d3 from 'd3';
const ChartWrapper = () => {
const chartArea = useRef(null);
const [chart,setChart] = useState(null);
const [nodes,setNodes] = useState(data);
let flag = true;
useEffect(() => {
if (!chart)
setChart(new Chart(chartArea.current,nodes))
else {
chart.update(nodes);
}
},[nodes]);
d3.interval(() => {
let newNodes = flag ? data : data2
setNodes(newNodes);
flag = !flag
},3000)
return (<div className="chart-area" ref={chartArea}></div>)
}
export default ChartWrapper;
这是Chart class
,其中包含构造函数和update() function
。
import * as d3 from "d3";
import "./Chart.css";
const MARGIN = { TOP: 20,RIGHT: 20,BottOM: 20,LEFT: 20 };
const WIDTH = 400 - MARGIN.LEFT - MARGIN.RIGHT;
const HEIGHT = 400 - MARGIN.TOP - MARGIN.BottOM;
const AA_RED = "#cb3327";
const AA_BLUE = "#184485";
export default class Chart {
constructor(chartarea,data) {
const vis = this;
vis.data = data;
vis.svg = d3
.select(chartarea)
.append("svg")
.attr("width",WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
.attr("height",HEIGHT + MARGIN.BottOM + MARGIN.RIGHT)
.append("g")
.attr("transfrom",`translate(${MARGIN.LEFT},${MARGIN.RIGHT})`);
vis.link = vis.svg
.selectAll(".link")
.data(vis.data.links)
.enter()
.append("line")
.attr("class","link");
vis.force = d3
.forceSimulation(vis.data.nodes)
.force(
"link",d3
.forceLink()
.id(function (d) {
return d.name;
})
.strength(0.4)
.links(vis.data.links)
)
.force("charge",d3.forceManyBody().strength(-500))
.force("x",d3.forceX())
.force("y",d3.forceY())
.force("center",d3.forceCenter(WIDTH / 2,HEIGHT / 2))
.force(
"collision",d3
.forceCollide()
.radius((node) => {
return 50;
})
.iterations(3)
)
.on("tick",function () {
vis.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;
});
vis.node.attr("transform",function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
vis.node = vis.svg
.selectAll(".node")
.data(vis.data.nodes)
.enter()
.append("g")
.attr("class","node")
.call(
d3
.drag()
.on("start",dragstarted)
.on("drag",dragged)
.on("end",dragended)
);
vis.node
.append("circle")
.attr("r",(d) => {
return d.type === "application" ? 30 : 20;
})
.attr("fill",(d) => {
return d.type === "application" ? AA_RED : AA_BLUE;
});
vis.node
.append("text")
.attr("dx",(d) => {
return d.type === "application" ? -8 : 24;
})
.attr("dy",".35em")
.text(function (d) {
return d.name;
});
function dragstarted(event,d) {
if (!event.active) vis.force.alphaTarget(0.3).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) vis.force.alphaTarget(0);
d.fx = null;
d.fy = null;
}
}
update(data) {
const vis = this;
vis.data = data;
function dragstarted(event,d) {
if (!event.active) vis.force.alphaTarget(0);
d.fx = null;
d.fy = null;
}
//join
vis.node = vis.svg.selectAll(".node").data(vis.data.nodes);
vis.link = vis.svg.selectAll(".link").data(vis.data.links);
//exit
vis.node.exit().remove();
vis.link.exit().remove();
//update
vis.node
.append("circle")
.attr("r",(d) => {
return d.type === "application" ? AA_RED : AA_BLUE;
});
vis.link.append("line").attr("class","link");
//enter
vis.node = vis.node
.enter()
.append("g")
.attr("class",dragended)
);
vis.link = vis.link.enter().append("line").attr("class","link");
//restart simulation
vis.force
.nodes(vis.data.nodes)
.force(
"link",d3
.forceCollide()
.radius((node) => {
return 50;
})
.iterations(3)
)
.restart();
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)