kmap-term-tree 0.9.21 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/demo/index.html +124 -10
- package/demo/kmap.html +64 -0
- package/dist/src/KmapTermTree.d.ts +37 -46
- package/dist/src/KmapTermTree.js +641 -216
- package/dist/src/KmapTermTree.js.map +1 -1
- package/dist/src/asciimath-parser.d.ts +17 -0
- package/dist/src/asciimath-parser.js +472 -0
- package/dist/src/asciimath-parser.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/katex-css.d.ts +2 -0
- package/dist/src/katex-css.js +7 -0
- package/dist/src/katex-css.js.map +1 -0
- package/dist/src/model.d.ts +30 -0
- package/dist/src/model.js +26 -0
- package/dist/src/model.js.map +1 -0
- package/dist/src/parser.js.map +1 -1
- package/dist/src/tokenizer.js.map +1 -1
- package/dist/stories/index.stories.d.ts +20 -0
- package/dist/stories/index.stories.js +26 -2
- package/dist/stories/index.stories.js.map +1 -1
- package/dist/test/asciimath-parser.test.d.ts +1 -0
- package/dist/test/asciimath-parser.test.js +45 -0
- package/dist/test/asciimath-parser.test.js.map +1 -0
- package/dist/test/kmap-term-tree.test.js +45 -8
- package/dist/test/kmap-term-tree.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -50
- package/src/KmapTermTree.ts +675 -230
- package/src/asciimath-parser.ts +554 -0
- package/src/index.ts +2 -0
- package/src/katex-css.ts +7 -0
- package/src/model.ts +57 -0
- package/stories/index.stories.ts +35 -2
- package/test/asciimath-parser.test.ts +50 -0
- package/test/kmap-term-tree.test.ts +66 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KmapTermTree.js","sourceRoot":"","sources":["../../src/KmapTermTree.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,GAAG,EAAE,IAAI,EAAE,UAAU,EAAkB,GAAG,EAAC,MAAM,KAAK,CAAC;AAC/D,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAC,SAAS,EAAC,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAC,MAAM,EAAW,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAgBrC,MAAM,OAAO,YAAa,SAAQ,UAAU;IAA5C;;QAkEU,WAAM,GAAW,IAAI,MAAM,EAAE,CAAC;QAGZ,YAAO,GAAW,CAAC,CAAC;IAiJhD,CAAC;IApIC,aAAa;IACb,aAAa,CAAC,EAAC,MAAM,EAAC;QACpB,aAAa;QACb,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAES,MAAM,CAAC,kBAAkC;QACjD,IAAI,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAClC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE;gBAC3B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAE/C,IAAI,GAAG,GAA4B,EAAE,CAAC;gBACtC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBAErD,IAAI,WAAW,GAAiB,EAAE,CAAC;gBACnC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE;oBAC/B,IAAI,CAAC,CAAC,aAAa,KAAK,SAAS;wBAC/B,WAAW,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,EAAC,CAAC,CAAA;oBACpE,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS;wBAChC,WAAW,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,EAAC,CAAC,CAAA;gBACvE,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;gBAClB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;aAChC;SACF;QACD,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACnC,CAAC;IAEO,UAAU,CAAC,IAAc,EAAE,GAA4B;QAC7D,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,IAAI,CAAC,aAAa;YACpB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACxE,IAAI,IAAI,CAAC,cAAc;YACrB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACzE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA;0CACW,IAAI,CAAC,OAAO;OAC/C,CAAC,CAAC,CAAC,EAAE;QACJ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;;YAEpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;qCACF,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;WAClE,CAAC;;;YAGA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;mBACpB,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;WACvC,CAAC;;OAEJ;QACA,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;;YAE7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;qCACF,CAAC,CAAC,EAAE,YAAY,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,SAAS,CAAC,KAAK,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;WACnI,CAAC;;OAEL,CAAC,CAAC,CAAC,EAAE;;4BAEgB,IAAI,CAAC,aAAa;;KAEzC,CAAC;IACJ,CAAC;IAES,KAAK,CAAC,OAAO,CAAC,kBAAkC;QACxD,IAAI,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;YACzC,MAAM,IAAI,CAAC,cAAc,CAAC;YAE1B,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,SAAS,EAAG;gBACzC,IAAI,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC;gBACnD,6BAA6B;gBAC7B,kCAAkC;gBAClC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,4BAA4B,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC1E,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,oCAAoC,EAAE,YAAY,GAAG,IAAI,CAAC,CAAC;gBAClF,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,iGAAiG,CAAC;gBACtH,iCAAiC;aAClC;YAED,IAAI,KAAK,GAAW,EAAE,CAAC;YACvB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,WAAW,EAAE;gBACzC,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,WAAW,EAAE;oBACzC,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;oBACrC,IAAI,IAAI;wBACN,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;iBACpB;gBACD,IAAI,CAAC,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;aACjC;SACF;IACH,CAAC;IAED,QAAQ,CAAC,UAAsB;QAC7B,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACjE,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE;YACd,OAAO;QACT,IAAI,OAAO,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,GAAG,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;QAE3C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;IAED,qBAAqB,CAAC,OAAoB;QACxC,IAAI,CAAC,GAAW,CAAC,CAAC;QAClB,IAAI,CAAC,GAAW,CAAC,CAAC;QAClB,IAAI,EAAE,GAAuB,OAAO,CAAC;QACrC,OAAO,EAAE,KAAK,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,YAA2B,EAAE;YACvD,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC;YACnB,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;SACnB;QACD,OAAO;YACL,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;YACJ,KAAK,EAAE,OAAO,CAAC,WAAW;YAC1B,MAAM,EAAE,OAAO,CAAC,YAAY;SAC7B,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,SAAS,CAAC,KAAa;QACpC,QAAQ,KAAK,EAAE;YACb,KAAK,GAAG;gBACN,OAAO,GAAG,CAAA;YACZ,KAAK,GAAG;gBACN,OAAO,GAAG,CAAC,CAAC,aAAa;YAC3B;gBACE,OAAO,KAAK,CAAC;SAChB;IACH,CAAC;;AAlND,eAAe;AACR,mBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DlB,CAAC;AAI0B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CAAe;AAChB;IAAzB,QAAQ,CAAC,EAAC,IAAI,EAAE,MAAM,EAAC,CAAC;6CAAqB;AAErC;IAAR,KAAK,EAAE;4CAAkB;AACjB;IAAR,KAAK,EAAE;2CAAoB;AACnB;IAAR,KAAK,EAAE;8CAAqB;AACpB;IAAR,KAAK,EAAE;4CAAkC;AACjC;IAAR,KAAK,EAAE;+CAAoB;AAEnB;IAAR,KAAK,EAAE;iDAA4B;AAEL;IAA9B,KAAK,CAAC,sBAAsB,CAAC;kDAAiC;AAC7C;IAAjB,KAAK,CAAC,SAAS,CAAC;mDAAgC;AAwInD,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAAhD;;QAS4B,YAAO,GAAW,EAAE,CAAC;QACtB,UAAK,GAAW,EAAE,CAAC;IA+B9C,CAAC;IA7BC,MAAM;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,YAA2B,CAAC;QAChD,cAAc;QACd,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;+DACiB,MAAM,CAAC,WAAW,aAAa,MAAM,CAAC,YAAY;QACzG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;mBACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;OAC5B,CAAC;;KAEH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAU;QACd,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QAC9C,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/C,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;QACxC,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAEzC,IAAI,KAAK,GAAG,CAAC,GAAG,GAAC,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QACvC,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,IAAI,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC;QACxB,IAAI,GAAG,GAAG,GAAG,CAAC;QACd,IAAI,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC;QACtB,OAAO,IAAI,GAAI,KAAK,GAAG,GAAG,GAAG,KAAK;YAChC,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;cACrB,GAAG,GAAI,GAAG,GAAG,GAAG,GAAG,GAAG;cACtB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC5B,CAAC;;AAtCM,uBAAM,GAAG,GAAG,CAAA;;;;;;GAMlB,CAAC;AAEwB;IAAzB,QAAQ,CAAC,EAAC,IAAI,EAAE,MAAM,EAAC,CAAC;iDAAsB;AACtB;IAAxB,QAAQ,CAAC,EAAC,IAAI,EAAE,KAAK,EAAC,CAAC;+CAAoB;AAgC9C,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAC","sourcesContent":["import {css, html, LitElement, PropertyValues, svg} from 'lit';\nimport {property, state, query} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport {Parser, TermNode} from \"./parser.js\";\nimport {Token} from \"./tokenizer.js\";\n\ninterface Connection {\n from: number,\n to: number,\n}\ninterface Position {\n x: number,\n y: number,\n width: number,\n height: number,\n}\ninterface Edge {\n from: Position,\n to: Position,\n}\nexport class KmapTermTree extends LitElement {\n declare shadowRoot: ShadowRoot;\n\n // language=CSS\n static styles = css`\n :host {\n display: block;\n color: var(--kmap-term-tree-text-color, #000);\n position: relative;\n }\n .tokens, .nodes, kmap-term-tree-edges {\n position: absolute;\n }\n .tokens, .nodes {\n white-space: nowrap;\n }\n .notokens {\n white-space: nowrap;\n height: 0px;\n }\n .notokens div {\n display: inline-block;\n }\n kmap-term-tree-edges {\n width: 100%;\n height: 100%;\n }\n .token {\n display: inline-block;\n }\n .token, .node {\n display: inline-block;\n position: relative;\n background-color: var(--kmap-term-tree-background-color, white);\n }\n .node {\n display: inline-block;\n position: relative;\n border: 1px solid var(--kmap-term-tree-border-color, #005b9f);\n padding: 0px 4px;\n border-radius: 1em;\n margin: -1px -5px;\n }\n .node[depth=\"0\"], .node:not([depth]) {\n visibility: hidden;\n }\n .node[depth=\"1\"] {\n top: calc(var(--kmap-term-tree-vertical-distance, 1.5em) * 1.5);\n }\n .node[depth=\"2\"] {\n top: calc(var(--kmap-term-tree-vertical-distance, 1.5em) * 3);\n }\n .node[depth=\"3\"] {\n top: calc(var(--kmap-term-tree-vertical-distance, 1.5em) * 4.5);\n }\n .node[depth=\"4\"] {\n top: calc(var(--kmap-term-tree-vertical-distance, 1.5em) * 6);\n }\n .node[depth=\"5\"] {\n top: calc(var(--kmap-term-tree-vertical-distance, 1.5em) * 7.5);\n }\n .node[depth=\"6\"] {\n top: calc(var(--kmap-term-tree-vertical-distance, 1.5em) * 9);\n }\n `;\n\n private parser: Parser = new Parser();\n\n @property({ type: String }) term?: string;\n @property({type: Number}) tension: number = 0;\n\n @state() tokens?: Token[];\n @state() nodes?: TermNode[];\n @state() termNode?: TermNode;\n @state() depths?: {[key: string]: number};\n @state() maxDepths?: number;\n\n @state() connections?: Connection[];\n\n @query(\"kmap-term-tree-edges\") edgesElement?: KmapTermTreeEdge;\n @query(\"#tokens\") tokensElement?: HTMLDivElement;\n\n // @ts-ignore\n updateSlotted({target}) {\n // @ts-ignore\n this.term = target.assignedNodes().map((n) => n.textContent).join('');\n }\n\n protected update(_changedProperties: PropertyValues) {\n if (_changedProperties.has(\"term\")) {\n if (this.term !== undefined) {\n this.tokens = Token.tokenize(this.term);\n this.termNode = this.parser.parse(this.tokens);\n\n let map: {[key: string]: number} = {};\n this.maxDepths = this.calcDepths(this.termNode, map);\n\n let connections: Connection[] = [];\n this.termNode.breadthFirst((n) => {\n if (n.leftChildNode !== undefined)\n connections.push({from: n.token.id, to: n.leftChildNode.token.id})\n if (n.rightChildNode !== undefined)\n connections.push({from: n.token.id, to: n.rightChildNode.token.id})\n });\n this.depths = map;\n this.connections = connections;\n }\n }\n super.update(_changedProperties);\n }\n\n private calcDepths(node: TermNode, map: { [p: string]: number }): number {\n let depth = 0;\n if (node.leftChildNode)\n depth = Math.max(depth, this.calcDepths(node.leftChildNode, map) + 1);\n if (node.rightChildNode)\n depth = Math.max(depth, this.calcDepths(node.rightChildNode, map) + 1);\n map[node.token.id] = depth;\n return depth;\n }\n\n render() {\n return html`\n ${this.connections ? html`\n <kmap-term-tree-edges .tension=\"${this.tension}\"></kmap-term-tree-edges>\n ` : ''}\n ${!this.tokens ? '' : html`\n <div class=\"tokens\" id=\"tokens\">\n ${this.tokens.map((t) => html`\n <div class=\"token\" id=\"${t.id}\">${KmapTermTree._prettify(t.value)}</div>\n `)}\n </div>\n <div class=\"notokens\">\n ${this.tokens.map((t) => html`\n <div>${KmapTermTree._prettify(t.value)}</div>\n `)}\n </div>\n ` }\n ${this.tokens && this.depths ? html`\n <div class=\"nodes\">\n ${this.tokens.map((t) => html`\n <div class=\"node\" id=\"n${t.id}\" depth=\"${ifDefined(this.depths ? this.depths[t.id]: undefined)}\">${KmapTermTree._prettify(t.value)}</div>\n `)}\n </div>\n ` : ''}\n <div hidden>\n <slot @slotchange=${this.updateSlotted}></slot>\n </div>\n `;\n }\n\n protected async updated(_changedProperties: PropertyValues) {\n if (_changedProperties.has(\"connections\")) {\n await this.updateComplete;\n\n if (this.tokensElement && this.maxDepths ) {\n let tokensHeight = this.tokensElement.offsetHeight;\n //console.log(this.maxDepths)\n //console.log(tokensHeight + \"px\")\n this.style.setProperty(\"--kmap-term-tree-max-depth\", \"\" + this.maxDepths);\n this.style.setProperty(\"--kmap-term-tree-vertical-distance\", tokensHeight + \"px\");\n this.style.height = \"calc(3px + var(--kmap-term-tree-vertical-distance) * (var(--kmap-term-tree-max-depth)*1.5 + 1))\";\n //console.log(this.style.height);\n }\n\n let edges: Edge[] = [];\n if (this.edgesElement && this.connections) {\n for (const connection of this.connections) {\n let edge = this._connect(connection);\n if (edge)\n edges.push(edge);\n }\n this.edgesElement.edges = edges;\n }\n }\n }\n\n _connect(connection: Connection): Edge | undefined {\n let from = this.shadowRoot.getElementById(\"n\" + connection.from);\n let to = this.shadowRoot.getElementById(\"n\" + connection.to);\n if (!from || !to)\n return;\n let frompos = this._findAbsolutePosition(from);\n let topos = this._findAbsolutePosition(to);\n\n return { from: frompos, to: topos };\n }\n\n _findAbsolutePosition(element: HTMLElement): Position {\n var x: number = 0;\n var y: number = 0;\n var el: HTMLElement | null = element;\n for (; el !== this; el = el.offsetParent as HTMLElement) {\n x += el.offsetLeft;\n y += el.offsetTop;\n }\n return {\n x: x,\n y: y,\n width: element.offsetWidth,\n height: element.offsetHeight,\n };\n }\n\n private static _prettify(value: string) {\n switch (value) {\n case '*':\n return \"·\"\n case '-':\n return \"−\"; // math minus\n default:\n return value;\n }\n }\n}\n\nexport class KmapTermTreeEdge extends LitElement {\n static styles = css`\n :host {\n display: block;\n stroke: var(--kmap-term-tree-edge-color, #fbc02d);\n position: relative;\n }\n `;\n\n @property({type: Number}) tension: number = .5;\n @property({type: Array}) edges: Edge[] = [];\n\n render() {\n const parent = this.offsetParent as HTMLElement;\n //language=SVG\n return this.edges === undefined ? '' : svg`\n <svg style=\"position:absolute;left:0px;top:0px\" width=\"${parent.clientWidth}\" height=\"${parent.clientHeight}\">\n ${this.edges.map(edge => svg`\n <path d=\"${this._path(edge)}\" fill=\"none\" stroke-width=\"2\" stroke-opacity=\".9\"/>\n `)}\n </svg>\n `;\n }\n\n _path(edge: Edge) {\n let fromx = edge.from.x + edge.from.width / 2;\n let fromy = edge.from.y + edge.from.height / 2;\n let tox = edge.to.x + edge.to.width / 2;\n let toy = edge.to.y + edge.to.height / 2;\n\n var delta = (toy-fromy) * this.tension;\n var hx1 = fromx;\n var hy1 = fromy + delta;\n var hx2 = tox;\n var hy2 = toy - delta;\n return \"M \" + fromx + \" \" + fromy +\n \" C \" + hx1 + \" \" + hy1\n + \" \" + hx2 + \" \" + hy2\n + \" \" + tox + \" \" + toy;\n }\n\n}\nwindow.customElements.define('kmap-term-tree-edges', KmapTermTreeEdge);\n"]}
|
|
1
|
+
{"version":3,"file":"KmapTermTree.js","sourceRoot":"","sources":["../../src/KmapTermTree.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, PropertyValues, svg } from 'lit';\nimport { property, state, query } from 'lit/decorators.js';\nimport katex from 'katex';\nimport { katexStyles } from './katex-css.js';\nimport { TermNode, TreeEdge } from './model.js';\nimport { parseAsciiMath, astToAnnotatedLatex } from './asciimath-parser.js';\n\nexport class KmapTermTree extends LitElement {\n static styles = [\n katexStyles,\n css`\n :host {\n display: block;\n position: relative;\n font-family: var(\n --kmap-term-tree-font-family,\n system-ui,\n -apple-system,\n sans-serif\n );\n color: var(--kmap-term-tree-text-color, #1f2937);\n user-select: none;\n width: 100%;\n }\n\n .container {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n box-sizing: border-box;\n }\n\n .tree-canvas {\n position: relative;\n width: 100%;\n min-height: 80px;\n }\n\n .formula-wrapper {\n position: relative;\n z-index: 2;\n display: flex;\n justify-content: center;\n align-items: center;\n padding-top: 4px;\n font-size: var(--kmap-term-tree-formula-font-size, 1.35rem);\n }\n\n .highlight-overlay {\n position: absolute;\n z-index: 1;\n pointer-events: none;\n background-color: var(\n --kmap-term-tree-highlight-color,\n rgba(251, 191, 36, 0.28)\n );\n border: 2px solid\n var(--kmap-term-tree-highlight-outline, rgba(245, 158, 11, 0.75));\n border-radius: 6px;\n box-sizing: border-box;\n transition: left 0.12s ease-out, top 0.12s ease-out,\n width 0.12s ease-out, height 0.12s ease-out;\n }\n\n .edges-svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 1;\n overflow: visible;\n }\n\n .edge-path {\n fill: none;\n stroke: var(--kmap-term-tree-edge-color, #f59e0b);\n stroke-width: 2.2;\n stroke-linecap: round;\n opacity: 0.85;\n transition: stroke 0.2s ease, stroke-width 0.2s ease, opacity 0.2s ease;\n }\n\n .edge-path.highlighted {\n stroke: var(--kmap-term-tree-highlight-edge-color, #d97706);\n stroke-width: 3.2;\n opacity: 1;\n }\n\n .tree-node {\n position: absolute;\n z-index: 2;\n transform: translate(-50%, -50%);\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n cursor: pointer;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n }\n\n .tree-node:hover,\n .tree-node.active {\n transform: translate(-50%, -50%) scale(1.15);\n }\n\n .node-badge {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background: var(--kmap-term-tree-background-color, #ffffff);\n border: 2px solid var(--kmap-term-tree-border-color, #0284c7);\n color: var(--kmap-term-tree-node-text-color, #0284c7);\n font-weight: 700;\n font-size: 1rem;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n box-sizing: border-box;\n transition: all 0.2s ease;\n }\n\n .tree-node:hover .node-badge,\n .tree-node.active .node-badge {\n background: var(--kmap-term-tree-active-node-bg, #0284c7);\n color: #ffffff;\n border-color: var(--kmap-term-tree-active-node-border, #0284c7);\n box-shadow: 0 4px 8px rgba(2, 132, 199, 0.35);\n }\n\n .node-label {\n margin-top: 2px;\n font-size: 0.7rem;\n font-weight: 500;\n color: #64748b;\n white-space: nowrap;\n background: rgba(255, 255, 255, 0.95);\n padding: 1px 4px;\n border-radius: 4px;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n }\n\n /* KaTeX Highlight */\n .highlight-term {\n background-color: var(\n --kmap-term-tree-highlight-color,\n rgba(251, 191, 36, 0.35)\n ) !important;\n border-radius: 4px;\n outline: 2px solid\n var(--kmap-term-tree-highlight-outline, rgba(245, 158, 11, 0.7));\n transition: background-color 0.2s ease, outline 0.2s ease;\n }\n\n .info-bar {\n margin-top: 12px;\n padding: 6px 14px;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 0.88rem;\n display: flex;\n align-items: center;\n gap: 8px;\n color: #334155;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n }\n\n .info-badge {\n font-weight: 700;\n color: #0284c7;\n background: #e0f2fe;\n padding: 2px 8px;\n border-radius: 4px;\n }\n\n .error-msg {\n color: #dc2626;\n padding: 8px;\n font-size: 0.9rem;\n }\n `,\n ];\n\n @property({ type: String }) term?: string;\n @property({ type: Number }) tension: number = 0.5;\n @property({ type: Boolean }) showLabels: boolean = false;\n @property({ type: Boolean }) showDetails: boolean = true;\n\n @state() private ast?: TermNode;\n @state() private error?: string;\n @state() private flatNodes: TermNode[] = [];\n @state() private edges: TreeEdge[] = [];\n @state() private activeNodeId?: string;\n @state() private activeSubtreeIds: Set<string> = new Set();\n @state() private treeHeight: number = 100;\n @state() private highlightRect?: {\n left: number;\n top: number;\n width: number;\n height: number;\n };\n\n @query('#formula') private formulaElement?: HTMLElement;\n @query('.tree-canvas') private treeCanvasElement?: HTMLElement;\n\n private resizeObserver?: ResizeObserver;\n private lastObservedWidth = 0;\n private resizeFrameId?: number;\n private animationTimers: number[] = [];\n\n connectedCallback() {\n super.connectedCallback();\n this.resizeObserver = new ResizeObserver(entries => {\n for (const entry of entries) {\n const width = entry.contentRect.width;\n if (Math.abs(width - this.lastObservedWidth) > 0.5) {\n this.lastObservedWidth = width;\n this.triggerLayoutUpdate();\n }\n }\n });\n\n window.addEventListener('animationend', this.onAnimationOrTransitionEnd);\n window.addEventListener('transitionend', this.onAnimationOrTransitionEnd);\n\n if (typeof document !== 'undefined' && document.fonts) {\n document.fonts.ready.then(() => {\n if (this.isConnected) {\n this.recalculateLayout();\n }\n });\n }\n }\n\n disconnectedCallback() {\n if (this.resizeFrameId) {\n cancelAnimationFrame(this.resizeFrameId);\n }\n this.clearAnimationTimers();\n window.removeEventListener('animationend', this.onAnimationOrTransitionEnd);\n window.removeEventListener('transitionend', this.onAnimationOrTransitionEnd);\n this.resizeObserver?.disconnect();\n super.disconnectedCallback();\n }\n\n private onAnimationOrTransitionEnd = () => {\n this.triggerLayoutUpdate();\n };\n\n private triggerLayoutUpdate() {\n if (this.resizeFrameId) {\n cancelAnimationFrame(this.resizeFrameId);\n }\n this.resizeFrameId = requestAnimationFrame(() => {\n if (this.isConnected) {\n this.recalculateLayout();\n }\n });\n }\n\n private watchAncestorAnimations() {\n let curr: Element | null = this;\n const animations: Animation[] = [];\n\n while (curr) {\n if (typeof curr.getAnimations === 'function') {\n for (const anim of curr.getAnimations()) {\n if (anim.playState === 'running' || anim.pending) {\n animations.push(anim);\n }\n }\n }\n const root = curr.getRootNode() as ShadowRoot | Document;\n if (root && 'host' in root) {\n curr = (root as ShadowRoot).host;\n } else {\n curr = curr.parentElement;\n }\n }\n\n if (animations.length > 0) {\n Promise.all(animations.map(a => a.finished.catch(() => {}))).then(() => {\n if (this.isConnected) {\n this.recalculateLayout();\n }\n });\n }\n }\n\n private scheduleAnimationCheck() {\n this.clearAnimationTimers();\n this.watchAncestorAnimations();\n\n const t1 = window.setTimeout(() => {\n if (!this.isConnected) return;\n this.watchAncestorAnimations();\n this.recalculateLayout();\n }, 50);\n\n const t2 = window.setTimeout(() => {\n if (!this.isConnected) return;\n this.recalculateLayout();\n }, 320);\n\n const t3 = window.setTimeout(() => {\n if (!this.isConnected) return;\n this.recalculateLayout();\n }, 450);\n\n this.animationTimers.push(t1, t2, t3);\n }\n\n private clearAnimationTimers() {\n for (const t of this.animationTimers) {\n clearTimeout(t);\n }\n this.animationTimers = [];\n }\n\n // Support slotted content: <kmap-term-tree>2a+3b</kmap-term-tree>\n updateSlotted(event: Event) {\n const slot = event.target as HTMLSlotElement;\n const text = slot\n .assignedNodes()\n .map(n => n.textContent)\n .join('')\n .trim();\n if (text && text !== this.term) {\n this.term = text;\n }\n }\n\n protected willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('term') && this.term !== undefined) {\n this.parseInput(this.term);\n }\n }\n\n private parseInput(termStr: string) {\n try {\n this.error = undefined;\n const cleanTerm = termStr.trim();\n if (!cleanTerm) {\n this.ast = undefined;\n this.flatNodes = [];\n this.edges = [];\n return;\n }\n\n this.ast = parseAsciiMath(cleanTerm);\n this.activeNodeId = this.ast.id;\n this.activeSubtreeIds = this.collectSubtreeIds(this.ast);\n } catch (e: any) {\n this.error = e.message || 'Fehler beim Parsen des Terms';\n this.ast = undefined;\n this.flatNodes = [];\n this.edges = [];\n }\n }\n\n protected async updated(changedProperties: PropertyValues) {\n if (changedProperties.has('term') || changedProperties.has('ast')) {\n this.renderKaTeX();\n await this.updateComplete;\n this.recalculateLayout();\n if (this.treeCanvasElement && this.resizeObserver) {\n this.resizeObserver.observe(this.treeCanvasElement);\n }\n this.scheduleAnimationCheck();\n }\n }\n\n private renderKaTeX() {\n if (!this.formulaElement || !this.ast) return;\n\n try {\n const latex = astToAnnotatedLatex(this.ast);\n katex.render(latex, this.formulaElement, {\n trust: true,\n strict: false,\n throwOnError: false,\n });\n } catch (err: any) {\n this.error = err.message;\n }\n }\n\n private recalculateLayout() {\n if (\n !this.ast ||\n !this.formulaElement ||\n !this.treeCanvasElement ||\n !this.shadowRoot\n )\n return;\n\n const canvasRect = this.treeCanvasElement.getBoundingClientRect();\n const offsetWidth = this.treeCanvasElement.offsetWidth;\n const offsetHeight = this.treeCanvasElement.offsetHeight;\n\n if (canvasRect.width === 0 || offsetWidth === 0) return;\n this.lastObservedWidth = offsetWidth;\n\n const scaleX = canvasRect.width / offsetWidth;\n const scaleY = offsetHeight > 0 ? canvasRect.height / offsetHeight : scaleX;\n if (scaleX < 0.01 || scaleY < 0.01) return;\n\n const flatNodes: TermNode[] = [];\n const nodeMap = new Map<string, TermNode>();\n\n // 1. Collect all nodes and measure leaf positions from KaTeX DOM elements\n const collectAndPositionLeaves = (node: TermNode) => {\n nodeMap.set(node.id, node);\n\n if (node.children.length === 0) {\n // Leaf node: measure rendered KaTeX span\n const el = this.shadowRoot!.getElementById(node.id);\n if (el) {\n const rect = el.getBoundingClientRect();\n node.x = (rect.left - canvasRect.left + rect.width / 2) / scaleX;\n node.y = (rect.bottom - canvasRect.top) / scaleY;\n node.width = rect.width / scaleX;\n node.height = rect.height / scaleY;\n } else {\n node.x = offsetWidth / 2;\n node.y = 20;\n }\n } else {\n flatNodes.push(node);\n for (const child of node.children) {\n collectAndPositionLeaves(child);\n }\n }\n };\n\n collectAndPositionLeaves(this.ast);\n\n // 2. Position inner nodes bottom-up based on children coordinates\n const formulaRect = this.formulaElement.getBoundingClientRect();\n const formulaBottomRel = (formulaRect.bottom - canvasRect.top) / scaleY;\n const initialGap = 34; // distance from formula bottom to level 1 operators\n const rowHeight = 40; // distance between tree levels\n\n const positionInnerNodes = (node: TermNode) => {\n for (const child of node.children) {\n if (child.children.length > 0) {\n positionInnerNodes(child);\n }\n }\n\n if (node.children.length > 0) {\n if (node.type === 'function' || node.isUnary) {\n // Center under the full function / unary expression: e.g. sin(arg) or -arg\n const el = this.shadowRoot!.getElementById(node.id);\n if (el) {\n const rect = el.getBoundingClientRect();\n node.x = (rect.left - canvasRect.left + rect.width / 2) / scaleX;\n } else {\n node.x = node.children[0].x ?? 0;\n }\n } else {\n const first = node.children[0];\n const last = node.children[node.children.length - 1];\n node.x = ((first.x ?? 0) + (last.x ?? 0)) / 2;\n }\n node.y = formulaBottomRel + initialGap + (node.depth - 1) * rowHeight;\n }\n };\n\n positionInnerNodes(this.ast);\n\n // 3. Build edges between parent nodes and their children\n const edges: TreeEdge[] = [];\n for (const node of flatNodes) {\n if (node.x === undefined || node.y === undefined) continue;\n\n for (const child of node.children) {\n if (child.x === undefined || child.y === undefined) continue;\n\n edges.push({\n fromNodeId: child.id,\n toNodeId: node.id,\n fromX: child.x,\n fromY: child.y + (child.depth > 0 ? 14 : 2),\n toX: node.x,\n toY: node.y - 14,\n });\n }\n }\n\n const maxDepth = this.ast.depth;\n this.treeHeight = Math.max(\n 60,\n formulaBottomRel + initialGap + (maxDepth - 1) * rowHeight + 24\n );\n this.flatNodes = flatNodes;\n this.edges = edges;\n this.updateHighlightRect(this.activeNodeId);\n this.requestUpdate();\n }\n\n private collectSubtreeIds(node: TermNode): Set<string> {\n const ids = new Set<string>();\n const traverse = (n: TermNode) => {\n ids.add(n.id);\n for (const c of n.children) traverse(c);\n };\n traverse(node);\n return ids;\n }\n\n private onNodeHover(node: TermNode, enter: boolean) {\n if (!enter) {\n // Revert highlight to root node\n if (this.ast) {\n this.setActiveNode(this.ast);\n }\n return;\n }\n this.setActiveNode(node);\n }\n\n private setActiveNode(node: TermNode) {\n this.activeNodeId = node.id;\n this.activeSubtreeIds = this.collectSubtreeIds(node);\n this.updateHighlightRect(node.id);\n this.requestUpdate();\n }\n\n private findNode(\n root: TermNode | undefined,\n id: string\n ): TermNode | undefined {\n if (!root) return undefined;\n if (root.id === id) return root;\n for (const child of root.children) {\n const found = this.findNode(child, id);\n if (found) return found;\n }\n return undefined;\n }\n\n private getNodeVisualBounds(\n node: TermNode\n ): { top: number; bottom: number; left: number; right: number } | null {\n if (!this.shadowRoot) return null;\n\n let minTop = Infinity;\n let maxBottom = -Infinity;\n let minLeft = Infinity;\n let maxRight = -Infinity;\n\n const collectBounds = (n: TermNode) => {\n const el = this.shadowRoot!.getElementById(n.id);\n if (el) {\n const r = el.getBoundingClientRect();\n if (r.width > 0 && r.height > 0) {\n minTop = Math.min(minTop, r.top);\n maxBottom = Math.max(maxBottom, r.bottom);\n minLeft = Math.min(minLeft, r.left);\n maxRight = Math.max(maxRight, r.right);\n }\n }\n for (const child of n.children) {\n collectBounds(child);\n }\n };\n\n collectBounds(node);\n\n if (minTop === Infinity) return null;\n return { top: minTop, bottom: maxBottom, left: minLeft, right: maxRight };\n }\n\n private updateHighlightRect(nodeId?: string) {\n if (!nodeId || !this.shadowRoot || !this.treeCanvasElement || !this.ast) {\n this.highlightRect = undefined;\n return;\n }\n\n const node = this.findNode(this.ast, nodeId);\n if (!node) {\n this.highlightRect = undefined;\n return;\n }\n\n const bounds = this.getNodeVisualBounds(node);\n if (!bounds) {\n this.highlightRect = undefined;\n return;\n }\n\n const canvasRect = this.treeCanvasElement.getBoundingClientRect();\n const offsetWidth = this.treeCanvasElement.offsetWidth;\n const offsetHeight = this.treeCanvasElement.offsetHeight;\n if (canvasRect.width === 0 || offsetWidth === 0) {\n this.highlightRect = undefined;\n return;\n }\n\n const scaleX = canvasRect.width / offsetWidth;\n const scaleY = offsetHeight > 0 ? canvasRect.height / offsetHeight : scaleX;\n if (scaleX < 0.01 || scaleY < 0.01) {\n this.highlightRect = undefined;\n return;\n }\n\n const paddingX = 4;\n const paddingY = 4;\n\n this.highlightRect = {\n left: (bounds.left - canvasRect.left) / scaleX - paddingX,\n top: (bounds.top - canvasRect.top) / scaleY - paddingY,\n width: (bounds.right - bounds.left) / scaleX + paddingX * 2,\n height: (bounds.bottom - bounds.top) / scaleY + paddingY * 2,\n };\n }\n\n private renderPath(edge: TreeEdge): string {\n const delta = (edge.toY - edge.fromY) * this.tension;\n const hx1 = edge.fromX;\n const hy1 = edge.fromY + delta;\n const hx2 = edge.toX;\n const hy2 = edge.toY - delta;\n\n return `M ${edge.fromX} ${edge.fromY} C ${hx1} ${hy1} ${hx2} ${hy2} ${edge.toX} ${edge.toY}`;\n }\n\n render() {\n const activeNode =\n this.flatNodes.find(n => n.id === this.activeNodeId) || this.ast;\n const isRoot = activeNode?.id === this.ast?.id;\n\n return html`\n <div class=\"container\">\n <!-- Canvas area with formula, edges, and operator nodes sharing the same coordinate space -->\n <div class=\"tree-canvas\" style=\"height: ${this.treeHeight}px\">\n ${this.highlightRect\n ? html`\n <div\n class=\"highlight-overlay\"\n style=\"left: ${this.highlightRect.left}px; top: ${this\n .highlightRect.top}px; width: ${this.highlightRect\n .width}px; height: ${this.highlightRect.height}px;\"\n ></div>\n `\n : ''}\n\n <div class=\"formula-wrapper\">\n <div id=\"formula\"></div>\n </div>\n\n ${this.error\n ? html`<div class=\"error-msg\">${this.error}</div>`\n : html`\n <svg class=\"edges-svg\">\n ${this.edges.map(\n edge => svg`\n <path\n class=\"edge-path ${\n this.activeSubtreeIds.has(edge.fromNodeId) &&\n this.activeSubtreeIds.has(edge.toNodeId)\n ? 'highlighted'\n : ''\n }\"\n d=\"${this.renderPath(edge)}\"\n />\n `\n )}\n </svg>\n\n ${this.flatNodes.map(\n node => html`\n <div\n class=\"tree-node ${this.activeNodeId === node.id\n ? 'active'\n : ''}\"\n style=\"left: ${node.x}px; top: ${node.y}px;\"\n @mouseenter=${() => this.onNodeHover(node, true)}\n @mouseleave=${() => this.onNodeHover(node, false)}\n @click=${() => this.setActiveNode(node)}\n >\n <div class=\"node-badge\" title=\"${node.label}\">\n ${node.symbol}\n </div>\n ${this.showLabels\n ? html`<span class=\"node-label\">${node.label}</span>`\n : ''}\n </div>\n `\n )}\n `}\n </div>\n\n <!-- Didactic info box -->\n ${this.showDetails && activeNode\n ? html`\n <div class=\"info-bar\">\n <span>${isRoot ? 'Hauptrechenart:' : 'Teilterm:'}</span>\n <span class=\"info-badge\">${activeNode.label}</span>\n <span style=\"color: #64748b\">\n ${activeNode.children.length === 2\n ? `(verknüpft 2 Teilterme mit ${activeNode.symbol})`\n : activeNode.isUnary\n ? `(wirkt auf ${\n activeNode.children[0].label || 'Ausdruck'\n })`\n : ''}\n </span>\n </div>\n `\n : ''}\n\n <div hidden>\n <slot @slotchange=${this.updateSlotted}></slot>\n </div>\n </div>\n `;\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TermNode } from './model.js';
|
|
2
|
+
export declare function resetNodeIdCounter(): void;
|
|
3
|
+
/**
|
|
4
|
+
* Calculates depths bottom-up:
|
|
5
|
+
* Leaves have depth 0.
|
|
6
|
+
* A parent node has depth = max(children.depth) + 1.
|
|
7
|
+
* Returns the maximum depth of the tree.
|
|
8
|
+
*/
|
|
9
|
+
export declare function calculateDepths(node: TermNode): number;
|
|
10
|
+
/**
|
|
11
|
+
* Parses an AsciiMath string into a TermNode AST with Math-JSON support.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseAsciiMath(input: string): TermNode;
|
|
14
|
+
/**
|
|
15
|
+
* Generates LaTeX from the AST with embedded `\htmlId{...}` for KaTeX.
|
|
16
|
+
*/
|
|
17
|
+
export declare function astToAnnotatedLatex(node: TermNode): string;
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { GERMAN_LABELS, OPERATOR_SYMBOLS } from './model.js';
|
|
2
|
+
const KNOWN_FUNCTIONS = new Set([
|
|
3
|
+
'sin',
|
|
4
|
+
'cos',
|
|
5
|
+
'tan',
|
|
6
|
+
'cot',
|
|
7
|
+
'sec',
|
|
8
|
+
'csc',
|
|
9
|
+
'arcsin',
|
|
10
|
+
'arccos',
|
|
11
|
+
'arctan',
|
|
12
|
+
'sinh',
|
|
13
|
+
'cosh',
|
|
14
|
+
'tanh',
|
|
15
|
+
'exp',
|
|
16
|
+
'ln',
|
|
17
|
+
'log',
|
|
18
|
+
'sqrt',
|
|
19
|
+
'abs',
|
|
20
|
+
]);
|
|
21
|
+
const FUNCTION_MAP = {
|
|
22
|
+
sin: 'Sin',
|
|
23
|
+
cos: 'Cos',
|
|
24
|
+
tan: 'Tan',
|
|
25
|
+
cot: 'Cot',
|
|
26
|
+
arcsin: 'Arcsin',
|
|
27
|
+
arccos: 'Arccos',
|
|
28
|
+
arctan: 'Arctan',
|
|
29
|
+
sinh: 'Sinh',
|
|
30
|
+
cosh: 'Cosh',
|
|
31
|
+
tanh: 'Tanh',
|
|
32
|
+
ln: 'Ln',
|
|
33
|
+
log: 'Log',
|
|
34
|
+
sqrt: 'Sqrt',
|
|
35
|
+
abs: 'Abs',
|
|
36
|
+
exp: 'Exp',
|
|
37
|
+
};
|
|
38
|
+
const GREEK_LETTERS = new Set([
|
|
39
|
+
'alpha',
|
|
40
|
+
'beta',
|
|
41
|
+
'gamma',
|
|
42
|
+
'delta',
|
|
43
|
+
'epsilon',
|
|
44
|
+
'zeta',
|
|
45
|
+
'eta',
|
|
46
|
+
'theta',
|
|
47
|
+
'iota',
|
|
48
|
+
'kappa',
|
|
49
|
+
'lambda',
|
|
50
|
+
'mu',
|
|
51
|
+
'nu',
|
|
52
|
+
'xi',
|
|
53
|
+
'pi',
|
|
54
|
+
'rho',
|
|
55
|
+
'sigma',
|
|
56
|
+
'tau',
|
|
57
|
+
'upsilon',
|
|
58
|
+
'phi',
|
|
59
|
+
'chi',
|
|
60
|
+
'psi',
|
|
61
|
+
'omega',
|
|
62
|
+
]);
|
|
63
|
+
class Tokenizer {
|
|
64
|
+
constructor(input) {
|
|
65
|
+
this.pos = 0;
|
|
66
|
+
this.input = input.trim();
|
|
67
|
+
}
|
|
68
|
+
tokenize() {
|
|
69
|
+
const rawTokens = [];
|
|
70
|
+
while (this.pos < this.input.length) {
|
|
71
|
+
const ch = this.input[this.pos];
|
|
72
|
+
if (/\s/.test(ch)) {
|
|
73
|
+
this.pos++;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Numbers: integer or floating point
|
|
77
|
+
if (/\d/.test(ch)) {
|
|
78
|
+
let num = '';
|
|
79
|
+
while (this.pos < this.input.length &&
|
|
80
|
+
/[\d.]/.test(this.input[this.pos])) {
|
|
81
|
+
num += this.input[this.pos++];
|
|
82
|
+
}
|
|
83
|
+
rawTokens.push({ type: 'NUMBER', value: num });
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// Words: functions, greek letters, or sequences of variable characters
|
|
87
|
+
if (/[a-zA-Z]/.test(ch)) {
|
|
88
|
+
let word = '';
|
|
89
|
+
while (this.pos < this.input.length &&
|
|
90
|
+
/[a-zA-Z]/.test(this.input[this.pos])) {
|
|
91
|
+
word += this.input[this.pos++];
|
|
92
|
+
}
|
|
93
|
+
const lower = word.toLowerCase();
|
|
94
|
+
if (KNOWN_FUNCTIONS.has(lower)) {
|
|
95
|
+
rawTokens.push({ type: 'FUNCTION', value: lower });
|
|
96
|
+
}
|
|
97
|
+
else if (GREEK_LETTERS.has(lower)) {
|
|
98
|
+
rawTokens.push({ type: 'VARIABLE', value: lower });
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// In school mathematics, "2ab" or "xy" means 2 * a * b or x * y
|
|
102
|
+
for (const char of word) {
|
|
103
|
+
rawTokens.push({ type: 'VARIABLE', value: char });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// 'xx' or '·' or '*' as multiplication
|
|
109
|
+
if (ch === 'x' && this.input[this.pos + 1] === 'x') {
|
|
110
|
+
rawTokens.push({ type: 'OPERATOR', value: '*' });
|
|
111
|
+
this.pos += 2;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (ch === '·' || ch === '*') {
|
|
115
|
+
rawTokens.push({ type: 'OPERATOR', value: '*' });
|
|
116
|
+
this.pos++;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// Division: '/' or ':'
|
|
120
|
+
if (ch === '/' || ch === ':') {
|
|
121
|
+
rawTokens.push({ type: 'OPERATOR', value: ch });
|
|
122
|
+
this.pos++;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// Other operators
|
|
126
|
+
if (ch === '+' || ch === '-' || ch === '^') {
|
|
127
|
+
rawTokens.push({ type: 'OPERATOR', value: ch });
|
|
128
|
+
this.pos++;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// Parentheses & brackets
|
|
132
|
+
if (ch === '(' || ch === '[') {
|
|
133
|
+
rawTokens.push({ type: 'LPAREN', value: ch });
|
|
134
|
+
this.pos++;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (ch === ')' || ch === ']') {
|
|
138
|
+
rawTokens.push({ type: 'RPAREN', value: ch });
|
|
139
|
+
this.pos++;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (ch === ',') {
|
|
143
|
+
rawTokens.push({ type: 'COMMA', value: ch });
|
|
144
|
+
this.pos++;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
// Fallback: skip unrecognized characters
|
|
148
|
+
this.pos++;
|
|
149
|
+
}
|
|
150
|
+
// Insert implicit multiplication between operands where appropriate
|
|
151
|
+
const tokens = [];
|
|
152
|
+
for (let i = 0; i < rawTokens.length; i++) {
|
|
153
|
+
const cur = rawTokens[i];
|
|
154
|
+
tokens.push(cur);
|
|
155
|
+
if (i < rawTokens.length - 1) {
|
|
156
|
+
const next = rawTokens[i + 1];
|
|
157
|
+
const curEndsOperand = cur.type === 'NUMBER' ||
|
|
158
|
+
cur.type === 'VARIABLE' ||
|
|
159
|
+
cur.type === 'RPAREN';
|
|
160
|
+
const nextStartsOperand = next.type === 'NUMBER' ||
|
|
161
|
+
next.type === 'VARIABLE' ||
|
|
162
|
+
next.type === 'FUNCTION' ||
|
|
163
|
+
next.type === 'LPAREN';
|
|
164
|
+
if (curEndsOperand && nextStartsOperand) {
|
|
165
|
+
tokens.push({ type: 'OPERATOR', value: '*', implicit: true });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
tokens.push({ type: 'EOF', value: '' });
|
|
170
|
+
return tokens;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
let nodeIdCounter = 1;
|
|
174
|
+
export function resetNodeIdCounter() {
|
|
175
|
+
nodeIdCounter = 1;
|
|
176
|
+
}
|
|
177
|
+
class PrattParser {
|
|
178
|
+
constructor(tokens) {
|
|
179
|
+
this.pos = 0;
|
|
180
|
+
this.tokens = tokens;
|
|
181
|
+
}
|
|
182
|
+
current() {
|
|
183
|
+
return this.tokens[this.pos];
|
|
184
|
+
}
|
|
185
|
+
consume(expectedType) {
|
|
186
|
+
const token = this.current();
|
|
187
|
+
if (expectedType && token.type !== expectedType) {
|
|
188
|
+
throw new Error(`Erwartet ${expectedType}, aber erhalten: ${token.type} (${token.value})`);
|
|
189
|
+
}
|
|
190
|
+
this.pos++;
|
|
191
|
+
return token;
|
|
192
|
+
}
|
|
193
|
+
parse(precedence = 0) {
|
|
194
|
+
let left = this.parsePrefix();
|
|
195
|
+
while (true) {
|
|
196
|
+
const token = this.current();
|
|
197
|
+
if (token.type !== 'OPERATOR')
|
|
198
|
+
break;
|
|
199
|
+
const opPrec = this.getInfixPrecedence(token.value);
|
|
200
|
+
if (opPrec <= precedence)
|
|
201
|
+
break;
|
|
202
|
+
this.pos++;
|
|
203
|
+
left = this.parseInfix(left, token, opPrec);
|
|
204
|
+
}
|
|
205
|
+
return left;
|
|
206
|
+
}
|
|
207
|
+
parsePrefix() {
|
|
208
|
+
const token = this.current();
|
|
209
|
+
if (token.type === 'NUMBER') {
|
|
210
|
+
this.pos++;
|
|
211
|
+
const val = parseFloat(token.value);
|
|
212
|
+
return {
|
|
213
|
+
id: `n${nodeIdCounter++}`,
|
|
214
|
+
type: 'literal',
|
|
215
|
+
value: val,
|
|
216
|
+
raw: token.value,
|
|
217
|
+
symbol: token.value,
|
|
218
|
+
label: `Zahl ${token.value}`,
|
|
219
|
+
mathJson: val,
|
|
220
|
+
children: [],
|
|
221
|
+
depth: 0,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (token.type === 'VARIABLE') {
|
|
225
|
+
this.pos++;
|
|
226
|
+
return {
|
|
227
|
+
id: `n${nodeIdCounter++}`,
|
|
228
|
+
type: 'variable',
|
|
229
|
+
raw: token.value,
|
|
230
|
+
symbol: token.value,
|
|
231
|
+
label: `Variable ${token.value}`,
|
|
232
|
+
mathJson: token.value,
|
|
233
|
+
children: [],
|
|
234
|
+
depth: 0,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (token.type === 'FUNCTION') {
|
|
238
|
+
this.pos++;
|
|
239
|
+
const fnName = FUNCTION_MAP[token.value] || token.value;
|
|
240
|
+
let arg;
|
|
241
|
+
if (this.current().type === 'LPAREN') {
|
|
242
|
+
this.consume('LPAREN');
|
|
243
|
+
arg = this.parse(0);
|
|
244
|
+
this.consume('RPAREN');
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
arg = this.parse(35); // higher than *, /, ^
|
|
248
|
+
}
|
|
249
|
+
const symbol = token.value === 'sqrt' ? '√' : token.value;
|
|
250
|
+
return {
|
|
251
|
+
id: `n${nodeIdCounter++}`,
|
|
252
|
+
type: 'function',
|
|
253
|
+
op: fnName,
|
|
254
|
+
symbol,
|
|
255
|
+
label: GERMAN_LABELS[fnName] || fnName,
|
|
256
|
+
mathJson: [fnName, arg.mathJson],
|
|
257
|
+
children: [arg],
|
|
258
|
+
depth: 0,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// Unary plus or minus
|
|
262
|
+
if (token.type === 'OPERATOR' &&
|
|
263
|
+
(token.value === '-' || token.value === '+')) {
|
|
264
|
+
this.pos++;
|
|
265
|
+
const op = token.value;
|
|
266
|
+
const operand = this.parse(30); // Prefix unary precedence
|
|
267
|
+
if (op === '-') {
|
|
268
|
+
return {
|
|
269
|
+
id: `n${nodeIdCounter++}`,
|
|
270
|
+
type: 'operator',
|
|
271
|
+
isUnary: true,
|
|
272
|
+
op: 'Negate',
|
|
273
|
+
symbol: '−',
|
|
274
|
+
label: GERMAN_LABELS['Negate'],
|
|
275
|
+
mathJson: ['Negate', operand.mathJson],
|
|
276
|
+
children: [operand],
|
|
277
|
+
depth: 0,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
return operand;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Parentheses
|
|
285
|
+
if (token.type === 'LPAREN') {
|
|
286
|
+
this.pos++;
|
|
287
|
+
const expr = this.parse(0);
|
|
288
|
+
this.consume('RPAREN');
|
|
289
|
+
expr.isParenthesized = true;
|
|
290
|
+
return expr;
|
|
291
|
+
}
|
|
292
|
+
throw new Error(`Unerwartetes Zeichen: ${token.value || token.type}`);
|
|
293
|
+
}
|
|
294
|
+
getInfixPrecedence(op) {
|
|
295
|
+
switch (op) {
|
|
296
|
+
case '+':
|
|
297
|
+
case '-':
|
|
298
|
+
return 10;
|
|
299
|
+
case '*':
|
|
300
|
+
case '/':
|
|
301
|
+
case ':':
|
|
302
|
+
return 20;
|
|
303
|
+
case '^':
|
|
304
|
+
return 40;
|
|
305
|
+
default:
|
|
306
|
+
return 0;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
parseInfix(left, token, precedence) {
|
|
310
|
+
const op = token.value;
|
|
311
|
+
const isRightAssoc = op === '^';
|
|
312
|
+
const nextPrec = isRightAssoc ? precedence - 1 : precedence;
|
|
313
|
+
const right = this.parse(nextPrec);
|
|
314
|
+
let opName = 'Add';
|
|
315
|
+
if (op === '-')
|
|
316
|
+
opName = 'Subtract';
|
|
317
|
+
else if (op === '*')
|
|
318
|
+
opName = 'Multiply';
|
|
319
|
+
else if (op === '/' || op === ':')
|
|
320
|
+
opName = 'Divide';
|
|
321
|
+
else if (op === '^')
|
|
322
|
+
opName = 'Power';
|
|
323
|
+
const symbol = OPERATOR_SYMBOLS[opName] || op;
|
|
324
|
+
const label = GERMAN_LABELS[opName] || opName;
|
|
325
|
+
return {
|
|
326
|
+
id: `n${nodeIdCounter++}`,
|
|
327
|
+
type: 'operator',
|
|
328
|
+
op: opName,
|
|
329
|
+
symbol,
|
|
330
|
+
label,
|
|
331
|
+
implicit: token.implicit,
|
|
332
|
+
mathJson: [opName, left.mathJson, right.mathJson],
|
|
333
|
+
children: [left, right],
|
|
334
|
+
depth: 0,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Calculates depths bottom-up:
|
|
340
|
+
* Leaves have depth 0.
|
|
341
|
+
* A parent node has depth = max(children.depth) + 1.
|
|
342
|
+
* Returns the maximum depth of the tree.
|
|
343
|
+
*/
|
|
344
|
+
export function calculateDepths(node) {
|
|
345
|
+
if (node.children.length === 0) {
|
|
346
|
+
node.depth = 0;
|
|
347
|
+
return 0;
|
|
348
|
+
}
|
|
349
|
+
let maxChild = 0;
|
|
350
|
+
for (const child of node.children) {
|
|
351
|
+
maxChild = Math.max(maxChild, calculateDepths(child));
|
|
352
|
+
}
|
|
353
|
+
node.depth = maxChild + 1;
|
|
354
|
+
return node.depth;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Parses an AsciiMath string into a TermNode AST with Math-JSON support.
|
|
358
|
+
*/
|
|
359
|
+
export function parseAsciiMath(input) {
|
|
360
|
+
resetNodeIdCounter();
|
|
361
|
+
const tokenizer = new Tokenizer(input);
|
|
362
|
+
const tokens = tokenizer.tokenize();
|
|
363
|
+
const parser = new PrattParser(tokens);
|
|
364
|
+
const root = parser.parse(0);
|
|
365
|
+
calculateDepths(root);
|
|
366
|
+
return root;
|
|
367
|
+
}
|
|
368
|
+
function getOperatorPrecedence(node) {
|
|
369
|
+
if (node.type !== 'operator')
|
|
370
|
+
return 999;
|
|
371
|
+
if (node.isUnary)
|
|
372
|
+
return 30;
|
|
373
|
+
switch (node.op) {
|
|
374
|
+
case 'Add':
|
|
375
|
+
case 'Subtract':
|
|
376
|
+
return 10;
|
|
377
|
+
case 'Multiply':
|
|
378
|
+
case 'Divide':
|
|
379
|
+
return 20;
|
|
380
|
+
case 'Power':
|
|
381
|
+
return 40;
|
|
382
|
+
default:
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function needsParens(parent, child, isLeft) {
|
|
387
|
+
if (child.isParenthesized)
|
|
388
|
+
return true;
|
|
389
|
+
if (child.type !== 'operator')
|
|
390
|
+
return false;
|
|
391
|
+
const pPrec = getOperatorPrecedence(parent);
|
|
392
|
+
const cPrec = getOperatorPrecedence(child);
|
|
393
|
+
if (cPrec < pPrec)
|
|
394
|
+
return true;
|
|
395
|
+
if (cPrec === pPrec) {
|
|
396
|
+
// Subtraction and division are left-associative, right operand needs parentheses
|
|
397
|
+
if (!isLeft && (parent.op === 'Subtract' || parent.op === 'Divide'))
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Generates LaTeX from the AST with embedded `\htmlId{...}` for KaTeX.
|
|
404
|
+
*/
|
|
405
|
+
export function astToAnnotatedLatex(node) {
|
|
406
|
+
if (node.type === 'literal') {
|
|
407
|
+
return `\\htmlId{${node.id}}{${node.raw}}`;
|
|
408
|
+
}
|
|
409
|
+
if (node.type === 'variable') {
|
|
410
|
+
// Greek letters support (e.g. \pi, \alpha)
|
|
411
|
+
const varName = GREEK_LETTERS.has(node.symbol)
|
|
412
|
+
? `\\${node.symbol}`
|
|
413
|
+
: node.symbol;
|
|
414
|
+
return `\\htmlId{${node.id}}{${varName}}`;
|
|
415
|
+
}
|
|
416
|
+
if (node.type === 'function') {
|
|
417
|
+
const childLatex = astToAnnotatedLatex(node.children[0]);
|
|
418
|
+
let fnSymbol;
|
|
419
|
+
if (node.op === 'Sqrt' || node.symbol === '√' || node.symbol === 'sqrt') {
|
|
420
|
+
fnSymbol = `\\sqrt{${childLatex}}`;
|
|
421
|
+
}
|
|
422
|
+
else if (node.symbol === 'abs') {
|
|
423
|
+
fnSymbol = `\\left|${childLatex}\\right|`;
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
fnSymbol = `\\operatorname{${node.symbol}}\\left(${childLatex}\\right)`;
|
|
427
|
+
}
|
|
428
|
+
return `\\htmlId{${node.id}}{${fnSymbol}}`;
|
|
429
|
+
}
|
|
430
|
+
if (node.type === 'operator') {
|
|
431
|
+
if (node.isUnary) {
|
|
432
|
+
const childLatex = astToAnnotatedLatex(node.children[0]);
|
|
433
|
+
return `\\htmlId{${node.id}}{-${childLatex}}`;
|
|
434
|
+
}
|
|
435
|
+
const left = node.children[0];
|
|
436
|
+
const right = node.children[1];
|
|
437
|
+
let leftLatex = astToAnnotatedLatex(left);
|
|
438
|
+
let rightLatex = astToAnnotatedLatex(right);
|
|
439
|
+
if (needsParens(node, left, true)) {
|
|
440
|
+
leftLatex = `\\left(${leftLatex}\\right)`;
|
|
441
|
+
}
|
|
442
|
+
if (needsParens(node, right, false)) {
|
|
443
|
+
rightLatex = `\\left(${rightLatex}\\right)`;
|
|
444
|
+
}
|
|
445
|
+
if (node.op === 'Add') {
|
|
446
|
+
return `\\htmlId{${node.id}}{${leftLatex} \\htmlId{op_${node.id}}{+} ${rightLatex}}`;
|
|
447
|
+
}
|
|
448
|
+
if (node.op === 'Subtract') {
|
|
449
|
+
return `\\htmlId{${node.id}}{${leftLatex} \\htmlId{op_${node.id}}{-} ${rightLatex}}`;
|
|
450
|
+
}
|
|
451
|
+
if (node.op === 'Multiply') {
|
|
452
|
+
// Implicit multiplication styling (e.g. 2a, 4ac, (2+a)(3-b))
|
|
453
|
+
const isImplicit = node.implicit ||
|
|
454
|
+
(left.type === 'literal' &&
|
|
455
|
+
(right.type === 'variable' || right.type === 'function')) ||
|
|
456
|
+
(left.type === 'variable' && right.type === 'variable') ||
|
|
457
|
+
right.isParenthesized;
|
|
458
|
+
const opSymbol = isImplicit
|
|
459
|
+
? ''
|
|
460
|
+
: ' \\htmlId{op_' + node.id + '}{\\cdot} ';
|
|
461
|
+
return `\\htmlId{${node.id}}{${leftLatex}${opSymbol}${rightLatex}}`;
|
|
462
|
+
}
|
|
463
|
+
if (node.op === 'Divide') {
|
|
464
|
+
return `\\htmlId{${node.id}}{\\frac{${leftLatex}}{${rightLatex}}}`;
|
|
465
|
+
}
|
|
466
|
+
if (node.op === 'Power') {
|
|
467
|
+
return `\\htmlId{${node.id}}{${leftLatex}^{${rightLatex}}}`;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return '';
|
|
471
|
+
}
|
|
472
|
+
//# sourceMappingURL=asciimath-parser.js.map
|