var width = window.innerWidth var height = window.innerHeight var svg = d3.select('svg') .attr('width', width) .attr('width', height) var g = svg.select('#vis') // create 50 items that have x and y uniformly random var data = d3.range(50).map(function (n) { return { x: Math.floor(d3.randomUniform(1, width-10)()), y: Math.floor(d3.randomUniform(1, height-10)()), id: n } }) // scale for some colour differentiation var sequentialScale = d3.scaleSequential() .domain([0, 50]) .interpolator(d3.interpolateRainbow) // append the 50 circles driven by the data g.selectAll('circle') .data(data) .enter() .append('circle') .attr('r', 2) .attr('cx', function (d) { return d.x; }) .attr('cy', function (d) { return d.y; }) .style('fill', function (d, i) { return sequentialScale(i); }) // loop 50 times (length of data) data.forEach(function (o, n) { // append 50 lines driven by the data g.selectAll('line.id-' + n) .data(data) .enter() .append('line') .attr('class', 'id-' + n) // append a line form a reference (point in data) .attr('x1', data[n].x) .attr('y1', data[n].y) // connecting to all other points (all points in data) .attr('x2', function (d) { return d.x; }) .attr('y2', function (d) { return d.y; }) .attr('stroke', function (d, i) { return sequentialScale(i); }) }) // add some interaction so we can see the sets of lines :) var voronoi = d3.voronoi() .x(function (d) { return d.x; }) .y(function (d) { return d.y; }) .size([width, height])(data) // draw the polygons var voronoiPolygons = g.append('g') .attr('class', 'voronoi-polygons') var binding = voronoiPolygons .selectAll('path') .data(voronoi.polygons()) binding.enter().append('path') // .style('stroke', 'tomato') .style('fill', 'transparent') .attr('d', function (d) { return ("M" + (d.join('L')) + "Z"); }) .on('mouseover', function (d) { g.selectAll(':not(.id-' + d.data.id + ')') .style('opacity', 0.1) }) .on('mouseout', function () { return g.selectAll('line').style('opacity', 0.9); })