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>