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}