UNPKG

@zsnout/ithkuil

Version:

A set of tools which can generate and parse romanized Ithkuil text and which can generate Ithkuil script from text and JSON data.

110 lines (109 loc) 4.49 kB
import { jsx as _jsx } from "@zsnout/ithkuil-jsx/jsx-runtime"; import { AnchorX, AnchorY } from "../utilities/anchor.js"; import { Clone } from "../utilities/clone.js"; import { getBBox } from "../utilities/get-bbox.js"; import { doShapesIntersect } from "../utilities/intersection-check.js"; import { Translate } from "../utilities/translate.js"; const isArray = /* @__PURE__ */ (() => Array.isArray)(); /** * Combines several shapes into a single row. * * @param props Properties that modify the output of this `Row`. * @returns An `SVGGElement` containing the elements. */ export function Row(props) { const INITIAL_CHECKING_INTERVAL = Math.abs(props.compact?.baseSpacingInterval || 5); const SPACING_IMPROVEMENT_COUNT = props.compact?.spacingImprovements ?? 5; const space = props.space ?? 10; let row = (_jsx("g", {})); let first; let rest; if (Array.isArray(props.children)) { ; [first, ...rest] = props.children; } else { first = props.children; } if (props.intro) { if (isArray(props.intro)) { row.append(...props.intro); } else { row.append(props.intro); } if (first) { ; (rest ??= []).unshift(first); } } else if (first) { row.appendChild(first); } if (props.compact) { outer: for (const el of rest || []) { if (props.vertical) { AnchorY({ at: props.reverse ? "b" : "t", children: el }); } else { AnchorX({ at: props.reverse ? "r" : "l", children: el }); } const comparedBase = el == rest[0] ? row : row.children[row.children.length - 1] || row; const compared = comparedBase instanceof SVGGraphicsElement ? comparedBase : (_jsx("g", { children: comparedBase })); const comparedBox = getBBox(compared); let CHECKING_INTERVAL = INITIAL_CHECKING_INTERVAL; const makeShape = props.vertical ? props.reverse ? (y) => (_jsx(Translate, { y: comparedBox.y - y, children: _jsx(Clone, { children: el }) })) : (y) => (_jsx(Translate, { y: comparedBox.y + comparedBox.height + y, children: _jsx(Clone, { children: el }) })) : props.reverse ? (x) => (_jsx(Translate, { x: comparedBox.x - x, children: _jsx(Clone, { children: el }) })) : (x) => (_jsx(Translate, { x: comparedBox.x + comparedBox.width + x, children: _jsx(Clone, { children: el }) })); const max = props.vertical ? comparedBox.height : comparedBox.width; const min = -max; for (let x = max; x > min; x -= CHECKING_INTERVAL) { if (doShapesIntersect(makeShape(x), compared, space)) { // Intersects at lower bound. let lower = x; // Does not intersect at upper bound. let upper = x + CHECKING_INTERVAL; for (let i = 0; i < SPACING_IMPROVEMENT_COUNT; i++) { const x = (lower + upper) / 2; if (doShapesIntersect(makeShape(x), compared, space)) { lower = x; } else { upper = x; } } const position = (lower + upper) / 2; row.appendChild(makeShape(position)); continue outer; } } row.appendChild(makeShape(space)); } } else { for (const el of rest || []) { const box = getBBox(row); if (props.vertical) { if (props.reverse) { row.appendChild(_jsx(AnchorY, { at: "b", y: box.y - space, children: el })); } else { row.appendChild(_jsx(AnchorY, { at: "t", y: box.y + box.height + space, children: el })); } } else { if (props.reverse) { row.appendChild(_jsx(AnchorX, { at: "r", x: box.x - space, children: el })); } else { row.appendChild(_jsx(AnchorX, { at: "l", x: box.x + box.width + space, children: el })); } } } } return row; }