block by nitaku d6a766a92ce2ba88af4d19dfabc46f89

Multihue Cushion Voronoi

Full Screen

A multihue version of the previous example.

index.js

// Generated by CoffeeScript 1.10.0
(function() {
  var cells, cells_data, defs, enter_gradients, gradients, height, radius, sites, sites_data, svg, voronoi, width;

  svg = d3.select('svg');

  width = svg.node().getBoundingClientRect().width;

  height = svg.node().getBoundingClientRect().height;

  defs = svg.append('defs');

  radius = 10;

  sites_data = d3.range(20).map(function() {
    return {
      x: Math.round(Math.random() * (width - radius * 2) + radius),
      y: Math.round(Math.random() * (height - radius * 2) + radius)
    };
  });

  voronoi = d3.voronoi().x(function(d) {
    return d.x;
  }).y(function(d) {
    return d.y;
  }).extent([[-1, -1], [width + 1, height + 1]]);

  cells_data = voronoi.polygons(sites_data);

  gradients = defs.selectAll('.gradient').data(sites_data);

  enter_gradients = gradients.enter().append('radialGradient').attrs({
    "class": 'gradient',
    gradientUnits: 'userSpaceOnUse',
    id: function(d, i) {
      return "gradient_" + i;
    },
    cx: function(d) {
      return d.x;
    },
    cy: function(d) {
      return d.y;
    },
    r: 300
  });

  enter_gradients.append('stop').attrs({
    offset: '0%',
    'stop-color': d3.hcl(80 + 0, 40, 100)
  });

  enter_gradients.append('stop').attrs({
    offset: '25%',
    'stop-color': d3.hcl(80 + 40, 40, 75)
  });

  enter_gradients.append('stop').attrs({
    offset: '50%',
    'stop-color': d3.hcl(80 + 80, 40, 50)
  });

  enter_gradients.append('stop').attrs({
    offset: '75%',
    'stop-color': d3.hcl(80 + 120, 40, 25)
  });

  enter_gradients.append('stop').attrs({
    offset: '100%',
    'stop-color': d3.hcl(80 + 160, 40, 0)
  });

  cells = svg.selectAll('.cell').data(cells_data);

  cells.enter().append('path').attrs({
    "class": 'cell',
    d: function(d) {
      if (d == null) {
        return null;
      } else {
        return "M" + d.join("L") + "Z";
      }
    },
    fill: function(d, i) {
      return "url(#gradient_" + i + ")";
    }
  });

  sites = svg.selectAll('.site').data(sites_data);

  sites.enter().append('circle').attrs({
    "class": 'site',
    r: radius,
    cx: function(d) {
      return d.x;
    },
    cy: function(d) {
      return d.y;
    }
  });

}).call(this);

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Multihue Cushion Voronoi</title>
  <link type="text/css" href="index.css" rel="stylesheet"/>
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>
</head>
<body>
  <svg></svg>
  <script src="index.js"></script>
</body>
</html>

index.coffee

svg = d3.select 'svg'
width = svg.node().getBoundingClientRect().width
height = svg.node().getBoundingClientRect().height

defs = svg.append 'defs'
    
radius = 10

sites_data = d3.range(20).map () ->
  return {
    x: Math.round(Math.random() * (width - radius * 2) + radius),
    y: Math.round(Math.random() * (height - radius * 2) + radius)
  }

voronoi = d3.voronoi()
  .x (d) -> d.x
  .y (d) -> d.y
  .extent [[-1, -1], [width + 1, height + 1]]
  
cells_data = voronoi.polygons(sites_data)

# define cells gradients
gradients = defs.selectAll '.gradient'
  .data sites_data
  
enter_gradients = gradients.enter().append 'radialGradient'
  .attrs
    class: 'gradient'
    gradientUnits: 'userSpaceOnUse'
    id: (d,i) -> "gradient_#{i}"
    cx: (d) -> d.x
    cy: (d) -> d.y
    r: 300
    
enter_gradients.append 'stop'
  .attrs
    offset: '0%'
    'stop-color': d3.hcl(80+0,40,100)
    
enter_gradients.append 'stop'
  .attrs
    offset: '25%'
    'stop-color': d3.hcl(80+40,40,75)
    
enter_gradients.append 'stop'
  .attrs
    offset: '50%'
    'stop-color': d3.hcl(80+80,40,50)
    
enter_gradients.append 'stop'
  .attrs
    offset: '75%'
    'stop-color': d3.hcl(80+120,40,25)
    
enter_gradients.append 'stop'
  .attrs
    offset: '100%'
    'stop-color': d3.hcl(80+160,40,0)

# render cells
cells = svg.selectAll '.cell'
  .data cells_data
  
cells.enter().append 'path'
  .attrs
    class: 'cell'
    d: (d) ->  if not d? then null else "M" + d.join("L") + "Z"
    fill: (d,i) -> "url(#gradient_#{i})"


# render sites
sites = svg.selectAll '.site'
  .data sites_data
  
sites.enter().append 'circle'
  .attrs
    class: 'site'
    r: radius
    cx: (d) -> d.x
    cy: (d) -> d.y
    

index.css

body, html {
  padding: 0;
  margin: 0;
  height: 100%;
}
svg {
  width: 100%;
  height: 100%;
  background: white;
}

.site {
  fill: #DDD;
  stroke: gray;
}
.cell {
  shape-rendering: crispEdges;
}