canvas
View Compiled
html, body, canvas
width: 100%
height: 100%
overflow: hidden
content-zooming: none
user-select: none
body
cursor: pointer
View Compiled
let af;
let t = 0;
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const avgNeighbors = (map, ro, co) => {
let sum = 0;
let count = 0;
for (let r = ro - 1; r <= ro + 1; ++r) {
if (r < 0 || r >= map.length) continue;
for (let c = co - 1; c <= co + 1; ++c) {
if (c < 0 || c >= map[0].length) continue;
sum += map[r][c];
++count;
}
}
return sum / count;
};
const smoothMap = (oldMap) => {
const newMap = oldMap.slice(0);
for (let r = 0; r < oldMap.length; ++r) {
for (let c = 0; c < oldMap[0].length; ++c) {
const a = avgNeighbors(oldMap, r, c);
newMap[r][c] = a;
}
}
return newMap;
};
const createMap = (w, h) => {
let map = new Array(h);
for (let r = 0; r < h; ++r) {
map[r] = new Array(w);
for (let c = 0; c < w; ++c) {
map[r][c] = Math.random();
}
}
for (let i = 0; i < 5; ++i) map = smoothMap(map);
let max = map[0][0];
let min = map[0][0];
for (let r = 0; r < h; ++r) {
for (let c = 0; c < w; ++c) {
max = Math.max(max, map[r][c]);
min = Math.min(min, map[r][c]);
}
}
return { map, max, min };
};
const project = (x, y, z) => {
return {
px: ((x * (z + 3)) / canvas.width) * 50 + canvas.width / 2,
py: ((y * (z + 3)) / canvas.height) * 50 + canvas.height / 2
};
};
const render = (mapValues) => {
const { map, max, min } = mapValues;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const w = map[0].length;
const h = map.length;
const points = new Array(h);
for (let r = 0; r < h; ++r) {
points[r] = new Array(w);
}
for (let r = 0; r < h; ++r) {
for (let c = 0; c < w; ++c) {
const x = ((c - w / 2) / w) * 2 * canvas.width;
const y = ((r - h / 2) / h) * 2 * canvas.height;
const v = (map[r][c] - min) / (max - min);
const rad = (Math.sin(v * Math.PI * 2 + t) + 1) / 2;
const { px, py } = project(x, y, rad);
points[r][c] = { x: px, y: py, v: rad };
}
}
for (let r = 0; r < h; ++r) {
for (let c = 0; c < w; ++c) {
const pa = points[r][c];
if (r > 0 && c > 0) {
const pb = points[r - 1][c];
const pc = points[r][c - 1];
const v = pa.v + pb.v + pc.v / 3;
ctx.beginPath();
ctx.moveTo(pa.x, pa.y);
ctx.lineTo(pb.x, pb.y);
ctx.lineTo(pc.x, pc.y);
ctx.fillStyle = `hsl(${v * 30 + 200},100%,${51 + v * 15}%)`;
ctx.fill();
}
if (r < h - 1 && c < w - 1) {
const pb = points[r + 1][c];
const pc = points[r][c + 1];
const v = pa.v + pb.v + pc.v / 3;
ctx.beginPath();
ctx.moveTo(pa.x, pa.y);
ctx.lineTo(pb.x, pb.y);
ctx.lineTo(pc.x, pc.y);
ctx.fillStyle = `hsl(${v * 30 + 200},100%,${50 + v * 15}%)`;
ctx.fill();
}
}
}
t += 0.05;
af = requestAnimationFrame(() => render(mapValues));
};
const init = () => {
cancelAnimationFrame(af);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
render(createMap(16, 16));
};
window.onclick = init;
window.onresize = init;
init();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.