Layouting Algorithm

by egon

HTML

<canvas id="view"></canvas>    
<script src="main.js"></script>

CSS

#view { background: #fff; }
body, html { background: #444; width: 100%; height: 100%; margin: 0px;}

JavaScript

var view = document.getElementById("view");
var context = view.getContext("2d");

var area = R(0,0,640,480).insetBy(5);

function rcolor(lightness){
  return 'hsla(' + (Math.random()*360|0) + ',70%,' + (lightness||70) + '%,0.8)';
}

function R(left, top, right, bottom){
  return {
    left:left, top:top||left, right:right||left, bottom:bottom||top||left,

    clone: function(){ return R(this.left, this.top, this.right, this.bottom); },

    get width(){ return this.right - this.left; },
    get height(){ return this.bottom - this.top; },
    get size(){ return {x: this.width, y: this.height}},
    // inset/outset by a single value
    insetBy: function(v){
      return R(this.left + v, this.top + v, this.right - v, this.bottom - v);
    },
    outsetBy: function(v){ return insetBy(-v); },
    // inset explicitly each side
    inset: function(sides){
      return R(this.left + sides.left, this.top + sides.top, this.right - sides.right, this.bottom - sides.bottom);
    },
    outset: function(sides){
      return R(this.left - sides.left, this.top - sides.top, this.right + sides.right, this.bottom + sides.bottom);
    },
    offset: function(p){
      return R(this.left + p.x, this.top + p.y, this.right + p.x, this.bottom + p.y);
    },
    stroke: function(context, color, lineWidth){
      context.lineWidth = lineWidth || 2;
      context.strokeStyle = color;
      context.beginPath();
      context.rect(this.left, this.top, this.right - this.left, this.bottom - this.top);
      context.closePath();
      context.stroke();
    },
    fill: function(context, color){
      context.fillStyle = color;
      context.fillRect(this.left, this.top, this.right - this.left, this.bottom - this.top);
    },
    toString: function(){
      return "[" + [this.left,this.top,this.right,this.bottom].join(", ") + "]";
    }
  };
}

function NewBlock(name, opts, children){
  var b = {
    name: name,
    color: rcolor(),
    size: { x:"100%", y:"100%" },
    position: "center",
   ...