поэтому в React я копирую и вставляю элемент пузырьковой диаграммы d3, не зная слишком много о реакции. Я ввожу данные в пузырьковую диаграмму со своими собственными данными json. Когда я запускаю его, он выдает «не могу читать из неопределенного» из-за d.data.Name.substring (0, d.r / 3). Мне кажется, что я неправильно определяю свой объект json (d3.hierachy и некоторые функции, похоже, запрашивают детей или что-то в этом роде), вот мои коды:
RoadmapList.json:
[
{
"Name": "Computer Science",
"Count": 4156
},
{
"Name": "Home Economics",
"Count": 689
},
{
"Name": "Venture Capital Investment",
"Count": 890
},
{
"Name": "Fabric design",
"Count": 167
},
{
"Name": "Deep Learning Researchers",
"Count": 812
}
]
А в Bubble.js, моем компоненте пузырьковой диаграммы, кстати, когда я использую состояния, он работает, но поскольку мне нужно динамическое обновление, я использую this.props.roadmapdata
Bubble.js:
import React, { Component } from "react";
import * as d3 from "d3";
class Bubble extends Component {
constructor(props) {
super(props);
}
componentWillReceiveProps(nextProps) {
d3.select("nodes").remove("nodes");
var diameter = 600;
var color = d3.scaleOrdinal(d3.schemeCategory10);
var bubble = d3
.pack(this.props.RoadmapData)
.size([diameter, diameter])
.padding(1.5);
var svg = d3
.select("body")
.append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
var node = svg
.selectAll(".node")
.data(this.props.RoadmapData)
.enter()
.filter(function(d) {
return !d.children;
})
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title").text(function(d) {
return d.Name + ": " + d.Count;
});
node
.append("circle")
.attr("r", function(d) {
return d.r;
})
.style("fill", function(d, i) {
return color(i);
});
node
.append("text")
.attr("dy", ".2em")
.style("text-anchor", "middle")
.text(function(d) {
return d.data.Name.substring(0, d.r / 3);
})
.attr("font-family", "sans-serif")
.attr("font-size", function(d) {
return d.r / 5;
})
.attr("fill", "white");
node
.append("text")
.attr("dy", "1.3em")
.style("text-anchor", "middle")
.text(function(d) {
return d.data.Count;
})
.attr("font-family", "Gill Sans", "Gill Sans MT")
.attr("font-size", function(d) {
return d.r / 5;
})
.attr("fill", "white");
}
render() {
return <div>{this.node}</div>;
}
}
export default Bubble;
Благодарность!





Вот пример использования пузырьковой диаграммы и реакции с использованием d3.packSiblings.
Элемент <svg> имеет ссылка, поэтому, когда компонент смонтирован, вы можете использовать d3 для создания / обновления / удаления элементов.
Примечание:
dataForPacking - это просто карта для создания атрибутов, требуемых для упаковки d3, таких как, r, x, z, затем имя ваших данных, количество.
Есть поле ввода, чтобы проиллюстрировать, как setState обновляет исходные данные реквизита новыми данными и повторно отображает пузырек. Есть много способов сделать это лучше, но это хорошее начало.
const dataJSON = [
{
Name: "Computer Science",
Count: 4156
},
{
Name: "Home Economics",
Count: 689
},
{
Name: "Venture Capital Investment",
Count: 890
},
{
Name: "Fabric design",
Count: 167
},
{
Name: "Deep Learning Researchers",
Count: 812
}
];
const dataForPacking = (data) => {
return {
r: data.Count,
x: 0,
y: 0,
Count: data.Count,
Name: data.Name
};
};
class Bubble extends React.Component {
constructor(props) {
super(props);
this.state = {
width: this.props.size[0],
height: this.props.size[1],
data: this.props.data
};
this.svgRef = React.createRef();
this.drawBubble = this.drawBubble.bind(this);
}
componentDidMount() {
this.drawBubble()
}
componentDidUpdate() {
this.drawBubble()
}
drawBubble = () => {
const svg = d3.select(this.svgRef.current);
svg.select("g").remove();
const diameter = 600;
const color = d3.scaleOrdinal(d3.schemeCategory10);
const circles = svg
.append("g")
.attr("class", "circles")
.attr(
"transform",
`translate(${this.state.width / 2},
${this.state.height / 2})scale(0.02)`
);
const node = circles
.selectAll(".node")
.data(d3.packSiblings(this.state.data))
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title").text(function(d) {
return d.Name + ": " + d.Count;
});
node
.append("circle")
.attr("r", function(d) {
return d.r;
})
.style("fill", function(d, i) {
return color(i);
});
node
.append("text")
.attr("dy", ".2em")
.style("text-anchor", "middle")
.text(function(d) {
return d.Name.substring(0, d.r / 3);
})
.attr("font-family", "sans-serif")
.attr("font-size", function(d) {
return d.r / 5;
})
.attr("fill", "white");
node
.append("text")
.attr("dy", "1.3em")
.style("text-anchor", "middle")
.text(function(d) {
return d.Count;
})
.attr("font-family", "Gill Sans", "Gill Sans MT")
.attr("font-size", function(d) {
return d.r / 5;
})
.attr("fill", "white");
};
keyPress = event => {
if (event.key === "Enter") {
const newDataArray = event.currentTarget.value.split(",");
if (!newDataArray[1] || isNaN(newDataArray[1])){
return;
}
const newData = {
Name: newDataArray[0],
Count: Number(newDataArray[1])
};
this.setState(prevState => ({
data: [...prevState.data, dataForPacking(newData)]
}))
event.currentTarget.value = "";
}
};
reset = () => {
this.setState(prevState => ({
data: this.props.data.map(e => dataForPacking(e))
}))
};
render() {
return (
<div>
<span>Name, Count </span>
<input type = "text" onKeyPress = {this.keyPress} />
<button onClick = {this.reset}>reset</button>
<svg
ref = {this.svgRef}
width = {this.props.size[0]}
height = {this.props.size[1]}
/>
</div>
);
}
}
ReactDOM.render(
<Bubble data = {dataJSON.map(e=> dataForPacking(e))} size = {[600, 200]} />,
document.getElementById("app")
);<script src = "https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0/umd/react-dom.production.min.js"></script>
<div id = "app"><div>
Спасибо, cal_br_mar, сегодня днем реализую это решение!