231 lines
9.2 KiB
HTML
231 lines
9.2 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
<meta name="generator" content="Observable Framework v1.13.3">
|
|
<title>Genuary26 - 2 | Genuary02</title>
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap" crossorigin>
|
|
<link rel="preload" as="style" href="./_observablehq/theme-air,near-midnight.dcdbf18e.css">
|
|
<link rel="preload" as="style" href="./_observablehq/stdlib/inputs.ea9fd553.css">
|
|
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap" crossorigin>
|
|
<link rel="stylesheet" type="text/css" href="./_observablehq/theme-air,near-midnight.dcdbf18e.css">
|
|
<link rel="stylesheet" type="text/css" href="./_observablehq/stdlib/inputs.ea9fd553.css">
|
|
<link rel="modulepreload" href="./_observablehq/client.28f3e803.js">
|
|
<link rel="modulepreload" href="./_observablehq/runtime.e080113b.js">
|
|
<link rel="modulepreload" href="./_observablehq/stdlib.73a8ec5a.js">
|
|
<link rel="modulepreload" href="./_npm/d3@7.9.0/e780feca.js">
|
|
<link rel="modulepreload" href="./_observablehq/stdlib/inputs.4ef1d259.js">
|
|
<link rel="modulepreload" href="./_npm/htl@0.3.1/72f4716c.js">
|
|
<link rel="modulepreload" href="./_npm/isoformat@0.2.1/18cbf477.js">
|
|
<link rel="modulepreload" href="./_npm/d3-array@3.2.4/e93ca09f.js">
|
|
<link rel="modulepreload" href="./_npm/d3-axis@3.0.0/0f2de24d.js">
|
|
<link rel="modulepreload" href="./_npm/d3-brush@3.0.0/65eb105b.js">
|
|
<link rel="modulepreload" href="./_npm/d3-chord@3.0.1/7ef8fb2e.js">
|
|
<link rel="modulepreload" href="./_npm/d3-color@3.1.0/aeb57b94.js">
|
|
<link rel="modulepreload" href="./_npm/d3-contour@4.0.2/1d2aed74.js">
|
|
<link rel="modulepreload" href="./_npm/d3-delaunay@6.0.4/5ced1d52.js">
|
|
<link rel="modulepreload" href="./_npm/d3-dispatch@3.0.1/9ba9c7f3.js">
|
|
<link rel="modulepreload" href="./_npm/d3-drag@3.0.0/4202580c.js">
|
|
<link rel="modulepreload" href="./_npm/d3-dsv@3.0.1/9cffc2bd.js">
|
|
<link rel="modulepreload" href="./_npm/d3-ease@3.0.1/cdd7e898.js">
|
|
<link rel="modulepreload" href="./_npm/d3-fetch@3.0.1/b4e2ad9a.js">
|
|
<link rel="modulepreload" href="./_npm/d3-force@3.0.0/5e804d15.js">
|
|
<link rel="modulepreload" href="./_npm/d3-format@3.1.0/86074ef6.js">
|
|
<link rel="modulepreload" href="./_npm/d3-geo@3.1.1/40599fb3.js">
|
|
<link rel="modulepreload" href="./_npm/d3-hierarchy@3.1.2/e49e792c.js">
|
|
<link rel="modulepreload" href="./_npm/d3-interpolate@3.0.1/8d1e5425.js">
|
|
<link rel="modulepreload" href="./_npm/d3-path@3.1.0/20d3f133.js">
|
|
<link rel="modulepreload" href="./_npm/d3-polygon@3.0.1/7553081f.js">
|
|
<link rel="modulepreload" href="./_npm/d3-quadtree@3.0.1/0dfd751c.js">
|
|
<link rel="modulepreload" href="./_npm/d3-random@3.0.1/3c90ee06.js">
|
|
<link rel="modulepreload" href="./_npm/d3-scale@4.0.2/843b6a76.js">
|
|
<link rel="modulepreload" href="./_npm/d3-scale-chromatic@3.1.0/ba24c2e7.js">
|
|
<link rel="modulepreload" href="./_npm/d3-selection@3.0.0/4d94e5b7.js">
|
|
<link rel="modulepreload" href="./_npm/d3-shape@3.2.0/6d3a6726.js">
|
|
<link rel="modulepreload" href="./_npm/d3-time@3.1.0/9f03c579.js">
|
|
<link rel="modulepreload" href="./_npm/d3-time-format@4.1.0/07c9626f.js">
|
|
<link rel="modulepreload" href="./_npm/d3-timer@3.0.1/b58a267d.js">
|
|
<link rel="modulepreload" href="./_npm/d3-transition@3.0.1/004da2ac.js">
|
|
<link rel="modulepreload" href="./_npm/d3-zoom@3.0.0/b5786b3f.js">
|
|
<link rel="modulepreload" href="./_npm/internmap@2.0.3/e08981d9.js">
|
|
<link rel="modulepreload" href="./_npm/delaunator@5.0.1/02d43215.js">
|
|
<link rel="modulepreload" href="./_npm/robust-predicates@3.0.2/aa00730b.js">
|
|
<link rel="icon" href="./_file/observable.1af93621.png" type="image/png" sizes="32x32">
|
|
<script type="module">
|
|
|
|
import {define} from "./_observablehq/client.28f3e803.js";
|
|
|
|
define({id: "fc1b3d75", outputs: ["WIDTH","HEIGHT","CELL","CELLW","CELLH","GEN_TIME","INIT_PROB","restart"], body: () => {
|
|
const WIDTH = 800;
|
|
const HEIGHT = 600;
|
|
|
|
const CELL = 10;
|
|
const CELLW = 80;
|
|
const CELLH = 60;
|
|
const GEN_TIME = 1000;
|
|
const INIT_PROB = 0.5;
|
|
|
|
const restart = { restart: false };
|
|
|
|
return {WIDTH,HEIGHT,CELL,CELLW,CELLH,GEN_TIME,INIT_PROB,restart};
|
|
}});
|
|
|
|
define({id: "4fd53651", inputs: ["view","Inputs"], outputs: ["trigger"], body: (view,Inputs) => {
|
|
const trigger = view(Inputs.button("Restart"));
|
|
return {trigger};
|
|
}});
|
|
|
|
define({id: "1eae74b2", inputs: ["trigger","restart"], body: (trigger,restart) => {
|
|
trigger;
|
|
restart["restart"] = true;
|
|
}});
|
|
|
|
define({id: "6dda8554", inputs: ["CELLW","CELLH","CELL","INIT_PROB","restart","GEN_TIME"], outputs: ["neighbours","show_grid"], body: (CELLW,CELLH,CELL,INIT_PROB,restart,GEN_TIME) => {
|
|
|
|
function neighbours(i, j, id) {
|
|
const VWRAP = CELLW * (CELLH - 1);
|
|
const e = i > 0 ? id - 1 : id + CELLW - 1;
|
|
const w = i < CELLW - 1 ? id + 1 : id - CELLW + 1;
|
|
const n = [e, id, w].map((v) => j > 0 ? v - CELLW : v + VWRAP);
|
|
const s = [e, id, w].map((v) => j < CELLH - 1 ? v + CELLW : v - VWRAP);
|
|
return [...n, e, w, ...s];
|
|
}
|
|
|
|
|
|
const show_grid = (async function* () {
|
|
const grid = [];
|
|
|
|
for( let j = 0; j < CELLH; j++ ) {
|
|
for ( let i = 0; i < CELLW; i++ ) {
|
|
const id = j * CELLW + i;
|
|
const cell = { id: id, x: (i + 0.5) * CELL, y: (j + 0.5) * CELL, live: Math.random() > INIT_PROB };
|
|
cell["n"] = neighbours(i, j, id);
|
|
grid.push(cell);
|
|
}
|
|
}
|
|
|
|
|
|
let i = 0;
|
|
while ( true ) {
|
|
if( restart["restart"] ) {
|
|
grid.forEach((c) => c.live = Math.random() > INIT_PROB);
|
|
restart["restart"] = false
|
|
}
|
|
yield grid.filter((d) => d.live);
|
|
i++;
|
|
const ngrid = [];
|
|
for( const id in grid ) {
|
|
const live_n = grid[id].n.filter((i) => grid[i].live).length;
|
|
if( grid[id].live ) {
|
|
ngrid[id] = ( live_n > 2 && live_n < 4 );
|
|
} else {
|
|
ngrid[id] = ( live_n === 3 );
|
|
}
|
|
}
|
|
for( const id in grid ) {
|
|
grid[id].live = ngrid[id];
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, GEN_TIME));
|
|
}
|
|
})();
|
|
|
|
|
|
|
|
return {neighbours,show_grid};
|
|
}});
|
|
|
|
define({id: "983245fe", inputs: ["d3","WIDTH","HEIGHT","display"], outputs: ["svg","bg_g","cells_g","ease"], body: (d3,WIDTH,HEIGHT,display) => {
|
|
// Set up the svg canvas
|
|
|
|
const svg = d3.create("svg")
|
|
.attr("width", WIDTH)
|
|
.attr("height", HEIGHT)
|
|
.attr("viewBox", [ 0, 0, WIDTH, HEIGHT ]);
|
|
|
|
|
|
svg.append("clipPath")
|
|
.attr("id", "clipRect")
|
|
.append("rect")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("width", WIDTH)
|
|
.attr("height", HEIGHT);
|
|
|
|
|
|
const bg_g = svg.append("g")
|
|
.attr("id", "background");
|
|
|
|
bg_g.selectAll("rect")
|
|
.data( [ { bg: "white" } ] )
|
|
.join("rect")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("width", WIDTH)
|
|
.attr("height", HEIGHT)
|
|
.attr("fill", (d) => d.bg)
|
|
;
|
|
|
|
const cells_g = svg.append("g")
|
|
.attr("id", "cells");
|
|
// .attr("clip-path", "url(#clipRect)");
|
|
|
|
display(svg.node());
|
|
|
|
const ease = d3.easeElastic.period(0.4).amplitude(3);
|
|
return {svg,bg_g,cells_g,ease};
|
|
}});
|
|
|
|
define({id: "8b3388da", inputs: ["cells_g","show_grid","ease"], body: (cells_g,show_grid,ease) => {
|
|
cells_g.selectAll("circle")
|
|
.data(show_grid, d => d.id)
|
|
.join(
|
|
enter => enter.append("circle")
|
|
.attr("cx", (d) => d.x)
|
|
.attr("cy", (d) => d.y)
|
|
.attr("fill", "green")
|
|
.transition()
|
|
.ease(ease)
|
|
.duration(1000)
|
|
.attr("r", (d) => 10),
|
|
update => update.attr("fill", "blue"),
|
|
exit => exit
|
|
.transition()
|
|
.duration(2000)
|
|
.attr("r", 0)
|
|
.attr("cy", (d) => d.y + 400)
|
|
.remove()
|
|
);
|
|
|
|
|
|
|
|
}});
|
|
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="observablehq-center">
|
|
<aside id="observablehq-toc" data-selector="h1:not(:first-of-type)[id], h2:first-child[id], :not(h1) + h2[id]">
|
|
<nav>
|
|
</nav>
|
|
</aside>
|
|
<main id="observablehq-main" class="observablehq">
|
|
<h1 id="genuary26-2" tabindex="-1"><a class="observablehq-header-anchor" href="#genuary26-2">Genuary26 - 2</a></h1>
|
|
<p>Prompt: <a href="https://en.wikipedia.org/wiki/Twelve_basic_principles_of_animation" target="_blank" rel="noopener noreferrer">Twelve principles of animation</a></p>
|
|
<p><a href="https://en.wikipedia.org/wiki/Conway's_Game_of_Life" target="_blank" rel="noopener noreferrer">Conway's Game of Life</a> jazzed up with some d3 transitions.</p>
|
|
<p><a href="https://etc.mikelynch.org/genuary26/" target="_blank" rel="noopener noreferrer">back to Genuary26</a></p>
|
|
<div class="observablehq observablehq--block"><!--:fc1b3d75:--></div>
|
|
<div class="observablehq observablehq--block"><!--:4fd53651:--></div>
|
|
<div class="observablehq observablehq--block"><!--:1eae74b2:--></div>
|
|
<div class="observablehq observablehq--block"><!--:6dda8554:--></div>
|
|
<div class="observablehq observablehq--block"><!--:983245fe:--></div>
|
|
<div class="observablehq observablehq--block"><!--:8b3388da:--></div>
|
|
</main>
|
|
<footer id="observablehq-footer">
|
|
<div>Built with <a href="https://observablehq.com/" target="_blank" rel="noopener noreferrer">Observable</a> on <a title="2026-01-03T08:29:42">Jan 3, 2026</a>.</div>
|
|
</footer>
|
|
</div>
|
|
</body>
|
|
</html>
|