@zukhruf/diagram 0.3.31 → 0.3.33
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/dist/lib/layouts/graph/areas.js +17 -8
- package/dist/lib/layouts/graph/areas.js.map +1 -1
- package/dist/lib/layouts/graph/attach.d.ts +25 -0
- package/dist/lib/layouts/graph/attach.d.ts.map +1 -0
- package/dist/lib/layouts/graph/attach.js +216 -0
- package/dist/lib/layouts/graph/attach.js.map +1 -0
- package/dist/lib/layouts/graph/connections.d.ts +38 -0
- package/dist/lib/layouts/graph/connections.d.ts.map +1 -0
- package/dist/lib/layouts/graph/connections.js +112 -0
- package/dist/lib/layouts/graph/connections.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts +1 -1
- package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -1
- package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -1
- package/dist/lib/layouts/graph/gutters.d.ts +1 -2
- package/dist/lib/layouts/graph/gutters.d.ts.map +1 -1
- package/dist/lib/layouts/graph/gutters.js +20 -19
- package/dist/lib/layouts/graph/gutters.js.map +1 -1
- package/dist/lib/layouts/graph/labels.d.ts +16 -0
- package/dist/lib/layouts/graph/labels.d.ts.map +1 -0
- package/dist/lib/layouts/graph/labels.js +76 -0
- package/dist/lib/layouts/graph/labels.js.map +1 -0
- package/dist/lib/layouts/graph/layout.d.ts.map +1 -1
- package/dist/lib/layouts/graph/layout.js +34 -13
- package/dist/lib/layouts/graph/layout.js.map +1 -1
- package/dist/lib/layouts/graph/measure.d.ts +7 -6
- package/dist/lib/layouts/graph/measure.d.ts.map +1 -1
- package/dist/lib/layouts/graph/measure.js +35 -29
- package/dist/lib/layouts/graph/measure.js.map +1 -1
- package/dist/lib/layouts/graph/min-heap.d.ts +12 -0
- package/dist/lib/layouts/graph/min-heap.d.ts.map +1 -0
- package/dist/lib/layouts/graph/min-heap.js +60 -0
- package/dist/lib/layouts/graph/min-heap.js.map +1 -0
- package/dist/lib/layouts/graph/node-content.d.ts +1 -2
- package/dist/lib/layouts/graph/node-content.d.ts.map +1 -1
- package/dist/lib/layouts/graph/node-content.js +43 -42
- package/dist/lib/layouts/graph/node-content.js.map +1 -1
- package/dist/lib/layouts/graph/path.d.ts +14 -0
- package/dist/lib/layouts/graph/path.d.ts.map +1 -0
- package/dist/lib/layouts/graph/path.js +55 -0
- package/dist/lib/layouts/graph/path.js.map +1 -0
- package/dist/lib/layouts/graph/route-search.d.ts +34 -0
- package/dist/lib/layouts/graph/route-search.d.ts.map +1 -0
- package/dist/lib/layouts/graph/route-search.js +208 -0
- package/dist/lib/layouts/graph/route-search.js.map +1 -0
- package/dist/lib/layouts/graph/route.d.ts +16 -0
- package/dist/lib/layouts/graph/route.d.ts.map +1 -0
- package/dist/lib/layouts/graph/route.js +241 -0
- package/dist/lib/layouts/graph/route.js.map +1 -0
- package/dist/lib/layouts/graph/sides.d.ts +23 -0
- package/dist/lib/layouts/graph/sides.d.ts.map +1 -0
- package/dist/lib/layouts/graph/sides.js +91 -0
- package/dist/lib/layouts/graph/sides.js.map +1 -0
- package/dist/lib/layouts/graph/tokens.d.ts +2 -7
- package/dist/lib/layouts/graph/tokens.d.ts.map +1 -1
- package/dist/lib/layouts/graph/tokens.js +91 -104
- package/dist/lib/layouts/graph/tokens.js.map +1 -1
- package/dist/lib/model/diagram-ir.d.ts +0 -3
- package/dist/lib/model/diagram-ir.d.ts.map +1 -1
- package/dist/lib/model/diagram-ir.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-content.js","names":["labelLines","textBlock","CONNECTOR_PAD","x","y","CONNECTOR_MIN_HEIGHT","NOTHING","text","bullets","nodeContent","node","tokens","kind","junctionContent","markerContent","connectorContent","applianceContent","noteContent","boxContent","pad","frame","LABEL_GAP","PAD_X","PAD_Y","isCard","textAlign","description","undefined","items","length","cardContent","icon","iconRowContent","lines","label","textColor","fonts","boxLabel","w","h","place","inner","centreX","centredTop","ICON","ICON_GAP","title","Math","max","size","BLOCK_GAP","BULLET_INDENT","body","iconW","headerH","sections","filter","section","bulletRise","map","reduce","sum","top","next","at","headerTop","descriptionTop","itemsTop","itemRuns","run","note","MARKER_ICON","marker","gap","cx","CONNECTOR_ICON","connector","cy","JUNCTION","APPLIANCE","appliance","glyph","applianceGlyph","bodyX","bodyY","min","bodyW","bodyH","slant","mastX","antenna","jackCount","floor","appliancePorts","jackSpacing","jacks","Array","from","_","index","face","parts","box"],"sources":["../../../../src/lib/layouts/graph/node-content.ts"],"sourcesContent":["import type { Box, DiagramNode, Point } from '../../model/diagram-ir.ts';\nimport type { NodeLayout } from './graph-layout-result.ts';\nimport { labelLines, textBlock } from './text-block.ts';\nimport type { LayoutTokens } from './tokens.ts';\n\nexport type ContentPlacement = Pick<NodeLayout, 'text' | 'bullets'> &\n Partial<Pick<NodeLayout, 'icon' | 'appliance'>>;\n\n/** What a node draws inside its frame: its measured size, the padding around it, and where it goes. */\nexport type NodeContent = {\n w: number;\n h: number;\n pad: { x: number; y: number };\n place(inner: Box): ContentPlacement;\n};\n\n/** Mirrors the connector pill drawn before content sizing: 10px side inset, 4px above and below the text, 28px tall at least. */\nconst CONNECTOR_PAD = { x: 10, y: 4 };\nconst CONNECTOR_MIN_HEIGHT = 28;\n\nconst NOTHING: ContentPlacement = { text: [], bullets: [] };\n\nexport function nodeContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): NodeContent {\n switch (node.kind) {\n case 'junction':\n return junctionContent(tokens);\n case 'marker':\n return markerContent(node, tokens);\n case 'connector':\n return connectorContent(node, tokens);\n case 'appliance':\n return applianceContent(node, tokens);\n case 'note':\n return noteContent(node, tokens);\n default:\n return boxContent(node, tokens);\n }\n}\n\nfunction boxContent(node: DiagramNode, tokens: LayoutTokens): NodeContent {\n const pad =\n node.frame === 'none'\n ? { x: tokens.LABEL_GAP, y: tokens.LABEL_GAP }\n : { x: tokens.PAD_X, y: tokens.PAD_Y };\n const isCard =\n node.textAlign === 'start' ||\n node.description !== undefined ||\n (node.items?.length ?? 0) > 0;\n if (isCard) return { ...cardContent(node, tokens), pad };\n if (node.icon) return { ...iconRowContent(node, tokens), pad };\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.boxLabel,\n );\n return {\n w: lines.w,\n h: lines.h,\n pad,\n place: (inner) => ({\n text: lines.place(centreX(inner), centredTop(inner, lines.h), 'middle'),\n bullets: [],\n }),\n };\n}\n\nfunction iconRowContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): Omit<NodeContent, 'pad'> {\n const { ICON, ICON_GAP } = tokens;\n const title = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.title,\n );\n const w = title.w > 0 ? ICON + ICON_GAP + title.w : ICON;\n const h = Math.max(ICON, title.h);\n return {\n w,\n h,\n place: (inner) => {\n const x = inner.x + (inner.w - w) / 2;\n const y = centredTop(inner, h);\n return {\n icon: { x, y: y + (h - ICON) / 2, size: ICON },\n text: title.place(x + ICON + ICON_GAP, y + (h - title.h) / 2, 'start'),\n bullets: [],\n };\n },\n };\n}\n\nfunction cardContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): Omit<NodeContent, 'pad'> {\n const { ICON, ICON_GAP, BLOCK_GAP, BULLET_INDENT } = tokens;\n const title = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.title,\n );\n const description = textBlock(\n labelLines(node.description, node.textColor),\n tokens.fonts.body,\n );\n const items = textBlock(\n labelLines(node.items, node.textColor),\n tokens.fonts.body,\n );\n let iconW = 0;\n if (node.icon) iconW = title.w > 0 ? ICON + ICON_GAP : ICON;\n const headerH = Math.max(node.icon ? ICON : 0, title.h);\n const sections = [\n { h: headerH, w: iconW + title.w },\n { h: description.h, w: description.w },\n { h: items.h, w: items.h > 0 ? BULLET_INDENT + items.w : 0 },\n ].filter((section) => section.h > 0);\n const bulletRise = tokens.fonts.body.size * 0.3;\n return {\n w: Math.max(0, ...sections.map((section) => section.w)),\n h:\n sections.reduce((sum, section) => sum + section.h, 0) +\n Math.max(0, sections.length - 1) * BLOCK_GAP,\n place: (inner) => {\n let top = inner.y;\n const next = (h: number) => {\n const at = top;\n if (h > 0) top += h + BLOCK_GAP;\n return at;\n };\n const headerTop = next(headerH);\n const descriptionTop = next(description.h);\n const itemsTop = next(items.h);\n const itemRuns = items.place(inner.x + BULLET_INDENT, itemsTop, 'start');\n return {\n ...(node.icon\n ? {\n icon: {\n x: inner.x,\n y: headerTop + (headerH - ICON) / 2,\n size: ICON,\n },\n }\n : {}),\n text: [\n ...title.place(\n inner.x + iconW,\n headerTop + (headerH - title.h) / 2,\n 'start',\n ),\n ...description.place(inner.x, descriptionTop, 'start'),\n ...itemRuns,\n ],\n bullets: itemRuns.map((run) => ({\n x: inner.x + BULLET_INDENT / 4,\n y: run.y - bulletRise,\n })),\n };\n },\n };\n}\n\nfunction noteContent(node: DiagramNode, tokens: LayoutTokens): NodeContent {\n const lines = textBlock(\n labelLines(node.label, node.textColor ?? 'dim'),\n tokens.fonts.note,\n );\n return {\n w: lines.w,\n h: lines.h,\n pad: { x: tokens.LABEL_GAP, y: tokens.LABEL_GAP },\n place: (inner) => ({\n text: lines.place(inner.x, inner.y, 'start'),\n bullets: [],\n }),\n };\n}\n\nfunction markerContent(node: DiagramNode, tokens: LayoutTokens): NodeContent {\n const { MARKER_ICON, BLOCK_GAP } = tokens;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.marker,\n );\n const gap = lines.h > 0 ? BLOCK_GAP : 0;\n const h = MARKER_ICON + gap + lines.h;\n return {\n w: Math.max(MARKER_ICON, lines.w),\n h,\n pad: { x: tokens.LABEL_GAP, y: tokens.LABEL_GAP },\n place: (inner) => {\n const top = centredTop(inner, h);\n const cx = centreX(inner);\n return {\n icon: { x: cx - MARKER_ICON / 2, y: top, size: MARKER_ICON },\n text: lines.place(cx, top + MARKER_ICON + gap, 'middle'),\n bullets: [],\n };\n },\n };\n}\n\nfunction connectorContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): NodeContent {\n const { CONNECTOR_ICON, BLOCK_GAP } = tokens;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.connector,\n );\n const iconW = node.icon ? CONNECTOR_ICON + (lines.w > 0 ? BLOCK_GAP : 0) : 0;\n const h = Math.max(CONNECTOR_MIN_HEIGHT - 2 * CONNECTOR_PAD.y, lines.h);\n return {\n w: iconW + lines.w,\n h,\n pad: CONNECTOR_PAD,\n place: (inner) => {\n const cy = inner.y + inner.h / 2;\n const top = cy - lines.h / 2;\n if (!node.icon) {\n return {\n text: lines.place(centreX(inner), top, 'middle'),\n bullets: [],\n };\n }\n return {\n icon: { x: inner.x, y: cy - CONNECTOR_ICON / 2, size: CONNECTOR_ICON },\n text: lines.place(inner.x + iconW, top, 'start'),\n bullets: [],\n };\n },\n };\n}\n\nfunction junctionContent(tokens: LayoutTokens): NodeContent {\n return {\n w: tokens.JUNCTION,\n h: tokens.JUNCTION,\n pad: { x: 0, y: 0 },\n place: () => NOTHING,\n };\n}\n\nfunction applianceContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): NodeContent {\n const { APPLIANCE, LABEL_GAP } = tokens;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.appliance,\n );\n return {\n w: Math.max(APPLIANCE.w, lines.w + 2 * LABEL_GAP),\n h: APPLIANCE.h + (lines.h > 0 ? lines.h + LABEL_GAP : 0),\n pad: { x: 0, y: 0 },\n place: (inner) => {\n const glyph = {\n x: centreX(inner) - APPLIANCE.w / 2,\n y: inner.y,\n ...APPLIANCE,\n };\n return {\n appliance: applianceGlyph(node, glyph),\n text: lines.place(centreX(inner), glyph.y + glyph.h, 'middle'),\n bullets: [],\n };\n },\n };\n}\n\n/** The router glyph: a slanted body, an optional antenna and a row of jacks, as the renderers drew it before content sizing. */\nfunction applianceGlyph(\n node: DiagramNode,\n glyph: Box,\n): NonNullable<NodeLayout['appliance']> {\n const bodyX = glyph.x + 4;\n const bodyY = glyph.y + Math.max(12, Math.min(22, glyph.h * 0.28));\n const bodyW = glyph.w - 8;\n const bodyH = glyph.h - (bodyY - glyph.y) - 12;\n const slant = Math.max(4, Math.min(16, bodyW * 0.28, bodyH * 0.75));\n const body: Point[] = [\n { x: bodyX + slant, y: bodyY },\n { x: bodyX + bodyW, y: bodyY + 6 },\n { x: bodyX + bodyW - slant, y: bodyY + bodyH },\n { x: bodyX, y: bodyY + bodyH - 6 },\n ];\n const mastX = bodyX + slant + bodyW * 0.2;\n const antenna: [Point, Point][] =\n (node.antenna ?? true)\n ? [\n [\n { x: bodyX + slant + bodyW * 0.18, y: bodyY + 1 },\n { x: mastX - 3, y: glyph.y + 3 },\n ],\n [\n { x: mastX + 1, y: bodyY + 2 },\n { x: mastX + 1, y: glyph.y + 8 },\n ],\n ]\n : [];\n const jackCount = Math.max(0, Math.floor(node.appliancePorts ?? 4));\n const jackSpacing = Math.min(\n 13,\n Math.max(8, (bodyW - slant - 42) / Math.max(jackCount, 1)),\n );\n const jacks = Array.from({ length: jackCount }, (_, index) => ({\n x: bodyX + slant + 16 + index * jackSpacing,\n y: bodyY + bodyH - 15,\n w: 5,\n h: 12,\n }));\n const face: [Point, Point] = [\n { x: bodyX + slant, y: bodyY + bodyH - 1 },\n { x: bodyX + bodyW - slant, y: bodyY + bodyH + 3 },\n ];\n // Through a variable, not a literal, so the return skips the excess-property check against NodeLayout['appliance'].\n const parts = { body, face, antenna, jacks };\n return parts;\n}\n\nfunction centreX(box: Box): number {\n return box.x + box.w / 2;\n}\n\nfunction centredTop(box: Box, h: number): number {\n return box.y + (box.h - h) / 2;\n}\n"],"mappings":"AAEA,SAASA,UAAU,EAAEC,SAAS,QAAQ,iBAAiB;;AAMvD;;AAQA;AACA,MAAMC,aAAa,GAAG;EAAEC,CAAC,EAAE,EAAE;EAAEC,CAAC,EAAE;AAAE,CAAC;AACrC,MAAMC,oBAAoB,GAAG,EAAE;AAE/B,MAAMC,OAAyB,GAAG;EAAEC,IAAI,EAAE,EAAE;EAAEC,OAAO,EAAE;AAAG,CAAC;AAE3D,OAAO,SAASC,WAAWA,CACzBC,IAAiB,EACjBC,MAAoB,EACP;EACb,QAAQD,IAAI,CAACE,IAAI;IACf,KAAK,UAAU;MACb,OAAOC,eAAe,CAACF,MAAM,CAAC;IAChC,KAAK,QAAQ;MACX,OAAOG,aAAa,CAACJ,IAAI,EAAEC,MAAM,CAAC;IACpC,KAAK,WAAW;MACd,OAAOI,gBAAgB,CAACL,IAAI,EAAEC,MAAM,CAAC;IACvC,KAAK,WAAW;MACd,OAAOK,gBAAgB,CAACN,IAAI,EAAEC,MAAM,CAAC;IACvC,KAAK,MAAM;MACT,OAAOM,WAAW,CAACP,IAAI,EAAEC,MAAM,CAAC;IAClC;MACE,OAAOO,UAAU,CAACR,IAAI,EAAEC,MAAM,CAAC;EACnC;AACF;AAEA,SAASO,UAAUA,CAACR,IAAiB,EAAEC,MAAoB,EAAe;EACxE,MAAMQ,GAAG,GACPT,IAAI,CAACU,KAAK,KAAK,MAAM,GACjB;IAAEjB,CAAC,EAAEQ,MAAM,CAACU,SAAS;IAAEjB,CAAC,EAAEO,MAAM,CAACU;EAAU,CAAC,GAC5C;IAAElB,CAAC,EAAEQ,MAAM,CAACW,KAAK;IAAElB,CAAC,EAAEO,MAAM,CAACY;EAAM,CAAC;EAC1C,MAAMC,MAAM,GACVd,IAAI,CAACe,SAAS,KAAK,OAAO,IAC1Bf,IAAI,CAACgB,WAAW,KAAKC,SAAS,IAC9B,CAACjB,IAAI,CAACkB,KAAK,EAAEC,MAAM,IAAI,CAAC,IAAI,CAAC;EAC/B,IAAIL,MAAM,EAAE,OAAO;IAAE,GAAGM,WAAW,CAACpB,IAAI,EAAEC,MAAM,CAAC;IAAEQ;EAAI,CAAC;EACxD,IAAIT,IAAI,CAACqB,IAAI,EAAE,OAAO;IAAE,GAAGC,cAAc,CAACtB,IAAI,EAAEC,MAAM,CAAC;IAAEQ;EAAI,CAAC;EAC9D,MAAMc,KAAK,GAAGhC,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAACC,QACf,CAAC;EACD,OAAO;IACLC,CAAC,EAAEL,KAAK,CAACK,CAAC;IACVC,CAAC,EAAEN,KAAK,CAACM,CAAC;IACVpB,GAAG;IACHqB,KAAK,EAAGC,KAAK,KAAM;MACjBlC,IAAI,EAAE0B,KAAK,CAACO,KAAK,CAACE,OAAO,CAACD,KAAK,CAAC,EAAEE,UAAU,CAACF,KAAK,EAAER,KAAK,CAACM,CAAC,CAAC,EAAE,QAAQ,CAAC;MACvE/B,OAAO,EAAE;IACX,CAAC;EACH,CAAC;AACH;AAEA,SAASwB,cAAcA,CACrBtB,IAAiB,EACjBC,MAAoB,EACM;EAC1B,MAAM;IAAEiC,IAAI;IAAEC;EAAS,CAAC,GAAGlC,MAAM;EACjC,MAAMmC,KAAK,GAAG7C,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAACU,KACf,CAAC;EACD,MAAMR,CAAC,GAAGQ,KAAK,CAACR,CAAC,GAAG,CAAC,GAAGM,IAAI,GAAGC,QAAQ,GAAGC,KAAK,CAACR,CAAC,GAAGM,IAAI;EACxD,MAAML,CAAC,GAAGQ,IAAI,CAACC,GAAG,CAACJ,IAAI,EAAEE,KAAK,CAACP,CAAC,CAAC;EACjC,OAAO;IACLD,CAAC;IACDC,CAAC;IACDC,KAAK,EAAGC,KAAK,IAAK;MAChB,MAAMtC,CAAC,GAAGsC,KAAK,CAACtC,CAAC,GAAG,CAACsC,KAAK,CAACH,CAAC,GAAGA,CAAC,IAAI,CAAC;MACrC,MAAMlC,CAAC,GAAGuC,UAAU,CAACF,KAAK,EAAEF,CAAC,CAAC;MAC9B,OAAO;QACLR,IAAI,EAAE;UAAE5B,CAAC;UAAEC,CAAC,EAAEA,CAAC,GAAG,CAACmC,CAAC,GAAGK,IAAI,IAAI,CAAC;UAAEK,IAAI,EAAEL;QAAK,CAAC;QAC9CrC,IAAI,EAAEuC,KAAK,CAACN,KAAK,CAACrC,CAAC,GAAGyC,IAAI,GAAGC,QAAQ,EAAEzC,CAAC,GAAG,CAACmC,CAAC,GAAGO,KAAK,CAACP,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QACtE/B,OAAO,EAAE;MACX,CAAC;IACH;EACF,CAAC;AACH;AAEA,SAASsB,WAAWA,CAClBpB,IAAiB,EACjBC,MAAoB,EACM;EAC1B,MAAM;IAAEiC,IAAI;IAAEC,QAAQ;IAAEK,SAAS;IAAEC;EAAc,CAAC,GAAGxC,MAAM;EAC3D,MAAMmC,KAAK,GAAG7C,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAACU,KACf,CAAC;EACD,MAAMpB,WAAW,GAAGzB,SAAS,CAC3BD,UAAU,CAACU,IAAI,CAACgB,WAAW,EAAEhB,IAAI,CAACyB,SAAS,CAAC,EAC5CxB,MAAM,CAACyB,KAAK,CAACgB,IACf,CAAC;EACD,MAAMxB,KAAK,GAAG3B,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACkB,KAAK,EAAElB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAACgB,IACf,CAAC;EACD,IAAIC,KAAK,GAAG,CAAC;EACb,IAAI3C,IAAI,CAACqB,IAAI,EAAEsB,KAAK,GAAGP,KAAK,CAACR,CAAC,GAAG,CAAC,GAAGM,IAAI,GAAGC,QAAQ,GAAGD,IAAI;EAC3D,MAAMU,OAAO,GAAGP,IAAI,CAACC,GAAG,CAACtC,IAAI,CAACqB,IAAI,GAAGa,IAAI,GAAG,CAAC,EAAEE,KAAK,CAACP,CAAC,CAAC;EACvD,MAAMgB,QAAQ,GAAG,CACf;IAAEhB,CAAC,EAAEe,OAAO;IAAEhB,CAAC,EAAEe,KAAK,GAAGP,KAAK,CAACR;EAAE,CAAC,EAClC;IAAEC,CAAC,EAAEb,WAAW,CAACa,CAAC;IAAED,CAAC,EAAEZ,WAAW,CAACY;EAAE,CAAC,EACtC;IAAEC,CAAC,EAAEX,KAAK,CAACW,CAAC;IAAED,CAAC,EAAEV,KAAK,CAACW,CAAC,GAAG,CAAC,GAAGY,aAAa,GAAGvB,KAAK,CAACU,CAAC,GAAG;EAAE,CAAC,CAC7D,CAACkB,MAAM,CAAEC,OAAO,IAAKA,OAAO,CAAClB,CAAC,GAAG,CAAC,CAAC;EACpC,MAAMmB,UAAU,GAAG/C,MAAM,CAACyB,KAAK,CAACgB,IAAI,CAACH,IAAI,GAAG,GAAG;EAC/C,OAAO;IACLX,CAAC,EAAES,IAAI,CAACC,GAAG,CAAC,CAAC,EAAE,GAAGO,QAAQ,CAACI,GAAG,CAAEF,OAAO,IAAKA,OAAO,CAACnB,CAAC,CAAC,CAAC;IACvDC,CAAC,EACCgB,QAAQ,CAACK,MAAM,CAAC,CAACC,GAAG,EAAEJ,OAAO,KAAKI,GAAG,GAAGJ,OAAO,CAAClB,CAAC,EAAE,CAAC,CAAC,GACrDQ,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEO,QAAQ,CAAC1B,MAAM,GAAG,CAAC,CAAC,GAAGqB,SAAS;IAC9CV,KAAK,EAAGC,KAAK,IAAK;MAChB,IAAIqB,GAAG,GAAGrB,KAAK,CAACrC,CAAC;MACjB,MAAM2D,IAAI,GAAIxB,CAAS,IAAK;QAC1B,MAAMyB,EAAE,GAAGF,GAAG;QACd,IAAIvB,CAAC,GAAG,CAAC,EAAEuB,GAAG,IAAIvB,CAAC,GAAGW,SAAS;QAC/B,OAAOc,EAAE;MACX,CAAC;MACD,MAAMC,SAAS,GAAGF,IAAI,CAACT,OAAO,CAAC;MAC/B,MAAMY,cAAc,GAAGH,IAAI,CAACrC,WAAW,CAACa,CAAC,CAAC;MAC1C,MAAM4B,QAAQ,GAAGJ,IAAI,CAACnC,KAAK,CAACW,CAAC,CAAC;MAC9B,MAAM6B,QAAQ,GAAGxC,KAAK,CAACY,KAAK,CAACC,KAAK,CAACtC,CAAC,GAAGgD,aAAa,EAAEgB,QAAQ,EAAE,OAAO,CAAC;MACxE,OAAO;QACL,IAAIzD,IAAI,CAACqB,IAAI,GACT;UACEA,IAAI,EAAE;YACJ5B,CAAC,EAAEsC,KAAK,CAACtC,CAAC;YACVC,CAAC,EAAE6D,SAAS,GAAG,CAACX,OAAO,GAAGV,IAAI,IAAI,CAAC;YACnCK,IAAI,EAAEL;UACR;QACF,CAAC,GACD,CAAC,CAAC,CAAC;QACPrC,IAAI,EAAE,CACJ,GAAGuC,KAAK,CAACN,KAAK,CACZC,KAAK,CAACtC,CAAC,GAAGkD,KAAK,EACfY,SAAS,GAAG,CAACX,OAAO,GAAGR,KAAK,CAACP,CAAC,IAAI,CAAC,EACnC,OACF,CAAC,EACD,GAAGb,WAAW,CAACc,KAAK,CAACC,KAAK,CAACtC,CAAC,EAAE+D,cAAc,EAAE,OAAO,CAAC,EACtD,GAAGE,QAAQ,CACZ;QACD5D,OAAO,EAAE4D,QAAQ,CAACT,GAAG,CAAEU,GAAG,KAAM;UAC9BlE,CAAC,EAAEsC,KAAK,CAACtC,CAAC,GAAGgD,aAAa,GAAG,CAAC;UAC9B/C,CAAC,EAAEiE,GAAG,CAACjE,CAAC,GAAGsD;QACb,CAAC,CAAC;MACJ,CAAC;IACH;EACF,CAAC;AACH;AAEA,SAASzC,WAAWA,CAACP,IAAiB,EAAEC,MAAoB,EAAe;EACzE,MAAMsB,KAAK,GAAGhC,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,IAAI,KAAK,CAAC,EAC/CxB,MAAM,CAACyB,KAAK,CAACkC,IACf,CAAC;EACD,OAAO;IACLhC,CAAC,EAAEL,KAAK,CAACK,CAAC;IACVC,CAAC,EAAEN,KAAK,CAACM,CAAC;IACVpB,GAAG,EAAE;MAAEhB,CAAC,EAAEQ,MAAM,CAACU,SAAS;MAAEjB,CAAC,EAAEO,MAAM,CAACU;IAAU,CAAC;IACjDmB,KAAK,EAAGC,KAAK,KAAM;MACjBlC,IAAI,EAAE0B,KAAK,CAACO,KAAK,CAACC,KAAK,CAACtC,CAAC,EAAEsC,KAAK,CAACrC,CAAC,EAAE,OAAO,CAAC;MAC5CI,OAAO,EAAE;IACX,CAAC;EACH,CAAC;AACH;AAEA,SAASM,aAAaA,CAACJ,IAAiB,EAAEC,MAAoB,EAAe;EAC3E,MAAM;IAAE4D,WAAW;IAAErB;EAAU,CAAC,GAAGvC,MAAM;EACzC,MAAMsB,KAAK,GAAGhC,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAACoC,MACf,CAAC;EACD,MAAMC,GAAG,GAAGxC,KAAK,CAACM,CAAC,GAAG,CAAC,GAAGW,SAAS,GAAG,CAAC;EACvC,MAAMX,CAAC,GAAGgC,WAAW,GAAGE,GAAG,GAAGxC,KAAK,CAACM,CAAC;EACrC,OAAO;IACLD,CAAC,EAAES,IAAI,CAACC,GAAG,CAACuB,WAAW,EAAEtC,KAAK,CAACK,CAAC,CAAC;IACjCC,CAAC;IACDpB,GAAG,EAAE;MAAEhB,CAAC,EAAEQ,MAAM,CAACU,SAAS;MAAEjB,CAAC,EAAEO,MAAM,CAACU;IAAU,CAAC;IACjDmB,KAAK,EAAGC,KAAK,IAAK;MAChB,MAAMqB,GAAG,GAAGnB,UAAU,CAACF,KAAK,EAAEF,CAAC,CAAC;MAChC,MAAMmC,EAAE,GAAGhC,OAAO,CAACD,KAAK,CAAC;MACzB,OAAO;QACLV,IAAI,EAAE;UAAE5B,CAAC,EAAEuE,EAAE,GAAGH,WAAW,GAAG,CAAC;UAAEnE,CAAC,EAAE0D,GAAG;UAAEb,IAAI,EAAEsB;QAAY,CAAC;QAC5DhE,IAAI,EAAE0B,KAAK,CAACO,KAAK,CAACkC,EAAE,EAAEZ,GAAG,GAAGS,WAAW,GAAGE,GAAG,EAAE,QAAQ,CAAC;QACxDjE,OAAO,EAAE;MACX,CAAC;IACH;EACF,CAAC;AACH;AAEA,SAASO,gBAAgBA,CACvBL,IAAiB,EACjBC,MAAoB,EACP;EACb,MAAM;IAAEgE,cAAc;IAAEzB;EAAU,CAAC,GAAGvC,MAAM;EAC5C,MAAMsB,KAAK,GAAGhC,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAACwC,SACf,CAAC;EACD,MAAMvB,KAAK,GAAG3C,IAAI,CAACqB,IAAI,GAAG4C,cAAc,IAAI1C,KAAK,CAACK,CAAC,GAAG,CAAC,GAAGY,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC;EAC5E,MAAMX,CAAC,GAAGQ,IAAI,CAACC,GAAG,CAAC3C,oBAAoB,GAAG,CAAC,GAAGH,aAAa,CAACE,CAAC,EAAE6B,KAAK,CAACM,CAAC,CAAC;EACvE,OAAO;IACLD,CAAC,EAAEe,KAAK,GAAGpB,KAAK,CAACK,CAAC;IAClBC,CAAC;IACDpB,GAAG,EAAEjB,aAAa;IAClBsC,KAAK,EAAGC,KAAK,IAAK;MAChB,MAAMoC,EAAE,GAAGpC,KAAK,CAACrC,CAAC,GAAGqC,KAAK,CAACF,CAAC,GAAG,CAAC;MAChC,MAAMuB,GAAG,GAAGe,EAAE,GAAG5C,KAAK,CAACM,CAAC,GAAG,CAAC;MAC5B,IAAI,CAAC7B,IAAI,CAACqB,IAAI,EAAE;QACd,OAAO;UACLxB,IAAI,EAAE0B,KAAK,CAACO,KAAK,CAACE,OAAO,CAACD,KAAK,CAAC,EAAEqB,GAAG,EAAE,QAAQ,CAAC;UAChDtD,OAAO,EAAE;QACX,CAAC;MACH;MACA,OAAO;QACLuB,IAAI,EAAE;UAAE5B,CAAC,EAAEsC,KAAK,CAACtC,CAAC;UAAEC,CAAC,EAAEyE,EAAE,GAAGF,cAAc,GAAG,CAAC;UAAE1B,IAAI,EAAE0B;QAAe,CAAC;QACtEpE,IAAI,EAAE0B,KAAK,CAACO,KAAK,CAACC,KAAK,CAACtC,CAAC,GAAGkD,KAAK,EAAES,GAAG,EAAE,OAAO,CAAC;QAChDtD,OAAO,EAAE;MACX,CAAC;IACH;EACF,CAAC;AACH;AAEA,SAASK,eAAeA,CAACF,MAAoB,EAAe;EAC1D,OAAO;IACL2B,CAAC,EAAE3B,MAAM,CAACmE,QAAQ;IAClBvC,CAAC,EAAE5B,MAAM,CAACmE,QAAQ;IAClB3D,GAAG,EAAE;MAAEhB,CAAC,EAAE,CAAC;MAAEC,CAAC,EAAE;IAAE,CAAC;IACnBoC,KAAK,EAAEA,CAAA,KAAMlC;EACf,CAAC;AACH;AAEA,SAASU,gBAAgBA,CACvBN,IAAiB,EACjBC,MAAoB,EACP;EACb,MAAM;IAAEoE,SAAS;IAAE1D;EAAU,CAAC,GAAGV,MAAM;EACvC,MAAMsB,KAAK,GAAGhC,SAAS,CACrBD,UAAU,CAACU,IAAI,CAACwB,KAAK,EAAExB,IAAI,CAACyB,SAAS,CAAC,EACtCxB,MAAM,CAACyB,KAAK,CAAC4C,SACf,CAAC;EACD,OAAO;IACL1C,CAAC,EAAES,IAAI,CAACC,GAAG,CAAC+B,SAAS,CAACzC,CAAC,EAAEL,KAAK,CAACK,CAAC,GAAG,CAAC,GAAGjB,SAAS,CAAC;IACjDkB,CAAC,EAAEwC,SAAS,CAACxC,CAAC,IAAIN,KAAK,CAACM,CAAC,GAAG,CAAC,GAAGN,KAAK,CAACM,CAAC,GAAGlB,SAAS,GAAG,CAAC,CAAC;IACxDF,GAAG,EAAE;MAAEhB,CAAC,EAAE,CAAC;MAAEC,CAAC,EAAE;IAAE,CAAC;IACnBoC,KAAK,EAAGC,KAAK,IAAK;MAChB,MAAMwC,KAAK,GAAG;QACZ9E,CAAC,EAAEuC,OAAO,CAACD,KAAK,CAAC,GAAGsC,SAAS,CAACzC,CAAC,GAAG,CAAC;QACnClC,CAAC,EAAEqC,KAAK,CAACrC,CAAC;QACV,GAAG2E;MACL,CAAC;MACD,OAAO;QACLC,SAAS,EAAEE,cAAc,CAACxE,IAAI,EAAEuE,KAAK,CAAC;QACtC1E,IAAI,EAAE0B,KAAK,CAACO,KAAK,CAACE,OAAO,CAACD,KAAK,CAAC,EAAEwC,KAAK,CAAC7E,CAAC,GAAG6E,KAAK,CAAC1C,CAAC,EAAE,QAAQ,CAAC;QAC9D/B,OAAO,EAAE;MACX,CAAC;IACH;EACF,CAAC;AACH;;AAEA;AACA,SAAS0E,cAAcA,CACrBxE,IAAiB,EACjBuE,KAAU,EAC4B;EACtC,MAAME,KAAK,GAAGF,KAAK,CAAC9E,CAAC,GAAG,CAAC;EACzB,MAAMiF,KAAK,GAAGH,KAAK,CAAC7E,CAAC,GAAG2C,IAAI,CAACC,GAAG,CAAC,EAAE,EAAED,IAAI,CAACsC,GAAG,CAAC,EAAE,EAAEJ,KAAK,CAAC1C,CAAC,GAAG,IAAI,CAAC,CAAC;EAClE,MAAM+C,KAAK,GAAGL,KAAK,CAAC3C,CAAC,GAAG,CAAC;EACzB,MAAMiD,KAAK,GAAGN,KAAK,CAAC1C,CAAC,IAAI6C,KAAK,GAAGH,KAAK,CAAC7E,CAAC,CAAC,GAAG,EAAE;EAC9C,MAAMoF,KAAK,GAAGzC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAED,IAAI,CAACsC,GAAG,CAAC,EAAE,EAAEC,KAAK,GAAG,IAAI,EAAEC,KAAK,GAAG,IAAI,CAAC,CAAC;EACnE,MAAMnC,IAAa,GAAG,CACpB;IAAEjD,CAAC,EAAEgF,KAAK,GAAGK,KAAK;IAAEpF,CAAC,EAAEgF;EAAM,CAAC,EAC9B;IAAEjF,CAAC,EAAEgF,KAAK,GAAGG,KAAK;IAAElF,CAAC,EAAEgF,KAAK,GAAG;EAAE,CAAC,EAClC;IAAEjF,CAAC,EAAEgF,KAAK,GAAGG,KAAK,GAAGE,KAAK;IAAEpF,CAAC,EAAEgF,KAAK,GAAGG;EAAM,CAAC,EAC9C;IAAEpF,CAAC,EAAEgF,KAAK;IAAE/E,CAAC,EAAEgF,KAAK,GAAGG,KAAK,GAAG;EAAE,CAAC,CACnC;EACD,MAAME,KAAK,GAAGN,KAAK,GAAGK,KAAK,GAAGF,KAAK,GAAG,GAAG;EACzC,MAAMI,OAAyB,GAC5BhF,IAAI,CAACgF,OAAO,IAAI,IAAI,GACjB,CACE,CACE;IAAEvF,CAAC,EAAEgF,KAAK,GAAGK,KAAK,GAAGF,KAAK,GAAG,IAAI;IAAElF,CAAC,EAAEgF,KAAK,GAAG;EAAE,CAAC,EACjD;IAAEjF,CAAC,EAAEsF,KAAK,GAAG,CAAC;IAAErF,CAAC,EAAE6E,KAAK,CAAC7E,CAAC,GAAG;EAAE,CAAC,CACjC,EACD,CACE;IAAED,CAAC,EAAEsF,KAAK,GAAG,CAAC;IAAErF,CAAC,EAAEgF,KAAK,GAAG;EAAE,CAAC,EAC9B;IAAEjF,CAAC,EAAEsF,KAAK,GAAG,CAAC;IAAErF,CAAC,EAAE6E,KAAK,CAAC7E,CAAC,GAAG;EAAE,CAAC,CACjC,CACF,GACD,EAAE;EACR,MAAMuF,SAAS,GAAG5C,IAAI,CAACC,GAAG,CAAC,CAAC,EAAED,IAAI,CAAC6C,KAAK,CAAClF,IAAI,CAACmF,cAAc,IAAI,CAAC,CAAC,CAAC;EACnE,MAAMC,WAAW,GAAG/C,IAAI,CAACsC,GAAG,CAC1B,EAAE,EACFtC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAE,CAACsC,KAAK,GAAGE,KAAK,GAAG,EAAE,IAAIzC,IAAI,CAACC,GAAG,CAAC2C,SAAS,EAAE,CAAC,CAAC,CAC3D,CAAC;EACD,MAAMI,KAAK,GAAGC,KAAK,CAACC,IAAI,CAAC;IAAEpE,MAAM,EAAE8D;EAAU,CAAC,EAAE,CAACO,CAAC,EAAEC,KAAK,MAAM;IAC7DhG,CAAC,EAAEgF,KAAK,GAAGK,KAAK,GAAG,EAAE,GAAGW,KAAK,GAAGL,WAAW;IAC3C1F,CAAC,EAAEgF,KAAK,GAAGG,KAAK,GAAG,EAAE;IACrBjD,CAAC,EAAE,CAAC;IACJC,CAAC,EAAE;EACL,CAAC,CAAC,CAAC;EACH,MAAM6D,IAAoB,GAAG,CAC3B;IAAEjG,CAAC,EAAEgF,KAAK,GAAGK,KAAK;IAAEpF,CAAC,EAAEgF,KAAK,GAAGG,KAAK,GAAG;EAAE,CAAC,EAC1C;IAAEpF,CAAC,EAAEgF,KAAK,GAAGG,KAAK,GAAGE,KAAK;IAAEpF,CAAC,EAAEgF,KAAK,GAAGG,KAAK,GAAG;EAAE,CAAC,CACnD;EACD;EACA,MAAMc,KAAK,GAAG;IAAEjD,IAAI;IAAEgD,IAAI;IAAEV,OAAO;IAAEK;EAAM,CAAC;EAC5C,OAAOM,KAAK;AACd;AAEA,SAAS3D,OAAOA,CAAC4D,GAAQ,EAAU;EACjC,OAAOA,GAAG,CAACnG,CAAC,GAAGmG,GAAG,CAAChE,CAAC,GAAG,CAAC;AAC1B;AAEA,SAASK,UAAUA,CAAC2D,GAAQ,EAAE/D,CAAS,EAAU;EAC/C,OAAO+D,GAAG,CAAClG,CAAC,GAAG,CAACkG,GAAG,CAAC/D,CAAC,GAAGA,CAAC,IAAI,CAAC;AAChC","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"node-content.js","names":["labelLines","textBlock","LAYOUT_TOKENS","CONNECTOR_PAD","x","y","CONNECTOR_MIN_HEIGHT","NOTHING","text","bullets","nodeContent","node","kind","junctionContent","markerContent","connectorContent","applianceContent","noteContent","boxContent","pad","frame","LABEL_GAP","PAD_X","PAD_Y","isCard","textAlign","description","undefined","items","length","cardContent","icon","iconRowContent","lines","label","textColor","fonts","boxLabel","w","h","place","inner","centreX","centredTop","ICON","ICON_GAP","title","Math","max","size","BLOCK_GAP","BULLET_INDENT","body","iconW","headerH","sections","filter","section","bulletRise","map","reduce","sum","top","next","at","headerTop","descriptionTop","itemsTop","itemRuns","run","note","MARKER_ICON","marker","gap","cx","CONNECTOR_ICON","connector","cy","JUNCTION","APPLIANCE","appliance","glyph","applianceGlyph","bodyX","bodyY","min","bodyW","bodyH","slant","mastX","antenna","jackCount","floor","appliancePorts","jackSpacing","jacks","Array","from","_","index","face","parts","box"],"sources":["../../../../src/lib/layouts/graph/node-content.ts"],"sourcesContent":["import type { Box, DiagramNode, Point } from '../../model/diagram-ir.ts';\nimport type { NodeLayout } from './graph-layout-result.ts';\nimport { labelLines, textBlock } from './text-block.ts';\nimport { LAYOUT_TOKENS } from './tokens.ts';\n\nexport type ContentPlacement = Pick<NodeLayout, 'text' | 'bullets'> &\n Partial<Pick<NodeLayout, 'icon' | 'appliance'>>;\n\n/** What a node draws inside its frame: its measured size, the padding around it, and where it goes. */\nexport type NodeContent = {\n w: number;\n h: number;\n pad: { x: number; y: number };\n place(inner: Box): ContentPlacement;\n};\n\n/** Mirrors the connector pill drawn before content sizing: 10px side inset, 4px above and below the text, 28px tall at least. */\nconst CONNECTOR_PAD = { x: 10, y: 4 };\nconst CONNECTOR_MIN_HEIGHT = 28;\n\nconst NOTHING: ContentPlacement = { text: [], bullets: [] };\n\nexport function nodeContent(node: DiagramNode): NodeContent {\n switch (node.kind) {\n case 'junction':\n return junctionContent();\n case 'marker':\n return markerContent(node);\n case 'connector':\n return connectorContent(node);\n case 'appliance':\n return applianceContent(node);\n case 'note':\n return noteContent(node);\n default:\n return boxContent(node);\n }\n}\n\nfunction boxContent(node: DiagramNode): NodeContent {\n const pad =\n node.frame === 'none'\n ? { x: LAYOUT_TOKENS.LABEL_GAP, y: LAYOUT_TOKENS.LABEL_GAP }\n : { x: LAYOUT_TOKENS.PAD_X, y: LAYOUT_TOKENS.PAD_Y };\n const isCard =\n node.textAlign === 'start' ||\n node.description !== undefined ||\n (node.items?.length ?? 0) > 0;\n if (isCard) return { ...cardContent(node), pad };\n if (node.icon) return { ...iconRowContent(node), pad };\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n LAYOUT_TOKENS.fonts.boxLabel,\n );\n return {\n w: lines.w,\n h: lines.h,\n pad,\n place: (inner) => ({\n text: lines.place(centreX(inner), centredTop(inner, lines.h), 'middle'),\n bullets: [],\n }),\n };\n}\n\nfunction iconRowContent(node: DiagramNode): Omit<NodeContent, 'pad'> {\n const { ICON, ICON_GAP } = LAYOUT_TOKENS;\n const title = textBlock(\n labelLines(node.label, node.textColor),\n LAYOUT_TOKENS.fonts.title,\n );\n const w = title.w > 0 ? ICON + ICON_GAP + title.w : ICON;\n const h = Math.max(ICON, title.h);\n return {\n w,\n h,\n place: (inner) => {\n const x = inner.x + (inner.w - w) / 2;\n const y = centredTop(inner, h);\n return {\n icon: { x, y: y + (h - ICON) / 2, size: ICON },\n text: title.place(x + ICON + ICON_GAP, y + (h - title.h) / 2, 'start'),\n bullets: [],\n };\n },\n };\n}\n\nfunction cardContent(node: DiagramNode): Omit<NodeContent, 'pad'> {\n const { ICON, ICON_GAP, BLOCK_GAP, BULLET_INDENT } = LAYOUT_TOKENS;\n const title = textBlock(\n labelLines(node.label, node.textColor),\n LAYOUT_TOKENS.fonts.title,\n );\n const description = textBlock(\n labelLines(node.description, node.textColor),\n LAYOUT_TOKENS.fonts.body,\n );\n const items = textBlock(\n labelLines(node.items, node.textColor),\n LAYOUT_TOKENS.fonts.body,\n );\n let iconW = 0;\n if (node.icon) iconW = title.w > 0 ? ICON + ICON_GAP : ICON;\n const headerH = Math.max(node.icon ? ICON : 0, title.h);\n const sections = [\n { h: headerH, w: iconW + title.w },\n { h: description.h, w: description.w },\n { h: items.h, w: items.h > 0 ? BULLET_INDENT + items.w : 0 },\n ].filter((section) => section.h > 0);\n const bulletRise = LAYOUT_TOKENS.fonts.body.size * 0.3;\n return {\n w: Math.max(0, ...sections.map((section) => section.w)),\n h:\n sections.reduce((sum, section) => sum + section.h, 0) +\n Math.max(0, sections.length - 1) * BLOCK_GAP,\n place: (inner) => {\n let top = inner.y;\n const next = (h: number) => {\n const at = top;\n if (h > 0) top += h + BLOCK_GAP;\n return at;\n };\n const headerTop = next(headerH);\n const descriptionTop = next(description.h);\n const itemsTop = next(items.h);\n const itemRuns = items.place(inner.x + BULLET_INDENT, itemsTop, 'start');\n return {\n ...(node.icon\n ? {\n icon: {\n x: inner.x,\n y: headerTop + (headerH - ICON) / 2,\n size: ICON,\n },\n }\n : {}),\n text: [\n ...title.place(\n inner.x + iconW,\n headerTop + (headerH - title.h) / 2,\n 'start',\n ),\n ...description.place(inner.x, descriptionTop, 'start'),\n ...itemRuns,\n ],\n bullets: itemRuns.map((run) => ({\n x: inner.x + BULLET_INDENT / 4,\n y: run.y - bulletRise,\n })),\n };\n },\n };\n}\n\nfunction noteContent(node: DiagramNode): NodeContent {\n const lines = textBlock(\n labelLines(node.label, node.textColor ?? 'dim'),\n LAYOUT_TOKENS.fonts.note,\n );\n return {\n w: lines.w,\n h: lines.h,\n pad: { x: LAYOUT_TOKENS.LABEL_GAP, y: LAYOUT_TOKENS.LABEL_GAP },\n place: (inner) => ({\n text: lines.place(inner.x, inner.y, 'start'),\n bullets: [],\n }),\n };\n}\n\nfunction markerContent(node: DiagramNode): NodeContent {\n const { MARKER_ICON, BLOCK_GAP } = LAYOUT_TOKENS;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n LAYOUT_TOKENS.fonts.marker,\n );\n const gap = lines.h > 0 ? BLOCK_GAP : 0;\n const h = MARKER_ICON + gap + lines.h;\n return {\n w: Math.max(MARKER_ICON, lines.w),\n h,\n pad: { x: LAYOUT_TOKENS.LABEL_GAP, y: LAYOUT_TOKENS.LABEL_GAP },\n place: (inner) => {\n const top = centredTop(inner, h);\n const cx = centreX(inner);\n return {\n icon: { x: cx - MARKER_ICON / 2, y: top, size: MARKER_ICON },\n text: lines.place(cx, top + MARKER_ICON + gap, 'middle'),\n bullets: [],\n };\n },\n };\n}\n\nfunction connectorContent(node: DiagramNode): NodeContent {\n const { CONNECTOR_ICON, BLOCK_GAP } = LAYOUT_TOKENS;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n LAYOUT_TOKENS.fonts.connector,\n );\n const iconW = node.icon ? CONNECTOR_ICON + (lines.w > 0 ? BLOCK_GAP : 0) : 0;\n const h = Math.max(CONNECTOR_MIN_HEIGHT - 2 * CONNECTOR_PAD.y, lines.h);\n return {\n w: iconW + lines.w,\n h,\n pad: CONNECTOR_PAD,\n place: (inner) => {\n const cy = inner.y + inner.h / 2;\n const top = cy - lines.h / 2;\n if (!node.icon) {\n return {\n text: lines.place(centreX(inner), top, 'middle'),\n bullets: [],\n };\n }\n return {\n icon: { x: inner.x, y: cy - CONNECTOR_ICON / 2, size: CONNECTOR_ICON },\n text: lines.place(inner.x + iconW, top, 'start'),\n bullets: [],\n };\n },\n };\n}\n\nfunction junctionContent(): NodeContent {\n return {\n w: LAYOUT_TOKENS.JUNCTION,\n h: LAYOUT_TOKENS.JUNCTION,\n pad: { x: 0, y: 0 },\n place: () => NOTHING,\n };\n}\n\nfunction applianceContent(node: DiagramNode): NodeContent {\n const { APPLIANCE, LABEL_GAP } = LAYOUT_TOKENS;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n LAYOUT_TOKENS.fonts.appliance,\n );\n return {\n w: Math.max(APPLIANCE.w, lines.w + 2 * LABEL_GAP),\n h: APPLIANCE.h + (lines.h > 0 ? lines.h + LABEL_GAP : 0),\n pad: { x: 0, y: 0 },\n place: (inner) => {\n const glyph = {\n x: centreX(inner) - APPLIANCE.w / 2,\n y: inner.y,\n ...APPLIANCE,\n };\n return {\n appliance: applianceGlyph(node, glyph),\n text: lines.place(centreX(inner), glyph.y + glyph.h, 'middle'),\n bullets: [],\n };\n },\n };\n}\n\n/** The router glyph: a slanted body, an optional antenna and a row of jacks, as the renderers drew it before content sizing. */\nfunction applianceGlyph(\n node: DiagramNode,\n glyph: Box,\n): NonNullable<NodeLayout['appliance']> {\n const bodyX = glyph.x + 4;\n const bodyY = glyph.y + Math.max(12, Math.min(22, glyph.h * 0.28));\n const bodyW = glyph.w - 8;\n const bodyH = glyph.h - (bodyY - glyph.y) - 12;\n const slant = Math.max(4, Math.min(16, bodyW * 0.28, bodyH * 0.75));\n const body: Point[] = [\n { x: bodyX + slant, y: bodyY },\n { x: bodyX + bodyW, y: bodyY + 6 },\n { x: bodyX + bodyW - slant, y: bodyY + bodyH },\n { x: bodyX, y: bodyY + bodyH - 6 },\n ];\n const mastX = bodyX + slant + bodyW * 0.2;\n const antenna: [Point, Point][] =\n (node.antenna ?? true)\n ? [\n [\n { x: bodyX + slant + bodyW * 0.18, y: bodyY + 1 },\n { x: mastX - 3, y: glyph.y + 3 },\n ],\n [\n { x: mastX + 1, y: bodyY + 2 },\n { x: mastX + 1, y: glyph.y + 8 },\n ],\n ]\n : [];\n const jackCount = Math.max(0, Math.floor(node.appliancePorts ?? 4));\n const jackSpacing = Math.min(\n 13,\n Math.max(8, (bodyW - slant - 42) / Math.max(jackCount, 1)),\n );\n const jacks = Array.from({ length: jackCount }, (_, index) => ({\n x: bodyX + slant + 16 + index * jackSpacing,\n y: bodyY + bodyH - 15,\n w: 5,\n h: 12,\n }));\n const face: [Point, Point] = [\n { x: bodyX + slant, y: bodyY + bodyH - 1 },\n { x: bodyX + bodyW - slant, y: bodyY + bodyH + 3 },\n ];\n // Through a variable, not a literal, so the return skips the excess-property check against NodeLayout['appliance'].\n const parts = { body, face, antenna, jacks };\n return parts;\n}\n\nfunction centreX(box: Box): number {\n return box.x + box.w / 2;\n}\n\nfunction centredTop(box: Box, h: number): number {\n return box.y + (box.h - h) / 2;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Point } from '../../model/diagram-ir.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Drops every point that lies on the straight line through its neighbours.
|
|
4
|
+
*
|
|
5
|
+
* Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.
|
|
6
|
+
*/
|
|
7
|
+
export declare function simplifyPath(path: Point[]): Point[];
|
|
8
|
+
/**
|
|
9
|
+
* An SVG path through the points, with each bend rounded.
|
|
10
|
+
*
|
|
11
|
+
* Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.
|
|
12
|
+
*/
|
|
13
|
+
export declare function pathToSvg(points: Point[]): string;
|
|
14
|
+
//# sourceMappingURL=path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAKvD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAanD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAwBjD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** The radius of the rounded corner the SVG path draws at each bend. */
|
|
2
|
+
const CORNER_RADIUS = 8;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Drops every point that lies on the straight line through its neighbours.
|
|
6
|
+
*
|
|
7
|
+
* Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.
|
|
8
|
+
*/
|
|
9
|
+
export function simplifyPath(path) {
|
|
10
|
+
if (path.length < 3) return path;
|
|
11
|
+
const result = [path[0]];
|
|
12
|
+
for (const [index, current] of path.slice(1, -1).entries()) {
|
|
13
|
+
const previous = result.at(-1);
|
|
14
|
+
const next = path[index + 2];
|
|
15
|
+
const cross = (current.x - previous.x) * (next.y - current.y) - (current.y - previous.y) * (next.x - current.x);
|
|
16
|
+
if (cross !== 0) result.push(current);
|
|
17
|
+
}
|
|
18
|
+
result.push(path.at(-1));
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* An SVG path through the points, with each bend rounded.
|
|
24
|
+
*
|
|
25
|
+
* Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.
|
|
26
|
+
*/
|
|
27
|
+
export function pathToSvg(points) {
|
|
28
|
+
const [first, ...rest] = points;
|
|
29
|
+
if (!first) return '';
|
|
30
|
+
const parts = [`M ${first.x} ${first.y}`];
|
|
31
|
+
for (const [index, current] of rest.slice(0, -1).entries()) {
|
|
32
|
+
const previous = points[index];
|
|
33
|
+
const next = points[index + 2];
|
|
34
|
+
const dpx = current.x - previous.x;
|
|
35
|
+
const dpy = current.y - previous.y;
|
|
36
|
+
const dnx = next.x - current.x;
|
|
37
|
+
const dny = next.y - current.y;
|
|
38
|
+
const lp = Math.hypot(dpx, dpy);
|
|
39
|
+
const ln = Math.hypot(dnx, dny);
|
|
40
|
+
const r = Math.min(CORNER_RADIUS, lp / 2, ln / 2);
|
|
41
|
+
const cs = {
|
|
42
|
+
x: current.x - dpx / lp * r,
|
|
43
|
+
y: current.y - dpy / lp * r
|
|
44
|
+
};
|
|
45
|
+
const ce = {
|
|
46
|
+
x: current.x + dnx / ln * r,
|
|
47
|
+
y: current.y + dny / ln * r
|
|
48
|
+
};
|
|
49
|
+
parts.push(`L ${cs.x} ${cs.y}`, `Q ${current.x} ${current.y} ${ce.x} ${ce.y}`);
|
|
50
|
+
}
|
|
51
|
+
const last = rest.at(-1);
|
|
52
|
+
if (last) parts.push(`L ${last.x} ${last.y}`);
|
|
53
|
+
return parts.join(' ');
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","names":["CORNER_RADIUS","simplifyPath","path","length","result","index","current","slice","entries","previous","at","next","cross","x","y","push","pathToSvg","points","first","rest","parts","dpx","dpy","dnx","dny","lp","Math","hypot","ln","r","min","cs","ce","last","join"],"sources":["../../../../src/lib/layouts/graph/path.ts"],"sourcesContent":["import type { Point } from '../../model/diagram-ir.ts';\n\n/** The radius of the rounded corner the SVG path draws at each bend. */\nconst CORNER_RADIUS = 8;\n\n/**\n * Drops every point that lies on the straight line through its neighbours.\n *\n * Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.\n */\nexport function simplifyPath(path: Point[]): Point[] {\n if (path.length < 3) return path;\n const result: Point[] = [path[0]!];\n for (const [index, current] of path.slice(1, -1).entries()) {\n const previous = result.at(-1)!;\n const next = path[index + 2]!;\n const cross =\n (current.x - previous.x) * (next.y - current.y) -\n (current.y - previous.y) * (next.x - current.x);\n if (cross !== 0) result.push(current);\n }\n result.push(path.at(-1)!);\n return result;\n}\n\n/**\n * An SVG path through the points, with each bend rounded.\n *\n * Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.\n */\nexport function pathToSvg(points: Point[]): string {\n const [first, ...rest] = points;\n if (!first) return '';\n const parts = [`M ${first.x} ${first.y}`];\n for (const [index, current] of rest.slice(0, -1).entries()) {\n const previous = points[index]!;\n const next = points[index + 2]!;\n const dpx = current.x - previous.x;\n const dpy = current.y - previous.y;\n const dnx = next.x - current.x;\n const dny = next.y - current.y;\n const lp = Math.hypot(dpx, dpy);\n const ln = Math.hypot(dnx, dny);\n const r = Math.min(CORNER_RADIUS, lp / 2, ln / 2);\n const cs = { x: current.x - (dpx / lp) * r, y: current.y - (dpy / lp) * r };\n const ce = { x: current.x + (dnx / ln) * r, y: current.y + (dny / ln) * r };\n parts.push(\n `L ${cs.x} ${cs.y}`,\n `Q ${current.x} ${current.y} ${ce.x} ${ce.y}`,\n );\n }\n const last = rest.at(-1);\n if (last) parts.push(`L ${last.x} ${last.y}`);\n return parts.join(' ');\n}\n"],"mappings":"AAEA;AACA,MAAMA,aAAa,GAAG,CAAC;;AAEvB;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,YAAYA,CAACC,IAAa,EAAW;EACnD,IAAIA,IAAI,CAACC,MAAM,GAAG,CAAC,EAAE,OAAOD,IAAI;EAChC,MAAME,MAAe,GAAG,CAACF,IAAI,CAAC,CAAC,CAAC,CAAE;EAClC,KAAK,MAAM,CAACG,KAAK,EAAEC,OAAO,CAAC,IAAIJ,IAAI,CAACK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,CAAC,EAAE;IAC1D,MAAMC,QAAQ,GAAGL,MAAM,CAACM,EAAE,CAAC,CAAC,CAAC,CAAE;IAC/B,MAAMC,IAAI,GAAGT,IAAI,CAACG,KAAK,GAAG,CAAC,CAAE;IAC7B,MAAMO,KAAK,GACT,CAACN,OAAO,CAACO,CAAC,GAAGJ,QAAQ,CAACI,CAAC,KAAKF,IAAI,CAACG,CAAC,GAAGR,OAAO,CAACQ,CAAC,CAAC,GAC/C,CAACR,OAAO,CAACQ,CAAC,GAAGL,QAAQ,CAACK,CAAC,KAAKH,IAAI,CAACE,CAAC,GAAGP,OAAO,CAACO,CAAC,CAAC;IACjD,IAAID,KAAK,KAAK,CAAC,EAAER,MAAM,CAACW,IAAI,CAACT,OAAO,CAAC;EACvC;EACAF,MAAM,CAACW,IAAI,CAACb,IAAI,CAACQ,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC;EACzB,OAAON,MAAM;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASY,SAASA,CAACC,MAAe,EAAU;EACjD,MAAM,CAACC,KAAK,EAAE,GAAGC,IAAI,CAAC,GAAGF,MAAM;EAC/B,IAAI,CAACC,KAAK,EAAE,OAAO,EAAE;EACrB,MAAME,KAAK,GAAG,CAAC,KAAKF,KAAK,CAACL,CAAC,IAAIK,KAAK,CAACJ,CAAC,EAAE,CAAC;EACzC,KAAK,MAAM,CAACT,KAAK,EAAEC,OAAO,CAAC,IAAIa,IAAI,CAACZ,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,CAAC,EAAE;IAC1D,MAAMC,QAAQ,GAAGQ,MAAM,CAACZ,KAAK,CAAE;IAC/B,MAAMM,IAAI,GAAGM,MAAM,CAACZ,KAAK,GAAG,CAAC,CAAE;IAC/B,MAAMgB,GAAG,GAAGf,OAAO,CAACO,CAAC,GAAGJ,QAAQ,CAACI,CAAC;IAClC,MAAMS,GAAG,GAAGhB,OAAO,CAACQ,CAAC,GAAGL,QAAQ,CAACK,CAAC;IAClC,MAAMS,GAAG,GAAGZ,IAAI,CAACE,CAAC,GAAGP,OAAO,CAACO,CAAC;IAC9B,MAAMW,GAAG,GAAGb,IAAI,CAACG,CAAC,GAAGR,OAAO,CAACQ,CAAC;IAC9B,MAAMW,EAAE,GAAGC,IAAI,CAACC,KAAK,CAACN,GAAG,EAAEC,GAAG,CAAC;IAC/B,MAAMM,EAAE,GAAGF,IAAI,CAACC,KAAK,CAACJ,GAAG,EAAEC,GAAG,CAAC;IAC/B,MAAMK,CAAC,GAAGH,IAAI,CAACI,GAAG,CAAC9B,aAAa,EAAEyB,EAAE,GAAG,CAAC,EAAEG,EAAE,GAAG,CAAC,CAAC;IACjD,MAAMG,EAAE,GAAG;MAAElB,CAAC,EAAEP,OAAO,CAACO,CAAC,GAAIQ,GAAG,GAAGI,EAAE,GAAII,CAAC;MAAEf,CAAC,EAAER,OAAO,CAACQ,CAAC,GAAIQ,GAAG,GAAGG,EAAE,GAAII;IAAE,CAAC;IAC3E,MAAMG,EAAE,GAAG;MAAEnB,CAAC,EAAEP,OAAO,CAACO,CAAC,GAAIU,GAAG,GAAGK,EAAE,GAAIC,CAAC;MAAEf,CAAC,EAAER,OAAO,CAACQ,CAAC,GAAIU,GAAG,GAAGI,EAAE,GAAIC;IAAE,CAAC;IAC3ET,KAAK,CAACL,IAAI,CACR,KAAKgB,EAAE,CAAClB,CAAC,IAAIkB,EAAE,CAACjB,CAAC,EAAE,EACnB,KAAKR,OAAO,CAACO,CAAC,IAAIP,OAAO,CAACQ,CAAC,IAAIkB,EAAE,CAACnB,CAAC,IAAImB,EAAE,CAAClB,CAAC,EAC7C,CAAC;EACH;EACA,MAAMmB,IAAI,GAAGd,IAAI,CAACT,EAAE,CAAC,CAAC,CAAC,CAAC;EACxB,IAAIuB,IAAI,EAAEb,KAAK,CAACL,IAAI,CAAC,KAAKkB,IAAI,CAACpB,CAAC,IAAIoB,IAAI,CAACnB,CAAC,EAAE,CAAC;EAC7C,OAAOM,KAAK,CAACc,IAAI,CAAC,GAAG,CAAC;AACxB","ignoreList":[]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Box, Point } from '../../model/diagram-ir.ts';
|
|
2
|
+
/** A direction of travel: right, left, down, up. */
|
|
3
|
+
export type Heading = 0 | 1 | 2 | 3;
|
|
4
|
+
/** The routing grid's pitch. */
|
|
5
|
+
export declare const GRID = 4;
|
|
6
|
+
export type RouteSearch = {
|
|
7
|
+
/** Only grid points inside this box are searched. */
|
|
8
|
+
window: Box;
|
|
9
|
+
/** Coordinates the grid holds besides every multiple of GRID: the route's own ends, slots and stubs. */
|
|
10
|
+
lines: {
|
|
11
|
+
x: number[];
|
|
12
|
+
y: number[];
|
|
13
|
+
};
|
|
14
|
+
/** No route passes a grid point strictly inside one of these. */
|
|
15
|
+
walls: Box[];
|
|
16
|
+
/** Segments of routes already drawn: a route may cross them at a cost, never run along them. */
|
|
17
|
+
runs: [Point, Point][];
|
|
18
|
+
/** Group rects and title bands: crossing or hugging their borders costs extra. */
|
|
19
|
+
borders: Box[];
|
|
20
|
+
start: Point;
|
|
21
|
+
/** The heading of the stub that reaches `start`. */
|
|
22
|
+
startHeading: Heading;
|
|
23
|
+
goal: Point;
|
|
24
|
+
/** The heading of the stub that leaves `goal` for the entry side. */
|
|
25
|
+
goalHeading: Heading;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The cheapest orthogonal path from `start` to `goal` on a grid of GRID
|
|
29
|
+
* pitch, or undefined when the walls leave none. The search state is a grid
|
|
30
|
+
* point together with the heading that reached it, so a turn costs the same
|
|
31
|
+
* whichever way a point was reached.
|
|
32
|
+
*/
|
|
33
|
+
export declare function searchRoute(search: RouteSearch): Point[] | undefined;
|
|
34
|
+
//# sourceMappingURL=route-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-search.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/route-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAG5D,oDAAoD;AACpD,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEpC,gCAAgC;AAChC,eAAO,MAAM,IAAI,IAAI,CAAC;AA4BtB,MAAM,MAAM,WAAW,GAAG;IACxB,qDAAqD;IACrD,MAAM,EAAE,GAAG,CAAC;IACZ,wGAAwG;IACxG,KAAK,EAAE;QAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpC,iEAAiE;IACjE,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,gGAAgG;IAChG,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;IACvB,kFAAkF;IAClF,OAAO,EAAE,GAAG,EAAE,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,oDAAoD;IACpD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,GAAG,SAAS,CA6CpE"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { MinHeap } from "./min-heap.js";
|
|
2
|
+
|
|
3
|
+
/** A direction of travel: right, left, down, up. */
|
|
4
|
+
|
|
5
|
+
/** The routing grid's pitch. */
|
|
6
|
+
export const GRID = 4;
|
|
7
|
+
const TURN_COST = 14;
|
|
8
|
+
const EDGE_CROSSING_COST = 20;
|
|
9
|
+
const BORDER_CROSSING_COST = 6;
|
|
10
|
+
/** Charged for every grid step that runs parallel to a group border within HUG_DISTANCE of it. */
|
|
11
|
+
const BORDER_HUG_COST = 10;
|
|
12
|
+
const HUG_DISTANCE = 4;
|
|
13
|
+
/** A run of another edge closer than this to a grid line lies on that line. */
|
|
14
|
+
const RUN_TOLERANCE = GRID / 2;
|
|
15
|
+
const STEPS = {
|
|
16
|
+
0: [1, 0],
|
|
17
|
+
1: [-1, 0],
|
|
18
|
+
2: [0, 1],
|
|
19
|
+
3: [0, -1]
|
|
20
|
+
};
|
|
21
|
+
const HEADINGS = [0, 1, 2, 3];
|
|
22
|
+
const REVERSE = {
|
|
23
|
+
0: 1,
|
|
24
|
+
1: 0,
|
|
25
|
+
2: 3,
|
|
26
|
+
3: 2
|
|
27
|
+
};
|
|
28
|
+
function reverse(heading) {
|
|
29
|
+
return REVERSE[heading];
|
|
30
|
+
}
|
|
31
|
+
function isHorizontal(heading) {
|
|
32
|
+
return heading < 2;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The cheapest orthogonal path from `start` to `goal` on a grid of GRID
|
|
36
|
+
* pitch, or undefined when the walls leave none. The search state is a grid
|
|
37
|
+
* point together with the heading that reached it, so a turn costs the same
|
|
38
|
+
* whichever way a point was reached.
|
|
39
|
+
*/
|
|
40
|
+
export function searchRoute(search) {
|
|
41
|
+
const grid = new SearchGrid(search);
|
|
42
|
+
const start = grid.indexOf(search.start);
|
|
43
|
+
const goal = grid.indexOf(search.goal);
|
|
44
|
+
if (start === undefined || goal === undefined) return undefined;
|
|
45
|
+
if (grid.blocked[start] || grid.blocked[goal]) return undefined;
|
|
46
|
+
const states = grid.cells * 4;
|
|
47
|
+
const virtualGoal = states;
|
|
48
|
+
const cost = new Float64Array(states + 1).fill(Infinity);
|
|
49
|
+
const cameFrom = new Int32Array(states + 1).fill(-1);
|
|
50
|
+
const open = new MinHeap();
|
|
51
|
+
const startState = start * 4 + search.startHeading;
|
|
52
|
+
cost[startState] = 0;
|
|
53
|
+
open.push(startState, grid.estimate(start, goal));
|
|
54
|
+
while (open.size > 0) {
|
|
55
|
+
const state = open.pop();
|
|
56
|
+
if (state === virtualGoal) return grid.trace(cameFrom, cameFrom[state]);
|
|
57
|
+
const cell = state >> 2;
|
|
58
|
+
const heading = HEADINGS[state & 3];
|
|
59
|
+
const reached = cost[state];
|
|
60
|
+
if (cell === goal) {
|
|
61
|
+
if (heading === reverse(search.goalHeading)) continue;
|
|
62
|
+
const total = reached + (heading === search.goalHeading ? 0 : TURN_COST);
|
|
63
|
+
if (total < cost[virtualGoal]) {
|
|
64
|
+
cost[virtualGoal] = total;
|
|
65
|
+
cameFrom[virtualGoal] = state;
|
|
66
|
+
open.push(virtualGoal, total);
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
for (const next of HEADINGS) {
|
|
71
|
+
if (next === reverse(heading)) continue;
|
|
72
|
+
const step = grid.step(cell, next);
|
|
73
|
+
if (step === undefined) continue;
|
|
74
|
+
const nextState = step.cell * 4 + next;
|
|
75
|
+
const total = reached + step.cost + (next === heading ? 0 : TURN_COST);
|
|
76
|
+
if (total >= cost[nextState]) continue;
|
|
77
|
+
cost[nextState] = total;
|
|
78
|
+
cameFrom[nextState] = state;
|
|
79
|
+
open.push(nextState, total + grid.estimate(step.cell, goal));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The grid points of one search, with what each one costs to enter. */
|
|
86
|
+
class SearchGrid {
|
|
87
|
+
#alongRunH;
|
|
88
|
+
#alongRunV;
|
|
89
|
+
/** Group borders between grid column i − 1 and column i, at each row. */
|
|
90
|
+
#bordersBeforeX;
|
|
91
|
+
#bordersBeforeY;
|
|
92
|
+
#hugH;
|
|
93
|
+
#hugV;
|
|
94
|
+
constructor(search) {
|
|
95
|
+
const {
|
|
96
|
+
window
|
|
97
|
+
} = search;
|
|
98
|
+
this.xs = axis(window.x, window.x + window.w, search.lines.x);
|
|
99
|
+
this.ys = axis(window.y, window.y + window.h, search.lines.y);
|
|
100
|
+
this.cells = this.xs.length * this.ys.length;
|
|
101
|
+
this.blocked = new Uint8Array(this.cells);
|
|
102
|
+
this.#alongRunH = new Uint8Array(this.cells);
|
|
103
|
+
this.#alongRunV = new Uint8Array(this.cells);
|
|
104
|
+
this.#bordersBeforeX = new Uint8Array(this.cells);
|
|
105
|
+
this.#bordersBeforeY = new Uint8Array(this.cells);
|
|
106
|
+
this.#hugH = new Uint8Array(this.cells);
|
|
107
|
+
this.#hugV = new Uint8Array(this.cells);
|
|
108
|
+
for (const wall of search.walls) {
|
|
109
|
+
this.#fill(this.blocked, strictlyInside(this.xs, wall.x, wall.x + wall.w), strictlyInside(this.ys, wall.y, wall.y + wall.h));
|
|
110
|
+
}
|
|
111
|
+
for (const [a, b] of search.runs) {
|
|
112
|
+
if (a.y === b.y) {
|
|
113
|
+
this.#fill(this.#alongRunH, within(this.xs, Math.min(a.x, b.x), Math.max(a.x, b.x)), near(this.ys, a.y, RUN_TOLERANCE));
|
|
114
|
+
} else {
|
|
115
|
+
this.#fill(this.#alongRunV, near(this.xs, a.x, RUN_TOLERANCE), within(this.ys, Math.min(a.y, b.y), Math.max(a.y, b.y)));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const rect of search.borders) {
|
|
119
|
+
const rows = within(this.ys, rect.y, rect.y + rect.h);
|
|
120
|
+
const cols = within(this.xs, rect.x, rect.x + rect.w);
|
|
121
|
+
for (const x of [rect.x, rect.x + rect.w]) {
|
|
122
|
+
this.#fill(this.#bordersBeforeX, crossedBefore(this.xs, x), rows);
|
|
123
|
+
this.#fill(this.#hugV, near(this.xs, x, HUG_DISTANCE + 1e-6), rows);
|
|
124
|
+
}
|
|
125
|
+
for (const y of [rect.y, rect.y + rect.h]) {
|
|
126
|
+
this.#fill(this.#bordersBeforeY, cols, crossedBefore(this.ys, y));
|
|
127
|
+
this.#fill(this.#hugH, cols, near(this.ys, y, HUG_DISTANCE + 1e-6));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
indexOf(point) {
|
|
132
|
+
const i = this.xs.indexOf(point.x);
|
|
133
|
+
const j = this.ys.indexOf(point.y);
|
|
134
|
+
return i === -1 || j === -1 ? undefined : j * this.xs.length + i;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** A lower bound on the cost from `cell` to `goal`: one unit per GRID of distance. */
|
|
138
|
+
estimate(cell, goal) {
|
|
139
|
+
const width = this.xs.length;
|
|
140
|
+
return (Math.abs(this.xs[cell % width] - this.xs[goal % width]) + Math.abs(this.ys[Math.floor(cell / width)] - this.ys[Math.floor(goal / width)])) / GRID;
|
|
141
|
+
}
|
|
142
|
+
step(cell, heading) {
|
|
143
|
+
const width = this.xs.length;
|
|
144
|
+
const i = cell % width;
|
|
145
|
+
const j = Math.floor(cell / width);
|
|
146
|
+
const [di, dj] = STEPS[heading];
|
|
147
|
+
const ni = i + di;
|
|
148
|
+
const nj = j + dj;
|
|
149
|
+
if (ni < 0 || nj < 0 || ni >= width || nj >= this.ys.length) return undefined;
|
|
150
|
+
const next = nj * width + ni;
|
|
151
|
+
if (this.blocked[next]) return undefined;
|
|
152
|
+
const horizontal = isHorizontal(heading);
|
|
153
|
+
if ((horizontal ? this.#alongRunH : this.#alongRunV)[next]) return undefined;
|
|
154
|
+
const length = horizontal ? Math.abs(this.xs[ni] - this.xs[i]) : Math.abs(this.ys[nj] - this.ys[j]);
|
|
155
|
+
const crossed = horizontal ? this.#bordersBeforeX[j * width + Math.max(i, ni)] : this.#bordersBeforeY[Math.max(j, nj) * width + i];
|
|
156
|
+
const hugs = (horizontal ? this.#hugH : this.#hugV)[next] > 0;
|
|
157
|
+
const crossesRun = (horizontal ? this.#alongRunV : this.#alongRunH)[next] > 0;
|
|
158
|
+
return {
|
|
159
|
+
cell: next,
|
|
160
|
+
cost: length / GRID + crossed * BORDER_CROSSING_COST + (hugs ? BORDER_HUG_COST * length / GRID : 0) + (crossesRun ? EDGE_CROSSING_COST : 0)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
trace(cameFrom, last) {
|
|
164
|
+
const width = this.xs.length;
|
|
165
|
+
const points = [];
|
|
166
|
+
for (let state = last; state !== -1; state = cameFrom[state]) {
|
|
167
|
+
const cell = state >> 2;
|
|
168
|
+
points.push({
|
|
169
|
+
x: this.xs[cell % width],
|
|
170
|
+
y: this.ys[Math.floor(cell / width)]
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return points.reverse();
|
|
174
|
+
}
|
|
175
|
+
#fill(target, cols, rows) {
|
|
176
|
+
const width = this.xs.length;
|
|
177
|
+
for (const j of rows) for (const i of cols) target[j * width + i] += 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Every multiple of GRID in [from, to], with the extra lines inside it, sorted and distinct. */
|
|
182
|
+
function axis(from, to, extra) {
|
|
183
|
+
const values = new Set();
|
|
184
|
+
for (let v = Math.ceil(from / GRID) * GRID; v <= to; v += GRID) values.add(v);
|
|
185
|
+
for (const v of extra) if (v >= from && v <= to) values.add(v);
|
|
186
|
+
return [...values].sort((a, b) => a - b);
|
|
187
|
+
}
|
|
188
|
+
function indicesWhere(values, keep) {
|
|
189
|
+
const indices = [];
|
|
190
|
+
for (const [index, value] of values.entries()) if (keep(value)) indices.push(index);
|
|
191
|
+
return indices;
|
|
192
|
+
}
|
|
193
|
+
function strictlyInside(values, from, to) {
|
|
194
|
+
return indicesWhere(values, v => v > from && v < to);
|
|
195
|
+
}
|
|
196
|
+
function within(values, from, to) {
|
|
197
|
+
return indicesWhere(values, v => v >= from && v <= to);
|
|
198
|
+
}
|
|
199
|
+
function near(values, at, distance) {
|
|
200
|
+
return indicesWhere(values, v => Math.abs(v - at) < distance);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** The index i whose step from i − 1 crosses `at`. */
|
|
204
|
+
function crossedBefore(values, at) {
|
|
205
|
+
const i = values.findIndex(v => v >= at);
|
|
206
|
+
return i > 0 && values[i - 1] < at ? [i] : [];
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=route-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-search.js","names":["MinHeap","GRID","TURN_COST","EDGE_CROSSING_COST","BORDER_CROSSING_COST","BORDER_HUG_COST","HUG_DISTANCE","RUN_TOLERANCE","STEPS","HEADINGS","REVERSE","reverse","heading","isHorizontal","searchRoute","search","grid","SearchGrid","start","indexOf","goal","undefined","blocked","states","cells","virtualGoal","cost","Float64Array","fill","Infinity","cameFrom","Int32Array","open","startState","startHeading","push","estimate","size","state","pop","trace","cell","reached","goalHeading","total","next","step","nextState","alongRunH","alongRunV","bordersBeforeX","bordersBeforeY","hugH","hugV","constructor","window","xs","axis","x","w","lines","ys","y","h","length","Uint8Array","wall","walls","strictlyInside","a","b","runs","within","Math","min","max","near","rect","borders","rows","cols","crossedBefore","point","i","j","width","abs","floor","di","dj","ni","nj","horizontal","crossed","hugs","crossesRun","last","points","#fill","target","from","to","extra","values","Set","v","ceil","add","sort","indicesWhere","keep","indices","index","value","entries","at","distance","findIndex"],"sources":["../../../../src/lib/layouts/graph/route-search.ts"],"sourcesContent":["import type { Box, Point } from '../../model/diagram-ir.ts';\nimport { MinHeap } from './min-heap.ts';\n\n/** A direction of travel: right, left, down, up. */\nexport type Heading = 0 | 1 | 2 | 3;\n\n/** The routing grid's pitch. */\nexport const GRID = 4;\nconst TURN_COST = 14;\nconst EDGE_CROSSING_COST = 20;\nconst BORDER_CROSSING_COST = 6;\n/** Charged for every grid step that runs parallel to a group border within HUG_DISTANCE of it. */\nconst BORDER_HUG_COST = 10;\nconst HUG_DISTANCE = 4;\n/** A run of another edge closer than this to a grid line lies on that line. */\nconst RUN_TOLERANCE = GRID / 2;\n\nconst STEPS: Record<Heading, [number, number]> = {\n 0: [1, 0],\n 1: [-1, 0],\n 2: [0, 1],\n 3: [0, -1],\n};\nconst HEADINGS: Heading[] = [0, 1, 2, 3];\n\nconst REVERSE: Record<Heading, Heading> = { 0: 1, 1: 0, 2: 3, 3: 2 };\n\nfunction reverse(heading: Heading): Heading {\n return REVERSE[heading];\n}\n\nfunction isHorizontal(heading: Heading): boolean {\n return heading < 2;\n}\n\nexport type RouteSearch = {\n /** Only grid points inside this box are searched. */\n window: Box;\n /** Coordinates the grid holds besides every multiple of GRID: the route's own ends, slots and stubs. */\n lines: { x: number[]; y: number[] };\n /** No route passes a grid point strictly inside one of these. */\n walls: Box[];\n /** Segments of routes already drawn: a route may cross them at a cost, never run along them. */\n runs: [Point, Point][];\n /** Group rects and title bands: crossing or hugging their borders costs extra. */\n borders: Box[];\n start: Point;\n /** The heading of the stub that reaches `start`. */\n startHeading: Heading;\n goal: Point;\n /** The heading of the stub that leaves `goal` for the entry side. */\n goalHeading: Heading;\n};\n\n/**\n * The cheapest orthogonal path from `start` to `goal` on a grid of GRID\n * pitch, or undefined when the walls leave none. The search state is a grid\n * point together with the heading that reached it, so a turn costs the same\n * whichever way a point was reached.\n */\nexport function searchRoute(search: RouteSearch): Point[] | undefined {\n const grid = new SearchGrid(search);\n const start = grid.indexOf(search.start);\n const goal = grid.indexOf(search.goal);\n if (start === undefined || goal === undefined) return undefined;\n if (grid.blocked[start] || grid.blocked[goal]) return undefined;\n\n const states = grid.cells * 4;\n const virtualGoal = states;\n const cost = new Float64Array(states + 1).fill(Infinity);\n const cameFrom = new Int32Array(states + 1).fill(-1);\n const open = new MinHeap<number>();\n const startState = start * 4 + search.startHeading;\n cost[startState] = 0;\n open.push(startState, grid.estimate(start, goal));\n\n while (open.size > 0) {\n const state = open.pop()!;\n if (state === virtualGoal) return grid.trace(cameFrom, cameFrom[state]!);\n const cell = state >> 2;\n const heading = HEADINGS[state & 3]!;\n const reached = cost[state]!;\n if (cell === goal) {\n if (heading === reverse(search.goalHeading)) continue;\n const total = reached + (heading === search.goalHeading ? 0 : TURN_COST);\n if (total < cost[virtualGoal]!) {\n cost[virtualGoal] = total;\n cameFrom[virtualGoal] = state;\n open.push(virtualGoal, total);\n }\n continue;\n }\n for (const next of HEADINGS) {\n if (next === reverse(heading)) continue;\n const step = grid.step(cell, next);\n if (step === undefined) continue;\n const nextState = step.cell * 4 + next;\n const total = reached + step.cost + (next === heading ? 0 : TURN_COST);\n if (total >= cost[nextState]!) continue;\n cost[nextState] = total;\n cameFrom[nextState] = state;\n open.push(nextState, total + grid.estimate(step.cell, goal));\n }\n }\n return undefined;\n}\n\n/** The grid points of one search, with what each one costs to enter. */\nclass SearchGrid {\n readonly xs: number[];\n readonly ys: number[];\n readonly cells: number;\n readonly blocked: Uint8Array;\n readonly #alongRunH: Uint8Array;\n readonly #alongRunV: Uint8Array;\n /** Group borders between grid column i − 1 and column i, at each row. */\n readonly #bordersBeforeX: Uint8Array;\n readonly #bordersBeforeY: Uint8Array;\n readonly #hugH: Uint8Array;\n readonly #hugV: Uint8Array;\n\n constructor(search: RouteSearch) {\n const { window } = search;\n this.xs = axis(window.x, window.x + window.w, search.lines.x);\n this.ys = axis(window.y, window.y + window.h, search.lines.y);\n this.cells = this.xs.length * this.ys.length;\n this.blocked = new Uint8Array(this.cells);\n this.#alongRunH = new Uint8Array(this.cells);\n this.#alongRunV = new Uint8Array(this.cells);\n this.#bordersBeforeX = new Uint8Array(this.cells);\n this.#bordersBeforeY = new Uint8Array(this.cells);\n this.#hugH = new Uint8Array(this.cells);\n this.#hugV = new Uint8Array(this.cells);\n\n for (const wall of search.walls) {\n this.#fill(\n this.blocked,\n strictlyInside(this.xs, wall.x, wall.x + wall.w),\n strictlyInside(this.ys, wall.y, wall.y + wall.h),\n );\n }\n for (const [a, b] of search.runs) {\n if (a.y === b.y) {\n this.#fill(\n this.#alongRunH,\n within(this.xs, Math.min(a.x, b.x), Math.max(a.x, b.x)),\n near(this.ys, a.y, RUN_TOLERANCE),\n );\n } else {\n this.#fill(\n this.#alongRunV,\n near(this.xs, a.x, RUN_TOLERANCE),\n within(this.ys, Math.min(a.y, b.y), Math.max(a.y, b.y)),\n );\n }\n }\n for (const rect of search.borders) {\n const rows = within(this.ys, rect.y, rect.y + rect.h);\n const cols = within(this.xs, rect.x, rect.x + rect.w);\n for (const x of [rect.x, rect.x + rect.w]) {\n this.#fill(this.#bordersBeforeX, crossedBefore(this.xs, x), rows);\n this.#fill(this.#hugV, near(this.xs, x, HUG_DISTANCE + 1e-6), rows);\n }\n for (const y of [rect.y, rect.y + rect.h]) {\n this.#fill(this.#bordersBeforeY, cols, crossedBefore(this.ys, y));\n this.#fill(this.#hugH, cols, near(this.ys, y, HUG_DISTANCE + 1e-6));\n }\n }\n }\n\n indexOf(point: Point): number | undefined {\n const i = this.xs.indexOf(point.x);\n const j = this.ys.indexOf(point.y);\n return i === -1 || j === -1 ? undefined : j * this.xs.length + i;\n }\n\n /** A lower bound on the cost from `cell` to `goal`: one unit per GRID of distance. */\n estimate(cell: number, goal: number): number {\n const width = this.xs.length;\n return (\n (Math.abs(this.xs[cell % width]! - this.xs[goal % width]!) +\n Math.abs(\n this.ys[Math.floor(cell / width)]! -\n this.ys[Math.floor(goal / width)]!,\n )) /\n GRID\n );\n }\n\n step(\n cell: number,\n heading: Heading,\n ): { cell: number; cost: number } | undefined {\n const width = this.xs.length;\n const i = cell % width;\n const j = Math.floor(cell / width);\n const [di, dj] = STEPS[heading];\n const ni = i + di;\n const nj = j + dj;\n if (ni < 0 || nj < 0 || ni >= width || nj >= this.ys.length)\n return undefined;\n const next = nj * width + ni;\n if (this.blocked[next]) return undefined;\n const horizontal = isHorizontal(heading);\n if ((horizontal ? this.#alongRunH : this.#alongRunV)[next])\n return undefined;\n const length = horizontal\n ? Math.abs(this.xs[ni]! - this.xs[i]!)\n : Math.abs(this.ys[nj]! - this.ys[j]!);\n const crossed = horizontal\n ? this.#bordersBeforeX[j * width + Math.max(i, ni)]!\n : this.#bordersBeforeY[Math.max(j, nj) * width + i]!;\n const hugs = (horizontal ? this.#hugH : this.#hugV)[next]! > 0;\n const crossesRun =\n (horizontal ? this.#alongRunV : this.#alongRunH)[next]! > 0;\n return {\n cell: next,\n cost:\n length / GRID +\n crossed * BORDER_CROSSING_COST +\n (hugs ? (BORDER_HUG_COST * length) / GRID : 0) +\n (crossesRun ? EDGE_CROSSING_COST : 0),\n };\n }\n\n trace(cameFrom: Int32Array, last: number): Point[] {\n const width = this.xs.length;\n const points: Point[] = [];\n for (let state = last; state !== -1; state = cameFrom[state]!) {\n const cell = state >> 2;\n points.push({\n x: this.xs[cell % width]!,\n y: this.ys[Math.floor(cell / width)]!,\n });\n }\n return points.reverse();\n }\n\n #fill(target: Uint8Array, cols: number[], rows: number[]): void {\n const width = this.xs.length;\n for (const j of rows) for (const i of cols) target[j * width + i]! += 1;\n }\n}\n\n/** Every multiple of GRID in [from, to], with the extra lines inside it, sorted and distinct. */\nfunction axis(from: number, to: number, extra: number[]): number[] {\n const values = new Set<number>();\n for (let v = Math.ceil(from / GRID) * GRID; v <= to; v += GRID) values.add(v);\n for (const v of extra) if (v >= from && v <= to) values.add(v);\n return [...values].sort((a, b) => a - b);\n}\n\nfunction indicesWhere(\n values: number[],\n keep: (value: number) => boolean,\n): number[] {\n const indices: number[] = [];\n for (const [index, value] of values.entries())\n if (keep(value)) indices.push(index);\n return indices;\n}\n\nfunction strictlyInside(values: number[], from: number, to: number): number[] {\n return indicesWhere(values, (v) => v > from && v < to);\n}\n\nfunction within(values: number[], from: number, to: number): number[] {\n return indicesWhere(values, (v) => v >= from && v <= to);\n}\n\nfunction near(values: number[], at: number, distance: number): number[] {\n return indicesWhere(values, (v) => Math.abs(v - at) < distance);\n}\n\n/** The index i whose step from i − 1 crosses `at`. */\nfunction crossedBefore(values: number[], at: number): number[] {\n const i = values.findIndex((v) => v >= at);\n return i > 0 && values[i - 1]! < at ? [i] : [];\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DiagramGraphIR } from '../../model/diagram-ir.ts';
|
|
2
|
+
import type { GridAreas } from './areas.ts';
|
|
3
|
+
import type { EdgeLayout, GroupLayout, LeaderLayout, NodeLayout } from './graph-layout-result.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Routes every edge and note leader orthogonally, nearest cells first, and
|
|
6
|
+
* places each edge's label and badge before the next edge routes around
|
|
7
|
+
* them. It throws when a route or a label has no room; it never draws a
|
|
8
|
+
* diagonal or straight line through what is in the way.
|
|
9
|
+
*/
|
|
10
|
+
export declare function routeGraph(ir: DiagramGraphIR, nodes: NodeLayout[], groups: GroupLayout[], areas: GridAreas,
|
|
11
|
+
/** How far beyond the bounding box of its two shapes a route first searches. */
|
|
12
|
+
searchMargin: number): {
|
|
13
|
+
edges: EdgeLayout[];
|
|
14
|
+
leaders: LeaderLayout[];
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,cAAc,EAAS,MAAM,2BAA2B,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAO5C,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,EACX,MAAM,0BAA0B,CAAC;AAmBlC;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,UAAU,EAAE,EACnB,MAAM,EAAE,WAAW,EAAE,EACrB,KAAK,EAAE,SAAS;AAChB,gFAAgF;AAChF,YAAY,EAAE,MAAM,GACnB;IAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,CA2KlD"}
|