@xenolithengine/graph-render-pixi 0.7.0-beta.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/bezier.d.ts +30 -0
- package/dist/bezier.d.ts.map +1 -0
- package/dist/bezier.js +70 -0
- package/dist/bezier.js.map +1 -0
- package/dist/comment-renderer.d.ts +35 -0
- package/dist/comment-renderer.d.ts.map +1 -0
- package/dist/comment-renderer.js +194 -0
- package/dist/comment-renderer.js.map +1 -0
- package/dist/edge-paths.d.ts +24 -0
- package/dist/edge-paths.d.ts.map +1 -0
- package/dist/edge-paths.js +123 -0
- package/dist/edge-paths.js.map +1 -0
- package/dist/edge-renderer.d.ts +29 -0
- package/dist/edge-renderer.d.ts.map +1 -0
- package/dist/edge-renderer.js +99 -0
- package/dist/edge-renderer.js.map +1 -0
- package/dist/geom.d.ts +46 -0
- package/dist/geom.d.ts.map +1 -0
- package/dist/geom.js +54 -0
- package/dist/geom.js.map +1 -0
- package/dist/grid.d.ts +12 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +35 -0
- package/dist/grid.js.map +1 -0
- package/dist/icons.d.ts +14 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +32 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction.d.ts +69 -0
- package/dist/interaction.d.ts.map +1 -0
- package/dist/interaction.js +229 -0
- package/dist/interaction.js.map +1 -0
- package/dist/layout.d.ts +126 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +360 -0
- package/dist/layout.js.map +1 -0
- package/dist/macro-frame.d.ts +29 -0
- package/dist/macro-frame.d.ts.map +1 -0
- package/dist/macro-frame.js +116 -0
- package/dist/macro-frame.js.map +1 -0
- package/dist/node-renderer.d.ts +102 -0
- package/dist/node-renderer.d.ts.map +1 -0
- package/dist/node-renderer.js +776 -0
- package/dist/node-renderer.js.map +1 -0
- package/dist/reroute-renderer.d.ts +25 -0
- package/dist/reroute-renderer.d.ts.map +1 -0
- package/dist/reroute-renderer.js +163 -0
- package/dist/reroute-renderer.js.map +1 -0
- package/dist/style.d.ts +56 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/style.js +102 -0
- package/dist/style.js.map +1 -0
- package/dist/text-measure.d.ts +6 -0
- package/dist/text-measure.d.ts.map +1 -0
- package/dist/text-measure.js +21 -0
- package/dist/text-measure.js.map +1 -0
- package/dist/theme.d.ts +86 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +2 -0
- package/dist/theme.js.map +1 -0
- package/dist/viewport-math.d.ts +68 -0
- package/dist/viewport-math.d.ts.map +1 -0
- package/dist/viewport-math.js +106 -0
- package/dist/viewport-math.js.map +1 -0
- package/dist/viewport.d.ts +28 -0
- package/dist/viewport.d.ts.map +1 -0
- package/dist/viewport.js +47 -0
- package/dist/viewport.js.map +1 -0
- package/dist/virtualize.d.ts +55 -0
- package/dist/virtualize.d.ts.map +1 -0
- package/dist/virtualize.js +96 -0
- package/dist/virtualize.js.map +1 -0
- package/dist/widget-renderer.d.ts +150 -0
- package/dist/widget-renderer.d.ts.map +1 -0
- package/dist/widget-renderer.js +399 -0
- package/dist/widget-renderer.js.map +1 -0
- package/dist/xen-theme.d.ts +8 -0
- package/dist/xen-theme.d.ts.map +1 -0
- package/dist/xen-theme.js +23 -0
- package/dist/xen-theme.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 strelok2012
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @xenolithengine/graph-render-pixi
|
|
2
|
+
|
|
3
|
+
[](https://github.com/XenolithEngine/xenolith-graph#status)
|
|
4
|
+
[](https://github.com/XenolithEngine/xenolith-graph/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
PIXI v8 renderer for XenolithGraph — node/edge/widget rendering, viewport math, interaction, virtualization. PIXI is a peer dependency.
|
|
7
|
+
|
|
8
|
+
> **Beta** — public API in `STABLE-API.md` is the surface we plan to freeze, but it is **NOT frozen yet** — breaking changes can land at any point before v1.0. If you adopt now, pin an exact version.
|
|
9
|
+
|
|
10
|
+
Part of [XenolithGraph](https://github.com/XenolithEngine/xenolith-graph) — an AI-native, embeddable node-graph editor for the web with its own visual design language (Xen).
|
|
11
|
+
|
|
12
|
+
Most hosts don't import this directly — `@xenolithengine/graph-editor` wires it in. Reach for this package if you're writing a theme or a custom renderer pipeline.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @xenolithengine/graph-render-pixi pixi.js
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Peer dependency: `pixi.js@^8.6.0`. Themes pair with `@xenolithengine/graph-theme-xen` (also a peer).
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { renderNode, computeNodeLayout, createPixiTextMeasurer } from '@xenolithengine/graph-render-pixi'
|
|
26
|
+
import { xenTheme } from '@xenolithengine/graph-render-pixi'
|
|
27
|
+
|
|
28
|
+
const measurer = createPixiTextMeasurer()
|
|
29
|
+
const layout = computeNodeLayout(node, xenTheme.tokens, measurer)
|
|
30
|
+
const view = renderNode(node, { layout, theme: xenTheme, /* ... */ })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What's exported
|
|
34
|
+
|
|
35
|
+
- `renderNode`, `renderRerouteNode`, `renderWidgets`, `renderEdge`, `drawEdge`, `renderComment`, `renderMacroFrame`
|
|
36
|
+
- Layout: `computeNodeLayout`, `measureNodeSize`, `computeEdgePath`, `sampleBezier`, `bezierMidpoint`
|
|
37
|
+
- Viewport: `Viewport`, `InteractionManager`, `screenToWorld`, `worldToScreen`, `zoomAt`, `clampZoom`, `snapToGrid`, `fitView`
|
|
38
|
+
- Themes: `xenTheme`, `XenolithTheme`, `ThemeRenderContext`, `PaletteStyle`
|
|
39
|
+
- Virtualization / LOD: `shouldVirtualize`, `visibleWorldRect`, `reconcileVisibleNodes`, `useLOD`, `lodLevel`, `cellsForRect`
|
|
40
|
+
- Icons: `IconRegistry`, `BUILTIN_ICONS`
|
|
41
|
+
- Helpers: `createPixiTextMeasurer`, `createGridSprite`, `hexToRgba`, `resolveCategoryAccent`, `resolveEdgeColor`
|
|
42
|
+
|
|
43
|
+
## Docs
|
|
44
|
+
|
|
45
|
+
- [Theme authoring guide](https://xenolithengine.github.io/xenolith-graph/guides/api/)
|
|
46
|
+
- [API reference](https://xenolithengine.github.io/xenolith-graph/guides/api/) — every method exposed by `XenolithEditor`
|
|
47
|
+
- [GitHub](https://github.com/XenolithEngine/xenolith-graph)
|
|
48
|
+
|
|
49
|
+
MIT © XenolithEngine
|
package/dist/bezier.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PinLayout } from './layout.js';
|
|
2
|
+
export interface Vec2 {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface EdgePath {
|
|
7
|
+
start: Vec2;
|
|
8
|
+
c1: Vec2;
|
|
9
|
+
c2: Vec2;
|
|
10
|
+
end: Vec2;
|
|
11
|
+
}
|
|
12
|
+
export interface EdgeTokens {
|
|
13
|
+
/** Fraction of horizontal distance used as the handle spread. 0..1. */
|
|
14
|
+
bezierTension: number;
|
|
15
|
+
/** Minimum handle spread in pixels, applied even when pins are very close horizontally. */
|
|
16
|
+
minHorizontalSpread: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function computeEdgePath(from: PinLayout, to: PinLayout, tokens: EdgeTokens): EdgePath;
|
|
19
|
+
/** Point on the cubic bezier at t=0.5 — the wire's visual midpoint, where the edge handle dot is
|
|
20
|
+
* drawn and right-click picking is anchored. */
|
|
21
|
+
export declare function bezierMidpoint(path: EdgePath): Vec2;
|
|
22
|
+
/** Unit tangent at the end of the curve — the direction the wire is travelling as it arrives at the
|
|
23
|
+
* target pin. Used to orient an arrowhead. Falls back to the start→end direction for a degenerate
|
|
24
|
+
* (zero-length) final handle segment. */
|
|
25
|
+
export declare function endTangent(path: EdgePath): Vec2;
|
|
26
|
+
/** Triangle for an arrowhead at the curve's end: `[tip, left, right]`. The tip sits on the end
|
|
27
|
+
* point; the base is `size` px back along the incoming tangent and `size` wide. */
|
|
28
|
+
export declare function arrowHead(path: EdgePath, size: number): [Vec2, Vec2, Vec2];
|
|
29
|
+
export declare function sampleBezier(path: EdgePath, steps: number): Vec2[];
|
|
30
|
+
//# sourceMappingURL=bezier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bezier.d.ts","sourceRoot":"","sources":["../src/bezier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,IAAI,CAAA;IACX,EAAE,EAAE,IAAI,CAAA;IACR,EAAE,EAAE,IAAI,CAAA;IACR,GAAG,EAAE,IAAI,CAAA;CACV;AAED,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAA;IACrB,2FAA2F;IAC3F,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,QAAQ,CAW5F;AAED;iDACiD;AACjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAKnD;AAED;;0CAE0C;AAC1C,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAU/C;AAED;oFACoF;AACpF,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAU1E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,CAoBlE"}
|
package/dist/bezier.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export function computeEdgePath(from, to, tokens) {
|
|
2
|
+
const dx = Math.abs(to.x - from.x);
|
|
3
|
+
const spread = Math.max(tokens.minHorizontalSpread, dx * tokens.bezierTension);
|
|
4
|
+
const fromSign = from.side === 'right' ? 1 : -1;
|
|
5
|
+
const toSign = to.side === 'right' ? 1 : -1;
|
|
6
|
+
return {
|
|
7
|
+
start: { x: from.x, y: from.y },
|
|
8
|
+
c1: { x: from.x + fromSign * spread, y: from.y },
|
|
9
|
+
c2: { x: to.x + toSign * spread, y: to.y },
|
|
10
|
+
end: { x: to.x, y: to.y },
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Point on the cubic bezier at t=0.5 — the wire's visual midpoint, where the edge handle dot is
|
|
14
|
+
* drawn and right-click picking is anchored. */
|
|
15
|
+
export function bezierMidpoint(path) {
|
|
16
|
+
return {
|
|
17
|
+
x: 0.125 * path.start.x + 0.375 * path.c1.x + 0.375 * path.c2.x + 0.125 * path.end.x,
|
|
18
|
+
y: 0.125 * path.start.y + 0.375 * path.c1.y + 0.375 * path.c2.y + 0.125 * path.end.y,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Unit tangent at the end of the curve — the direction the wire is travelling as it arrives at the
|
|
22
|
+
* target pin. Used to orient an arrowhead. Falls back to the start→end direction for a degenerate
|
|
23
|
+
* (zero-length) final handle segment. */
|
|
24
|
+
export function endTangent(path) {
|
|
25
|
+
let dx = path.end.x - path.c2.x;
|
|
26
|
+
let dy = path.end.y - path.c2.y;
|
|
27
|
+
let len = Math.hypot(dx, dy);
|
|
28
|
+
if (len < 1e-6) {
|
|
29
|
+
dx = path.end.x - path.start.x;
|
|
30
|
+
dy = path.end.y - path.start.y;
|
|
31
|
+
len = Math.hypot(dx, dy) || 1;
|
|
32
|
+
}
|
|
33
|
+
return { x: dx / len, y: dy / len };
|
|
34
|
+
}
|
|
35
|
+
/** Triangle for an arrowhead at the curve's end: `[tip, left, right]`. The tip sits on the end
|
|
36
|
+
* point; the base is `size` px back along the incoming tangent and `size` wide. */
|
|
37
|
+
export function arrowHead(path, size) {
|
|
38
|
+
const dir = endTangent(path);
|
|
39
|
+
const back = { x: path.end.x - dir.x * size, y: path.end.y - dir.y * size };
|
|
40
|
+
const perp = { x: dir.y, y: -dir.x };
|
|
41
|
+
const half = size * 0.5;
|
|
42
|
+
return [
|
|
43
|
+
{ x: path.end.x, y: path.end.y },
|
|
44
|
+
{ x: back.x + perp.x * half, y: back.y + perp.y * half },
|
|
45
|
+
{ x: back.x - perp.x * half, y: back.y - perp.y * half },
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
export function sampleBezier(path, steps) {
|
|
49
|
+
if (steps < 1)
|
|
50
|
+
throw new Error(`sampleBezier: steps must be >= 1, got ${steps}`);
|
|
51
|
+
const out = [];
|
|
52
|
+
for (let i = 0; i <= steps; i++) {
|
|
53
|
+
const t = i / steps;
|
|
54
|
+
const u = 1 - t;
|
|
55
|
+
const tt = t * t;
|
|
56
|
+
const uu = u * u;
|
|
57
|
+
const uuu = uu * u;
|
|
58
|
+
const ttt = tt * t;
|
|
59
|
+
const a = uuu;
|
|
60
|
+
const b = 3 * uu * t;
|
|
61
|
+
const c = 3 * u * tt;
|
|
62
|
+
const d = ttt;
|
|
63
|
+
out.push({
|
|
64
|
+
x: a * path.start.x + b * path.c1.x + c * path.c2.x + d * path.end.x,
|
|
65
|
+
y: a * path.start.y + b * path.c1.y + c * path.c2.y + d * path.end.y,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=bezier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bezier.js","sourceRoot":"","sources":["../src/bezier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Container } from 'pixi.js';
|
|
2
|
+
import type { XenTokens } from '@xenolithengine/graph-theme-xen';
|
|
3
|
+
import type { Comment } from '@xenolithengine/graph-core';
|
|
4
|
+
export type CommentVisualState = 'default' | 'hover' | 'selected';
|
|
5
|
+
export interface CommentView {
|
|
6
|
+
/** Body layer (translucent fill + border + resize grip). Hosted BELOW the edges so wires between
|
|
7
|
+
* the nodes inside the frame draw on top of the tint. */
|
|
8
|
+
readonly container: Container;
|
|
9
|
+
/** Header layer (gradient/tint + rim + title + drag strip). Hosted ABOVE the edges so the header
|
|
10
|
+
* bar always reads clearly over any wires crossing the top of the frame. */
|
|
11
|
+
readonly headerLayer: Container;
|
|
12
|
+
/** Header strip — interactive: drag to move, double-click to rename, right-click for the menu. */
|
|
13
|
+
readonly header: Container;
|
|
14
|
+
/** Bottom-right resize grip — interactive. */
|
|
15
|
+
readonly resizeHandle: Container;
|
|
16
|
+
readonly headerHeight: number;
|
|
17
|
+
update(comment: Comment): void;
|
|
18
|
+
setVisualState(state: CommentVisualState): void;
|
|
19
|
+
/** Hide the baked title while a DOM edit overlay is open over the header (so text doesn't double up). */
|
|
20
|
+
setEditing(editing: boolean): void;
|
|
21
|
+
/** LOD: when true, draw the frame as a plain filled rectangle (body + border only) — header
|
|
22
|
+
* gradient/rim and the title are dropped, since at a far zoom they're sub-pixel anyway. */
|
|
23
|
+
setSimplified(simplified: boolean): void;
|
|
24
|
+
/** Free both layers AND the FillGradient GPU textures (Graphics.destroy doesn't touch the
|
|
25
|
+
* gradients — they leak otherwise). Always use this instead of destroying the containers directly. */
|
|
26
|
+
destroy(): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Comment/group frame. Body is a translucent tinted rounded rect; the header is rendered like a node
|
|
30
|
+
* header — colour gradient + a soft white top highlight + a bright rim line — so it matches the Xen
|
|
31
|
+
* node language exactly. Sits below the nodes; body is non-interactive (clicks reach nodes inside),
|
|
32
|
+
* only the header strip and corner grip capture pointer events. Hover/selected brighten the border.
|
|
33
|
+
*/
|
|
34
|
+
export declare function renderComment(comment: Comment, tokens: XenTokens, headerStyle?: 'gradient' | 'tint'): CommentView;
|
|
35
|
+
//# sourceMappingURL=comment-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-renderer.d.ts","sourceRoot":"","sources":["../src/comment-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAA0B,MAAM,SAAS,CAAA;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAA;AAEjE,MAAM,WAAW,WAAW;IAC1B;8DAC0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B;iFAC6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAA;IAC/B,kGAAkG;IAClG,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAA;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,cAAc,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC/C,yGAAyG;IACzG,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAClC;gGAC4F;IAC5F,aAAa,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CAAA;IACxC;2GACuG;IACvG,OAAO,IAAI,IAAI,CAAA;CAChB;AAqBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,GAAE,UAAU,GAAG,MAAmB,GAAG,WAAW,CAuJ7H"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { BitmapText, Color, Container, Graphics, FillGradient } from 'pixi.js';
|
|
2
|
+
const DEFAULT_COLOR = '#8A38F5';
|
|
3
|
+
const HANDLE = 14;
|
|
4
|
+
const rgba = (color, a) => {
|
|
5
|
+
const c = new Color(color);
|
|
6
|
+
return `rgba(${Math.round(c.red * 255)}, ${Math.round(c.green * 255)}, ${Math.round(c.blue * 255)}, ${a})`;
|
|
7
|
+
};
|
|
8
|
+
// Same header silhouette helpers the node renderer uses, so a comment header reads 1:1 with a node.
|
|
9
|
+
function topRoundedRect(g, w, h, r) {
|
|
10
|
+
const radius = Math.max(0, Math.min(r, w / 2, h));
|
|
11
|
+
return g.moveTo(radius, 0).lineTo(w - radius, 0).arcTo(w, 0, w, radius, radius)
|
|
12
|
+
.lineTo(w, h).lineTo(0, h).lineTo(0, radius).arcTo(0, 0, radius, 0, radius).closePath();
|
|
13
|
+
}
|
|
14
|
+
function topRimPath(g, w, r) {
|
|
15
|
+
const radius = Math.max(0, Math.min(r, w / 2));
|
|
16
|
+
return g.moveTo(0, radius).arcTo(0, 0, radius, 0, radius).lineTo(w - radius, 0).arcTo(w, 0, w, radius, radius);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Comment/group frame. Body is a translucent tinted rounded rect; the header is rendered like a node
|
|
20
|
+
* header — colour gradient + a soft white top highlight + a bright rim line — so it matches the Xen
|
|
21
|
+
* node language exactly. Sits below the nodes; body is non-interactive (clicks reach nodes inside),
|
|
22
|
+
* only the header strip and corner grip capture pointer events. Hover/selected brighten the border.
|
|
23
|
+
*/
|
|
24
|
+
export function renderComment(comment, tokens, headerStyle = 'gradient') {
|
|
25
|
+
const geo = tokens.geometry.comment;
|
|
26
|
+
const typo = tokens.typography.comment;
|
|
27
|
+
const headerHeight = geo.headerHeight;
|
|
28
|
+
// Default to the node corner radius so a comment frame reads 1:1 with a node header in any theme
|
|
29
|
+
// (Xen 7 / Liquid Glass 14); a theme that sets comment.radius overrides this.
|
|
30
|
+
const radius = geo.radius ?? tokens.geometry.node.radius;
|
|
31
|
+
const container = new Container({ label: `comment:${comment.id}` });
|
|
32
|
+
const headerLayer = new Container({ label: `comment-header-layer:${comment.id}` });
|
|
33
|
+
const body = new Graphics();
|
|
34
|
+
body.eventMode = 'none';
|
|
35
|
+
const headerBase = new Graphics();
|
|
36
|
+
headerBase.eventMode = 'none';
|
|
37
|
+
const headerFillG = new Graphics();
|
|
38
|
+
headerFillG.eventMode = 'none';
|
|
39
|
+
const headerHighlight = new Graphics();
|
|
40
|
+
headerHighlight.eventMode = 'none';
|
|
41
|
+
const headerRim = new Graphics();
|
|
42
|
+
headerRim.eventMode = 'none';
|
|
43
|
+
const border = new Graphics();
|
|
44
|
+
border.eventMode = 'none';
|
|
45
|
+
const header = new Container({ label: 'comment-header' });
|
|
46
|
+
header.eventMode = 'static';
|
|
47
|
+
header.cursor = 'move';
|
|
48
|
+
const headerHit = new Graphics();
|
|
49
|
+
headerHit.eventMode = 'static';
|
|
50
|
+
header.addChild(headerHit);
|
|
51
|
+
const title = new BitmapText({
|
|
52
|
+
text: comment.text,
|
|
53
|
+
style: { fontFamily: tokens.typography.fontFamily, fontSize: typo.size, fontWeight: '700', fill: typo.color },
|
|
54
|
+
});
|
|
55
|
+
title.eventMode = 'none';
|
|
56
|
+
// Anchor the title at its vertical centre and place it at the header's mid-line, so it sits at the
|
|
57
|
+
// exact same centre the DOM edit input uses (line-box = header height) — no jump entering edit mode.
|
|
58
|
+
title.anchor.set(0, 0.5);
|
|
59
|
+
title.x = 10;
|
|
60
|
+
title.y = headerHeight / 2;
|
|
61
|
+
const resizeHandle = new Container({ label: 'comment-resize' });
|
|
62
|
+
resizeHandle.eventMode = 'static';
|
|
63
|
+
resizeHandle.cursor = 'nwse-resize';
|
|
64
|
+
const handleGfx = new Graphics();
|
|
65
|
+
handleGfx.eventMode = 'static';
|
|
66
|
+
resizeHandle.addChild(handleGfx);
|
|
67
|
+
// Body layer (under edges): fill + border + resize grip. Header layer (over edges): the header bar
|
|
68
|
+
// visuals + the interactive drag strip + the title — so the header reads over crossing wires.
|
|
69
|
+
container.addChild(body, border, resizeHandle);
|
|
70
|
+
headerLayer.addChild(headerBase, headerFillG, headerHighlight, headerRim, header, title);
|
|
71
|
+
let current = comment;
|
|
72
|
+
let state = 'default';
|
|
73
|
+
let editing = false;
|
|
74
|
+
let simplified = false;
|
|
75
|
+
// Truncate the title with an ellipsis when it overflows the header width — but show the full text
|
|
76
|
+
// while editing (the caret can run past the frame; the user sees everything they type).
|
|
77
|
+
const RIGHT_PAD = 10;
|
|
78
|
+
const fitTitle = (full, w) => {
|
|
79
|
+
title.text = full;
|
|
80
|
+
if (editing)
|
|
81
|
+
return;
|
|
82
|
+
const maxW = w - title.x - RIGHT_PAD;
|
|
83
|
+
if (title.width <= maxW)
|
|
84
|
+
return;
|
|
85
|
+
let s = full;
|
|
86
|
+
while (s.length > 1) {
|
|
87
|
+
s = s.slice(0, -1);
|
|
88
|
+
title.text = `${s}…`;
|
|
89
|
+
if (title.width <= maxW)
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
// Gradients are built once (not per draw) — `update` runs every frame during a resize drag, and a
|
|
94
|
+
// fresh FillGradient each time leaks a GPU texture per frame. highlight/rim are colour-independent;
|
|
95
|
+
// the header fill is rebuilt only when the comment colour actually changes.
|
|
96
|
+
const highlightGrad = new FillGradient({
|
|
97
|
+
type: 'linear', start: { x: 0, y: 0 }, end: { x: 0, y: 1 },
|
|
98
|
+
colorStops: [{ offset: 0, color: 'rgba(255,255,255,0.25)' }, { offset: 0.6, color: 'rgba(255,255,255,0)' }], textureSpace: 'local',
|
|
99
|
+
});
|
|
100
|
+
const rimGrad = new FillGradient({
|
|
101
|
+
type: 'linear', start: { x: 0, y: 0 }, end: { x: 0, y: 1 },
|
|
102
|
+
colorStops: [{ offset: 0, color: 'rgba(255,255,255,0.8)' }, { offset: 1, color: 'rgba(255,255,255,0)' }], textureSpace: 'local',
|
|
103
|
+
});
|
|
104
|
+
const mkHeaderFill = (color) => new FillGradient({
|
|
105
|
+
// Node header recipe is a HORIZONTAL accent fade (left→right), accent@0.6 → transparent.
|
|
106
|
+
type: 'linear', start: { x: 0, y: 0 }, end: { x: 1, y: 0 },
|
|
107
|
+
colorStops: [{ offset: 0, color: rgba(color, 0.6) }, { offset: 1, color: rgba(color, 0) }], textureSpace: 'local',
|
|
108
|
+
});
|
|
109
|
+
let headerFill = mkHeaderFill(comment.color ?? DEFAULT_COLOR);
|
|
110
|
+
let headerFillColor = comment.color ?? DEFAULT_COLOR;
|
|
111
|
+
const drawBorder = () => {
|
|
112
|
+
const color = current.color ?? DEFAULT_COLOR;
|
|
113
|
+
const w = current.size.x, h = current.size.y;
|
|
114
|
+
border.clear();
|
|
115
|
+
if (state === 'selected') {
|
|
116
|
+
border.roundRect(0, 0, w, h, radius).stroke({ color: 0xffffff, width: 2, alpha: 0.95 });
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
border.roundRect(0, 0, w, h, radius).stroke({ color, width: state === 'hover' ? 2 : 1.5, alpha: state === 'hover' ? 0.85 : 0.55 });
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const draw = (c) => {
|
|
123
|
+
current = c;
|
|
124
|
+
const color = c.color ?? DEFAULT_COLOR;
|
|
125
|
+
const w = c.size.x, h = c.size.y;
|
|
126
|
+
// Translucent tinted body — the grid shows through; nodes inside paint on top.
|
|
127
|
+
body.clear().roundRect(0, 0, w, h, radius).fill({ color: tokens.color.surface.node, alpha: 0.55 })
|
|
128
|
+
.roundRect(0, 0, w, h, radius).fill({ color, alpha: 0.08 });
|
|
129
|
+
headerBase.clear();
|
|
130
|
+
headerFillG.clear();
|
|
131
|
+
headerHighlight.clear();
|
|
132
|
+
headerRim.clear();
|
|
133
|
+
container.position.set(c.position.x, c.position.y);
|
|
134
|
+
headerLayer.position.set(c.position.x, c.position.y);
|
|
135
|
+
if (simplified) {
|
|
136
|
+
// LOD: plain block — a touch more body tint to read as a solid rectangle, no header decoration.
|
|
137
|
+
body.roundRect(0, 0, w, h, radius).fill({ color, alpha: 0.12 });
|
|
138
|
+
headerLayer.visible = false;
|
|
139
|
+
handleGfx.clear();
|
|
140
|
+
drawBorder();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
headerLayer.visible = true;
|
|
144
|
+
if (headerStyle === 'tint') {
|
|
145
|
+
// 1:1 with the Liquid Glass node header: an accent tint inset 2px from the body edges (so the
|
|
146
|
+
// glass rim shows the small top/side gap), radius one less than the body corner.
|
|
147
|
+
headerFillG.roundRect(2, 2, w - 4, headerHeight - 1, Math.max(0, radius - 1)).fill({ color, alpha: 0.45 });
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Xen node header recipe: dark base + horizontal accent fade + white highlight + top rim.
|
|
151
|
+
topRoundedRect(headerBase, w, headerHeight, radius).fill({ color: tokens.color.surface.node });
|
|
152
|
+
if (color !== headerFillColor) {
|
|
153
|
+
headerFill.destroy();
|
|
154
|
+
headerFill = mkHeaderFill(color);
|
|
155
|
+
headerFillColor = color;
|
|
156
|
+
}
|
|
157
|
+
topRoundedRect(headerFillG, w, headerHeight, radius).fill(headerFill);
|
|
158
|
+
topRoundedRect(headerHighlight, w, headerHeight, radius).fill(highlightGrad);
|
|
159
|
+
topRimPath(headerRim, w, radius).stroke({ width: 0.75, fill: rimGrad, alignment: 0 });
|
|
160
|
+
}
|
|
161
|
+
headerHit.clear().rect(0, 0, w, headerHeight).fill({ color: 0xffffff, alpha: 0.001 });
|
|
162
|
+
handleGfx.clear()
|
|
163
|
+
.moveTo(w - 3, h - HANDLE).lineTo(w - 3, h - 3).lineTo(w - HANDLE, h - 3).stroke({ color, width: 2, alpha: 0.7 })
|
|
164
|
+
.rect(w - HANDLE - 4, h - HANDLE - 4, HANDLE + 8, HANDLE + 8).fill({ color: 0xffffff, alpha: 0.001 });
|
|
165
|
+
fitTitle(c.text, w);
|
|
166
|
+
drawBorder();
|
|
167
|
+
};
|
|
168
|
+
draw(comment);
|
|
169
|
+
return {
|
|
170
|
+
container, headerLayer, header, resizeHandle, headerHeight,
|
|
171
|
+
update: draw,
|
|
172
|
+
setVisualState: (s) => { if (s !== state) {
|
|
173
|
+
state = s;
|
|
174
|
+
drawBorder();
|
|
175
|
+
} },
|
|
176
|
+
// While editing show the full (un-truncated) title; redraw to apply.
|
|
177
|
+
setEditing: (e) => { if (e !== editing) {
|
|
178
|
+
editing = e;
|
|
179
|
+
draw(current);
|
|
180
|
+
} },
|
|
181
|
+
setSimplified: (s) => { if (s !== simplified) {
|
|
182
|
+
simplified = s;
|
|
183
|
+
draw(current);
|
|
184
|
+
} },
|
|
185
|
+
destroy: () => {
|
|
186
|
+
highlightGrad.destroy();
|
|
187
|
+
rimGrad.destroy();
|
|
188
|
+
headerFill.destroy();
|
|
189
|
+
container.destroy({ children: true });
|
|
190
|
+
headerLayer.destroy({ children: true });
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=comment-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-renderer.js","sourceRoot":"","sources":["../src/comment-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PinLayout } from './layout.js';
|
|
2
|
+
import type { Vec2 } from './bezier.js';
|
|
3
|
+
export type EdgePathStyle = 'bezier' | 'step' | 'smoothstep' | 'linear';
|
|
4
|
+
/** Straight line — first sample is `from`, last is `to`. */
|
|
5
|
+
export declare function computeLinearPolyline(from: PinLayout, to: PinLayout): Vec2[];
|
|
6
|
+
/** Orthogonal Z/U — leave each pin in its `side` direction for `offset` px, then a single
|
|
7
|
+
* vertical run, then horizontal to the target. Mirrors React Flow / Rete `curveStep` for
|
|
8
|
+
* flowchart-style diagrams. For the common right→left flow (out → in) the two pulls overlap
|
|
9
|
+
* and degenerate to a clean Z; for same-side / reverse pins the extensions sit outside the
|
|
10
|
+
* pin bounds, producing a U that doesn't cross the node body. `offset` defaults to a chunk of
|
|
11
|
+
* horizontal distance so close pins still get a visible elbow. */
|
|
12
|
+
export declare function computeStepPolyline(from: PinLayout, to: PinLayout, offset?: number): Vec2[];
|
|
13
|
+
/** Rounded step — same elbows as `computeStepPolyline` but the 90° corners get a quarter-arc
|
|
14
|
+
* approximation via 5-point insets. Cheap, looks like a Visio/Excalidraw orthogonal connector. */
|
|
15
|
+
export declare function computeSmoothStepPolyline(from: PinLayout, to: PinLayout, radius?: number): Vec2[];
|
|
16
|
+
/** Walk a polyline and return the point at half its arc length. Used so the midpoint handle
|
|
17
|
+
* sits visually centred on the wire regardless of how skewed the segments are. */
|
|
18
|
+
export declare function polylineMidpoint(pts: Vec2[]): Vec2;
|
|
19
|
+
/** Unit tangent of the last segment — the direction the wire is travelling as it lands on the
|
|
20
|
+
* target pin. Used to orient the arrowhead on non-bezier styles. */
|
|
21
|
+
export declare function polylineEndTangent(pts: Vec2[]): Vec2;
|
|
22
|
+
/** Arrowhead triangle on a polyline (matches `arrowHead` shape for bezier paths). */
|
|
23
|
+
export declare function polylineArrowHead(pts: Vec2[], size: number): [Vec2, Vec2, Vec2];
|
|
24
|
+
//# sourceMappingURL=edge-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-paths.d.ts","sourceRoot":"","sources":["../src/edge-paths.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAA;AAEvE,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,GAAG,IAAI,EAAE,CAE5E;AAED;;;;;mEAKmE;AACnE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAgB3F;AAYD;mGACmG;AACnG,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,SAAK,GAAG,IAAI,EAAE,CAwC7F;AAED;mFACmF;AACnF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,CAiBlD;AAED;qEACqE;AACrE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,CAMpD;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAW/E"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Alternative edge-path generators for G9 — pluggable wire curves (Rete `connection-path-plugin`
|
|
2
|
+
// parity). The default `'bezier'` route stays in `bezier.ts` UNTOUCHED; this module owns the
|
|
3
|
+
// polyline-based styles (step / smoothstep / linear). The renderer picks a style per edge via
|
|
4
|
+
// `RenderEdgeOptions.pathStyle`; this keeps the hot path zero-risk for the 95% bezier case.
|
|
5
|
+
//
|
|
6
|
+
// All polyline generators return a `Vec2[]` of ≥2 points. The renderer feeds them to lineTo()
|
|
7
|
+
// (and to the midpoint / arrowhead helpers below). The first/last point ARE the pin centres.
|
|
8
|
+
/** Straight line — first sample is `from`, last is `to`. */
|
|
9
|
+
export function computeLinearPolyline(from, to) {
|
|
10
|
+
return [{ x: from.x, y: from.y }, { x: to.x, y: to.y }];
|
|
11
|
+
}
|
|
12
|
+
/** Orthogonal Z/U — leave each pin in its `side` direction for `offset` px, then a single
|
|
13
|
+
* vertical run, then horizontal to the target. Mirrors React Flow / Rete `curveStep` for
|
|
14
|
+
* flowchart-style diagrams. For the common right→left flow (out → in) the two pulls overlap
|
|
15
|
+
* and degenerate to a clean Z; for same-side / reverse pins the extensions sit outside the
|
|
16
|
+
* pin bounds, producing a U that doesn't cross the node body. `offset` defaults to a chunk of
|
|
17
|
+
* horizontal distance so close pins still get a visible elbow. */
|
|
18
|
+
export function computeStepPolyline(from, to, offset) {
|
|
19
|
+
const fromSign = from.side === 'right' ? 1 : -1;
|
|
20
|
+
const toSign = to.side === 'right' ? 1 : -1;
|
|
21
|
+
const off = Math.max(20, Math.abs((to.x - from.x) * 0.5));
|
|
22
|
+
const stepX = offset ?? off;
|
|
23
|
+
const ax = from.x + fromSign * stepX; // extension X off the source pin
|
|
24
|
+
const bx = to.x + toSign * stepX; // extension X off the target pin
|
|
25
|
+
const midX = (ax + bx) / 2; // where the vertical run lives
|
|
26
|
+
return dedupConsecutive([
|
|
27
|
+
{ x: from.x, y: from.y },
|
|
28
|
+
{ x: ax, y: from.y }, // extend OUT from source pin in its side dir
|
|
29
|
+
{ x: midX, y: from.y }, // ride source y until the meet x (collapses if ax == midX)
|
|
30
|
+
{ x: midX, y: to.y }, // vertical run
|
|
31
|
+
{ x: bx, y: to.y }, // ride target y until the extension x
|
|
32
|
+
{ x: to.x, y: to.y },
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
function dedupConsecutive(pts) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const p of pts) {
|
|
38
|
+
const last = out[out.length - 1];
|
|
39
|
+
if (last && last.x === p.x && last.y === p.y)
|
|
40
|
+
continue;
|
|
41
|
+
out.push(p);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** Rounded step — same elbows as `computeStepPolyline` but the 90° corners get a quarter-arc
|
|
46
|
+
* approximation via 5-point insets. Cheap, looks like a Visio/Excalidraw orthogonal connector. */
|
|
47
|
+
export function computeSmoothStepPolyline(from, to, radius = 12) {
|
|
48
|
+
const step = computeStepPolyline(from, to);
|
|
49
|
+
// computeStepPolyline returns 3–6 points after dedup: 3 when source/target are colinear (no
|
|
50
|
+
// elbow), 4 in the canonical Z, more when the two extensions overlap and form a U. Only the
|
|
51
|
+
// 4-point canonical shape has the two-elbow geometry this rounder is built for; anything else
|
|
52
|
+
// (no elbow, or a multi-corner U) falls back to the bare step shape — no rounding artifact,
|
|
53
|
+
// no thrown exception (which was the crash in the edge-paths demo when from.y === to.y).
|
|
54
|
+
if (step.length !== 4)
|
|
55
|
+
return step;
|
|
56
|
+
const [a, b, c, d] = step;
|
|
57
|
+
const dirAB = Math.sign(b.x - a.x); // ±1 along x
|
|
58
|
+
const dirCD = Math.sign(d.x - c.x);
|
|
59
|
+
const dirBC = Math.sign(c.y - b.y); // ±1 along y
|
|
60
|
+
const r = Math.min(radius, Math.max(0, Math.abs(b.x - a.x) - 1), Math.max(0, Math.abs(d.x - c.x) - 1), Math.max(0, Math.abs(c.y - b.y) - 1) / 2);
|
|
61
|
+
if (r <= 0)
|
|
62
|
+
return step;
|
|
63
|
+
// Approximate each 90° corner with 3 evenly-spaced points along its quarter circle.
|
|
64
|
+
const corner = (centerX, centerY, fromX, fromY, toX, toY) => {
|
|
65
|
+
// Quarter from (fromX,fromY) → (toX,toY). Build with a quadratic approx: 2 inner points.
|
|
66
|
+
return [
|
|
67
|
+
{ x: fromX, y: fromY },
|
|
68
|
+
{ x: centerX + (fromX - centerX) * 0.5, y: centerY + (fromY - centerY) * 0.95 },
|
|
69
|
+
{ x: centerX + (toX - centerX) * 0.95, y: centerY + (toY - centerY) * 0.5 },
|
|
70
|
+
{ x: toX, y: toY },
|
|
71
|
+
];
|
|
72
|
+
};
|
|
73
|
+
const c1 = corner(b.x, b.y, b.x - dirAB * r, b.y, b.x, b.y + dirBC * r);
|
|
74
|
+
const c2 = corner(c.x, c.y, c.x, c.y - dirBC * r, c.x + dirCD * r, c.y);
|
|
75
|
+
return [a, ...c1, ...c2, d];
|
|
76
|
+
}
|
|
77
|
+
/** Walk a polyline and return the point at half its arc length. Used so the midpoint handle
|
|
78
|
+
* sits visually centred on the wire regardless of how skewed the segments are. */
|
|
79
|
+
export function polylineMidpoint(pts) {
|
|
80
|
+
if (pts.length === 0)
|
|
81
|
+
return { x: 0, y: 0 };
|
|
82
|
+
if (pts.length === 1)
|
|
83
|
+
return { ...pts[0] };
|
|
84
|
+
let total = 0;
|
|
85
|
+
for (let i = 1; i < pts.length; i++)
|
|
86
|
+
total += Math.hypot(pts[i].x - pts[i - 1].x, pts[i].y - pts[i - 1].y);
|
|
87
|
+
const target = total / 2;
|
|
88
|
+
let walked = 0;
|
|
89
|
+
for (let i = 1; i < pts.length; i++) {
|
|
90
|
+
const a = pts[i - 1], b = pts[i];
|
|
91
|
+
const seg = Math.hypot(b.x - a.x, b.y - a.y);
|
|
92
|
+
if (walked + seg >= target) {
|
|
93
|
+
const t = seg === 0 ? 0 : (target - walked) / seg;
|
|
94
|
+
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
95
|
+
}
|
|
96
|
+
walked += seg;
|
|
97
|
+
}
|
|
98
|
+
return { ...pts[pts.length - 1] };
|
|
99
|
+
}
|
|
100
|
+
/** Unit tangent of the last segment — the direction the wire is travelling as it lands on the
|
|
101
|
+
* target pin. Used to orient the arrowhead on non-bezier styles. */
|
|
102
|
+
export function polylineEndTangent(pts) {
|
|
103
|
+
if (pts.length < 2)
|
|
104
|
+
return { x: 1, y: 0 };
|
|
105
|
+
const a = pts[pts.length - 2], b = pts[pts.length - 1];
|
|
106
|
+
const dx = b.x - a.x, dy = b.y - a.y;
|
|
107
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
108
|
+
return { x: dx / len, y: dy / len };
|
|
109
|
+
}
|
|
110
|
+
/** Arrowhead triangle on a polyline (matches `arrowHead` shape for bezier paths). */
|
|
111
|
+
export function polylineArrowHead(pts, size) {
|
|
112
|
+
const end = pts[pts.length - 1] ?? { x: 0, y: 0 };
|
|
113
|
+
const dir = polylineEndTangent(pts);
|
|
114
|
+
const back = { x: end.x - dir.x * size, y: end.y - dir.y * size };
|
|
115
|
+
const perp = { x: dir.y, y: -dir.x };
|
|
116
|
+
const half = size * 0.5;
|
|
117
|
+
return [
|
|
118
|
+
{ x: end.x, y: end.y },
|
|
119
|
+
{ x: back.x + perp.x * half, y: back.y + perp.y * half },
|
|
120
|
+
{ x: back.x - perp.x * half, y: back.y - perp.y * half },
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=edge-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-paths.js","sourceRoot":"","sources":["../src/edge-paths.ts"],"names":[],"mappings":"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"}
|