javascript - React + d3 力图不更新最后添加节点的位置
问题描述
我有一个 React 组件,可以让我将节点添加到 d3 力图。每当我添加一个节点时,它在基础数据中的位置都会被模拟更新,但它的位置不会在视觉上更新,直到添加下一个节点。有人能够发现为什么吗?
我制作了一个简化的示例来演示该问题,也可以在此代码框中看到:
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;
解决方案
正如 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);
推荐阅读
- python - Pandas 布尔索引以比较 DataFrame 和字典列表中的结果
- git - 双向合并 git 分支时跳过文件
- php - mysql PDO存储过程调用在php页面上执行失败
- javascript - net::ERR_FAILED 加载本地 .json 文件时?
- node.js - 如何在nodejs中制作视频以指定质量流式传输?
- javascript - 解决在 IE8 上运行 javascript reduce() 方法的兼容性问题
- javascript - 为什么这段代码会给出未定义的错误?firebase 云功能
- r - R:从数据中创建指标变量并提取类别
- python - 为什么我的函数中的参数不起作用?
- r - 更改必应词典中单词的值