Skip to content

Instantly share code, notes, and snippets.

@keithcollins
Created September 14, 2019 17:10
Show Gist options
  • Save keithcollins/f944a0bd4c0f12f066b5545c8c6a7525 to your computer and use it in GitHub Desktop.
Save keithcollins/f944a0bd4c0f12f066b5545c8c6a7525 to your computer and use it in GitHub Desktop.
blobs
<style>
#chart {
max-width:940px;
margin: 0 auto;
}
</style>
<div id="chart"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://npmcdn.com/regl/dist/regl.min.js"></script>
<script>
const width = 940;
const height = 500;
const duration = 2000;
const max_radius = 20;
const max_distance = 200;
const force_strength = 0.03;
const fill_color = [.8,.8,.8];
const stroke_color = [0,0,0];
const circle_multiplier = (window.devicePixelRatio > 1) ? 4.0 : 2.0;
const centers = [
{x: width*0.25, y:height*0.25},
{x: width-width*0.25, y:height*0.25},
{x: width*0.25, y:height-height*0.25},
{x: width-width*0.25, y:height-height*0.25},
];
const data = d3.range(250).map(n => {
const r = Math.round(Math.random() * max_radius);
const center_index = Math.floor(Math.random() * 4) + 0;
return {
r: r,
x: centers[center_index].x,
y: centers[center_index].y,
center_x: centers[center_index].x,
center_y: centers[center_index].y,
random_x: Math.round(Math.random() * width),
random_y: Math.round(Math.random() * height),
stroke_size: .08/(r/max_radius),
charge: -Math.pow(r, 2.0) * force_strength
}
});
let simulation = null;
let i = 0;
const container = d3.select("#chart")
.style('height', height + 'px');
const runSimulation = function() {
const dur = (i == 0) ? 0 : duration;
const pos_x_field = ((i % 2) == 1) ? "center_x" : "random_x";
const pos_y_field = ((i % 2) == 1) ? "center_y" : "random_y";
i++;
const timeout_id = setTimeout(()=>{
simulation = d3.forceSimulation(data)
.velocityDecay(0.2)
.force('x', d3.forceX().strength(force_strength).x(d => d[pos_x_field] ))
.force('y', d3.forceY().strength(force_strength).y(d => d[pos_y_field] ))
.force('charge', d3.forceManyBody().strength(d => d.charge).distanceMax(max_distance))
.stop();
if (i < 100) runSimulation();
},dur);
}
runSimulation();
createREGL({
onDone,
container: container.node(),
extensions: ['oes_standard_derivatives']
});
function onDone(err, regl) {
const frameLoop = regl.frame(() => {
regl.clear({
color: [1,1,1,0],
depth: 1
});
if (simulation) simulation.tick();
drawPoints({
stage_width: width,
stage_height: height,
fill_color,
stroke_color,
circle_multiplier
});
});
const drawPoints = regl({
blend: {
enable: true,
func: {
srcRGB: 'src alpha',
srcAlpha: 'src alpha',
dstRGB: 'one minus src alpha',
dstAlpha: 'one minus src alpha'
}
},
depth: { enable: false },
attributes: {
position: () => data.map(d => [d.x, d.y]),
r: data.map(d => d.r),
stroke_size: data.map(d => d.stroke_size)
},
uniforms: {
stage_width: regl.prop('stage_width'),
stage_height: regl.prop('stage_height'),
stroke_width: regl.prop('stroke_width'),
fill_color: regl.prop('fill_color'),
stroke_color: regl.prop('stroke_color'),
circle_multiplier: regl.prop('circle_multiplier')
},
count: data.length,
primitive: 'points',
vert: `
precision mediump float;
attribute vec2 position;
attribute float r;
attribute float stroke_size;
varying float s_s;
uniform float stage_width;
uniform float stage_height;
uniform float circle_multiplier;
vec2 normalizeCoords(vec2 position) {
float x = position[0];
float y = position[1];
return vec2(
2.0 * ((x / stage_width) - 0.5),
-(2.0 * ((y / stage_height) - 0.5))
);
}
void main () {
s_s = stroke_size;
gl_PointSize = r*circle_multiplier;
gl_Position = vec4(normalizeCoords(position), 0.0, 1.0);
}`,
frag: `
#extension GL_OES_standard_derivatives : enable
precision mediump float;
uniform vec3 fill_color;
uniform vec3 stroke_color;
varying float s_s;
void main () {
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
float dist = dot(cxy, cxy);
float delta = fwidth(dist);
float alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, dist);
float outer_edge_center = 1.0 - s_s;
float stroke = 1.0 - smoothstep(outer_edge_center - delta, outer_edge_center + delta, dist);
// gl_FragColor = vec4(fill_color,1.0) * alpha;
gl_FragColor = vec4( mix(stroke_color, fill_color, stroke), 1.0 ) * alpha;
gl_FragColor.rgb *= gl_FragColor.a;
}`
});
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment