Skip to content

Instantly share code, notes, and snippets.

@syntagmatic
Forked from mbostock/.block
Last active June 11, 2016 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syntagmatic/be8287ae3724e0c83c31273b20710496 to your computer and use it in GitHub Desktop.
Save syntagmatic/be8287ae3724e0c83c31273b20710496 to your computer and use it in GitHub Desktop.
Outer Tangent
license: gpl-3.0
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.circle {
fill-opacity: .1;
fill: #000;
stroke-opacity: .5;
stroke: #000;
stroke-width: 2px;
}
line {
stroke-opacity: .8;
stroke: #0b3;
stroke-width: 2px;
}
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
// Based on http://stackoverflow.com/a/12037737
function outerTangent(x1, y1, r1, x2, y2, r2) {
var dx = x2 - x1;
var dy = y2 - y1;
var dist = Math.sqrt(dx*dx + dy*dy);
if (dist <= Math.abs(r2-r1)) return; // no valid tangents
// Rotation from x-axis
var angle1 = Math.atan2(dy,dx);
var angle2 = Math.acos((r1 - r2)/dist);
return [
[
[x1 + r1 * Math.cos(angle1 + angle2), y1 + r1 * Math.sin(angle1 + angle2)],
[x2 + r2 * Math.cos(angle1 + angle2), y2 + r2 * Math.sin(angle1 + angle2)]
],
[
[x1 + r1 * Math.cos(angle1 - angle2), y1 + r1 * Math.sin(angle1 - angle2)],
[x2 + r2 * Math.cos(angle1 - angle2), y2 + r2 * Math.sin(angle1 - angle2)]
]
];
}
var c1 = {x: 180, y: 150, r: 10},
c2 = {x: 500, y: 200, r: 120};
var color = d3.scale.category10();
var svg = d3.select("svg");
var circle = svg.selectAll(".circle")
.data([c1, c2])
.enter().append("g")
.attr("class", "circle")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged));
circle.append("circle")
.attr("r", function(d) { return d.r; });
var tangent = svg.selectAll(".line")
.data([
function() { return outerTangent(c1.x, c1.y, +c1.r, c2.x, c2.y, +c2.r); },
])
.enter().insert("g", ".line")
.attr("class", "line")
.style("stroke", function(d, i) { return color(i); });
tangent.append("line")
.attr("class", "line-1");
tangent.append("line")
.attr("class", "line-2");
update();
function dragstarted(d) {
this.parentNode.appendChild(this);
}
function dragged(d) {
d3.select(this).attr("transform", "translate(" + (d.x = d3.event.x) + "," + (d.y = d3.event.y) + ")");
update();
}
function update() {
tangent.each(function(f) {
var c = f();
if (c) {
d3.select(this).style("display", null);
tangent.select(".line-1")
.attr("x1", c[0][0][0])
.attr("x2", c[0][1][0])
.attr("y1", c[0][0][1])
.attr("y2", c[0][1][1]);
tangent.select(".line-2")
.attr("x1", c[1][0][0])
.attr("x2", c[1][1][0])
.attr("y1", c[1][0][1])
.attr("y2", c[1][1][1]);
} else {
d3.select(this).style("display", "none");
}
});
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment