import React, { useState } from "react"; import ReactDOM from "react-dom"; import { Point } from "../vendor/bezier-js"; import { Bbox, dilateBoundingBox, getBoundingBoxSize } from "./bounding-box"; import { FILL_REPLACEMENT_COLOR, STROKE_REPLACEMENT_COLOR } from "./colors"; import * as colors from "./colors"; import { Specs } from "./specs"; import _SvgVocabulary from "./svg-vocabulary.json"; import type { SvgSymbolData, SvgSymbolElement } from "./vocabulary"; const APP_ID = "app"; const appEl = document.getElementById(APP_ID); const SvgVocabulary: SvgSymbolData[] = _SvgVocabulary as any; if (!appEl) { throw new Error(`Unable to find #${APP_ID}!`); } type SvgSymbolContext = { stroke: string; fill: string; showSpecs: boolean; }; type SvgSymbolProps = { data: SvgSymbolData; scale?: number; } & SvgSymbolContext; const px = (value: number) => `${value}px`; function reactifySvgSymbolElement( ctx: SvgSymbolContext, el: SvgSymbolElement, key: number ): JSX.Element { let { fill, stroke } = el.props; if (fill === STROKE_REPLACEMENT_COLOR) { // The fill represents a "shadow" area, so use our stroke color here. fill = ctx.stroke; } else if (fill === FILL_REPLACEMENT_COLOR) { fill = ctx.fill; } if (stroke === STROKE_REPLACEMENT_COLOR) { stroke = ctx.stroke; } return React.createElement( el.tagName, { ...el.props, id: undefined, fill, stroke, key, }, el.children.map(reactifySvgSymbolElement.bind(null, ctx)) ); } const ATTACHMENT_POINT_RADIUS = 20; const AttachmentPoints: React.FC<{ color: string; points: Point[] }> = ( props ) => ( <> {props.points.map((p, i) => ( ))} ); const BoundingBoxes: React.FC<{ fill: string; bboxes: Bbox[] }> = (props) => ( <> {props.bboxes.map((b, i) => { const [width, height] = getBoundingBoxSize(b); return ( ); })} ); const SvgSymbolSpecs: React.FC<{ specs: Specs }> = ({ specs }) => { return ( <> {specs.tail && ( )} {specs.leg && ( )} {specs.arm && ( )} {specs.horn && ( )} {specs.crown && ( )} {specs.nesting && ( )} ); }; const BBOX_DILATION = 50; const SvgSymbol: React.FC = (props) => { const d = props.data; const bbox = dilateBoundingBox(d.bbox, BBOX_DILATION); const scale = props.scale || 1; const [width, height] = getBoundingBoxSize(bbox); return ( {props.data.layers.map(reactifySvgSymbolElement.bind(null, props))} {props.showSpecs && d.specs && } ); }; const App: React.FC<{}> = () => { const [stroke, setStroke] = useState("#000000"); const [fill, setFill] = useState("#ffffff"); const [showSpecs, setShowSpecs] = useState(false); return ( <>

Mystic Symbolic Vocabulary

setStroke(e.target.value)} id="stroke" />{" "} setFill(e.target.value)} id="fill" />{" "}

{SvgVocabulary.map((symbolData) => (
{symbolData.name}
))} ); }; ReactDOM.render(, appEl);