我有一个React组件,可以将节点添加到d3力图中。每当我添加一个节点时,其在基础数据中的位置都会通过仿真进行更新,但是直到添加下一个节点后,它的位置才会被直观地更新。有人能找出原因吗?
我制作了一个简单的示例来演示该问题,in this codesandbox也可以看到该示例:
import React from "react";
import shortid from "shortid";
import * as d3 from "d3";
const WIDTH = 500;
const HEIGHT = 500;
class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
nodes: [],
value: shortid(),
};
}
handleChange = event => {
this.setState({ value: event.target.value });
};
handleAddNode = event => {
event.preventDefault();
const newNodes = [...this.state.nodes, { id: this.state.value }];
this.setState({ nodes: newNodes, value: shortid() });
};
componentDidMount() {
this.initialise(this.state.nodes);
this.draw(this.state.nodes);
}
componentDidUpdate() {
this.draw(this.state.nodes);
}
initialise = nodes => {
const container = d3
.select(this.svg)
.attr("width", WIDTH)
.attr("height", HEIGHT)
.append("g")
.attr("class", "container")
.attr("transform", "translate(" + WIDTH / 2 + "," + HEIGHT / 2 + ")");
container.append("g").attr("class", "nodes");
this.simulation = d3
.forceSimulation(nodes)
.alphaDecay(0.2)
.force("charge", d3.forceManyBody())
.force("collide", d3.forceCollide().strength(1))
.on("tick", this.ticked);
};
draw = nodes => {
this.nodesSelection = d3
.select(".nodes")
.selectAll(".node")
.data(nodes);
this.nodesSelection
.enter()
.append("circle")
.attr("class", "node")
.attr("data-id", d => d.id)
.style("fill", "red")
.attr("r", 5);
this.simulation.nodes(nodes);
this.simulation.alpha(1).restart();
console.log(nodes);
};
ticked = () => {
this.nodesSelection.attr("cx", d => d.x).attr("cy", d => d.y);
};
render() {
return (
<div className="c-graph-container">
<form className="c-node-creator">
<div>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</div>
<button onClick={this.handleAddNode}>Add</button>
</form>
<svg ref={svg => (this.svg = svg)} className=".c-graph" />
</div>
);
}
}
export default Graph;
答案 0 :(得分:0)
正如安德鲁(Andrew)在评论中正确指出的那样,更新选择(this.nodesSelection)不包括回车选择(this.nodesSelection.enter())中的节点。由于选择是不可变的,因此除非重新选择或使用合并,否则更新选择在输入后不包含输入的节点。
所以我的解决方法是将选择行更改为:
this.nodesSelection = this.nodesSelection
.enter()
.append("circle")
.attr("class", "node")
.attr("data-id", d => d.id)
.style("fill", "red")
.attr("r", 5)
.merge(this.nodesSelection);