canvas.js
2.8 kB · javascript · 111 lines
1import { CLEAR, board } from "./frame.js";23const TAU = 2 * Math.PI;45// PAINT67const css = (c) => `rgba(${c[0]},${c[1]},${c[2]},${c[3] / 255})`;89function surface(pixels) {10 const [h, w] = pixels.shape;11 const src = pixels.colors;12 const bytes = src instanceof Uint8ClampedArray ? src : new Uint8ClampedArray(src.buffer, src.byteOffset, w * h * 4);13 const out = new OffscreenCanvas(w, h);14 out.getContext("2d").putImageData(new ImageData(bytes, w, h), 0, 0);15 return out;16}1718// CANVAS1920export function canvas(ctx, width, height, ground = CLEAR) {21 ctx.clearRect(0, 0, width, height);22 if (ground[3] > 0) {23 ctx.fillStyle = css(ground);24 ctx.fillRect(0, 0, width, height);25 }2627 function fill(c) {28 ctx.fillStyle = css(c);29 ctx.fill("evenodd");30 }3132 function stroke(c, thick) {33 ctx.strokeStyle = css(c);34 ctx.lineWidth = thick;35 ctx.lineCap = "round";36 ctx.lineJoin = "round";37 ctx.stroke();38 }3940 function path(pts) {41 ctx.beginPath();42 ctx.moveTo(pts[0][0], pts[0][1]);43 for (let i = 1; i < pts.length; i++) ctx.lineTo(pts[i][0], pts[i][1]);44 }4546 function disc(cx, cy, r, c) {47 if (!(r > 0)) return;48 ctx.beginPath();49 ctx.arc(cx, cy, r, 0, TAU);50 fill(c);51 }5253 function ring(cx, cy, r, thick, c) {54 if (r <= 0) return disc(cx, cy, r + thick / 2, c);55 ctx.beginPath();56 ctx.arc(cx, cy, r, 0, TAU);57 stroke(c, thick);58 }5960 function polygon(pts, c) {61 if (pts.length < 3) return;62 path(pts);63 ctx.closePath();64 fill(c);65 }6667 return {68 ...board(width, height),69 rect(x, y, w, h, c) {70 ctx.fillStyle = css(c);71 ctx.fillRect(x, y, w, h);72 },73 round_rect(x, y, w, h, r, c) {74 ctx.beginPath();75 ctx.roundRect(x, y, w, h, Math.max(Math.min(r, w / 2, h / 2), 0));76 fill(c);77 },78 disc,79 ring,80 segment(a, b, thick, c) {81 if (a[0] === b[0] && a[1] === b[1]) return disc(a[0], a[1], thick / 2, c);82 path([a, b]);83 stroke(c, thick);84 },85 polyline(pts, thick, c) {86 if (pts.length < 2) return;87 path(pts);88 stroke(c, thick);89 },90 triangle(a, b, c, color) {91 polygon([a, b, c], color);92 },93 polygon,94 arc(center, r, angles, thick, c) {95 const [cx, cy] = center;96 const lo = Math.min(angles[0], angles[1]);97 const span = Math.abs(angles[1] - angles[0]);98 if (span >= TAU) return ring(cx, cy, r, thick, c);99 if (span === 0) return disc(cx + r * Math.cos(lo), cy + r * Math.sin(lo), thick / 2, c);100 ctx.beginPath();101 ctx.arc(cx, cy, r, lo, lo + span);102 stroke(c, thick);103 },104 image(x, y, w, h, pixels) {105 const smooth = ctx.imageSmoothingEnabled;106 ctx.imageSmoothingEnabled = false;107 ctx.drawImage(surface(pixels), x, y, w, h);108 ctx.imageSmoothingEnabled = smooth;109 },110 };111}