Skip to content

Instantly share code, notes, and snippets.

@Kcnarf
Last active April 11, 2017 14:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kcnarf/fd540e784dc1cc7f609109ab1219ce61 to your computer and use it in GitHub Desktop.
Save Kcnarf/fd540e784dc1cc7f609109ab1219ce61 to your computer and use it in GitHub Desktop.
Voronoï playground - Do you see the path ?
license: gpl-3.0

No path is visible, only cells !

The idea of this block comes when I look at Voronoï tesselation where (sometimes) pathes emerge, due to the smooth chaining of cells's borders. This is put to its extreme in this block.

Acknowledgments to:

<html>
<head>
<meta charset="utf-8">
<title>Voronoï playground : Do you see the path ?</title>
<meta content="Voronoï playground : path emerging from Voronoï cells" name="description">
<style>
p {
position: absolute;
bottom: 10px;
right: 10px;
color: lightgrey;
text-align: end;
}
#path {
fill: none;
stroke-linecap: round;
stroke: white;
stroke-width: 20px;
}
#drawing-area {
filter: url("#saturate-around-path");
}
.cell {
fill: none;
stroke: cyan;
}
</style>
</head>
<body>
<svg>
<defs>
<filter id="saturate-around-path">
<feGaussianBlur result="blured" in="SourceAlpha" stdDeviation="10" />
<feComposite result="composed" in="SourceGraphic" in2="blured" operator="in"/>
</filter>
</defs>
</svg>
<p>
Click and drag to make your own path.<br/>
/!\ not working with intersections and path's portions that are too close.
</p>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://raw.githack.com/Kcnarf/d3-distanceLimitedVoronoi/master/distance-limited-voronoi.js"></script>
<script>
var width = 960,
height = 500,
_2PI = 2*Math.PI;
var sampling = 10,
squaredSampling = Math.pow(sampling, 2),
voronoiCellLimit = 40,
maxSpread = 20;
var pathData = [];
var line = d3.line()
.curve(d3.curveLinear);
var strokeOpacityScale = d3.scaleLinear()
.domain([0, 2*maxSpread])
.range([1, 0]);
var path = getStartingPath();
var voronoiSeeds = [];
var xAccessor = function(d) { return d.x; };
var yAccessor = function(d) { return d.y; };
var limitedVoronoi = d3.distanceLimitedVoronoi()
.x(xAccessor)
.y(yAccessor)
.limit(voronoiCellLimit)
.extent([[0, 0], [width, height]]);
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height)
.call(d3.drag()
.container(function(d) { return this; })
.subject(function(d) { var p = [d3.event.x, d3.event.y]; return [p, p]; })
.on("start", dragStarted)
.on("drag", dragging));
var drawingArea = svg.append("g")
.attr("id", "drawing-area");
var drawnPath = drawingArea.append("path")
.attr("id", "path")
.attr("d", path);
var voronoiLayer = drawingArea.append("g")
.attr("id", "voronoi-layer");
redrawVoronoi();
function dragStarted() {
pathData = [];
voronoiSeeds = [];
voronoiLayer.selectAll(".cell").remove();
}
function dragging() {
var d = d3.event.subject,
x0 = d3.event.x,
y0 = d3.event.y;
d3.event.on("drag", function() {
var x1 = d3.event.x,
y1 = d3.event.y,
dx = x1 - x0,
dy = y1 - y0;
if (dx * dx + dy * dy > squaredSampling) {
pathData.push([x0 = x1, y0 = y1]);
drawnPath.datum(pathData);
drawnPath.attr("d", line);
redrawVoronoi();
} else {
d[d.length - 1] = [x1, y1];
}
});
}
function redrawVoronoi() {
//begin: compute voronoi seeds, close to the path
var pathNode = drawnPath.node(),
pathLength = drawnPath.node().getTotalLength(),
length = voronoiSeeds.length/2*sampling;
var point0, point1, midX, midY, dx, dy,
angle, spread, strokeOpacity, strokeColor;
point1 = pathNode.getPointAtLength(length);
for (length+=sampling; length<=pathLength; length+=sampling) {
point0 = point1;
point1 = pathNode.getPointAtLength(length);
midX = (point0.x+point1.x)/2;
midY = (point0.y+point1.y)/2;
dx = point1.x-point0.x;
dy = point1.y-point0.y;
angle = Math.atan2(dy, dx);
spread = maxSpread*Math.abs(d3.randomNormal()());
strokeOpacity = strokeOpacityScale(spread);
strokeColor = d3.hsl((length/2)%360, 1, 0.45);
angle += Math.PI/2;
voronoiSeeds.push({
x: midX+spread*Math.cos(angle),
y: midY+spread*Math.sin(angle),
strokeOpacity : strokeOpacity,
strokeColor: strokeColor
});
angle += Math.PI;
voronoiSeeds.push({
x: midX+spread*Math.cos(angle),
y: midY+spread*Math.sin(angle),
strokeOpacity: strokeOpacity,
strokeColor: strokeColor
});
}
//end: compute voronoi seeds, close to the path
//begin: draw limited distance voronoi
limitedCells = limitedVoronoi(voronoiSeeds);
var drawnCells = voronoiLayer.selectAll(".cell")
.data(limitedCells);
drawnCells = drawnCells.enter()
.append("path")
.classed("cell", true)
.style("stroke-opacity", function(d) { return d.datum.strokeOpacity; })
.style("stroke", function(d) { return d.datum.strokeColor; })
.merge(drawnCells);
drawnCells.attr("d", function(d) { return d.path; });
//end: draw limited distance voronoi
}
function getStartingPath() {
return "M83,265L84,263.6666666666667C85,262.3333333333333,87,259.6666666666667,88.83333333333333,257.1666666666667C90.66666666666667,254.66666666666666,92.33333333333333,252.33333333333334,94.5,249.66666666666666C96.66666666666667,247,99.33333333333333,244,101.83333333333333,241C104.33333333333333,238,106.66666666666667,235,109.16666666666667,232.33333333333334C111.66666666666667,229.66666666666666,114.33333333333333,227.33333333333334,117.33333333333333,225.16666666666666C120.33333333333333,223,123.66666666666667,221,126.83333333333333,219.16666666666666C130,217.33333333333334,133,215.66666666666666,136,214C139,212.33333333333334,142,210.66666666666666,145.16666666666666,209.16666666666666C148.33333333333334,207.66666666666666,151.66666666666666,206.33333333333334,154.83333333333334,205.16666666666666C158,204,161,203,164.33333333333334,202.5C167.66666666666666,202,171.33333333333334,202,175.16666666666666,202C179,202,183,202,187,202C191,202,195,202,198.66666666666666,202.66666666666666C202.33333333333334,203.33333333333334,205.66666666666666,204.66666666666666,209,206.16666666666666C212.33333333333334,207.66666666666666,215.66666666666666,209.33333333333334,218.83333333333334,210.83333333333334C222,212.33333333333334,225,213.66666666666666,228,215.33333333333334C231,217,234,219,237.16666666666666,220.83333333333334C240.33333333333334,222.66666666666666,243.66666666666666,224.33333333333334,246.83333333333334,226.33333333333334C250,228.33333333333334,253,230.66666666666666,255.83333333333334,232.83333333333334C258.6666666666667,235,261.3333333333333,237,264.1666666666667,239.33333333333334C267,241.66666666666666,270,244.33333333333334,273,246.66666666666666C276,249,279,251,282,253C285,255,288,257,291,258.8333333333333C294,260.6666666666667,297,262.3333333333333,300.1666666666667,264C303.3333333333333,265.6666666666667,306.6666666666667,267.3333333333333,310.1666666666667,269C313.6666666666667,270.6666666666667,317.3333333333333,272.3333333333333,321.1666666666667,273.8333333333333C325,275.3333333333333,329,276.6666666666667,332.6666666666667,277.5C336.3333333333333,278.3333333333333,339.6666666666667,278.6666666666667,343.1666666666667,278.8333333333333C346.6666666666667,279,350.3333333333333,279,354.1666666666667,279C358,279,362,279,365.6666666666667,279C369.3333333333333,279,372.6666666666667,279,376,278.6666666666667C379.3333333333333,278.3333333333333,382.6666666666667,277.6666666666667,386,276.8333333333333C389.3333333333333,276,392.6666666666667,275,396.1666666666667,274C399.6666666666667,273,403.3333333333333,272,406.6666666666667,271C410,270,413,269,416.3333333333333,267.8333333333333C419.6666666666667,266.6666666666667,423.3333333333333,265.3333333333333,426.6666666666667,263.6666666666667C430,262,433,260,436.3333333333333,258.1666666666667C439.6666666666667,256.3333333333333,443.3333333333333,254.66666666666666,446.8333333333333,253C450.3333333333333,251.33333333333334,453.6666666666667,249.66666666666666,457.1666666666667,248C460.6666666666667,246.33333333333334,464.3333333333333,244.66666666666666,467.8333333333333,243C471.3333333333333,241.33333333333334,474.6666666666667,239.66666666666666,477.6666666666667,238.33333333333334C480.6666666666667,237,483.3333333333333,236,486.6666666666667,234.83333333333334C490,233.66666666666666,494,232.33333333333334,497.6666666666667,231.5C501.3333333333333,230.66666666666666,504.6666666666667,230.33333333333334,508,229.83333333333334C511.3333333333333,229.33333333333334,514.6666666666666,228.66666666666666,517.6666666666666,228.16666666666666C520.6666666666666,227.66666666666666,523.3333333333334,227.33333333333334,526.8333333333334,227C530.3333333333334,226.66666666666666,534.6666666666666,226.33333333333334,538.8333333333334,226.16666666666666C543,226,547,226,550.8333333333334,226.16666666666666C554.6666666666666,226.33333333333334,558.3333333333334,226.66666666666666,561.8333333333334,227.66666666666666C565.3333333333334,228.66666666666666,568.6666666666666,230.33333333333334,571.8333333333334,231.83333333333334C575,233.33333333333334,578,234.66666666666666,581,236.5C584,238.33333333333334,587,240.66666666666666,590,242.83333333333334C593,245,596,247,599,249C602,251,605,253,608,255.16666666666666C611,257.3333333333333,614,259.6666666666667,616.8333333333334,262C619.6666666666666,264.3333333333333,622.3333333333334,266.6666666666667,625.1666666666666,268.8333333333333C628,271,631,273,634.3333333333334,274.8333333333333C637.6666666666666,276.6666666666667,641.3333333333334,278.3333333333333,644.8333333333334,279.8333333333333C648.3333333333334,281.3333333333333,651.6666666666666,282.6666666666667,655,283.5C658.3333333333334,284.3333333333333,661.6666666666666,284.6666666666667,665.1666666666666,285C668.6666666666666,285.3333333333333,672.3333333333334,285.6666666666667,676,285.8333333333333C679.6666666666666,286,683.3333333333334,286,687,286C690.6666666666666,286,694.3333333333334,286,698,286.1666666666667C701.6666666666666,286.3333333333333,705.3333333333334,286.6666666666667,707.5,286.8333333333333C709.6666666666666,287,710.3333333333334,287,710.6666666666666,287L711,287";
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment