Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active April 23, 2023 20:06

Revisions

  1. mbostock revised this gist Oct 5, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -1 +1,2 @@
    license: gpl-3.0
    redirect: https://beta.observablehq.com/@mbostock/hover-voronoi
  2. mbostock revised this gist Jul 8, 2016. 1 changed file with 23 additions and 23 deletions.
    46 changes: 23 additions & 23 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -7,12 +7,12 @@
    stroke-opacity: 0.2;
    }

    .cells {
    .polygons {
    fill: none;
    stroke: #000;
    }

    .cells :first-child {
    .polygons :first-child {
    fill: #f00;
    }

    @@ -40,58 +40,58 @@
    var voronoi = d3.voronoi()
    .extent([[-1, -1], [width + 1, height + 1]]);

    var cell = svg.append("g")
    .attr("class", "cells")
    var polygon = svg.append("g")
    .attr("class", "polygons")
    .selectAll("path")
    .data(voronoi.polygons(sites))
    .enter().append("path")
    .attr("d", polygon);
    .call(redrawPolygon);

    var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(voronoi.links(sites))
    .enter().append("line")
    .attr("x1", function(d) { return d.source[0]; })
    .attr("y1", function(d) { return d.source[1]; })
    .attr("x2", function(d) { return d.target[0]; })
    .attr("y2", function(d) { return d.target[1]; });
    .call(redrawLink);

    var site = svg.append("g")
    .attr("class", "sites")
    .selectAll("circle")
    .data(sites)
    .enter().append("circle")
    .attr("cx", function(d) { return d[0]; })
    .attr("cy", function(d) { return d[1]; })
    .attr("r", 2.5);
    .attr("r", 2.5)
    .call(redrawSite);

    function moved() {
    sites[0] = d3.mouse(this);
    redraw();
    }

    function redraw() {
    var diagram = voronoi(sites),
    links = diagram.links(),
    polygons = diagram.polygons();
    var diagram = voronoi(sites);
    polygon = polygon.data(diagram.polygons()).call(redrawPolygon);
    link = link.data(diagram.links()), link.exit().remove();
    link = link.enter().append("line").merge(link).call(redrawLink);
    site = site.data(sites).call(redrawSite);
    }

    cell = cell.data(voronoi.polygons(sites))
    .attr("d", polygon);
    function redrawPolygon(polygon) {
    polygon
    .attr("d", function(d) { return d ? "M" + d.join("L") + "Z" : null; });
    }

    link = link.data(voronoi.links(sites))
    function redrawLink(link) {
    link
    .attr("x1", function(d) { return d.source[0]; })
    .attr("y1", function(d) { return d.source[1]; })
    .attr("x2", function(d) { return d.target[0]; })
    .attr("y2", function(d) { return d.target[1]; });
    }

    site = site.data(sites)
    function redrawSite(site) {
    site
    .attr("cx", function(d) { return d[0]; })
    .attr("cy", function(d) { return d[1]; });
    }

    function polygon(d) {
    return d ? "M" + d.join("L") + "Z" : null;
    }

    </script>
  3. mbostock revised this gist Jul 8, 2016. 4 changed files with 70 additions and 48 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    The Voronoi tessellation shows the closest point on the plane for a given set of points. This example updates the Voronoi diagram in response to mouse interaction! Colors by [Cynthia Brewer](http://colorbrewer.org/); algorithm by [Steven Fortune](http://ect.bell-labs.com/who/sjf/); implementation based on work by [Nicolas Garcia Belmonte](http://blog.thejit.org/2010/02/12/voronoi-tessellation/); interaction inspired by [Raymond Hill](http://www.raymondhill.net/blog/?p=9).
    An interactive demonstration of [d3-voronoi](https://github.com/d3/d3-voronoi) rendered to SVG. [Compare to Canvas.](/mbostock/6675193)
    116 changes: 69 additions & 47 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -2,74 +2,96 @@
    <meta charset="utf-8">
    <style>

    path {
    stroke: #fff;
    .links {
    stroke: #000;
    stroke-opacity: 0.2;
    }

    .cells {
    fill: none;
    stroke: #000;
    }

    path:first-child {
    fill: yellow !important;
    .cells :first-child {
    fill: #f00;
    }

    circle {
    .sites {
    fill: #000;
    pointer-events: none;
    stroke: #fff;
    }

    .q0-9 { fill: rgb(197,27,125); }
    .q1-9 { fill: rgb(222,119,174); }
    .q2-9 { fill: rgb(241,182,218); }
    .q3-9 { fill: rgb(253,224,239); }
    .q4-9 { fill: rgb(247,247,247); }
    .q5-9 { fill: rgb(230,245,208); }
    .q6-9 { fill: rgb(184,225,134); }
    .q7-9 { fill: rgb(127,188,65); }
    .q8-9 { fill: rgb(77,146,33); }
    .sites :first-child {
    fill: #fff;
    }

    </style>
    <body>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <svg width="960" height="500"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>

    var width = 960,
    height = 500;

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

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

    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .on("mousemove", function() { vertices[0] = d3.mouse(this); redraw(); });

    var path = svg.append("g").selectAll("path");

    svg.selectAll("circle")
    .data(vertices.slice(1))
    var svg = d3.select("svg").on("touchmove mousemove", moved),
    width = +svg.attr("width"),
    height = +svg.attr("height");

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

    var voronoi = d3.voronoi()
    .extent([[-1, -1], [width + 1, height + 1]]);

    var cell = svg.append("g")
    .attr("class", "cells")
    .selectAll("path")
    .data(voronoi.polygons(sites))
    .enter().append("path")
    .attr("d", polygon);

    var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(voronoi.links(sites))
    .enter().append("line")
    .attr("x1", function(d) { return d.source[0]; })
    .attr("y1", function(d) { return d.source[1]; })
    .attr("x2", function(d) { return d.target[0]; })
    .attr("y2", function(d) { return d.target[1]; });

    var site = svg.append("g")
    .attr("class", "sites")
    .selectAll("circle")
    .data(sites)
    .enter().append("circle")
    .attr("transform", function(d) { return "translate(" + d + ")"; })
    .attr("r", 1.5);
    .attr("cx", function(d) { return d[0]; })
    .attr("cy", function(d) { return d[1]; })
    .attr("r", 2.5);

    redraw();
    function moved() {
    sites[0] = d3.mouse(this);
    redraw();
    }

    function redraw() {
    path = path
    .data(voronoi(vertices), polygon);

    path.exit().remove();
    var diagram = voronoi(sites),
    links = diagram.links(),
    polygons = diagram.polygons();

    path.enter().append("path")
    .attr("class", function(d, i) { return "q" + (i % 9) + "-9"; })
    cell = cell.data(voronoi.polygons(sites))
    .attr("d", polygon);

    path.order();
    link = link.data(voronoi.links(sites))
    .attr("x1", function(d) { return d.source[0]; })
    .attr("y1", function(d) { return d.source[1]; })
    .attr("x2", function(d) { return d.target[0]; })
    .attr("y2", function(d) { return d.target[1]; });

    site = site.data(sites)
    .attr("cx", function(d) { return d[0]; })
    .attr("cy", function(d) { return d[1]; });
    }

    function polygon(d) {
    return "M" + d.join("L") + "Z";
    return d ? "M" + d.join("L") + "Z" : null;
    }

    </script>
    Binary file added preview.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  4. mbostock revised this gist Feb 9, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    license: gpl-3.0
  5. mbostock revised this gist Oct 31, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@

    </style>
    <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script>

    var width = 960,
  6. mbostock revised this gist Jun 11, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@

    </style>
    <body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script>

    var width = 960,
  7. mbostock revised this gist Oct 10, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    The Voronoi tesselation shows the closest point on the plane for a given set of points. This example updates the Voronoi diagram in response to mouse interaction! Colors by [Cynthia Brewer](http://colorbrewer.org/); algorithm by [Steven Fortune](http://ect.bell-labs.com/who/sjf/); implementation based on work by [Nicolas Garcia Belmonte](http://blog.thejit.org/2010/02/12/voronoi-tessellation/); interaction inspired by [Raymond Hill](http://www.raymondhill.net/blog/?p=9).
    The Voronoi tessellation shows the closest point on the plane for a given set of points. This example updates the Voronoi diagram in response to mouse interaction! Colors by [Cynthia Brewer](http://colorbrewer.org/); algorithm by [Steven Fortune](http://ect.bell-labs.com/who/sjf/); implementation based on work by [Nicolas Garcia Belmonte](http://blog.thejit.org/2010/02/12/voronoi-tessellation/); interaction inspired by [Raymond Hill](http://www.raymondhill.net/blog/?p=9).
  8. mbostock revised this gist Sep 23, 2013. 1 changed file with 12 additions and 14 deletions.
    26 changes: 12 additions & 14 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -3,28 +3,27 @@
    <style>

    path {
    stroke: #000;
    stroke: #fff;
    }

    path:first-child {
    fill: yellow !important;
    }

    circle {
    fill: #fff;
    stroke: #000;
    fill: #000;
    pointer-events: none;
    }

    .PiYG .q0-9{fill:rgb(197,27,125)}
    .PiYG .q1-9{fill:rgb(222,119,174)}
    .PiYG .q2-9{fill:rgb(241,182,218)}
    .PiYG .q3-9{fill:rgb(253,224,239)}
    .PiYG .q4-9{fill:rgb(247,247,247)}
    .PiYG .q5-9{fill:rgb(230,245,208)}
    .PiYG .q6-9{fill:rgb(184,225,134)}
    .PiYG .q7-9{fill:rgb(127,188,65)}
    .PiYG .q8-9{fill:rgb(77,146,33)}
    .q0-9 { fill: rgb(197,27,125); }
    .q1-9 { fill: rgb(222,119,174); }
    .q2-9 { fill: rgb(241,182,218); }
    .q3-9 { fill: rgb(253,224,239); }
    .q4-9 { fill: rgb(247,247,247); }
    .q5-9 { fill: rgb(230,245,208); }
    .q6-9 { fill: rgb(184,225,134); }
    .q7-9 { fill: rgb(127,188,65); }
    .q8-9 { fill: rgb(77,146,33); }

    </style>
    <body>
    @@ -44,7 +43,6 @@
    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("class", "PiYG")
    .on("mousemove", function() { vertices[0] = d3.mouse(this); redraw(); });

    var path = svg.append("g").selectAll("path");
    @@ -53,7 +51,7 @@
    .data(vertices.slice(1))
    .enter().append("circle")
    .attr("transform", function(d) { return "translate(" + d + ")"; })
    .attr("r", 2);
    .attr("r", 1.5);

    redraw();

  9. mbostock revised this gist Sep 23, 2013. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -58,14 +58,20 @@
    redraw();

    function redraw() {
    path = path.data(voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), identity);
    path = path
    .data(voronoi(vertices), polygon);

    path.exit().remove();
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", identity);

    path.enter().append("path")
    .attr("class", function(d, i) { return "q" + (i % 9) + "-9"; })
    .attr("d", polygon);

    path.order();
    }

    function identity(d) {
    return d;
    function polygon(d) {
    return "M" + d.join("L") + "Z";
    }

    </script>
  10. mbostock revised this gist Sep 23, 2013. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@
    }

    path:first-child {
    fill: yellow !important;
    fill: yellow !important;
    }

    circle {
    @@ -58,10 +58,14 @@
    redraw();

    function redraw() {
    path = path.data(voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), String);
    path = path.data(voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), identity);
    path.exit().remove();
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", String);
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", identity);
    path.order();
    }

    function identity(d) {
    return d;
    }

    </script>
  11. mbostock revised this gist Jun 24, 2013. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -38,6 +38,9 @@
    return [Math.random() * width, Math.random() * height];
    });

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

    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    @@ -55,7 +58,7 @@
    redraw();

    function redraw() {
    path = path.data(d3.geom.voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), String);
    path = path.data(voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), String);
    path.exit().remove();
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", String);
    path.order();
  12. mbostock revised this gist Dec 19, 2012. No changes.
  13. mbostock revised this gist Dec 19, 2012. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -58,6 +58,7 @@
    path = path.data(d3.geom.voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), String);
    path.exit().remove();
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", String);
    path.order();
    }

    </script>
  14. mbostock revised this gist Dec 19, 2012. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -3,10 +3,13 @@
    <style>

    path {
    fill: yellow;
    stroke: #000;
    }

    path:first-child {
    fill: yellow !important;
    }

    circle {
    fill: #fff;
    stroke: #000;
  15. mbostock revised this gist Dec 19, 2012. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -52,7 +52,6 @@
    redraw();

    function redraw() {
    vertices[0] = d3.mouse(this);
    path = path.data(d3.geom.voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), String);
    path.exit().remove();
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", String);
  16. mbostock revised this gist Dec 19, 2012. 1 changed file with 8 additions and 12 deletions.
    20 changes: 8 additions & 12 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -39,27 +39,23 @@
    .attr("width", width)
    .attr("height", height)
    .attr("class", "PiYG")
    .on("mousemove", update);
    .on("mousemove", function() { vertices[0] = d3.mouse(this); redraw(); });

    svg.selectAll("path")
    .data(d3.geom.voronoi(vertices))
    .enter().append("path")
    .attr("class", function(d, i) { return i ? "q" + (i % 9) + "-9" : null; })
    .attr("d", function(d) { return "M" + d.join("L") + "Z"; });
    var path = svg.append("g").selectAll("path");

    svg.selectAll("circle")
    .data(vertices.slice(1))
    .enter().append("circle")
    .attr("transform", function(d) { return "translate(" + d + ")"; })
    .attr("r", 2);

    function update() {
    redraw();

    function redraw() {
    vertices[0] = d3.mouse(this);
    svg.selectAll("path")
    .data(d3.geom.voronoi(vertices)
    .map(function(d) { return "M" + d.join("L") + "Z"; }))
    .filter(function(d) { return this.getAttribute("d") != d; })
    .attr("d", function(d) { return d; });
    path = path.data(d3.geom.voronoi(vertices).map(function(d) { return "M" + d.join("L") + "Z"; }), String);
    path.exit().remove();
    path.enter().append("path").attr("class", function(d, i) { return "q" + (i % 9) + "-9"; }).attr("d", String);
    }

    </script>
  17. mbostock revised this gist Nov 13, 2012. 1 changed file with 0 additions and 0 deletions.
    Binary file added thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  18. mbostock revised this gist Nov 12, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@
    }

    circle {
    fill: #ccc;
    fill: #fff;
    stroke: #000;
    pointer-events: none;
    }
  19. mbostock revised this gist Nov 12, 2012. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -24,6 +24,7 @@
    .PiYG .q8-9{fill:rgb(77,146,33)}

    </style>
    <body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

  20. mbostock created this gist Nov 12, 2012.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    The Voronoi tesselation shows the closest point on the plane for a given set of points. This example updates the Voronoi diagram in response to mouse interaction! Colors by [Cynthia Brewer](http://colorbrewer.org/); algorithm by [Steven Fortune](http://ect.bell-labs.com/who/sjf/); implementation based on work by [Nicolas Garcia Belmonte](http://blog.thejit.org/2010/02/12/voronoi-tessellation/); interaction inspired by [Raymond Hill](http://www.raymondhill.net/blog/?p=9).
    64 changes: 64 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>

    path {
    fill: yellow;
    stroke: #000;
    }

    circle {
    fill: #ccc;
    stroke: #000;
    pointer-events: none;
    }

    .PiYG .q0-9{fill:rgb(197,27,125)}
    .PiYG .q1-9{fill:rgb(222,119,174)}
    .PiYG .q2-9{fill:rgb(241,182,218)}
    .PiYG .q3-9{fill:rgb(253,224,239)}
    .PiYG .q4-9{fill:rgb(247,247,247)}
    .PiYG .q5-9{fill:rgb(230,245,208)}
    .PiYG .q6-9{fill:rgb(184,225,134)}
    .PiYG .q7-9{fill:rgb(127,188,65)}
    .PiYG .q8-9{fill:rgb(77,146,33)}

    </style>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var width = 960,
    height = 500;

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

    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("class", "PiYG")
    .on("mousemove", update);

    svg.selectAll("path")
    .data(d3.geom.voronoi(vertices))
    .enter().append("path")
    .attr("class", function(d, i) { return i ? "q" + (i % 9) + "-9" : null; })
    .attr("d", function(d) { return "M" + d.join("L") + "Z"; });

    svg.selectAll("circle")
    .data(vertices.slice(1))
    .enter().append("circle")
    .attr("transform", function(d) { return "translate(" + d + ")"; })
    .attr("r", 2);

    function update() {
    vertices[0] = d3.mouse(this);
    svg.selectAll("path")
    .data(d3.geom.voronoi(vertices)
    .map(function(d) { return "M" + d.join("L") + "Z"; }))
    .filter(function(d) { return this.getAttribute("d") != d; })
    .attr("d", function(d) { return d; });
    }

    </script>