I am trying to create a single level circle packing (into a rectangle) solution for ChartJS aiming for the following
- tightly packed, making maximum use of the available space
- automatically scale radii to ensure all circles fit within the confines without clipping or overlapping (ideally able to define a minimum gap between them as well to allow for hover animations etc)
- have an affinity towards an arbitrary point (default the center of the rectangle)
currently I have put together the following code from my answer to an earlier question, but as it uses the older D3.js functionality it's probably not a good long term solution.
Is there a way to enhance this solution to use forceSimulation
to enhance the fidelity of the data that I can then feed to Chart.JS? From initial experiments with that I'm happy that there will be a short period of time where the circles 'settle' but I've been struggling with both the automatic scaling (that the older layout.pack
gave me) and knowing when the layout is 'good enough' to display.
Chart.JS is required for our particular use-case, and while D3.js seems like it can be leveraged for this I'm open to other solutions which accomplish the same goal (eg this sample which is fast but sadly doesn't take into account the clipping at the edges or apply any scaling to avoid overlap)
var w = document.getElementById("c").offsetWidth,
h = document.getElementById("c").offsetHeight;
// build random set of circles for the d3 packing
var data = {
"name": "root",
"children": []
}
for (var i = 1; i <= 15; i++) {
data["children"].push({
"name": i,
"size": Math.floor((Math.random() * 200) + 1)
})
}
// use D3 to pack into the canvas size, with a little bit of padding
var nodes = d3.layout.pack()
.value(function(d) {
return d.size;
})
.size([w, h])
.padding(4)
.nodes(data);
// Get rid of root node
nodes.shift();
// take the packed nodes data, and push to format ChartJS expects for bubbles
nodedata = [];
for (i = 0; i < nodes.length; i++) {
node = nodes[i]
nodedata.push({
"x": node.x,
"y": node.y,
"r": node.r
})
}
// create a bubble chart with no labels, border lines etc
var bubbleChart = new Chart(document.getElementById("cc"), {
type: 'bubble',
data: {
datasets: [{
data: nodedata,
backgroundColor: "rgba(212,121,212,1)"
}]
},
options: {
scales: {
x: {
ticks: {
display: false,
},
grid: {
display: false
},
border: {
display: false
}
},
y: {
display: false,
ticks: {
display: false,
},
grid: {
display: false,
},
border: {
display: false
}
}
},
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
}
}
});
#c {
border: 1px solid black;
width: 380px;
height: 280px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div id="c"><canvas id="cc"></canvas></div>