@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
JavaScript
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;
}