JSFiddle - React, Tailwind, and code Playground

by cristiscu

HTML

<canvas id='canvas' width='300' height='300'></canvas>
    <div>
    <label>Circles   <input id='c' type='range' value='10' min='1'  max='100' step='1'></label><br />
    <label>Ratio     <input id='r' type='range' value='1'  min='.5' max='1.5' step='0.1'></label><br />
    <label>min radius<input id='a' type='range' value='1'  min='1' max='20'   step='1'></label><br />
    <label>max radius<input id='b' type='range' value='10' min='1' max='20'   step='1'></label>
    </div>
    <button onclick='draw()'>Draw</button>

CSS

canvas { background-color: white; }

JavaScript

// ===========================
// ancillary geometric classes
// ===========================
var Point = function (x, y)
{
    this.x = x;
    this.y = y;
}

Point.prototype = {
    dist: function (p) { return this.vect(p).norm(); },
    vect: function (p) { return new Point (p.x-this.x, p.y-this.y); },
    norm: function (p) { return Math.sqrt (this.x*this.x+this.y*this.y);},
    add : function (v) { return new Point (this.x + v.x, this.y + v.y);},
    mult: function (a) { return new Point (this.x * a, this.y * a);}
};
var Circle = function (radius, center)
{
    this.r = radius;
    this.c = center;
};

Circle.prototype = {
    surface:  function () { return Math.PI * this.r * this.r; },
    distance: function (circle) { return this.c.dist(circle.c) - this.r - circle.r; }
};


// =========================
// circle packer lives here!
// =========================
var Packer = function (circles, ratio)
{
    this.circles = circles;
    this.ratio   = ratio || 1;
    this.list = this.solve();
}

Packer.prototype = {
    // try to fit all circles into a rectangle of a given surface
    compute: function (surface)
    {
        // check if a circle is inside our rectangle
        function in_rect (radius, center)
        {
            if (center.x - radius < - w/2) return false;
            if (center.x + radius >   w/2) return false;
            if (center.y - radius < - h/2) return false;
            if (center.y + radius >   h/2) return false;
            return true;
        }
    
        // approximate a segment with an "infinite" radius circle
        function bounding_circle (x0, y0, x1, y1)
        {
            var xm = Math.abs ((x1-x0)*w);
            var ym = Math.abs ((y1-y0)*h);
            var m = xm > ym ? xm : ym;
            var theta = Math.asin(m/4/bounding_r);
            var r = bounding_r * Math.cos (theta);
            return new Circle (bounding_r, 
                new Point (r*(y0-y1)/2+(x0+x1)*w/4, 
                          ...