Skip to content

Instantly share code, notes, and snippets.

@Kcnarf
Last active December 3, 2018 08:29
Show Gist options
  • Save Kcnarf/7855451634a2d91ccbf24cc31b9a6be0 to your computer and use it in GitHub Desktop.
Save Kcnarf/7855451634a2d91ccbf24cc31b9a6be0 to your computer and use it in GitHub Desktop.
Blobbing Particles
license: gpl-3.0

This block is a recreation:

  • apply radial gradient to distanceLimitedVornoy cells
  • use 2 layers: cells of the same layer are blobbing/merging thanks to distanceLimitedVornoy technique; cells of distinct layers are overlapping

I guess the strange flickering effect comes from the definition of a radial gradient: it's center and width of the radial gradient are defined as a percentage. These percentages are computed among the BBox of the element on which the radial gradient is applied on. Because a cell's widht/height is constantly evolving (depending on neighbours proximity), the radial gradient's center/widht is also constantly evolving/shrinking.

See this block for a smoother version.

Acknowledgments to:

<meta charset="utf-8">
<style>
.layer {
opacity: 0.5;
}
.particle .seed {
fill: black;
}
.particle .influence-zone {
fill: url("#radial-gradient");
stroke: none;
}
</style>
<body>
<svg>
<defs>
<radialGradient id="radial-gradient" cx="50%" cy="50%" r="50%">
<stop offset="25%" stop-color="white"></stop>
<stop offset="100%" stop-color="black"></stop>
</radialGradient>
</defs>
</svg>
<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,
influenceRadius = 20;
var layerCount = 2,
particleCountPerLayer = 25,
particles = new Array(layerCount);
for (var l = 0; l < layerCount; ++l) {
particles[l] = new Array(particleCountPerLayer);
for (var i = 0; i < particleCountPerLayer; ++i) {
particles[l][i] = {
x: Math.random() * width,
y: Math.random() * height,
vx: 0,
vy: 0
};
}
}
var limitedVoronoi = d3.distanceLimitedVoronoi()
.limit(influenceRadius)
.extent([[-influenceRadius,-influenceRadius],[width+influenceRadius,height+influenceRadius]])
.x( function(d) { return d.x })
.y( function(d) { return d.y });
var svg = d3.select("svg");
svg.attr("width", width)
.attr("height", height);
svg.selectAll("g").data(d3.range(layerCount))
.enter()
.append("g")
.classed("layer", true)
.attr("id", function(d) { return "layer-"+d; });
for (var l = 0; l < layerCount; l++) {
var layer = svg.select("#layer-"+l);
var clipPathName = "clip-"+l+"-";
var drawnParticles = layer.selectAll(".particle").data(particles[0]);
enteringParticles = drawnParticles.enter()
.append("g")
.classed("particle", true);
enteringParticles
.append("path")
.classed("influence-zone", true)
}
d3.timer(function(elapsed) {
for (var l = 0; l < layerCount; l++) {
var layer = svg.select("#layer-"+l);
for (var i = 0; i < particleCountPerLayer; ++i) {
var p = particles[l][i];
p.x += p.vx;
p.y += p.vy;
if (p.x < -influenceRadius) {
p.x += (width+2*influenceRadius);
} else if (p.x > width+influenceRadius) {
p.x -= (width+2*influenceRadius);
}
if (p.y < -influenceRadius) {
p.y += (height+2*influenceRadius);
} else if (p.y > height+influenceRadius) {
p.y -= (height+2*influenceRadius);
}
p.vx += 0.2 * (Math.random() - .5) - 0.01 * p.vx;
p.vy += 0.2 * (Math.random() - .5) - 0.01 * p.vy;
}
var limitedCells = limitedVoronoi(particles[l]);
layer.selectAll(".particle .influence-zone").data(limitedCells)
.attr("d", function(d) { return d.path; });
}
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment