@oh-just-another/renderer-core 0.57.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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/animation-adapter.d.ts +91 -0
- package/dist/animation-adapter.d.ts.map +1 -0
- package/dist/animation-adapter.js +90 -0
- package/dist/animation-adapter.js.map +1 -0
- package/dist/built-in-renderers.d.ts +6 -0
- package/dist/built-in-renderers.d.ts.map +1 -0
- package/dist/built-in-renderers.js +517 -0
- package/dist/built-in-renderers.js.map +1 -0
- package/dist/constants.d.ts +97 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +115 -0
- package/dist/constants.js.map +1 -0
- package/dist/edge-cache-bitmap.d.ts +34 -0
- package/dist/edge-cache-bitmap.d.ts.map +1 -0
- package/dist/edge-cache-bitmap.js +42 -0
- package/dist/edge-cache-bitmap.js.map +1 -0
- package/dist/edge-cache.d.ts +32 -0
- package/dist/edge-cache.d.ts.map +1 -0
- package/dist/edge-cache.js +90 -0
- package/dist/edge-cache.js.map +1 -0
- package/dist/edge-renderer.d.ts +73 -0
- package/dist/edge-renderer.d.ts.map +1 -0
- package/dist/edge-renderer.js +554 -0
- package/dist/edge-renderer.js.map +1 -0
- package/dist/grid-renderer.d.ts +55 -0
- package/dist/grid-renderer.d.ts.map +1 -0
- package/dist/grid-renderer.js +173 -0
- package/dist/grid-renderer.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/js-rasterizer.d.ts +8 -0
- package/dist/js-rasterizer.d.ts.map +1 -0
- package/dist/js-rasterizer.js +86 -0
- package/dist/js-rasterizer.js.map +1 -0
- package/dist/layer-cache-composite.d.ts +39 -0
- package/dist/layer-cache-composite.d.ts.map +1 -0
- package/dist/layer-cache-composite.js +47 -0
- package/dist/layer-cache-composite.js.map +1 -0
- package/dist/layers.d.ts +14 -0
- package/dist/layers.d.ts.map +1 -0
- package/dist/layers.js +2 -0
- package/dist/layers.js.map +1 -0
- package/dist/rasterizer.d.ts +27 -0
- package/dist/rasterizer.d.ts.map +1 -0
- package/dist/rasterizer.js +10 -0
- package/dist/rasterizer.js.map +1 -0
- package/dist/render-target.d.ts +94 -0
- package/dist/render-target.d.ts.map +1 -0
- package/dist/render-target.js +2 -0
- package/dist/render-target.js.map +1 -0
- package/dist/scene-renderer.d.ts +126 -0
- package/dist/scene-renderer.d.ts.map +1 -0
- package/dist/scene-renderer.js +149 -0
- package/dist/scene-renderer.js.map +1 -0
- package/dist/shape-cache-bitmap.d.ts +42 -0
- package/dist/shape-cache-bitmap.d.ts.map +1 -0
- package/dist/shape-cache-bitmap.js +61 -0
- package/dist/shape-cache-bitmap.js.map +1 -0
- package/dist/shape-cache.d.ts +40 -0
- package/dist/shape-cache.d.ts.map +1 -0
- package/dist/shape-cache.js +67 -0
- package/dist/shape-cache.js.map +1 -0
- package/dist/shape-renderer.d.ts +36 -0
- package/dist/shape-renderer.d.ts.map +1 -0
- package/dist/shape-renderer.js +15 -0
- package/dist/shape-renderer.js.map +1 -0
- package/dist/text-editing.d.ts +81 -0
- package/dist/text-editing.d.ts.map +1 -0
- package/dist/text-editing.js +191 -0
- package/dist/text-editing.js.map +1 -0
- package/dist/text-layout.d.ts +44 -0
- package/dist/text-layout.d.ts.map +1 -0
- package/dist/text-layout.js +57 -0
- package/dist/text-layout.js.map +1 -0
- package/dist/text-shaper.d.ts +53 -0
- package/dist/text-shaper.d.ts.map +1 -0
- package/dist/text-shaper.js +19 -0
- package/dist/text-shaper.js.map +1 -0
- package/dist/tile-renderer.d.ts +126 -0
- package/dist/tile-renderer.d.ts.map +1 -0
- package/dist/tile-renderer.js +192 -0
- package/dist/tile-renderer.js.map +1 -0
- package/dist/worker-render.d.ts +54 -0
- package/dist/worker-render.d.ts.map +1 -0
- package/dist/worker-render.js +8 -0
- package/dist/worker-render.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { polygon as polygonMath } from "@oh-just-another/math";
|
|
2
|
+
import { getCornerRadius, registerRenderOverflow, FRAME_HEADER_HEIGHT, FRAME_HEADER_PADDING_X, FRAME_HEADER_FONT_SIZE, } from "@oh-just-another/scene";
|
|
3
|
+
import { registerElementRenderer } from "./shape-renderer.js";
|
|
4
|
+
import { layoutText } from "./text-editing.js";
|
|
5
|
+
import { resolveImageSource } from "./animation-adapter.js";
|
|
6
|
+
import { TEXT_DECORATION_THICKNESS, TEXT_UNDERLINE_OFFSET, TEXT_STRIKETHROUGH_OFFSET, } from "./constants.js";
|
|
7
|
+
const req = (v) => {
|
|
8
|
+
if (v === undefined)
|
|
9
|
+
throw new Error("packages/renderer-core: index out of range");
|
|
10
|
+
return v;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Applies common style fields to a target. Returns whether any fill or stroke
|
|
14
|
+
* was configured — shape renderers use the result to decide which paint call
|
|
15
|
+
* to issue.
|
|
16
|
+
*/
|
|
17
|
+
const applyStyle = (style, target) => {
|
|
18
|
+
const hasFill = style.fill !== undefined && style.fill !== "transparent";
|
|
19
|
+
const hasStroke = style.stroke !== undefined && style.stroke !== "transparent" && (style.strokeWidth ?? 1) > 0;
|
|
20
|
+
if (hasFill)
|
|
21
|
+
target.setFill(style.fill);
|
|
22
|
+
if (hasStroke) {
|
|
23
|
+
target.setStroke(style.stroke);
|
|
24
|
+
target.setStrokeWidth(style.strokeWidth ?? 1);
|
|
25
|
+
if (style.lineCap)
|
|
26
|
+
target.setLineCap(style.lineCap);
|
|
27
|
+
if (style.lineJoin)
|
|
28
|
+
target.setLineJoin(style.lineJoin);
|
|
29
|
+
if (style.dashArray)
|
|
30
|
+
target.setDashArray(style.dashArray);
|
|
31
|
+
}
|
|
32
|
+
if (style.opacity !== undefined)
|
|
33
|
+
target.setOpacity(style.opacity);
|
|
34
|
+
return { fill: hasFill, stroke: hasStroke };
|
|
35
|
+
};
|
|
36
|
+
const drawRectangle = (shape, target) => {
|
|
37
|
+
const { fill, stroke } = applyStyle(shape.style, target);
|
|
38
|
+
if (!fill && !stroke)
|
|
39
|
+
return;
|
|
40
|
+
const r = getCornerRadius(shape.style.roundness, shape.width, shape.height);
|
|
41
|
+
// Fill path — always uses the original shape geometry.
|
|
42
|
+
if (fill) {
|
|
43
|
+
target.beginPath();
|
|
44
|
+
if (r > 0) {
|
|
45
|
+
buildRoundedRectPath(target, 0, 0, shape.width, shape.height, r);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
target.rect(0, 0, shape.width, shape.height);
|
|
49
|
+
}
|
|
50
|
+
target.fill();
|
|
51
|
+
}
|
|
52
|
+
// Stroke path — offset by `strokeAlign` so the stroke sits inside
|
|
53
|
+
// / centred-on / outside the fill region. The default (omitted /
|
|
54
|
+
// `center`) reuses the fill geometry. Implemented at this layer so
|
|
55
|
+
// every backend (Canvas2D, WebGL2, SVG) honours strokeAlign without
|
|
56
|
+
// backend-specific work — the math is purely on the rect bounds.
|
|
57
|
+
if (stroke) {
|
|
58
|
+
const offset = strokeAlignOffset(shape.style);
|
|
59
|
+
const sx = offset;
|
|
60
|
+
const sy = offset;
|
|
61
|
+
const sw = shape.width - 2 * offset;
|
|
62
|
+
const sh = shape.height - 2 * offset;
|
|
63
|
+
if (sw <= 0 || sh <= 0)
|
|
64
|
+
return; // degenerate offset — skip
|
|
65
|
+
const sr = r > 0 ? Math.max(0, r - offset) : 0;
|
|
66
|
+
target.beginPath();
|
|
67
|
+
if (sr > 0) {
|
|
68
|
+
buildRoundedRectPath(target, sx, sy, sw, sh, sr);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
target.rect(sx, sy, sw, sh);
|
|
72
|
+
}
|
|
73
|
+
target.stroke();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Translate `Style.strokeAlign` into a path-offset distance in world
|
|
78
|
+
* units. The rendered stroke geometry shifts by `±half-width` along
|
|
79
|
+
* the inward / outward normal:
|
|
80
|
+
* center → 0 (path centred — Canvas2D / SVG default).
|
|
81
|
+
* inside → +half-width (path moves inward so the stroke's outer
|
|
82
|
+
* edge sits on the original fill boundary).
|
|
83
|
+
* outside → -half-width (path moves outward so the stroke's inner
|
|
84
|
+
* edge sits on the boundary).
|
|
85
|
+
*
|
|
86
|
+
* Only used by axis-aligned primitives (rectangle, container) where
|
|
87
|
+
* "inward" reduces to "subtract from bbox".
|
|
88
|
+
*/
|
|
89
|
+
const strokeAlignOffset = (style) => {
|
|
90
|
+
const align = style.strokeAlign ?? "center";
|
|
91
|
+
if (align === "center")
|
|
92
|
+
return 0;
|
|
93
|
+
const half = (style.strokeWidth ?? 1) / 2;
|
|
94
|
+
return align === "inside" ? half : -half;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Build a rounded-rect path via the standard "4 corners with
|
|
98
|
+
* quadratic Bezier arcs" pattern — same shape every backend
|
|
99
|
+
* understands without a special `roundRect()` API:
|
|
100
|
+
*
|
|
101
|
+
* ┌───arc───┐
|
|
102
|
+
* │ │
|
|
103
|
+
* arc arc
|
|
104
|
+
* │ │
|
|
105
|
+
* └───arc───┘
|
|
106
|
+
*
|
|
107
|
+
* Quadratic control points sit at each corner of the rect; the
|
|
108
|
+
* curve goes from `r` units along one side to `r` units along the
|
|
109
|
+
* adjacent side. WebGL2Target's zoom-aware flattener turns this
|
|
110
|
+
* into enough chord segments to stay sub-pixel smooth at any zoom.
|
|
111
|
+
*
|
|
112
|
+
* Radius `r` is pre-clamped by `getCornerRadius` to half the
|
|
113
|
+
* smaller side, so no overlap-handling is needed here.
|
|
114
|
+
*/
|
|
115
|
+
const buildRoundedRectPath = (target, x, y, w, h, r) => {
|
|
116
|
+
target.moveTo(x + r, y);
|
|
117
|
+
target.lineTo(x + w - r, y);
|
|
118
|
+
target.quadraticCurveTo(x + w, y, x + w, y + r);
|
|
119
|
+
target.lineTo(x + w, y + h - r);
|
|
120
|
+
target.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
|
|
121
|
+
target.lineTo(x + r, y + h);
|
|
122
|
+
target.quadraticCurveTo(x, y + h, x, y + h - r);
|
|
123
|
+
target.lineTo(x, y + r);
|
|
124
|
+
target.quadraticCurveTo(x, y, x + r, y);
|
|
125
|
+
target.closePath();
|
|
126
|
+
};
|
|
127
|
+
const drawEllipse = (shape, target) => {
|
|
128
|
+
const { fill, stroke } = applyStyle(shape.style, target);
|
|
129
|
+
if (!fill && !stroke)
|
|
130
|
+
return;
|
|
131
|
+
const rx = shape.width / 2;
|
|
132
|
+
const ry = shape.height / 2;
|
|
133
|
+
if (fill) {
|
|
134
|
+
target.beginPath();
|
|
135
|
+
target.ellipse(rx, ry, rx, ry);
|
|
136
|
+
target.fill();
|
|
137
|
+
}
|
|
138
|
+
if (stroke) {
|
|
139
|
+
// Inset / outset radii by `strokeAlignOffset` so the stroke
|
|
140
|
+
// sits inside / centred-on / outside the fill ellipse. Centre
|
|
141
|
+
// stays the same; radii shift uniformly. Degenerate (radius ≤ 0)
|
|
142
|
+
// skips the pass.
|
|
143
|
+
const offset = strokeAlignOffset(shape.style);
|
|
144
|
+
const srx = rx - offset;
|
|
145
|
+
const sry = ry - offset;
|
|
146
|
+
if (srx <= 0 || sry <= 0)
|
|
147
|
+
return;
|
|
148
|
+
target.beginPath();
|
|
149
|
+
target.ellipse(rx, ry, srx, sry);
|
|
150
|
+
target.stroke();
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const drawPolygon = (shape, target) => {
|
|
154
|
+
if (shape.points.length < 2)
|
|
155
|
+
return;
|
|
156
|
+
const { fill, stroke } = applyStyle(shape.style, target);
|
|
157
|
+
if (!fill && !stroke)
|
|
158
|
+
return;
|
|
159
|
+
if (fill) {
|
|
160
|
+
target.beginPath();
|
|
161
|
+
polygonPath(target, shape.points);
|
|
162
|
+
target.fill();
|
|
163
|
+
}
|
|
164
|
+
if (stroke) {
|
|
165
|
+
const offset = strokeAlignOffset(shape.style);
|
|
166
|
+
const pts = offset !== 0 ? polygonMath.offsetClosedPath(shape.points, offset) : shape.points;
|
|
167
|
+
target.beginPath();
|
|
168
|
+
polygonPath(target, pts);
|
|
169
|
+
target.stroke();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
/** Emit a closed polygon outline as `moveTo` + `lineTo`s + `closePath`. */
|
|
173
|
+
const polygonPath = (target, pts) => {
|
|
174
|
+
const first = pts[0];
|
|
175
|
+
if (first === undefined)
|
|
176
|
+
return;
|
|
177
|
+
target.moveTo(first.x, first.y);
|
|
178
|
+
for (let i = 1; i < pts.length; i++) {
|
|
179
|
+
const p = pts[i];
|
|
180
|
+
if (p === undefined)
|
|
181
|
+
continue;
|
|
182
|
+
target.lineTo(p.x, p.y);
|
|
183
|
+
}
|
|
184
|
+
target.closePath();
|
|
185
|
+
};
|
|
186
|
+
const drawPath = (shape, target) => {
|
|
187
|
+
if (shape.commands.length === 0)
|
|
188
|
+
return;
|
|
189
|
+
const { fill, stroke } = applyStyle(shape.style, target);
|
|
190
|
+
if (!fill && !stroke)
|
|
191
|
+
return;
|
|
192
|
+
target.beginPath();
|
|
193
|
+
for (const cmd of shape.commands) {
|
|
194
|
+
switch (cmd.kind) {
|
|
195
|
+
case "M":
|
|
196
|
+
target.moveTo(cmd.to.x, cmd.to.y);
|
|
197
|
+
break;
|
|
198
|
+
case "L":
|
|
199
|
+
target.lineTo(cmd.to.x, cmd.to.y);
|
|
200
|
+
break;
|
|
201
|
+
case "Q":
|
|
202
|
+
target.quadraticCurveTo(cmd.control.x, cmd.control.y, cmd.to.x, cmd.to.y);
|
|
203
|
+
break;
|
|
204
|
+
case "C":
|
|
205
|
+
target.bezierCurveTo(cmd.control1.x, cmd.control1.y, cmd.control2.x, cmd.control2.y, cmd.to.x, cmd.to.y);
|
|
206
|
+
break;
|
|
207
|
+
case "Z":
|
|
208
|
+
target.closePath();
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (fill)
|
|
213
|
+
target.fill();
|
|
214
|
+
if (stroke)
|
|
215
|
+
target.stroke();
|
|
216
|
+
};
|
|
217
|
+
const drawText = (shape, target) => {
|
|
218
|
+
const align = shape.style.textAlign ?? "left";
|
|
219
|
+
const weight = shape.style.fontWeight;
|
|
220
|
+
const fontStyle = shape.style.fontStyle;
|
|
221
|
+
target.setFont(shape.fontFamily, shape.fontSize, {
|
|
222
|
+
...(weight ? { weight } : {}),
|
|
223
|
+
...(fontStyle ? { style: fontStyle } : {}),
|
|
224
|
+
});
|
|
225
|
+
// Lines are positioned manually (per-line x below) so the caret
|
|
226
|
+
// geometry computed from the same `layoutText` lines up exactly, so
|
|
227
|
+
// the target always draws left-anchored.
|
|
228
|
+
target.setTextAlign("left");
|
|
229
|
+
target.setTextBaseline(shape.style.textBaseline ?? "top");
|
|
230
|
+
// Color: use fill if specified, otherwise default to black.
|
|
231
|
+
const color = shape.style.fill ?? "#000";
|
|
232
|
+
target.setFill(color);
|
|
233
|
+
if (shape.style.opacity !== undefined)
|
|
234
|
+
target.setOpacity(shape.style.opacity);
|
|
235
|
+
// Resolve per-line geometry once (x = align offset, top = i ×
|
|
236
|
+
// lineHeight). Single-line text skips the wrap engine.
|
|
237
|
+
const fontSize = shape.fontSize;
|
|
238
|
+
let lines;
|
|
239
|
+
if (shape.maxWidth === undefined && !shape.text.includes("\n")) {
|
|
240
|
+
lines = [{ text: shape.text, x: 0, width: target.measureText(shape.text).width, top: 0 }];
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// Measure with the target's own `measureText` so wrapping matches
|
|
244
|
+
// exactly what this backend draws (WebGL2 reports MSDF advances; the
|
|
245
|
+
// selection-box bounder + caret use the same source).
|
|
246
|
+
const measure = (s) => target.measureText(s).width;
|
|
247
|
+
const layout = layoutText(shape.text, measure, {
|
|
248
|
+
fontSize,
|
|
249
|
+
...(shape.maxWidth !== undefined ? { maxWidth: shape.maxWidth } : {}),
|
|
250
|
+
});
|
|
251
|
+
lines = layout.lines.map((line, i) => ({
|
|
252
|
+
text: line.text,
|
|
253
|
+
x: align === "center"
|
|
254
|
+
? layout.blockWidth / 2 - line.width / 2
|
|
255
|
+
: align === "right"
|
|
256
|
+
? layout.blockWidth - line.width
|
|
257
|
+
: 0,
|
|
258
|
+
width: line.width,
|
|
259
|
+
top: i * layout.lineHeight,
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
262
|
+
for (const l of lines)
|
|
263
|
+
target.fillText(l.text, l.x, l.top);
|
|
264
|
+
// Underline / strikethrough — thin filled rects per line, same on
|
|
265
|
+
// Canvas2D and WebGL2 (uses the current text fill colour).
|
|
266
|
+
const deco = shape.style.textDecoration;
|
|
267
|
+
if (deco?.underline || deco?.strikethrough) {
|
|
268
|
+
const thickness = Math.max(1, fontSize * TEXT_DECORATION_THICKNESS);
|
|
269
|
+
for (const l of lines) {
|
|
270
|
+
if (l.width <= 0)
|
|
271
|
+
continue;
|
|
272
|
+
if (deco.underline) {
|
|
273
|
+
target.beginPath();
|
|
274
|
+
target.rect(l.x, l.top + fontSize * TEXT_UNDERLINE_OFFSET, l.width, thickness);
|
|
275
|
+
target.fill();
|
|
276
|
+
}
|
|
277
|
+
if (deco.strikethrough) {
|
|
278
|
+
target.beginPath();
|
|
279
|
+
target.rect(l.x, l.top + fontSize * TEXT_STRIKETHROUGH_OFFSET - thickness / 2, l.width, thickness);
|
|
280
|
+
target.fill();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Variable-width brush stroke. Each segment between two `BrushPoint`s
|
|
287
|
+
* is drawn as a quad (two triangles) — its width interpolates from
|
|
288
|
+
* `p.width` at the head to `q.width` at the tail. Renders
|
|
289
|
+
* pressure-sensitive ink that gets thicker / thinner along the path
|
|
290
|
+
* without needing per-segment `setStrokeWidth` calls (which most 2D
|
|
291
|
+
* APIs treat as a single line width).
|
|
292
|
+
*/
|
|
293
|
+
const drawBrush = (shape, target) => {
|
|
294
|
+
const pts = shape.points;
|
|
295
|
+
if (pts.length === 0)
|
|
296
|
+
return;
|
|
297
|
+
const fill = shape.style.fill ?? shape.style.stroke ?? "#000";
|
|
298
|
+
target.setFill(fill);
|
|
299
|
+
target.setStroke(null);
|
|
300
|
+
// Single dot for one-point strokes — degenerate quad would be invisible.
|
|
301
|
+
if (pts.length === 1) {
|
|
302
|
+
const p = req(pts[0]);
|
|
303
|
+
target.beginPath();
|
|
304
|
+
target.ellipse(p.x, p.y, p.width, p.width);
|
|
305
|
+
target.fill();
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
309
|
+
const a = req(pts[i]);
|
|
310
|
+
const b = req(pts[i + 1]);
|
|
311
|
+
const dx = b.x - a.x;
|
|
312
|
+
const dy = b.y - a.y;
|
|
313
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
314
|
+
const nx = -dy / len;
|
|
315
|
+
const ny = dx / len;
|
|
316
|
+
target.beginPath();
|
|
317
|
+
target.moveTo(a.x + nx * a.width, a.y + ny * a.width);
|
|
318
|
+
target.lineTo(b.x + nx * b.width, b.y + ny * b.width);
|
|
319
|
+
target.lineTo(b.x - nx * b.width, b.y - ny * b.width);
|
|
320
|
+
target.lineTo(a.x - nx * a.width, a.y - ny * a.width);
|
|
321
|
+
target.closePath();
|
|
322
|
+
target.fill();
|
|
323
|
+
// End-cap as a disk at the joint — smooths the kink between segments.
|
|
324
|
+
target.beginPath();
|
|
325
|
+
target.ellipse(b.x, b.y, b.width, b.width);
|
|
326
|
+
target.fill();
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const drawImage = (shape, target) => {
|
|
330
|
+
// Priority: preloaded handle in metadata.image → animation-adapter
|
|
331
|
+
// frame (when `animationKind` is set and a matching adapter is
|
|
332
|
+
// registered) → static `src` fallback.
|
|
333
|
+
// For an animated source (GIF) prefer the per-frame image the
|
|
334
|
+
// registered adapter returns over `metadata.image` (a static
|
|
335
|
+
// first-frame `<img>`). `resolveImageSource` consults the adapter
|
|
336
|
+
// with `performance.now()`; it returns `null` while the async
|
|
337
|
+
// decode is still in flight — the backend's drawImage guard skips
|
|
338
|
+
// a null handle and the next AnimationTick frame picks it up.
|
|
339
|
+
const handle = shape.animationKind
|
|
340
|
+
? resolveImageSource(shape)
|
|
341
|
+
: (shape.metadata?.image ?? resolveImageSource(shape));
|
|
342
|
+
// `dynamic` → backends that cache the upload (WebGL2) re-upload the
|
|
343
|
+
// current frame. GIF / video sources flag `metadata.animated`, and
|
|
344
|
+
// any adapter-driven source is dynamic by definition.
|
|
345
|
+
const dynamic = shape.metadata?.animated === true || shape.animationKind !== undefined;
|
|
346
|
+
target.drawImage(handle, 0, 0, shape.width, shape.height, dynamic);
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* Registers renderers for every `BuiltinElement` type. Called by side-effect
|
|
350
|
+
* import of `@oh-just-another/renderer-canvas/setup` (see index).
|
|
351
|
+
*/
|
|
352
|
+
export const installBuiltinRenderers = () => {
|
|
353
|
+
registerElementRenderer("rectangle", drawRectangle);
|
|
354
|
+
registerElementRenderer("ellipse", drawEllipse);
|
|
355
|
+
registerElementRenderer("polygon", drawPolygon);
|
|
356
|
+
registerElementRenderer("path", drawPath);
|
|
357
|
+
registerElementRenderer("text", drawText);
|
|
358
|
+
registerElementRenderer("image", drawImage);
|
|
359
|
+
// Group shapes are invisible containers — the editor's overlay draws
|
|
360
|
+
// a halo for selected groups, but the shape itself paints nothing.
|
|
361
|
+
registerElementRenderer("group", () => {
|
|
362
|
+
/* intentional no-op: group shapes are invisible containers and paint nothing */
|
|
363
|
+
});
|
|
364
|
+
registerElementRenderer("frame", drawFrame);
|
|
365
|
+
// The frame paints its header strip ABOVE the rectangle, so its dirty
|
|
366
|
+
// region must extend up by the header height — otherwise deleting a
|
|
367
|
+
// frame leaves the header behind.
|
|
368
|
+
registerRenderOverflow("frame", () => ({ top: FRAME_HEADER_HEIGHT }));
|
|
369
|
+
registerElementRenderer("block-arrow", drawBlockArrow);
|
|
370
|
+
registerElementRenderer("brush", drawBrush);
|
|
371
|
+
};
|
|
372
|
+
/**
|
|
373
|
+
* Block-arrow silhouette: a rectangle body whose tip is replaced
|
|
374
|
+
* by a triangle, oriented by `direction`. Path is closed and filled
|
|
375
|
+
* with `style.fill`; stroke applies to the outline.
|
|
376
|
+
*
|
|
377
|
+
* right → ┌────┐▶
|
|
378
|
+
* │ body │
|
|
379
|
+
* └────┘
|
|
380
|
+
*
|
|
381
|
+
* up ↑ ▲
|
|
382
|
+
* ┌──┐
|
|
383
|
+
* │ │
|
|
384
|
+
* └──┘
|
|
385
|
+
*/
|
|
386
|
+
const drawBlockArrow = (shape, target) => {
|
|
387
|
+
const { fill, stroke } = applyStyle(shape.style, target);
|
|
388
|
+
const direction = shape.direction ?? "right";
|
|
389
|
+
const headRatio = Math.max(0.1, Math.min(0.9, shape.headRatio ?? 0.4));
|
|
390
|
+
const bodyT = Math.max(0.1, Math.min(0.9, shape.bodyThickness ?? 0.5));
|
|
391
|
+
const w = shape.width;
|
|
392
|
+
const h = shape.height;
|
|
393
|
+
// Compute the local path for a `right`-pointing arrow inside
|
|
394
|
+
// [0, w] × [0, h], then rotate the resulting points if the
|
|
395
|
+
// direction is different. Keeps the drawing primitives in one
|
|
396
|
+
// place.
|
|
397
|
+
const headW = w * headRatio;
|
|
398
|
+
const bodyW = w - headW;
|
|
399
|
+
const bodyHalfH = (h * bodyT) / 2;
|
|
400
|
+
const cy = h / 2;
|
|
401
|
+
let points = [
|
|
402
|
+
[0, cy - bodyHalfH],
|
|
403
|
+
[bodyW, cy - bodyHalfH],
|
|
404
|
+
[bodyW, 0],
|
|
405
|
+
[w, cy],
|
|
406
|
+
[bodyW, h],
|
|
407
|
+
[bodyW, cy + bodyHalfH],
|
|
408
|
+
[0, cy + bodyHalfH],
|
|
409
|
+
];
|
|
410
|
+
if (direction !== "right") {
|
|
411
|
+
points = points.map(([x, y]) => rotateLocal([x, y], direction, w, h));
|
|
412
|
+
}
|
|
413
|
+
const ptObjs = points.map(([x, y]) => ({ x, y }));
|
|
414
|
+
if (fill) {
|
|
415
|
+
target.beginPath();
|
|
416
|
+
polygonPath(target, ptObjs);
|
|
417
|
+
target.fill();
|
|
418
|
+
}
|
|
419
|
+
if (stroke) {
|
|
420
|
+
const offset = strokeAlignOffset(shape.style);
|
|
421
|
+
const sPts = offset !== 0 ? polygonMath.offsetClosedPath(ptObjs, offset) : ptObjs;
|
|
422
|
+
target.beginPath();
|
|
423
|
+
polygonPath(target, sPts);
|
|
424
|
+
target.stroke();
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const rotateLocal = ([x, y], direction, w, h) => {
|
|
428
|
+
switch (direction) {
|
|
429
|
+
case "left":
|
|
430
|
+
return [w - x, y];
|
|
431
|
+
case "up":
|
|
432
|
+
// Rotate 90° CCW around the box centre, then translate so the
|
|
433
|
+
// result still fits inside [0, w] × [0, h].
|
|
434
|
+
return [y * (w / h), h - x * (h / w)];
|
|
435
|
+
case "down":
|
|
436
|
+
return [(h - y) * (w / h), x * (h / w)];
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Frame: dashed outline + header strip with the frame's name.
|
|
441
|
+
* Hit-testing intentionally passes through the body (handled
|
|
442
|
+
* editor-side) so clicks on children inside the frame still land on
|
|
443
|
+
* the child, not the frame chrome.
|
|
444
|
+
*/
|
|
445
|
+
const FRAME_STROKE = "#888";
|
|
446
|
+
const FRAME_FILL = "#ffffff";
|
|
447
|
+
const FRAME_HEADER_ELLIPSIS = "…";
|
|
448
|
+
/**
|
|
449
|
+
* Trim `text` with a trailing ellipsis until it fits `maxWidth` (in the
|
|
450
|
+
* font already set on `target`). Returns the full text when it fits, the
|
|
451
|
+
* longest prefix + "…" otherwise, or just "…" when even one char can't
|
|
452
|
+
* fit. Binary-searches the prefix length to keep `measureText` calls ~log.
|
|
453
|
+
*/
|
|
454
|
+
const ellipsizeToWidth = (text, maxWidth, target) => {
|
|
455
|
+
if (maxWidth <= 0)
|
|
456
|
+
return "";
|
|
457
|
+
if (target.measureText(text).width <= maxWidth)
|
|
458
|
+
return text;
|
|
459
|
+
let lo = 0;
|
|
460
|
+
let hi = text.length;
|
|
461
|
+
while (lo < hi) {
|
|
462
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
463
|
+
const w = target.measureText(text.slice(0, mid) + FRAME_HEADER_ELLIPSIS).width;
|
|
464
|
+
if (w <= maxWidth)
|
|
465
|
+
lo = mid;
|
|
466
|
+
else
|
|
467
|
+
hi = mid - 1;
|
|
468
|
+
}
|
|
469
|
+
return lo > 0 ? text.slice(0, lo) + FRAME_HEADER_ELLIPSIS : FRAME_HEADER_ELLIPSIS;
|
|
470
|
+
};
|
|
471
|
+
const drawFrame = (shape, target, ctx) => {
|
|
472
|
+
// Body — solid fill + thin solid outline. Frames sit at the bottom
|
|
473
|
+
// z-order, so the fill backs their members without covering them.
|
|
474
|
+
// Honours an explicit `style.fill`, else default white.
|
|
475
|
+
target.setFill(shape.style.fill ?? FRAME_FILL);
|
|
476
|
+
target.setStroke(null);
|
|
477
|
+
target.setDashArray(null);
|
|
478
|
+
target.beginPath();
|
|
479
|
+
target.rect(0, 0, shape.width, shape.height);
|
|
480
|
+
target.fill();
|
|
481
|
+
// Outline on top of the fill — a 1px SCREEN-constant hairline (doesn't scale
|
|
482
|
+
// with zoom). The renderer draws in local coords where 1 unit = zoom × scale
|
|
483
|
+
// device px, so divide to keep the stroke at one device pixel. Falls back to
|
|
484
|
+
// 1 world-px when no zoom context is supplied (preview / export at 1:1).
|
|
485
|
+
const screenScale = (ctx?.zoom ?? 1) * (shape.scale.x || 1);
|
|
486
|
+
target.setFill(null);
|
|
487
|
+
target.setStroke(FRAME_STROKE);
|
|
488
|
+
target.setStrokeWidth(1 / (screenScale || 1));
|
|
489
|
+
target.setDashArray(null);
|
|
490
|
+
target.beginPath();
|
|
491
|
+
target.rect(0, 0, shape.width, shape.height);
|
|
492
|
+
target.stroke();
|
|
493
|
+
// Header label: the strip hugs the text width but never exceeds the
|
|
494
|
+
// frame's right edge; a name too long for the frame is ellipsised.
|
|
495
|
+
const name = shape.name ?? "Frame";
|
|
496
|
+
target.setFont("system-ui, sans-serif", FRAME_HEADER_FONT_SIZE);
|
|
497
|
+
const avail = shape.width - FRAME_HEADER_PADDING_X * 2;
|
|
498
|
+
const fits = target.measureText(name).width <= avail;
|
|
499
|
+
// Fits → the strip hugs the text. Too long → ellipsise the text and
|
|
500
|
+
// stretch the strip to the frame's full width (the label runs to the
|
|
501
|
+
// right edge).
|
|
502
|
+
const label = fits ? name : ellipsizeToWidth(name, avail, target);
|
|
503
|
+
const headerWidth = fits
|
|
504
|
+
? Math.min(target.measureText(name).width + FRAME_HEADER_PADDING_X * 2, shape.width)
|
|
505
|
+
: shape.width;
|
|
506
|
+
// Header label background — stretches to fit the (possibly truncated) text.
|
|
507
|
+
target.setFill("#222");
|
|
508
|
+
target.beginPath();
|
|
509
|
+
target.rect(0, -FRAME_HEADER_HEIGHT, headerWidth, FRAME_HEADER_HEIGHT);
|
|
510
|
+
target.fill();
|
|
511
|
+
// Header label text.
|
|
512
|
+
target.setFill("#ddd");
|
|
513
|
+
target.setTextBaseline("middle");
|
|
514
|
+
target.setTextAlign("left");
|
|
515
|
+
target.fillText(label, FRAME_HEADER_PADDING_X, -FRAME_HEADER_HEIGHT / 2);
|
|
516
|
+
};
|
|
517
|
+
//# sourceMappingURL=built-in-renderers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in-renderers.js","sourceRoot":"","sources":["../src/built-in-renderers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunable constants for the renderer core. All "magic numbers" used by
|
|
3
|
+
* `renderScene` / `renderLinks` / `renderGrid` live here so there is one
|
|
4
|
+
* place to tweak performance / visual behaviour.
|
|
5
|
+
*/
|
|
6
|
+
import type { LodOptions } from "./scene-renderer.js";
|
|
7
|
+
/**
|
|
8
|
+
* Default zoom thresholds for the level-of-detail pipeline. Tuned for
|
|
9
|
+
* a typical 1920×1080 viewport viewing a 10k-shape scene.
|
|
10
|
+
*
|
|
11
|
+
* - `placeholder: 0.15` — below 15% zoom (one screen ≈ 6.7× world),
|
|
12
|
+
* shapes degrade to flat AABB fills. Saves ~10× renderer cost per
|
|
13
|
+
* shape.
|
|
14
|
+
* - `hideText: 0.4` — below 40% zoom text glyphs are too small to read
|
|
15
|
+
* anyway; skipping the `wrapText` + `measureText` calls saves the
|
|
16
|
+
* bulk of text rendering cost.
|
|
17
|
+
*
|
|
18
|
+
* Hosts override per-render by passing `RenderSceneOptions.lod`.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DEFAULT_LOD: LodOptions;
|
|
21
|
+
/**
|
|
22
|
+
* Grey colour used for placeholder fills when LOD switches to the
|
|
23
|
+
* cheapest path. A mid-tone neutral that blends with most scene
|
|
24
|
+
* palettes; override via `RenderSceneOptions.placeholderFill`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_PLACEHOLDER_FILL = "#bbb";
|
|
27
|
+
/**
|
|
28
|
+
* Viewport-rect inflation factor applied by hosts when computing the
|
|
29
|
+
* world-space culling rect. 0.05 = 5% padding on each side — enough
|
|
30
|
+
* to avoid flicker during a one-frame pan without keeping much
|
|
31
|
+
* off-screen geometry alive in the renderer.
|
|
32
|
+
*/
|
|
33
|
+
export declare const VIEWPORT_CULL_PADDING_RATIO = 0.05;
|
|
34
|
+
/**
|
|
35
|
+
* Text-decoration geometry (underline / strikethrough), as fractions of
|
|
36
|
+
* font size, measured from the line's top (the renderer draws text with
|
|
37
|
+
* a top baseline).
|
|
38
|
+
*
|
|
39
|
+
* - `TEXT_DECORATION_THICKNESS` — line thickness ≈ 6% of font size
|
|
40
|
+
* (clamped to ≥1 px in the renderer).
|
|
41
|
+
* - `TEXT_UNDERLINE_OFFSET` — underline top, ~92% down (just below the
|
|
42
|
+
* glyph baseline).
|
|
43
|
+
* - `TEXT_STRIKETHROUGH_OFFSET` — strikethrough centre, ~50% (x-height).
|
|
44
|
+
*/
|
|
45
|
+
export declare const TEXT_DECORATION_THICKNESS = 0.06;
|
|
46
|
+
export declare const TEXT_UNDERLINE_OFFSET = 0.92;
|
|
47
|
+
export declare const TEXT_STRIKETHROUGH_OFFSET = 0.5;
|
|
48
|
+
/**
|
|
49
|
+
* Corner radius (world px) for the rounded bends of an elbow (orthogonal)
|
|
50
|
+
* connector and of a straight connector broken by user waypoints. Each
|
|
51
|
+
* corner is replaced by a quadratic arc of this radius, clamped to half the
|
|
52
|
+
* shorter adjacent segment so short segments don't overshoot. 0 disables
|
|
53
|
+
* rounding (sharp corners). Range: 0–16.
|
|
54
|
+
*/
|
|
55
|
+
export declare const LINK_CORNER_RADIUS = 10;
|
|
56
|
+
/** Stroke colour for the ruled (`"lines"`) grid. Neutral step-6 gray. */
|
|
57
|
+
export declare const GRID_LINE_COLOR: string;
|
|
58
|
+
/** Fill colour for the dotted (`"dots"`) grid — darker step-9 gray so the dots stay legible on a gray canvas. */
|
|
59
|
+
export declare const GRID_DOT_FILL: string;
|
|
60
|
+
/** On-screen stroke width (px) of a grid line. Divided by zoom at the use site so the line stays 1 px regardless of view scale. */
|
|
61
|
+
export declare const GRID_LINE_WIDTH_PX = 1;
|
|
62
|
+
/**
|
|
63
|
+
* Dot radius (screen px) for `gridStyle === "dots"`. Constant across
|
|
64
|
+
* zoom (divided by `zoom` at the use site). Reads as a crisp anchor on
|
|
65
|
+
* a gray surface. Range: 1.0–2.0.
|
|
66
|
+
*/
|
|
67
|
+
export declare const GRID_DOT_RADIUS_PX = 1;
|
|
68
|
+
/**
|
|
69
|
+
* Below this on-screen spacing (px) a grid level paints nothing —
|
|
70
|
+
* denser rendering reads as a flat haze. Only used by the fixed-ladder
|
|
71
|
+
* path (`options.levels`); the default dynamic ladder uses the fade
|
|
72
|
+
* bands below instead.
|
|
73
|
+
*/
|
|
74
|
+
export declare const GRID_MIN_SCREEN_SPACING_PX = 4;
|
|
75
|
+
/** Ratio between adjacent rungs. 4 keeps the 64/16/4/1 cadence. */
|
|
76
|
+
export declare const GRID_LEVEL_SUBDIV = 4;
|
|
77
|
+
/**
|
|
78
|
+
* How many self-similar rungs to paint at once (finest first). 3 keeps a
|
|
79
|
+
* stable fully-opaque coarse tier while the finest rung fades in/out.
|
|
80
|
+
*/
|
|
81
|
+
export declare const GRID_LEVEL_RUNGS = 3;
|
|
82
|
+
/**
|
|
83
|
+
* Line grid fade band (on-screen px). A rung is invisible at/below
|
|
84
|
+
* `FROM`, ramps to full opacity by `FULL`, and stays full above. Tuned
|
|
85
|
+
* so at 100 % (gridSize 20) the 20 px rung reads faint and the 80 px rung
|
|
86
|
+
* is solid, while subdividing forever.
|
|
87
|
+
*/
|
|
88
|
+
export declare const GRID_LINE_FADE_FROM_PX = 12;
|
|
89
|
+
export declare const GRID_LINE_FADE_FULL_PX = 56;
|
|
90
|
+
/**
|
|
91
|
+
* Dot grid fade band. Lower / tighter than lines so the base `gridSize`
|
|
92
|
+
* dot lattice is fully solid at 100 % (the denser dot field) yet still
|
|
93
|
+
* subdivides on zoom-in.
|
|
94
|
+
*/
|
|
95
|
+
export declare const GRID_DOT_FADE_FROM_PX = 10;
|
|
96
|
+
export declare const GRID_DOT_FADE_FULL_PX = 20;
|
|
97
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,EAAE,UAGzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AASrC,yEAAyE;AACzE,eAAO,MAAM,eAAe,QAAa,CAAC;AAE1C,iHAAiH;AACjH,eAAO,MAAM,aAAa,QAAiB,CAAC;AAE5C,mIAAmI;AACnI,eAAO,MAAM,kBAAkB,IAAM,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAY5C,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,qBAAqB,KAAK,CAAC"}
|