Skip to content

Instantly share code, notes, and snippets.

@louking
Last active November 5, 2017 20:46
Show Gist options
  • Save louking/5362898bf5ed4388fdd4120518d77a95 to your computer and use it in GitHub Desktop.
Save louking/5362898bf5ed4388fdd4120518d77a95 to your computer and use it in GitHub Desktop.
circles explode
license: apache-2.0
height: 500
scrolling: no
border: yes

Use d3.js to draw some circles. When circles are at same location there may be other attributes which are interesting about the overlapping circles. This is a method to separate those circles on the user interface to give the user separate handling.

circle {
fill: steelblue;
stroke: black;
stroke-width: 1.5px;
}
circle.handle {
fill: red;
}
var rcircle = 10, // r for circle
dexp = rcircle * 4, // distance for explosion
durt = 500, // transition duration (msec)
pi = Math.PI;
var t = d3.transition(durt);
var svg = d3.select("svg");
d3.json(
"circles.json",
function(error, data) {
if (error) throw error;
// showing general pattern from https://bl.ocks.org/mbostock/3808218 but in this case only enter() will be executed
// data join
var circle = svg.selectAll("circle").data(data);
// update
// nothing to do here
// enter
circle
.enter()
.append("circle")
.merge(circle)
.attr("r", rcircle)
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("cid", function(d) { return d.id; })
.attr("class", function(d) { return "c-loc-" + d.loc; })
.on("click", explodeData);
// exit
circle.exit().remove();
}
);
function explodeData(d, i) {
// Use D3 to select element and also all at same location
var thisc = d3.select(this);
var theselocs = d3.selectAll(".c-loc-" + d.loc)
var numlocs = theselocs.size();
// if only one at location, maybe there is some special processing
if (numlocs == 1) {
// handle single selection click
// multiple at location, explode
} else {
// if not selected yet, explode all in same loc
if (!thisc.attr("exploded")) {
theselocs.attr("exploded", true);
var cx = Number(thisc.attr("cx"));
var cy = Number(thisc.attr("cy"));
// create lines now so they're underneath
// x1 = x2, y1 = y2 initially because we'll be transitioning
theselocs.each(function (d,i) {
svg.append('line')
.attr("class", "l-loc-" + d.loc)
.attr("x1", cx)
.attr("y1", cy)
.attr("x2", cx)
.attr("y2", cy)
.attr("stroke-width", 1.5)
.attr("stroke", "black")
.transition(durt)
.attr("x2", cx + dexp * Math.cos((2*pi/numlocs)*i))
.attr("y2", cy + dexp * Math.sin((2*pi/numlocs)*i))
});
// create handle for original location
svg.append("circle")
.attr("id", "exploded-" + d.loc)
.attr("class", "handle")
.attr("c-loc", d.loc)
.attr("r", rcircle)
.attr("cx", cx)
.attr("cy", cy)
.on("click", unexplodeData);
// explode
theselocs
.each(function(d, i){
thisc = d3.select(this);
// move to end to obsure line
thisc.raise();
// transition to new location
thisc.transition(t)
.attr("cx", cx + dexp * Math.cos((2*pi/numlocs)*i))
.attr("cy", cy + dexp * Math.sin((2*pi/numlocs)*i));
});
// if exploded and individual selected, maybe there is some special processing
} else {
// handle single selection click
}
} // multiple at location
};
function unexplodeData(d, i) {
// Use D3 to select element
var thisc = d3.select(this);
var loc = thisc.attr("c-loc");
var cx = thisc.attr("cx");
var cy = thisc.attr("cy");
// set exploded circles to original state
d3.selectAll(".c-loc-" + loc)
.transition(t)
.attr("selected", null)
.attr("cx", cx)
.attr("cy", cy)
.attr("exploded", null);
// shrink lines
d3.selectAll(".l-loc-" + loc)
.transition(t)
.attr("x2", cx)
.attr("y2", cy)
.remove()
// remove handle
d3.select("#exploded-" + loc).remove();
};
[
{ "id":1, "loc":1, "x":140, "y":180 },
{ "id":2, "loc":1, "x":140, "y":180 },
{ "id":3, "loc":1, "x":140, "y":180 },
{ "id":4, "loc":1, "x":140, "y":180 },
{ "id":5, "loc":2, "x":520, "y":70 },
{ "id":6, "loc":2, "x":520, "y":70 },
{ "id":7, "loc":2, "x":520, "y":70 },
{ "id":8, "loc":2, "x":520, "y":70 },
{ "id":9, "loc":2, "x":520, "y":70 },
{ "id":10, "loc":2, "x":520, "y":70 }
]
<link href="circles.css" rel="stylesheet">
<svg width=720 height=250></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="circles.js"></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment