Skip to content

Instantly share code, notes, and snippets.

@philipcdavis
Last active January 21, 2017 22:54
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 philipcdavis/86080a7d3d658f4e1ee3953410edd368 to your computer and use it in GitHub Desktop.
Save philipcdavis/86080a7d3d658f4e1ee3953410edd368 to your computer and use it in GitHub Desktop.
Mitchell's Best Candidate Bounded

Forked from Mike Bostock's example

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Heart</title>
</head>
<style>
canvas {
margin: 0 auto;
display: block;
}
</style>
<body>
<div id="chart"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script type="text/javascript">
var chart = d3.select("#chart");
var canvas = chart.append("canvas");
canvas.node().width = 1920;
canvas.node().height = 1000;
canvas.node().style.width = "960px";
canvas.node().style.height = "500px";
canvas.node().getContext('2d').scale(2,2);
var context = canvas.node().getContext("2d");
var heart = new Path2D("M240.438984,75.1180229 C213.906656,13.0479209 138.485199,27.5290591 138.001548,99.5711057 C137.727478,139.139685 173.916719,153.927901 198.010636,169.746443 C221.387137,185.100328 238.004604,206.070503 240.608262,215 C242.841121,206.248285 261.360952,184.667995 282.988245,169.31411 C306.634785,152.521808 343.271403,138.703311 342.997334,99.1387726 C342.485469,26.9189442 265.766213,15.5207045 240.438984,75.1180229 Z");
// forked from @mbostock's example
// https://bl.ocks.org/mbostock/6224050
var maxRadius = 15, // maximum radius of circle
padding = 5, // padding between circles; also minimum radius
margin = {top: -maxRadius, right: -maxRadius, bottom: -maxRadius, left: -maxRadius},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var k = 1, // initial number of candidates to consider per circle
m = 6, // initial number of circles to add per frame
n = 500, // remaining number of circles to add
newCircle = bestCircleGenerator(maxRadius, padding);
var timer = d3.timer(function(elapsed) {
if (elapsed > 1500) timer.stop();
for (var i = 0; i < m && --n >= 0; ++i) {
var circle = newCircle(k);
context.beginPath();
context.arc(circle[0], circle[1], circle[2], 0, 2 * Math.PI, false);
context.fillStyle = d3.interpolateOrRd(Math.random());
context.fill();
}
return !n;
});
function bestCircleGenerator(maxRadius, padding) {
var quadtree = d3.quadtree().extent([[0, 0], [width, height]]),
searchRadius = maxRadius * 2,
maxRadius2 = maxRadius * maxRadius;
return function(k) {
var bestX, bestY, bestDistance = 0;
for (var i = 0; i < k || bestDistance < padding; ++i) {
var x = Math.random() * width;
var y = Math.random() * height;
// Check if point is in the SVG path
if (!context.isPointInPath(heart, x, y)) {
do {
x = Math.random() * width;
y = Math.random() * height;
} while (!context.isPointInPath(heart, x, y))
}
var rx1 = x - searchRadius,
rx2 = x + searchRadius,
ry1 = y - searchRadius,
ry2 = y + searchRadius,
minDistance = maxRadius; // minimum distance for this candidate
quadtree.visit(function(node, x1, y1, x2, y2) {
if (p = node.data) {
var p,
dx = x - p[0],
dy = y - p[1],
d2 = dx * dx + dy * dy;
r2 = 10;
if (d2 < r2) return minDistance = 0, true; // within a circle
var d = Math.sqrt(d2) - p[2];
if (d < minDistance) minDistance = d;
}
return !minDistance || x1 > rx2 || x2 < rx1 || y1 > ry2 || y2 < ry1; // or outside search radius
});
if (minDistance > bestDistance) bestX = x, bestY = y, bestDistance = minDistance;
}
var best = [bestX, bestY, bestDistance - padding];
quadtree.add(best);
return best;
};
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment