p5/D3 Cookbook

Combining the power of D3.js with the simplicity of p5.js

Creating Interactive Voronoi Layout

D3 Concepts Used

d3.geom.voronoi()

By Sarah Groff-Palermo (github: @sarahgp). With help from Mike Bostock and the p5/D3 cookbook.

This example creates an interactive Voronoi layout calculated by D3.geom.voronoi() and drawn by p5.

In order for the canvas to appear as a background for the page, special CSS is required for the <canvas> element:

canvas {
    position:absolute;
    top:0;
    left:0;
    z-index:-1;
  }
var c, width, height, polydraw, colorArr, vertices, voronoi, polygons;
var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false),
    body = document.body,
    html = document.documentElement;

function getWidth() {
  return body.clientWidth;
}

function getHeight() {
  return Math.max(body.scrollHeight, body.offsetHeight, 
                    html.clientHeight, html.scrollHeight, html.offsetHeight);
}

function setup() {

  width = getWidth();
  height = getHeight();

  colorMode(HSL);
  c = createCanvas(width, height);

  colorArr = [color(240, 5, 29, .05),
              color(240, 5, 29, .1),
              color(240, 5, 29, .15),
              color(240, 5, 39, .05),
              color(240, 5, 39, .1),
              color(240, 5, 39, .15),
              color(240, 5, 49, .05),
              color(240, 5, 49, .1),
              color(240, 5, 49, .05)];

  vertices = d3.range(140).map(function(d) {
      return [Math.random() * width, Math.random() * height];
    });

  voronoi = d3.geom.voronoi()
      .clipExtent([[0, 0], [width, height]]);

  polygons = voronoi(vertices);

  polydraw = function() {
    
    stroke(255);

    for (var j = 0, jL = polygons.length; j < jL; j++) {
      
      var singlegon = polygons[j];

      j === 0 ? fill(color(60, 100, 50, 1)) : 
                fill(colorArr[j % colorArr.length]);

      beginShape();

      for (var k = 0, kL = singlegon.length; k < kL; k++){
        vertex(singlegon[k][0], singlegon[k][1]);
      }

      endShape(CLOSE);

    }
  }

  polydraw();

}

// on iOS links become unclickable with movement
if (!iOS) { 
  function mouseMoved() {
    c.clear();
    vertices[0] = [mouseX, mouseY];
    polygons = voronoi(vertices);
    polydraw();
  }
}

function windowResized(){  
  width = getWidth();
  height = getHeight();
  resizeCanvas(width, height);
  voronoi = d3.geom.voronoi()
      .clipExtent([[0, 0], [width, height]]);
  vertices = d3.range(140).map(function(d) {
        return [Math.random() * width, Math.random() * height];
      });
  polygons = voronoi(vertices);
  polydraw();
}