UNPKG

@thi.ng/hdom-canvas

Version:

@thi.ng/hdom component wrapper for declarative canvas scenegraphs

132 lines (131 loc) 3.52 kB
import { NO_OP } from "@thi.ng/api/api"; import { isArray } from "@thi.ng/checks/is-array"; import { isNotStringAndIterable } from "@thi.ng/checks/is-not-string-iterable"; import { diffArray } from "@thi.ng/diff/array"; import { assert } from "@thi.ng/errors/assert"; import { equiv, releaseTree } from "@thi.ng/hdom/diff"; import { draw } from "@thi.ng/hiccup-canvas/draw"; const FN = "function"; const STR = "string"; const canvas = { render(_, attribs, ...body) { const cattribs = { ...attribs }; delete cattribs.__diff; delete cattribs.__normalize; const dpr = window.devicePixelRatio || 1; if (dpr !== 1) { !cattribs.style && (cattribs.style = {}); cattribs.style.width = `${cattribs.width}px`; cattribs.style.height = `${cattribs.height}px`; cattribs.width *= dpr; cattribs.height *= dpr; } return [ "canvas", cattribs, [ "g", { __impl: IMPL, __diff: attribs.__diff !== false, __normalize: attribs.__normalize !== false, __release: attribs.__release === true, __serialize: false, __clear: attribs.__clear, scale: dpr !== 1 ? dpr : null }, ...body ] ]; } }; const createTree = (_, canvas2, tree) => { const ctx = canvas2.getContext("2d"); assert(!!ctx, "canvas ctx unavailable"); const attribs = tree[1]; if (attribs) { if (attribs.__skip) return; if (attribs.__clear !== false) { ctx.clearRect(0, 0, canvas2.width, canvas2.height); } } draw(ctx, tree); }; const normalizeTree = (opts, tree) => { if (tree == null) { return tree; } if (isArray(tree)) { const tag = tree[0]; if (typeof tag === FN) { return normalizeTree( opts, tag.apply(null, [opts.ctx, ...tree.slice(1)]) ); } if (typeof tag === STR) { const attribs = tree[1]; if (attribs?.__normalize === false) { return tree; } const res = [tree[0], attribs]; for (let i = 2, n = tree.length; i < n; i++) { const n2 = normalizeTree(opts, tree[i]); n2 != null && res.push(n2); } return res; } } else if (typeof tree === FN) { return normalizeTree(opts, tree(opts.ctx)); } else if (typeof tree.toHiccup === FN) { return normalizeTree(opts, tree.toHiccup(opts.ctx)); } else if (typeof tree.deref === FN) { return normalizeTree(opts, tree.deref()); } else if (isNotStringAndIterable(tree)) { const res = []; for (let t of tree) { const n = normalizeTree(opts, t); n != null && res.push(n); } return res; } return tree; }; const diffTree = (opts, parent, prev, curr, child) => { const attribs = curr[1]; if (attribs.__skip) return; if (attribs.__diff === false) { releaseTree(prev); return createTree(opts, parent, curr); } let impl = attribs.__impl; if (impl && impl !== IMPL) { return impl.diffTree(opts, parent, prev, curr, child); } const delta = diffArray(prev, curr, "only-distance", equiv); if (delta.distance > 0) { return createTree(opts, parent, curr); } }; const IMPL = { createTree, normalizeTree, diffTree, hydrateTree: NO_OP, getElementById: NO_OP, createElement: NO_OP, createTextElement: NO_OP, replaceChild: NO_OP, getChild: NO_OP, removeAttribs: NO_OP, removeChild: NO_OP, setAttrib: NO_OP, setContent: NO_OP }; export { IMPL, canvas, createTree, diffTree, normalizeTree };