public
Created

Space-filling with an arbitrary number of circles with predefined radii

  • Download Gist
gistfile1.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
/*
*
* Space-filling with circles
*
* Authors: Kris Van Bael.
* Small modifications by Louis Mullie.
*
*
* Usage:
*
* drawCircles(paper, circles, colors)
* - Paper is a Raphael Paper object.
* - Circles is an array of radii.
* - Colors is an array of colors.
*
* Example:
* var paper = Raphael(10, 50, 800, 600);
* var colors = ['#99cccc', '#99ccff', '#ff6633', '#cccc66'];
* var radii = [90, 50, 60, 100, 60, 40, 90, 50, 60, 100, 60, 40];
*
* drawCircles(paper, radii, colors);
*
* Requires Raphael (http://raphaeljs.com/).
*/
function createGrid(columns, rows, size) {
 
var grid = [];
var y = size / 2.0;
 
for (row = 0; row < rows; row++) {
var distanceFromTop = y;
var distanceFromBottom = height - y;
for (col = 0; col < columns; col++) {
var i = row * columns + col;
grid[i] = (distanceFromTop <  distanceFromBottom) ?
distanceFromTop : distanceFromBottom;
}
y += size;
}
 
var x = size / 2.0;
 
for (col = 0; col < columns; col++) {
var distanceFromLeft = x;
var distanceFromRight = width - x;
for (row = 0; row < rows; row++) {
var i = row * columns + col;
if (grid[i] > distanceFromLeft) {
grid[i] = distanceFromLeft;
}
if (grid[i] > distanceFromRight) { 
grid[i] = distanceFromRight;
}
}
x += size;
}
 
return grid;
 
}
 
function drawCircles(paper, circles, colors) {
var size = Math.sqrt(paper.width * paper.height / 1000);
var columns = Math.ceil(paper.width / size);
var rows = Math.ceil(paper.height / size);
var grid = createGrid(columns, rows, size);
var json = [];
circles = circles.sort().reverse();
for (circle = 0; circle < circles.length; circle++) {
 
// We assume circles are sorted large to small!
var radius = circles[circle];
 
// Find gridpoint with largest distance from anything
var i = 0;
var maxR = 0;
var maxC = 0;
var maxDist = grid[0];
 
for (row = 0; row < rows; row++) {
for (col = 0; col < columns; col++) {
if (maxDist < grid[i]) {
maxR = row;
maxC = col;
maxDist = grid[i];
}
i++;
}
}
 
var k = Math.random() * colors.length;
var c = colors[Math.floor(k)];
var x = size / 2.0 + maxC * size;
var y = size / 2.0 + maxR * size;
 
var offset = (maxDist - radius) / 2.0;
x += Math.random() * offset;
y += Math.random() * offset;
 
json.push({
type: "circle",
cx: x,
cy: y,
r: radius,
stroke: Raphael.rgb2hsb(c),
fill: '#ffffff'
});
 
// Update Distance array with new circle;
i = 0;
var yy = size / 2.0;
 
for (r = 0; r < rows; r++) {
 
var xx = size / 2.0;
 
for (c = 0; c < columns; c++) {
var d2 = (xx - x) * (xx - x) + (yy - y) * (yy - y);
var prev2 = grid[i] + radius;
prev2 *= prev2;
 
if (prev2 > d2) {
var d = Math.sqrt(d2) - radius;
if (grid[i] > d) {
grid[i] = d;
}
}
xx += size;
i++;
}
 
yy += size;
}
}
 
paper.add(json);
 
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.