Imperfect Rectangles

to generate a new and unique variation

Source Code

Every variart piece is open source, you can see exactly how it is drawn from the code.

// adapted from http://rectangleworld.com/blog/archives/443

var colors = [];

var displayWidth = width;
var displayHeight = height;

function setLinePoints(iterations) {
  var pointList = {};
  pointList.first = {x:0, y:1};
  var lastPoint = {x:1, y:1}
  var minY = 1;
  var maxY = 1;
  var point;
  var nextPoint;
  var dx, newX, newY;
  var ratio;
  
  var minRatio = 0.33;
  
  pointList.first.next = lastPoint;
  for (var i = 0; i < iterations; i++) {
    point = pointList.first;
    while (point.next != null) {
      nextPoint = point.next;
      
      ratio = minRatio + Math.random()*(1 - 2*minRatio);
      newX = point.x + ratio*(nextPoint.x - point.x);
      
      //find the smaller interval
      if (ratio < 0.5) {
        dx = newX - point.x;
      }
      else {
        dx = nextPoint.x - newX;
      }
      
      newY = point.y + ratio*(nextPoint.y - point.y);
      newY += dx*(Math.random()*2 - 1);
      
      var newPoint = {x:newX, y:newY};
      
      //min, max
      if (newY < minY) {
        minY = newY;
      }
      else if (newY > maxY) {
        maxY = newY;
      }
      
      //put between points
      newPoint.next = nextPoint;
      point.next = newPoint;
      
      point = nextPoint;
    }
  }
  
  //normalize to values between 0 and 1
  if (maxY != minY) {
    var normalizeRate = 1/(maxY - minY);
    point = pointList.first;
    while (point != null) {
      point.y = normalizeRate*(point.y - minY);
      point = point.next;
    }
  }
  
  //unlikely that max = min, but could happen if using zero iterations. In this case, set all points equal to 1.
  else {
    point = pointList.first;
    while (point != null) {
      point.y = 1;
      point = point.next;
    }
  }
      
  return pointList;   
}
  
function generate() {
  var x0, y0, w, h;
  var lineColor;
  var fillColor;
  
  var minWidth = 80;
  var maxWidth = 280;
  var minHeight = minWidth;
  var maxHeight = maxWidth;
  
  var numRects = 6;
  
  for (var i = 0; i < numRects; i++) {
    r = Math.floor(Math.random()*255);
    g = Math.floor(Math.random()*255);
    b = Math.floor(Math.random()*255);
    a = 0.9;
    
    fillColor = "rgba("+r+","+g+","+b+","+a+")";
    lineColor = "rgba("+r+","+g+","+b+","+a+")";
    
    
    w = minWidth + Math.random()*(maxWidth - minWidth);
    h = minHeight + Math.random()*(maxHeight - minHeight);
    x0 = 6 + Math.random()*(displayWidth - w - 6);
    y0 = 6 + Math.random()*(displayHeight - w - 6);
    
    drawRect(x0, y0, w, h, lineColor, fillColor);
  }
}

function drawRect(x0,y0,w,h,lineColor,fillColor) {
  var cornerDrift = 3;
  var drawDriftX = 3;
  var drawDriftY = 3;
  var corner = [];
  var driftVector = [];
  var pointList;
  var i,j;
  var nextCorner;
  var iterates = 8;
  var nextX, nextY;
  var functionPoint;
  var endpointY;
  
  x0 += cornerDrift*(2*Math.random()-1);
  y0 += cornerDrift*(2*Math.random()-1);
  
  for (i = 0; i < 4; i++) {
    corner[i] = {};
  }
  
  corner[0].x = x0 + cornerDrift*(Math.random()*2 - 1);
  corner[0].y = y0 + cornerDrift*(Math.random()*2 - 1);
  
  corner[1].x = x0 + w + cornerDrift*(Math.random()*2 - 1);
  corner[1].y = y0 + cornerDrift*(Math.random()*2 - 1);
  
  corner[2].x = x0 + w + cornerDrift*(Math.random()*2 - 1);
  corner[2].y = y0 + h + cornerDrift*(Math.random()*2 - 1);
  
  corner[3].x = x0 + cornerDrift*(Math.random()*2 - 1);
  corner[3].y = y0 + h + cornerDrift*(Math.random()*2 - 1);
  
  driftVector[0] = {x:0, y:drawDriftY};
  driftVector[1] = {x:drawDriftX, y:0};
  driftVector[2] = {x:0, y:drawDriftY};
  driftVector[3] = {x:drawDriftX, y:0};
  
  var points = [];
  
  points.push(corner[0].x, corner[0].y);
  
  for (i = 0; i < 4; i++) {
    nextCorner = corner[(i + 1) % 4];
    pointList = setLinePoints(iterates);
    functionPoint = pointList.first;
    endpointY = functionPoint.y;
    while (functionPoint != null) {
      nextX = corner[i].x + functionPoint.x*(nextCorner.x - corner[i].x);
      nextY = corner[i].y + functionPoint.x*(nextCorner.y - corner[i].y);
      nextX += driftVector[i].x*(functionPoint.y - endpointY);
      nextY += driftVector[i].y*(functionPoint.y - endpointY);
      console.log('lineTo', nextX, nextY);
      points.push(nextX, nextY);
      functionPoint = functionPoint.next;
    }
  }
  s.polyline(points).attr({
    fill: fillColor,
    opacity: 0.2,
    stroke: lineColor,
    strokeWidth: 2
  });
}

generate();