Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
circle pack to fill any SVG shape
var _canvasProps = {width: 300, height: 300};
var _options = {spacing: 1, numCircles: 1000, minSize: 1, maxSize: 10, higherAccuracy: false};
var _placedCirclesArr = [];
var _isFilled = function (imgData, imageWidth, x, y) {
x = Math.round(x);
y = Math.round(y);
var a = imgData.data[((imageWidth * y) + x) * 4 + 3];
return a > 0;
};
var _isCircleInside = function (imgData, imageWidth, x, y, r) {
//if (!_isFilled(imgData, imageWidth, x, y)) return false;
//--use 4 points around circle as good enough approximation
if (!_isFilled(imgData, imageWidth, x, y - r)) return false;
if (!_isFilled(imgData, imageWidth, x, y + r)) return false;
if (!_isFilled(imgData, imageWidth, x + r, y)) return false;
if (!_isFilled(imgData, imageWidth, x - r, y)) return false;
if (_options.higherAccuracy) {
//--use another 4 points between the others as better approximation
var o = Math.cos(Math.PI / 4);
if (!_isFilled(imgData, imageWidth, x + o, y + o)) return false;
if (!_isFilled(imgData, imageWidth, x - o, y + o)) return false;
if (!_isFilled(imgData, imageWidth, x - o, y - o)) return false;
if (!_isFilled(imgData, imageWidth, x + o, y - o)) return false;
}
return true;
};
var _touchesPlacedCircle = function (x, y, r) {
return _placedCirclesArr.some(function (circle) {
return _dist(x, y, circle.x, circle.y) < circle.size + r + _options.spacing;//return true immediately if any match
});
};
var _dist = function (x1, y1, x2, y2) {
var a = x1 - x2;
var b = y1 - y2;
return Math.sqrt(a * a + b * b);
};
var _placeCircles = function (imgData) {
var i = _circles.length;
_placedCirclesArr = [];
while (i > 0) {
i--;
var circle = _circles[i];
var safety = 1000;
while (!circle.x && safety-- > 0) {
var x = Math.random() * _canvasProps.width;
var y = Math.random() * _canvasProps.height;
if (_isCircleInside(imgData, _canvasProps.width, x, y, circle.size)) {
if (!_touchesPlacedCircle(x, y, circle.size)) {
circle.x = x;
circle.y = y;
_placedCirclesArr.push(circle);
}
}
}
}
};
var _makeCircles = function () {
var circles = [];
for (var i = 0; i < _options.numCircles; i++) {
var circle = {
color: _colors[Math.round(Math.random() * _colors.length)],
size: _options.minSize + Math.random() * Math.random() * (_options.maxSize - _options.minSize) //do random twice to prefer more smaller ones
};
circles.push(circle);
}
circles.sort(function (a, b) {
return a.size - b.size;
});
return circles;
};
var _drawCircles = function (ctx) {
ctx.save();
$.each(_circles, function (i, circle) {
ctx.fillStyle = circle.color;
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.size, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill()
});
ctx.restore();
};
var _drawSvg = function (ctx, path, callback) {
var img = new Image(ctx);
img.onload = function () {
ctx.drawImage(img, 0, 0);
callback();
};
img.src = path;
};
var _colors = ['#993300', '#a5c916', '#00AA66', '#FF9900'];
var _circles = _makeCircles();
$(document).ready(function () {
var $canvas = $('<canvas>').attr(_canvasProps).appendTo('body');
var $canvas2 = $('<canvas>').attr(_canvasProps).appendTo('body');
var ctx = $canvas[0].getContext('2d');
_drawSvg(ctx, 'note.svg', function() {
var imgData = ctx.getImageData(0, 0, _canvasProps.width, _canvasProps.height);
_placeCircles(imgData);
_drawCircles($canvas2[0].getContext('2d'));
});
});
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Shape Circles</title>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<script src="circlePackShape.js"></script>
</body>
</html>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@smmsamm

This comment has been minimized.

Copy link

smmsamm commented May 1, 2019

Do you think How I use your libraries in adobe illustrator?
https://stackoverflow.com/questions/15746335/can-adobe-jsx-scripts-include-other-script-files

@smmsamm

This comment has been minimized.

Copy link

smmsamm commented May 1, 2019

Can you add some features for text packing for making wordcloud?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.