56

Programming abstract art

 6 years ago
source link: https://www.tuicool.com/articles/hit/jAF3EjJ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Javascript abstract art! Click on the canvas for another masterpiece.

The current implementation uses a recursive function to split the canvas up into mini boxes. This is then ajusted to add a random factor in splitting and corrected to ensure that the boxes are of a minimum size.

// globals
var minWidth, minHeight;

var render = function(canvasId) {

  var canvas = document.getElementById(canvasId);
  var cWidth = canvas.width;
  var cHeight = canvas.height;
  var depth = 4;

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, cWidth, cHeight);

    try {
      splitGrid(ctx, depth, 0, 0, cWidth, cHeight);
    } catch (err) {
      console.error(err);
    }
  }
}


/**
 * Split a given bounding box width-wise randomly and
 * for each width split, create 2 vertical bounding boxes.
 *
 * Depending on the depth, recursively call to split the grid further
 * or simply fill the bounding box using a similar algorithm
 */
var splitGrid = function(ctx, depth, gx, gy, cWidth, cHeight) {

  if (depth % 2 !== 0 || depth < 2) {
    throw new Error('depth needs to be a multiple of 2 (min 2)');
  }

  var x = 0,
    y = 0,
    width = 0,
    height = 0;

  //
  // start at 0 and then loop until the width has been reached, splitting on each loop
  //
  // note that while the algorithm works on x, y, width and height as a bounding box
  // the actual values that need to be passed along need to be corrected via gx and gy
  // so that the final drawing on the context knows where to go.
  //
  while (x < cWidth) {

    // reset y to 0, we split our box vertically only once
    y = 0;

    // get the minimum width (relative to the depth)
    // then correct for overflow to keep it smooth
    // also need to check for shady widths

    if (cWidth <= self.minWidth * depth) {
      width = cWidth;
    } else {
      width = chance.integer({ min: self.minWidth * depth, max: cWidth });
      width = width - (width % (self.minWidth * depth));
    }

    // correct for the last box in the series
    if (x + width > cWidth) {
      width = cWidth - x;
    }

    // similar concept with height except no last box correction required as we only split it once
    if (cHeight <= self.minHeight * depth) {
      height = cHeight;
    } else {
      height = chance.integer({ min: self.minHeight * depth, max: cHeight });
      height = height - (height % (self.minHeight * depth));
    }

    if (depth <= 2) {
      fillGrid(ctx, x + gx, y + gy, width, height);
    } else {
      splitGrid(ctx, depth - 2, x + gx, y + gy, width, height);
    }

    // simple split twice
    y = height;
    height = cHeight - height;

    if (height != 0) {
      if (depth <= 2) {
        fillGrid(ctx, x + gx, y + gy, width, height);
      } else {
        splitGrid(ctx, depth - 2, x + gx, y + gy, width, height);
      }
    }

    x += width;
  }

}


/**
 * Use a similar algorithm as fill grid to randomly split the bounding box width-wise
 * and draw rectangles (2 per width split again)
 */
var fillGrid = function(ctx, gx, gy, cWidth, cHeight) {

  if (cWidth <= 0 || cHeight <= 0) {
    return;
  }

  var x = 0,
    y = 0,
    width = 0,
    height = 0;

  while (x < cWidth) {

    y = 0;

    // because we have a dynamically sized canvas, it is possible to end up with shady widths and heights
    if (cWidth <= minWidth) {
      width = cWidth;
    } else {
      width = chance.integer({ min: minWidth, max: cWidth });
      width = width - (width % minWidth);
    }

    if (x + width > cWidth) {
      width = cWidth - x;
    }

    if (cHeight <= minHeight) {
      height = cHeight;
    } else {
      height = chance.integer({ min: minHeight, max: cHeight });
      height = height - (height % minHeight);
    }

    ctx.fillStyle = getColor();
    ctx.fillRect(x + gx, y + gy, width, height);

    y = height;
    height = cHeight - height;

    ctx.fillStyle = getColor();
    ctx.fillRect(x + gx, y + gy, width, height);

    x += width;
  }

}

var getColor = function() {

  var r = chance.integer({ min: 1, max: 255 }),
    g = chance.integer({ min: 1, max: 255 }),
    b = chance.integer({ min: 1, max: 255 });

  var color = 'rgb(' + r + ',' + g + ',' + b + ')';

  return color;
}

See also JavaScript Art: Triangles for a simpler concept.

Feel free to send me anemail with a screenshot of your favorite canvas :)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK