An interactive demonstration of d3-voronoi rendered to SVG. Compare to Canvas.
forked from mbostock's block: Voronoi Tessellation
| license: gpl-3.0 |
An interactive demonstration of d3-voronoi rendered to SVG. Compare to Canvas.
forked from mbostock's block: Voronoi Tessellation
| !function(a,b){"function"==typeof define&&define.amd?define(function(){return a.DoublyLinkedList=b()}):"object"==typeof exports?module.exports=b():a.DoublyLinkedList=b()}(this,function(){function a(a){this.data=a,this.previous=null,this.next=null}function b(){this._head=null,this._tail=null,this._length=0,this._isCircular=!1}var c={},d=Math.floor,e=Math.random;return a.prototype={constructor:a,hasPrevious:function(){return null!==this.previous},hasNext:function(){return null!==this.next}},b.VERSION="0.1.6",b.forge=function(){return new this},b.forgeCircular=function(){return this.forge().makeCircular()},b.prototype={constructor:b,makeCircular:function(){return this.isEmpty()||(this._head.previous=this._tail,this._tail.next=this._head),this._isCircular=!0,this},makeLinear:function(){return this.isEmpty()||(this._head.previous=null,this._tail.next=null),this._isCircular=!1,this},add:function(b){var c=new a(b),d=this._tail;return this.isEmpty()?(this._head=c,this._tail=c):(d.next=c,c.previous=d,this._tail=c),this._length+=1,this._isCircular&&this.makeCircular(),this},getAt:function(a){var b=this._getAt(a);return null!==b?b.data:null},getFirst:function(){var a=this._head;return null!==a?a.data:null},getPrevious:function(a){var b=this._getAdjacent(a,!1);return null!==b?b.data:null},getNext:function(a){var b=this._getAdjacent(a);return null!==b?b.data:null},getLast:function(){var a=this._tail;return null!==a?a.data:null},getRandom:function(){var a=0,b=this.getLength(),c=d(e()*(b-a))+a;return this.getAt(c)},getIndexOf:function(a){var b=0,d=-1;return this._traverse(function(e){return e.data===a?(d=b,c):void(b+=1)}),d},getLastIndexOf:function(a){var b=this._length-1,d=-1;return this._traverse(function(e){return e.data===a?(d=b,c):void(b-=1)},this._tail,!1),d},some:function(a,b,d){var e=this._get(b),f=!1;return this._traverse(function(b){return f=a.call(d,b.data),f?c:void 0},e),f},every:function(a,b,d){var e=this._get(b),f=!0;return this._traverse(function(b){return f=a.call(d,b.data),f?void 0:c},e),f},forEach:function(a,b,c){var d=this._get(b);this._traverse(function(b){a.call(c,b.data)},d)},forEachReverse:function(a,b,c){var d=this._get(b);this._traverse(function(b){a.call(c,b.data)},d,!1)},removeAt:function(a){var b=this._getAt(a),c=this._isHead(b),d=this._isTail(b);return null!==b?(c&&(this._head=b.next),d&&(this._tail=b.previous),b.hasNext()&&(b.next.previous=b.previous),b.hasPrevious()&&(b.previous.next=b.next),this._length-=1,(c||d||this._isCircular)&&this.makeCircular(),b.data):null},toArray:function(){for(var a=[],b=this._head;null!==b;)a.push(b.data),b=b.next;return a},toString:function(){return this.toArray().toString()},getLength:function(){return this._length},isEmpty:function(){return 0===this._length},isCircular:function(){return this._isCircular},_get:function(a){var b=null;return this._traverse(function(d){return d.data===a?(b=d,c):void 0}),b},_getAt:function(a){var b,c;if(a>-1&&a<this._length){for(b=this._head,c=0;a>c;)b=b.next,c+=1;return b}return null},_getAdjacent:function(a,b){b="boolean"==typeof b?b:!0;var d=b?"next":"previous",e=null;return this._traverse(function(b){return b.data===a?(e=b,c):void 0}),null!==e?e[d]:null},_traverse:function(a,b,d,e){b=b||this._head,d="boolean"==typeof d?d:!0;var f,g=b,h=this._length,i=d?"next":"previous";for(f=0;h>f;f+=1){if(null===g||a.call(e,g,this)===c)return;g=g[i]}},_isHead:function(a){return a===this._head},_isTail:function(a){return a===this._tail}},b}); |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| .links { | |
| stroke: #000; | |
| stroke-opacity: 0.2; | |
| } | |
| .polygons { | |
| fill: none; | |
| stroke: #000; | |
| } | |
| .polygons :first-child { | |
| fill: #f00; | |
| } | |
| .sites { | |
| fill: #000; | |
| stroke: #fff; | |
| } | |
| .sites :first-child { | |
| fill: #fff; | |
| } | |
| </style> | |
| <svg width="400" height="200"></svg> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/buckets/1.90.0/buckets.js"></script> | |
| <script> | |
| var svg = d3.select("svg"), | |
| width = +svg.attr("width"), | |
| height = +svg.attr("height"); | |
| svg.append("g") | |
| .attr("class", "sitesL"); | |
| svg.append("g") | |
| .attr("class", "sitesR"); | |
| var sites = d3.range(6) | |
| .map(function(d) { return [Math.random() * width, Math.random() * height]; }); | |
| // var polygon = svg.append("g") | |
| // .attr("class", "polygons") | |
| // .selectAll("path") | |
| // .data(voronoi.polygons(sites)) | |
| // .enter().append("path") | |
| // .call(redrawPolygon); | |
| // var link = svg.append("g") | |
| // .attr("class", "links") | |
| // .selectAll("line") | |
| // .data(voronoi.links(sites)) | |
| // .enter().append("line") | |
| // .call(redrawLink); | |
| var sites = sites.sort((a,b) => a[0] - b[0]) | |
| var siteL = sites.splice(0, sites.length/2).reverse(); | |
| var siteR = sites.splice(sites.length/2 - 1); | |
| var site = d3.select(".sitesL").selectAll("circle") | |
| .data(siteL).enter().append("circle") | |
| .attr("r", 2.5) | |
| .attr("cx", (d) => { | |
| return d[0]}) | |
| .attr("cy", (d) => d[1]) | |
| var site = d3.select(".sitesR") | |
| .selectAll("circle") | |
| .data(siteR).enter().append("circle") | |
| .attr("r", 2.5) | |
| .attr("cx", (d) => d[0]) | |
| .attr("cy", (d) => d[1]) | |
| .attr("fill", "red") | |
| var lastL = siteL[0] | |
| var firstR = siteR[0] | |
| svg.append("line") // attach a line | |
| .attr("id", "line") | |
| .style("stroke", "black") // colour the line | |
| .attr("x1", lastL[0]) // x position of the first end of the line | |
| .attr("y1", lastL[1]) // y position of the first end of the line | |
| .attr("x2", firstR[0]) // x position of the second end of the line | |
| .attr("y2", firstR[1]); // y position of the second end of the line | |
| var getSlope = function(p2,p1){ | |
| return (200-p2[1] - (200 - p1[1])) / (p2[0] - p1[0]) | |
| } | |
| var i = 0; | |
| var j = 0; | |
| var slope = getSlope(siteR[0], siteL[0]) | |
| var n = true | |
| while (n) { | |
| n = false | |
| while (siteL[i + 1] && getSlope(siteR[j], siteL[i+1]) > slope) { | |
| n = true | |
| console.log('i',slope, i , siteL[i][0], siteR[j][0]) | |
| slope = getSlope(siteR[j], siteL[i + 1]) | |
| d3.select("svg").append('line') | |
| .attr("x1", siteL[i+1][0]) | |
| .attr("y1", siteL[i+1][1]) | |
| .attr("x2", siteR[j][0]) | |
| .attr("y2", siteR[j][1]) | |
| .attr("stroke", "red") | |
| i++; | |
| } | |
| while (siteR[j + 1] && getSlope(siteR[j + 1], siteL[i]) < slope) { | |
| n = true | |
| console.log('j',slope, j , siteL[i][0], siteR[j][0]) | |
| slope = getSlope(siteR[j + 1], siteL[i]) | |
| d3.select("svg").append('line') | |
| .attr("x1", siteL[i][0]) // x position of the first end of the line | |
| .attr("y1", siteL[i][1]) | |
| .attr("x2", siteR[j+1][0]) | |
| .attr("y2", siteR[j+1][1]). | |
| attr("stroke", "blue") | |
| j++; | |
| } | |
| } | |
| console.log("break") | |
| </script> |
| �PNG | |