mudlet-map-renderer 2.1.0 → 2.2.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/README.md +14 -0
- package/dist/{MapReader-mU_4JWv_.js → MapReader-Brzg-X7T.js} +1 -1
- package/dist/{MapReader-mU_4JWv_.js.map → MapReader-Brzg-X7T.js.map} +1 -1
- package/dist/assets/worker-DtQws85m.js.map +1 -0
- package/dist/binary.mjs +1 -1
- package/dist/export/flushSceneShapes.d.ts +1 -1
- package/dist/flushSceneShapes-Duhi0OQv.js +2937 -0
- package/dist/flushSceneShapes-Duhi0OQv.js.map +1 -0
- package/dist/hit/HitTester.d.ts +19 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +855 -3445
- package/dist/index.mjs.map +1 -1
- package/dist/offscreen.mjs +355 -0
- package/dist/offscreen.mjs.map +1 -0
- package/dist/overlay/SceneOverlay.d.ts +16 -3
- package/dist/rendering/KonvaRenderBackend.d.ts +4 -0
- package/dist/rendering/MapRenderer.d.ts +12 -3
- package/dist/rendering/offscreen/OffscreenCanvasBackend.d.ts +109 -0
- package/dist/rendering/offscreen/index.d.ts +11 -0
- package/dist/rendering/offscreen/protocol.d.ts +100 -0
- package/dist/rendering/offscreen/renderFrame.d.ts +28 -0
- package/dist/rendering/offscreen/serializeTransform.d.ts +20 -0
- package/dist/rendering/offscreen/worker.d.ts +15 -0
- package/dist/style/Style.d.ts +12 -0
- package/dist/style/index.d.ts +10 -1
- package/dist/style/shape/GraphPaperStyle.d.ts +16 -0
- package/dist/style/shape/StainedGlassStyle.d.ts +15 -0
- package/dist/style/shape/TopographicStyle.d.ts +14 -0
- package/dist/style/shape/WatercolorStyle.d.ts +32 -0
- package/dist/style/shape/index.d.ts +5 -0
- package/dist/style/shape/paintMap.d.ts +8 -0
- package/package.json +6 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { E as e, T as t, _ as n, a as r, b as i, g as a, h as o, k as s, m as c, o as l, r as u, t as d, v as f, w as p, x as m, y as h } from "./flushSceneShapes-Duhi0OQv.js";
|
|
2
|
+
import g from "konva";
|
|
3
|
+
//#region src/rendering/offscreen/serializeTransform.ts
|
|
4
|
+
function _(e) {
|
|
5
|
+
let t = e(0, 0), n = e(1, 0), r = e(0, 1);
|
|
6
|
+
return [
|
|
7
|
+
n.x - t.x,
|
|
8
|
+
n.y - t.y,
|
|
9
|
+
r.x - t.x,
|
|
10
|
+
r.y - t.y,
|
|
11
|
+
t.x,
|
|
12
|
+
t.y
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
function v(e) {
|
|
16
|
+
return !e.worldToScene || !e.sceneToWorld ? { kind: "identity" } : {
|
|
17
|
+
kind: "affine",
|
|
18
|
+
forward: _((t, n) => e.worldToScene(t, n)),
|
|
19
|
+
inverse: _((t, n) => e.sceneToWorld(t, n))
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/rendering/offscreen/OffscreenCanvasBackend.ts
|
|
24
|
+
var y = "rgb(120, 72, 0)";
|
|
25
|
+
function b() {
|
|
26
|
+
return typeof document < "u" && typeof HTMLCanvasElement < "u" && typeof HTMLCanvasElement.prototype.transferControlToOffscreen == "function";
|
|
27
|
+
}
|
|
28
|
+
var x = class {
|
|
29
|
+
constructor(n, i, a = {}) {
|
|
30
|
+
this.hitTester = new l(), this.currentStyle = r, this._coordinateTransform = t, this.coordinateInverse = t, this.lastHitShapes = [], this.boundsByShape = /* @__PURE__ */ new Map(), this.sceneOverlays = /* @__PURE__ */ new Map(), this.viewportSubscribers = /* @__PURE__ */ new Set(), this.liveEffects = /* @__PURE__ */ new Map(), this.pendingExports = /* @__PURE__ */ new Map(), this.exportSeq = 0, this.destroyed = !1, this.state = n, this.container = i, this.pipeline = new o(n.mapReader, n.settings), this.dpr = a.devicePixelRatio ?? (typeof devicePixelRatio < "u" ? devicePixelRatio : 1), this.transport = a.transport ?? a.createTransport?.();
|
|
31
|
+
let u = i?.clientWidth ?? 1, d = i?.clientHeight ?? 1;
|
|
32
|
+
if (this.camera = new e(u, d), this.events = new s(i), this.culling = new p(n.settings, () => {
|
|
33
|
+
this.postSettings(), this.postCamera();
|
|
34
|
+
}), this.transport) {
|
|
35
|
+
let e = (e) => this.handleWorkerMessage(e.data);
|
|
36
|
+
this.transport.addEventListener ? this.transport.addEventListener("message", e) : this.transport.onmessage = e;
|
|
37
|
+
}
|
|
38
|
+
if (i && this.transport && b()) {
|
|
39
|
+
getComputedStyle(i).position === "static" && (i.style.position = "relative");
|
|
40
|
+
let e = document.createElement("canvas");
|
|
41
|
+
e.style.position = "absolute", e.style.inset = "0", e.style.width = "100%", e.style.height = "100%", e.style.display = "block", i.appendChild(e), i.style.backgroundColor = n.settings.backgroundColor;
|
|
42
|
+
let t = e.transferControlToOffscreen();
|
|
43
|
+
this.transport.postMessage({
|
|
44
|
+
type: "init",
|
|
45
|
+
canvas: t,
|
|
46
|
+
width: u,
|
|
47
|
+
height: d,
|
|
48
|
+
dpr: this.dpr,
|
|
49
|
+
settings: n.settings
|
|
50
|
+
}, [t]), this.interactionHandler = new c(i, this.camera, n, {
|
|
51
|
+
clientToMapPoint: (e, t) => this.camera.clientToMapPoint(e, t, i.getBoundingClientRect()),
|
|
52
|
+
pickAtPoint: (e, t) => this.hitTester.pick(e, t)
|
|
53
|
+
}, this.events);
|
|
54
|
+
}
|
|
55
|
+
this.cameraChangeHandler = () => this.onCameraChange(), this.camera.on("change", this.cameraChangeHandler), this.applyStyleTransforms(), this.subscribeToState(n), this.postCamera();
|
|
56
|
+
}
|
|
57
|
+
get coordinateTransform() {
|
|
58
|
+
return this._coordinateTransform;
|
|
59
|
+
}
|
|
60
|
+
post(e, t) {
|
|
61
|
+
this.destroyed || !this.transport || this.transport.postMessage(e, t);
|
|
62
|
+
}
|
|
63
|
+
postSettings() {
|
|
64
|
+
this.post({
|
|
65
|
+
type: "settings",
|
|
66
|
+
settings: this.state.settings
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
postCamera() {
|
|
70
|
+
this.post({
|
|
71
|
+
type: "camera",
|
|
72
|
+
camera: {
|
|
73
|
+
scale: this.camera.getScale(),
|
|
74
|
+
offsetX: this.camera.position.x,
|
|
75
|
+
offsetY: this.camera.position.y
|
|
76
|
+
},
|
|
77
|
+
viewport: this.camera.getViewportBounds(),
|
|
78
|
+
width: this.camera.width,
|
|
79
|
+
height: this.camera.height
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
postScene() {
|
|
83
|
+
let e = this.lastResult;
|
|
84
|
+
if (!e) {
|
|
85
|
+
this.post({
|
|
86
|
+
type: "scene",
|
|
87
|
+
link: {
|
|
88
|
+
shapes: [],
|
|
89
|
+
bounds: []
|
|
90
|
+
},
|
|
91
|
+
room: {
|
|
92
|
+
shapes: [],
|
|
93
|
+
bounds: []
|
|
94
|
+
},
|
|
95
|
+
topLabel: [],
|
|
96
|
+
transform: v(this.currentStyle)
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
let t = this.styleContext();
|
|
101
|
+
this.post({
|
|
102
|
+
type: "scene",
|
|
103
|
+
link: this.styleLayer(e.sceneShapes.link, t),
|
|
104
|
+
room: this.styleLayer(e.sceneShapes.room, t),
|
|
105
|
+
topLabel: this.styleShapes(e.sceneShapes.topLabel, t),
|
|
106
|
+
transform: v(this.currentStyle)
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
postOverlays() {
|
|
110
|
+
let e = this.styleContext(), t = [];
|
|
111
|
+
for (let n of this.buildCurrentRoomOverlayShapes()) t.push(...this.styleOne(n, e, !1));
|
|
112
|
+
for (let n of d(this.state)) t.push(...this.styleOne(n, e, !1));
|
|
113
|
+
for (let n of this.sceneOverlays.values()) {
|
|
114
|
+
let r = n.render(this.state, this.camera.getViewportBounds());
|
|
115
|
+
if (!r) continue;
|
|
116
|
+
let i = Array.isArray(r) ? r : [r];
|
|
117
|
+
for (let r of i) t.push(...this.styleOne(r, e, n.sceneSpace ?? !1));
|
|
118
|
+
}
|
|
119
|
+
this.post({
|
|
120
|
+
type: "overlays",
|
|
121
|
+
shapes: t
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
styleContext() {
|
|
125
|
+
return {
|
|
126
|
+
scale: this.camera.getScale(),
|
|
127
|
+
roomSize: this.state.settings.roomSize
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
styleOne(e, t, n) {
|
|
131
|
+
return n || this.currentStyle === r ? [e] : u([e], this.currentStyle, t);
|
|
132
|
+
}
|
|
133
|
+
styleShapes(e, t) {
|
|
134
|
+
return this.currentStyle === r ? e : u(e, this.currentStyle, t);
|
|
135
|
+
}
|
|
136
|
+
styleLayer(e, t) {
|
|
137
|
+
let n = [], i = [];
|
|
138
|
+
for (let a of e) {
|
|
139
|
+
let e = this.boundsByShape.get(a) ?? null, o = this.currentStyle === r ? [a] : u([a], this.currentStyle, t);
|
|
140
|
+
for (let t of o) n.push(t), i.push(e);
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
shapes: n,
|
|
144
|
+
bounds: i
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
refresh() {
|
|
148
|
+
let { currentAreaInstance: e, currentZIndex: t, positionRoomId: n } = this.state;
|
|
149
|
+
if (!e || t === void 0) return;
|
|
150
|
+
let r = e.getPlane(t);
|
|
151
|
+
if (!r) {
|
|
152
|
+
this.lastResult = void 0, this.lastHitShapes = [], this.boundsByShape.clear(), this.hitTester.clear(), this.postSettings(), this.postScene(), this.postOverlays(), this.postCamera();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
let i = this.pipeline.buildScene(e, r, t, this.state.lens);
|
|
156
|
+
this.lastResult = i, this.lastHitShapes = i.hitShapes, this.boundsByShape = this.buildBoundsMap(i), this.hitTester.build(this.lastHitShapes, this.state.settings.roomSize, this._coordinateTransform, this.coordinateLayerOffset), this.container && (this.container.style.backgroundColor = this.state.settings.backgroundColor), this.postSettings(), this.postScene(), this.postOverlays(), this.postCamera();
|
|
157
|
+
}
|
|
158
|
+
buildBoundsMap(e) {
|
|
159
|
+
let t = /* @__PURE__ */ new Map(), n = this.state.settings.roomSize / 2;
|
|
160
|
+
for (let { room: r, shape: i } of e.roomShapeRefs.values()) t.set(i, {
|
|
161
|
+
x: r.x - n,
|
|
162
|
+
y: r.y - n,
|
|
163
|
+
width: this.state.settings.roomSize,
|
|
164
|
+
height: this.state.settings.roomSize
|
|
165
|
+
});
|
|
166
|
+
for (let { shape: n, bounds: r } of e.standaloneExitShapeRefs) t.set(n, r);
|
|
167
|
+
for (let { shape: n, bounds: r } of e.labelShapeRefs) t.set(n, r);
|
|
168
|
+
for (let { shape: n, bounds: r } of e.specialExitShapeRefs) t.set(n, r);
|
|
169
|
+
for (let { shape: n, bounds: r } of e.stubShapeRefs) t.set(n, r);
|
|
170
|
+
for (let { shape: n, bounds: r } of e.areaExitLabelShapeRefs) t.set(n, r);
|
|
171
|
+
return t;
|
|
172
|
+
}
|
|
173
|
+
buildCurrentRoomOverlayShapes() {
|
|
174
|
+
let e = this.state, t = e.positionRoomId;
|
|
175
|
+
if (t === void 0) return [];
|
|
176
|
+
let r = e.mapReader.getRoom(t);
|
|
177
|
+
if (!r || r.area !== e.currentArea || r.z !== e.currentZIndex) return [];
|
|
178
|
+
let o = e.settings;
|
|
179
|
+
if (!o.highlightCurrentRoom) return [];
|
|
180
|
+
let s = [], c = this.pipeline.exitRenderer, l = e.lens, u = /* @__PURE__ */ new Map();
|
|
181
|
+
if (u.set(r.id, r), e.currentAreaInstance && e.currentZIndex !== void 0) {
|
|
182
|
+
let t = e.currentAreaInstance.getLinkExits(e.currentZIndex).filter((e) => e.a === r.id || e.b === r.id);
|
|
183
|
+
for (let n of t) {
|
|
184
|
+
let t = c.renderDataWithColor(n, y, e.currentZIndex);
|
|
185
|
+
t && s.push(this.pipeline.buildExitShape(t));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
for (let e of i(r, o, y)) s.push(n(e, r.id));
|
|
189
|
+
for (let e of m(r, o, y)) s.push(a(e));
|
|
190
|
+
return [...Object.values(r.exits), ...Object.values(r.specialExits)].forEach((t) => {
|
|
191
|
+
let n = e.mapReader.getRoom(t);
|
|
192
|
+
n && n.area === e.currentArea && n.z === e.currentZIndex && l.isVisible(n) && u.set(n.id, n);
|
|
193
|
+
}), u.forEach((t, n) => {
|
|
194
|
+
let i = n === r.id, a = h(t, e.mapReader, o, {
|
|
195
|
+
strokeOverride: i ? y : o.lineColor,
|
|
196
|
+
flatPipeline: !0
|
|
197
|
+
});
|
|
198
|
+
a.children.push(...f(t, e.mapReader, o)), s.push(a);
|
|
199
|
+
}), s;
|
|
200
|
+
}
|
|
201
|
+
setStyle(e) {
|
|
202
|
+
this.currentStyle = e, this.lastHitShapes = [], this.hitTester.clear(), this.applyStyleTransforms(), this.refresh();
|
|
203
|
+
}
|
|
204
|
+
applyStyleTransforms() {
|
|
205
|
+
let e = this.currentStyle, n = e.worldToScene ? (t, n) => e.worldToScene(t, n) : t, r = e.sceneToWorld ? (t, n) => e.sceneToWorld(t, n) : t, i = this.coordinateInverse, a = e.sceneLayerOffset ? (t) => e.sceneLayerOffset(t) : void 0;
|
|
206
|
+
this._coordinateTransform = n, this.coordinateInverse = r, this.coordinateLayerOffset = a, this.culling.setCoordinateTransform(n), this.lastHitShapes.length > 0 && this.hitTester.build(this.lastHitShapes, this.state.settings.roomSize, n, a);
|
|
207
|
+
let o = this.camera.getScale(), s = this.camera.width / 2, c = this.camera.height / 2, l = i((s - this.camera.position.x) / o, (c - this.camera.position.y) / o), u = n(l.x, l.y);
|
|
208
|
+
this.camera.position = {
|
|
209
|
+
x: s - u.x * o,
|
|
210
|
+
y: c - u.y * o
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
onCameraChange() {
|
|
214
|
+
this.postCamera();
|
|
215
|
+
let e = this.camera.getViewportBounds();
|
|
216
|
+
this.events.emit("pan", e);
|
|
217
|
+
for (let e of this.viewportSubscribers) e();
|
|
218
|
+
if (this.liveEffectStage) {
|
|
219
|
+
this.syncEffectStage();
|
|
220
|
+
let t = this.camera.getScale();
|
|
221
|
+
for (let n of this.liveEffects.values()) n.updateViewport(e, t, this._coordinateTransform);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
subscribeToState(e) {
|
|
225
|
+
e.events.on("area", () => this.refresh()), e.events.on("position", ({ roomId: e, center: t, areaChanged: n }) => this.onPositionChanged(e, t, n)), e.events.on("center", ({ roomId: t, instant: n }) => {
|
|
226
|
+
let r = e.mapReader.getRoom(t);
|
|
227
|
+
if (r) {
|
|
228
|
+
let e = this._coordinateTransform(r.x, r.y);
|
|
229
|
+
this.camera.panToMapPointAnimated(e.x, e.y, n || this.state.settings.instantMapMove);
|
|
230
|
+
}
|
|
231
|
+
}), e.events.on("highlight", () => this.postOverlays()), e.events.on("path", () => this.postOverlays()), e.events.on("clear", () => this.postOverlays()), e.events.on("lens", () => this.refresh());
|
|
232
|
+
}
|
|
233
|
+
onPositionChanged(e, t, n) {
|
|
234
|
+
if (e !== void 0 && t) {
|
|
235
|
+
let t = this.state.mapReader.getRoom(e);
|
|
236
|
+
if (t) {
|
|
237
|
+
let e = this._coordinateTransform(t.x, t.y);
|
|
238
|
+
this.camera.panToMapPointAnimated(e.x, e.y, n || this.state.settings.instantMapMove);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
this.postOverlays();
|
|
242
|
+
}
|
|
243
|
+
updateBackground() {
|
|
244
|
+
this.container && (this.container.style.backgroundColor = this.state.settings.backgroundColor), this.postSettings(), this.postCamera();
|
|
245
|
+
}
|
|
246
|
+
addSceneOverlay(e, t) {
|
|
247
|
+
let n = this.sceneOverlays.get(e);
|
|
248
|
+
n && n.detach?.(), this.sceneOverlays.set(e, t), t.attach?.(this.createOverlayContext(e, t)), this.postOverlays();
|
|
249
|
+
}
|
|
250
|
+
removeSceneOverlay(e) {
|
|
251
|
+
let t = this.sceneOverlays.get(e);
|
|
252
|
+
t && (t.detach?.(), this.sceneOverlays.delete(e), this.postOverlays());
|
|
253
|
+
}
|
|
254
|
+
getSceneOverlays() {
|
|
255
|
+
return this.sceneOverlays.values();
|
|
256
|
+
}
|
|
257
|
+
createOverlayContext(e, t) {
|
|
258
|
+
return {
|
|
259
|
+
state: this.state,
|
|
260
|
+
onViewportChange: (e) => (this.viewportSubscribers.add(e), () => this.viewportSubscribers.delete(e)),
|
|
261
|
+
invalidate: () => {
|
|
262
|
+
this.sceneOverlays.get(e) === t && this.postOverlays();
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
ensureEffectStage() {
|
|
267
|
+
if (this.liveEffectStage || !this.container) return;
|
|
268
|
+
let e = document.createElement("div");
|
|
269
|
+
e.style.position = "absolute", e.style.inset = "0", e.style.pointerEvents = "none", this.container.appendChild(e);
|
|
270
|
+
let t = new g.Stage({
|
|
271
|
+
container: e,
|
|
272
|
+
width: this.camera.width,
|
|
273
|
+
height: this.camera.height,
|
|
274
|
+
listening: !1
|
|
275
|
+
}), n = new g.Layer({ listening: !1 });
|
|
276
|
+
t.add(n), this.liveEffectHost = e, this.liveEffectStage = t, this.liveEffectLayer = n, this.syncEffectStage();
|
|
277
|
+
}
|
|
278
|
+
syncEffectStage() {
|
|
279
|
+
let e = this.liveEffectStage;
|
|
280
|
+
if (!e) return;
|
|
281
|
+
(e.width() !== this.camera.width || e.height() !== this.camera.height) && (e.width(this.camera.width), e.height(this.camera.height));
|
|
282
|
+
let t = this.camera.getScale();
|
|
283
|
+
e.scale({
|
|
284
|
+
x: t,
|
|
285
|
+
y: t
|
|
286
|
+
}), e.position(this.camera.position), e.batchDraw();
|
|
287
|
+
}
|
|
288
|
+
addLiveEffect(e, t) {
|
|
289
|
+
this.removeLiveEffect(e), this.ensureEffectStage(), this.liveEffectLayer && (t.attach(this.liveEffectLayer), this.liveEffects.set(e, t), this.syncEffectStage(), t.updateViewport(this.camera.getViewportBounds(), this.camera.getScale(), this._coordinateTransform));
|
|
290
|
+
}
|
|
291
|
+
removeLiveEffect(e) {
|
|
292
|
+
let t = this.liveEffects.get(e);
|
|
293
|
+
t && (t.destroy(), this.liveEffects.delete(e), this.liveEffectLayer?.batchDraw());
|
|
294
|
+
}
|
|
295
|
+
getDrawnExits() {
|
|
296
|
+
return this.lastResult?.drawnExits ?? [];
|
|
297
|
+
}
|
|
298
|
+
getDrawnSpecialExits() {
|
|
299
|
+
return this.lastResult?.drawnSpecialExits ?? [];
|
|
300
|
+
}
|
|
301
|
+
getDrawnStubs() {
|
|
302
|
+
return this.lastResult?.drawnStubs ?? [];
|
|
303
|
+
}
|
|
304
|
+
exportCanvas() {}
|
|
305
|
+
captureViewport(e) {
|
|
306
|
+
if (!this.transport) return Promise.reject(/* @__PURE__ */ Error("No worker transport"));
|
|
307
|
+
let t = ++this.exportSeq;
|
|
308
|
+
return new Promise((n) => {
|
|
309
|
+
this.pendingExports.set(t, n), this.post({
|
|
310
|
+
type: "export",
|
|
311
|
+
requestId: t,
|
|
312
|
+
pixelRatio: e?.pixelRatio ?? this.dpr
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
handleWorkerMessage(e) {
|
|
317
|
+
if (e.type === "export") {
|
|
318
|
+
let t = this.pendingExports.get(e.requestId);
|
|
319
|
+
t && (this.pendingExports.delete(e.requestId), t(e.bitmap));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
destroy() {
|
|
323
|
+
if (!this.destroyed) {
|
|
324
|
+
this.destroyed = !0, this.state.events.removeAllListeners(), this.interactionHandler?.destroy();
|
|
325
|
+
for (let e of this.liveEffects.values()) e.destroy();
|
|
326
|
+
this.liveEffects.clear(), this.liveEffectStage?.destroy(), this.liveEffectStage = void 0, this.liveEffectLayer = void 0, this.liveEffectHost?.remove(), this.liveEffectHost = void 0;
|
|
327
|
+
for (let e of this.sceneOverlays.values()) e.detach?.();
|
|
328
|
+
this.sceneOverlays.clear(), this.viewportSubscribers.clear(), this.pendingExports.clear(), this.camera.cancelAnimation(), this.cameraChangeHandler &&= (this.camera.off("change", this.cameraChangeHandler), void 0), this.post({ type: "destroy" }), this.transport?.terminate?.(), this.events.removeAllListeners();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}, S = "(function(){function e(e,t,n={}){if(!t.gridEnabled)return[];let r=n.inverseTransform??((e,t)=>({x:e,y:t})),{minX:i,maxX:a,minY:o,maxY:s}=e,c=r(i,o),l=r(a,o),u=r(a,s),d=r(i,s),f=Math.min(c.x,l.x,u.x,d.x),p=Math.max(c.x,l.x,u.x,d.x),m=Math.min(c.y,l.y,u.y,d.y),h=Math.max(c.y,l.y,u.y,d.y),g=t.gridSize*2,_=Math.floor((f-g)/t.gridSize)*t.gridSize,v=Math.ceil((p+g)/t.gridSize)*t.gridSize,y=Math.floor((m-g)/t.gridSize)*t.gridSize,b=Math.ceil((h+g)/t.gridSize)*t.gridSize,x=[],S={stroke:t.gridColor,strokeWidth:t.gridLineWidth};for(let e=_;e<=v;e+=t.gridSize)x.push({type:`line`,points:[e,y,e,b],paint:S,grid:!0,layer:`grid`});for(let e=y;e<=b;e+=t.gridSize)x.push({type:`line`,points:[_,e,v,e],paint:S,grid:!0,layer:`grid`});return x}function t(e){return typeof e==`object`&&!!e}function n(e,n,r,i,a,o){return t(e)?e.type===`linear`?{type:`linear`,x0:(n+e.x0)*i+a,y0:(r+e.y0)*i+o,x1:(n+e.x1)*i+a,y1:(r+e.y1)*i+o,stops:e.stops}:{type:`radial`,cx:(n+e.cx)*i+a,cy:(r+e.cy)*i+o,r:e.r*i,fx:e.fx===void 0?void 0:(n+e.fx)*i+a,fy:e.fy===void 0?void 0:(r+e.fy)*i+o,fr:e.fr===void 0?void 0:e.fr*i,stops:e.stops}:e}let r=`room`;function i(e,t){let i=new Map;function c(e){let t=i.get(e);return t||(t=[],i.set(e,t)),t}function l(e,t,i,l,d,f,p){let m=e.layer??p??r;switch(e.type){case`rect`:{let r={type:`rect`,x:(t+e.x)*l+d,y:(i+e.y)*l+f,w:e.width*l,h:e.height*l,fill:n(e.paint.fill,t,i,l,d,f),stroke:e.paint.stroke,sw:(e.paint.strokeWidth??0)*l,cr:(e.cornerRadius??0)*l,dash:o(e.paint.dash,l,e.paint.dashEnabled)};c(m).push(r);return}case`circle`:c(m).push({type:`circle`,cx:(t+e.cx)*l+d,cy:(i+e.cy)*l+f,r:e.radius*l,fill:n(e.paint.fill,t,i,l,d,f),stroke:e.paint.stroke,sw:(e.paint.strokeWidth??0)*l,dash:o(e.paint.dash,l,e.paint.dashEnabled)});return;case`line`:{let n={type:`line`,points:a(e.points,t,i,l,d,f),stroke:e.paint.stroke,sw:(e.paint.strokeWidth??0)*l,dash:o(e.paint.dash,l,e.paint.dashEnabled),lineCap:e.lineCap,lineJoin:e.lineJoin,alpha:e.paint.alpha};c(m).push(n);return}case`polygon`:{let r={type:`polygon`,vertices:a(e.vertices,t,i,l,d,f),fill:n(e.paint.fill,t,i,l,d,f),stroke:e.paint.stroke,sw:(e.paint.strokeWidth??0)*l};c(m).push(r);return}case`text`:{let n=s(e.transform,t,i,l,d,f),r={type:`text`,x:n?0:(t+e.x)*l+d,y:n?0:(i+e.y)*l+f,text:e.text,fontSize:e.fontSize*l,fontFamily:e.fontFamily??`sans-serif`,fontStyle:e.fontStyle??`normal`,fill:e.fill??`black`,stroke:e.stroke,sw:(e.strokeWidth??0)*l,align:e.align??`left`,vAlign:e.verticalAlign??`top`,w:(e.width??0)*l,h:(e.height??0)*l,baselineRatio:e.baselineRatio,konvaCorrectionRatio:e.konvaCorrectionRatio,transform:n};c(m).push(r);return}case`image`:{let n=s(e.transform,t,i,l,d,f),r=n?0:(t+e.x)*l+d,a=n?0:(i+e.y)*l+f;c(m).push({type:`image`,x:r,y:a,w:e.width*l,h:e.height*l,src:e.src,transform:n});return}case`group`:u(e,t,i,l,d,f,m);return}}function u(e,t,n,i,a,o,s){let u=e.layer??s;if(e.noScale){let s=(t+e.x)*i+a,d=(n+e.y)*i+o,f=c(u??r);f.push({type:`pushTransform`,matrix:[1,0,0,1,s,d]});for(let t of e.children)l(t,0,0,1,0,0,u);f.push({type:`popTransform`});return}let d=t+e.x,f=n+e.y;for(let t of e.children)l(t,d,f,i,a,o,u)}for(let n of e)l(n,0,0,t.scale,t.offsetX,t.offsetY,void 0);let d=[];for(let[e,t]of i)d.push({layer:e,commands:t});return d}function a(e,t,n,r,i,a){let o=Array(e.length);for(let s=0;s<e.length;s+=2)o[s]=(t+e[s])*r+i,o[s+1]=(n+e[s+1])*r+a;return o}function o(e,t,n){if(n===!1)return;if(!e||e.length===0)return e;let r=Array(e.length);for(let n=0;n<e.length;n++)r[n]=e[n]*t;return r}function s(e,t,n,r,i,a){if(!e)return;let[o,s,c,l,u,d]=e;return[o*r,s*r,c*r,l*r,u*r+t*r+i,d*r+n*r+a]}function c(e,t){if(typeof t==`string`)return t;if(t.type===`linear`){let n=e.createLinearGradient(t.x0,t.y0,t.x1,t.y1);for(let e of t.stops)n.addColorStop(e.offset,e.color);return n}let n=t.fx??t.cx,r=t.fy??t.cy,i=t.fr??0,a=e.createRadialGradient(n,r,i,t.cx,t.cy,t.r);for(let e of t.stops)a.addColorStop(e.offset,e.color);return a}let l=e=>{if(typeof Image<`u`){let t=new Image;return t.src=e,t}return null};function u(e,t,n={}){let r=n.imageFactory??l;for(let n of t)d(e,n.commands,r)}function d(e,t,n){let r=0;for(let i of t)switch(i.type){case`pushTransform`:e.save(),r++,e.transform(...i.matrix);break;case`pushClip`:e.save(),r++,e.beginPath(),e.rect(i.x,i.y,i.w,i.h),e.clip();break;case`popTransform`:case`popClip`:r>0&&(e.restore(),r--);break;default:f(e,i,n);break}for(;r>0;)e.restore(),r--}function f(e,t,n){switch(t.type){case`rect`:e.beginPath(),t.cr>0&&typeof e.roundRect==`function`?e.roundRect(t.x,t.y,t.w,t.h,t.cr):e.rect(t.x,t.y,t.w,t.h),t.fill&&(e.fillStyle=c(e,t.fill),e.fill()),t.stroke&&t.sw>0&&(e.strokeStyle=t.stroke,e.lineWidth=t.sw,e.setLineDash(t.dash??[]),e.stroke());break;case`circle`:e.beginPath(),e.arc(t.cx,t.cy,t.r,0,Math.PI*2),t.fill&&(e.fillStyle=c(e,t.fill),e.fill()),t.stroke&&t.sw>0&&(e.strokeStyle=t.stroke,e.lineWidth=t.sw,e.setLineDash(t.dash??[]),e.stroke());break;case`line`:{if(t.points.length<4)break;let n=e.globalAlpha;t.alpha!==void 0&&(e.globalAlpha=t.alpha),e.beginPath(),e.moveTo(t.points[0],t.points[1]);for(let n=2;n<t.points.length;n+=2)e.lineTo(t.points[n],t.points[n+1]);t.stroke&&(e.strokeStyle=t.stroke),e.lineWidth=t.sw,e.setLineDash(t.dash??[]),t.lineCap&&(e.lineCap=t.lineCap),t.lineJoin&&(e.lineJoin=t.lineJoin),e.stroke(),t.alpha!==void 0&&(e.globalAlpha=n);break}case`polygon`:if(t.vertices.length<4)break;e.beginPath(),e.moveTo(t.vertices[0],t.vertices[1]);for(let n=2;n<t.vertices.length;n+=2)e.lineTo(t.vertices[n],t.vertices[n+1]);e.closePath(),t.fill&&(e.fillStyle=c(e,t.fill),e.fill()),t.stroke&&t.sw>0&&(e.strokeStyle=t.stroke,e.lineWidth=t.sw,e.setLineDash([]),e.stroke());break;case`text`:{let n=t.fontSize*100,r=`${t.fontStyle} ${n}px ${t.fontFamily}`;e.save(),e.font=r,e.fillStyle=t.fill,t.stroke&&t.sw>0&&(e.strokeStyle=t.stroke,e.lineWidth=t.sw*100,e.lineJoin=`round`);let i=t.baselineRatio!==void 0;if(t.transform)if(e.transform(...t.transform),e.scale(1/100,1/100),e.textAlign=`center`,i){e.textBaseline=`alphabetic`;let n=(t.h/2+t.baselineRatio*t.fontSize)*100;t.stroke&&t.sw>0&&e.strokeText(t.text,t.w*100/2,n),e.fillText(t.text,t.w*100/2,n)}else{e.textBaseline=`middle`;let n=t.w*100/2,r=t.h*100/2;t.stroke&&t.sw>0&&e.strokeText(t.text,n,r),e.fillText(t.text,n,r)}else if(t.w>0&&t.h>0){e.textAlign=t.align||`left`;let n=t.align===`center`?t.x+t.w/2:t.align===`right`?t.x+t.w:t.x;if(e.scale(1/100,1/100),t.vAlign===`middle`&&i){e.textBaseline=`alphabetic`;let r=t.y+t.h/2+t.baselineRatio*t.fontSize;t.stroke&&t.sw>0&&e.strokeText(t.text,n*100,r*100),e.fillText(t.text,n*100,r*100)}else{e.textBaseline=t.vAlign===`middle`?`middle`:`top`;let r=t.vAlign===`middle`?t.y+t.h/2:t.y;t.stroke&&t.sw>0&&e.strokeText(t.text,n*100,r*100),e.fillText(t.text,n*100,r*100)}}else e.textAlign=`left`,e.textBaseline=`top`,e.scale(1/100,1/100),t.stroke&&t.sw>0&&e.strokeText(t.text,t.x*100,t.y*100),e.fillText(t.text,t.x*100,t.y*100);e.restore();break}case`image`:{let r=n(t.src);if(!r)break;t.transform?(e.save(),e.transform(...t.transform),e.drawImage(r,0,0,t.w,t.h),e.restore()):e.drawImage(r,t.x,t.y,t.w,t.h);break}}}function p(e,t,n){return{x:e[0]*t+e[2]*n+e[4],y:e[1]*t+e[3]*n+e[5]}}function m(e){if(e.kind===`identity`)return;let t=e.forward;return(e,n)=>p(t,e,n)}function h(e){if(e.kind===`identity`)return;let t=e.inverse;return(e,n)=>p(t,e,n)}function g(e,t,n,r,i){let a=i(e,t),o=i(n,t),s=i(n,r),c=i(e,r);return{minX:Math.min(a.x,o.x,s.x,c.x),minY:Math.min(a.y,o.y,s.y,c.y),maxX:Math.max(a.x,o.x,s.x,c.x),maxY:Math.max(a.y,o.y,s.y,c.y)}}function _(e,t,n){let{minX:r,maxX:i,minY:a,maxY:o}=t,s=[];for(let t=0;t<e.shapes.length;t++){let c=e.bounds[t];if(!c){s.push(e.shapes[t]);continue}let l=c.x,u=c.y,d=c.x+c.width,f=c.y+c.height;if(n){let e=g(l,u,d,f,n);l=e.minX,u=e.minY,d=e.maxX,f=e.maxY}d>=r&&l<=i&&f>=a&&u<=o&&s.push(e.shapes[t])}return s}function v(t,n){let{scene:r,overlays:a,camera:o,viewport:s,settings:c,width:l,height:d,imageFactory:f}=n,p=f?{imageFactory:f}:void 0;if(t.fillStyle=c.backgroundColor,t.fillRect(0,0,l,d),!r)return;let g=m(r.transform),v=e(s,c,{inverseTransform:h(r.transform)});v.length>0&&u(t,i(v,o),p);let y=c.cullingEnabled?_(r.link,s,g):r.link.shapes;y.length>0&&u(t,i(y,o),p);let b=c.cullingEnabled?_(r.room,s,g):r.room.shapes;b.length>0&&u(t,i(b,o),p),a.length>0&&u(t,i(a,o),p),r.topLabel.length>0&&u(t,i(r.topLabel,o),p)}let y=globalThis,b=null,x=null,S=1,C=1,w=1,T=null,E=null,D=[],O={scale:1,offsetX:0,offsetY:0},k={minX:0,maxX:0,minY:0,maxY:0},A=!1,j=!1,M=new Map;function N(e){let t=M.get(e);return t===void 0?(M.set(e,null),fetch(e).then(e=>e.blob()).then(e=>createImageBitmap(e)).then(t=>{if(M.size>64){let t=M.keys().next().value;if(t!==void 0&&t!==e){let e=M.get(t);e&&e.close(),M.delete(t)}}M.set(e,t),F()}).catch(()=>{}),null):t}let P=typeof requestAnimationFrame<`u`?e=>{requestAnimationFrame(e)}:e=>{setTimeout(()=>e(0),16)};function F(){A=!0,!j&&(j=!0,P(()=>{j=!1,A&&L()}))}function I(){b&&(b.width=Math.max(1,Math.round(C*S)),b.height=Math.max(1,Math.round(w*S)),x=b.getContext(`2d`))}function L(){A=!1,!(!x||!T)&&(x.setTransform(S,0,0,S,0,0),v(x,{scene:E,overlays:D,camera:O,viewport:k,settings:T,width:C,height:w,imageFactory:N}))}async function R(e){if(!b)return;A&&L();let t=await createImageBitmap(b);y.postMessage({type:`export`,requestId:e,bitmap:t},[t])}y.onmessage=e=>{let t=e.data;switch(t.type){case`init`:b=t.canvas,S=t.dpr,C=t.width,w=t.height,T=t.settings,I(),y.postMessage({type:`ready`},[]),F();break;case`settings`:T=t.settings,F();break;case`scene`:E={link:t.link,room:t.room,topLabel:t.topLabel,transform:t.transform},F();break;case`overlays`:D=t.shapes,F();break;case`camera`:O=t.camera,k=t.viewport,(t.width!==C||t.height!==w)&&(C=t.width,w=t.height,I()),F();break;case`resize`:C=t.width,w=t.height,S=t.dpr,I(),F();break;case`export`:R(t.requestId);break;case`destroy`:b=null,x=null,E=null,D=[],T=null;for(let e of M.values())e?.close();M.clear();break}}})();\n//# sourceMappingURL=worker-DtQws85m.js.map", C = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", S], { type: "text/javascript;charset=utf-8" });
|
|
332
|
+
function w(e) {
|
|
333
|
+
let t;
|
|
334
|
+
try {
|
|
335
|
+
if (t = C && (self.URL || self.webkitURL).createObjectURL(C), !t) throw "";
|
|
336
|
+
let n = new Worker(t, { name: e?.name });
|
|
337
|
+
return n.addEventListener("error", () => {
|
|
338
|
+
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
339
|
+
}), n;
|
|
340
|
+
} catch {
|
|
341
|
+
return new Worker("data:text/javascript;charset=utf-8," + encodeURIComponent(S), { name: e?.name });
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/rendering/offscreen/index.ts
|
|
346
|
+
function T(e, t = {}) {
|
|
347
|
+
return (n) => new x(n, e, {
|
|
348
|
+
...t,
|
|
349
|
+
createTransport: t.createTransport ?? (() => new w())
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
353
|
+
export { x as OffscreenCanvasBackend, T as createOffscreenBackend };
|
|
354
|
+
|
|
355
|
+
//# sourceMappingURL=offscreen.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offscreen.mjs","names":[],"sources":["../src/rendering/offscreen/serializeTransform.ts","../src/rendering/offscreen/OffscreenCanvasBackend.ts","../src/rendering/offscreen/index.ts"],"sourcesContent":["/**\n * Flatten a {@link Style}'s coordinate warp into a {@link SerializableTransform}\n * the worker can use without the (non-serialisable) style closures.\n *\n * All current built-in styles are either flat (`worldToScene` absent → identity)\n * or affine (Isometric). We reconstruct the affine matrix by sampling the\n * closure at three basis points — exact for affine maps. A future non-affine\n * style would be mis-sampled here; callers should fall back to main-thread\n * culling for such styles (see OffscreenCanvasBackend).\n */\n\nimport type {Style} from \"../../style/Style\";\nimport type {AffineMatrix, SerializableTransform} from \"./protocol\";\n\ntype TransformFn = (x: number, y: number) => {x: number; y: number};\n\n/** Recover the affine matrix `[a,b,c,d,e,f]` of a (presumed affine) map. */\nfunction sampleAffine(fn: TransformFn): AffineMatrix {\n const o = fn(0, 0);\n const x = fn(1, 0);\n const y = fn(0, 1);\n return [x.x - o.x, x.y - o.y, y.x - o.x, y.y - o.y, o.x, o.y];\n}\n\n/** Build the flattened transform for a style. Identity styles short-circuit. */\nexport function serializeTransform(style: Style): SerializableTransform {\n if (!style.worldToScene || !style.sceneToWorld) {\n return {kind: \"identity\"};\n }\n return {\n kind: \"affine\",\n forward: sampleAffine((x, y) => style.worldToScene!(x, y)),\n inverse: sampleAffine((x, y) => style.sceneToWorld!(x, y)),\n };\n}\n\nfunction applyMatrix(m: AffineMatrix, x: number, y: number): {x: number; y: number} {\n return {x: m[0] * x + m[2] * y + m[4], y: m[1] * x + m[3] * y + m[5]};\n}\n\n/**\n * World → scene projector for the worker's cull-bounds test. Returns\n * `undefined` for the identity transform so callers can skip projection.\n */\nexport function forwardFn(transform: SerializableTransform): TransformFn | undefined {\n if (transform.kind === \"identity\") return undefined;\n const m = transform.forward;\n return (x, y) => applyMatrix(m, x, y);\n}\n\n/**\n * Scene → world projector for the worker's grid Cartesian-bounds computation.\n * Returns `undefined` for the identity transform (grid layout treats absent\n * inverse as identity).\n */\nexport function inverseFn(transform: SerializableTransform): TransformFn | undefined {\n if (transform.kind === \"identity\") return undefined;\n const m = transform.inverse;\n return (x, y) => applyMatrix(m, x, y);\n}\n","/**\n * OffscreenCanvasBackend — opt-in {@link InteractiveBackend} that renders in a\n * Web Worker via `OffscreenCanvas`.\n *\n * The main thread keeps everything that must stay synchronous or that touches\n * the DOM: the {@link Camera}, {@link CullingManager}, {@link HitTester},\n * interaction handling, and the (text-measuring, therefore DOM-bound) scene\n * build. It styles the resulting shapes, then ships plain {@link Shape} lists to\n * the worker. The worker owns the per-frame hot path (cull → draw commands →\n * rasterise). See {@link renderFrame} and {@link worker}.\n *\n * Differences from {@link KonvaRenderBackend}:\n * - `exportCanvas` returns `undefined` (the live canvas lives in the worker and\n * isn't readable here) — use the headless `CanvasExporter`/`PngBytesExporter`,\n * which rebuild from state. An async {@link captureViewport} is offered for\n * callers that genuinely need a live snapshot.\n * - Image shapes (image labels, ambient-light vignette) ARE supported: the\n * worker decodes their `src` via `createImageBitmap` (see worker.ts).\n * - Live effects ARE supported, but run on a main-thread Konva overlay stage\n * composited above the worker canvas (Konva animations can't run in a\n * worker); the map itself still rasterises off-thread.\n */\n\nimport Konva from \"konva\";\nimport type {InteractiveBackend} from \"../MapRenderer\";\nimport type {MapState} from \"../../MapState\";\nimport type {RendererEventMap} from \"../../types/Settings\";\nimport {Camera} from \"../../camera/Camera\";\nimport {CullingManager} from \"../../CullingManager\";\nimport {HitTester, type LayerOffset} from \"../../hit/HitTester\";\nimport {TypedEventEmitter} from \"../../TypedEventEmitter\";\nimport {InteractionHandler} from \"../../InteractionHandler\";\nimport {ScenePipeline, type SceneBuildResult, type DrawnExitEntry, type DrawnSpecialExitEntry, type DrawnStubEntry} from \"../../ScenePipeline\";\nimport {buildBuiltInOverlayShapes} from \"../../export/flushSceneShapes\";\nimport {layoutRoom} from \"../../scene/elements/RoomLayout\";\nimport {layoutInnerExits} from \"../../scene/elements/ExitLayout\";\nimport {computeSpecialExits} from \"../../scene/SpecialExitStyle\";\nimport {specialExitToShape} from \"../../scene/elements/SpecialExitLayout\";\nimport {computeStubs} from \"../../scene/StubStyle\";\nimport {stubToShape} from \"../../scene/elements/StubLayout\";\nimport type {Shape, GroupShape} from \"../../scene/Shape\";\nimport type {Style, StyleContext} from \"../../style/Style\";\nimport {identityStyle} from \"../../style/Style\";\nimport {applyStyleToShapes} from \"../../style/applyStyle\";\nimport type {CoordFn} from \"../../coord/CoordFn\";\nimport {IDENTITY_TRANSFORM} from \"../../coord/CoordFn\";\nimport type {SceneOverlay, SceneOverlayContext} from \"../../overlay/SceneOverlay\";\nimport type {LiveEffect} from \"../../overlay/LiveEffect\";\nimport type {ExportCanvas} from \"../../export/Exporter\";\nimport {serializeTransform} from \"./serializeTransform\";\nimport type {Bounds, LayerPayload, MainToWorkerMessage, WorkerToMainMessage} from \"./protocol\";\n\nconst currentRoomColor = \"rgb(120, 72, 0)\";\n\n/** Transport the backend talks to. A real `Worker` satisfies this directly. */\nexport interface WorkerTransport {\n postMessage(message: MainToWorkerMessage, transfer?: Transferable[]): void;\n addEventListener?(type: \"message\", handler: (ev: {data: WorkerToMainMessage}) => void): void;\n onmessage?: ((ev: {data: WorkerToMainMessage}) => void) | null;\n terminate?(): void;\n}\n\nexport interface OffscreenBackendOptions {\n /** Pre-created transport (used by the inline-worker factory and by tests). */\n transport?: WorkerTransport;\n /** Lazily create the transport. Ignored when {@link transport} is provided. */\n createTransport?: () => WorkerTransport;\n /** Override the device pixel ratio (tests / forcing 1x). */\n devicePixelRatio?: number;\n}\n\nfunction supportsOffscreen(): boolean {\n return (\n typeof document !== \"undefined\" &&\n typeof HTMLCanvasElement !== \"undefined\" &&\n typeof HTMLCanvasElement.prototype.transferControlToOffscreen === \"function\"\n );\n}\n\nexport class OffscreenCanvasBackend implements InteractiveBackend {\n readonly camera: Camera;\n readonly culling: CullingManager;\n readonly events: TypedEventEmitter<RendererEventMap>;\n readonly hitTester: HitTester = new HitTester();\n\n private readonly state: MapState;\n private readonly container?: HTMLDivElement;\n private readonly transport?: WorkerTransport;\n private readonly pipeline: ScenePipeline;\n private readonly dpr: number;\n\n private currentStyle: Style = identityStyle;\n private _coordinateTransform: CoordFn = IDENTITY_TRANSFORM;\n private coordinateInverse: CoordFn = IDENTITY_TRANSFORM;\n private coordinateLayerOffset: LayerOffset | undefined;\n\n private lastResult?: SceneBuildResult;\n private lastHitShapes: Shape[] = [];\n private boundsByShape: Map<Shape, Bounds> = new Map();\n\n private interactionHandler?: InteractionHandler;\n private cameraChangeHandler?: () => void;\n private readonly sceneOverlays: Map<string, SceneOverlay> = new Map();\n private readonly viewportSubscribers: Set<() => void> = new Set();\n private readonly liveEffects: Map<string, LiveEffect> = new Map();\n // Live effects can't run in the worker (Konva animations), so they render on\n // a main-thread Konva stage composited above the worker's canvas. The map\n // still rasterises off-thread; only the (light) effect animation is local.\n private liveEffectStage?: Konva.Stage;\n private liveEffectLayer?: Konva.Layer;\n private liveEffectHost?: HTMLDivElement;\n private readonly pendingExports: Map<number, (bitmap: ImageBitmap) => void> = new Map();\n private exportSeq = 0;\n private destroyed = false;\n\n constructor(state: MapState, container?: HTMLDivElement, options: OffscreenBackendOptions = {}) {\n this.state = state;\n this.container = container;\n this.pipeline = new ScenePipeline(state.mapReader, state.settings);\n this.dpr = options.devicePixelRatio ?? (typeof devicePixelRatio !== \"undefined\" ? devicePixelRatio : 1);\n this.transport = options.transport ?? options.createTransport?.();\n\n const width = container?.clientWidth ?? 1;\n const height = container?.clientHeight ?? 1;\n this.camera = new Camera(width, height);\n this.events = new TypedEventEmitter<RendererEventMap>(container);\n this.culling = new CullingManager(state.settings, () => {\n // Culling runs in the worker per camera frame; a mode change just\n // needs the fresh settings + a redraw.\n this.postSettings();\n this.postCamera();\n });\n\n if (this.transport) {\n const onMessage = (ev: {data: WorkerToMainMessage}) => this.handleWorkerMessage(ev.data);\n if (this.transport.addEventListener) this.transport.addEventListener(\"message\", onMessage);\n else this.transport.onmessage = onMessage;\n }\n\n if (container && this.transport && supportsOffscreen()) {\n // The map canvas and any live-effect overlay stack absolutely inside\n // the container, so it must establish a positioning context.\n if (getComputedStyle(container).position === \"static\") {\n container.style.position = \"relative\";\n }\n const canvas = document.createElement(\"canvas\");\n canvas.style.position = \"absolute\";\n canvas.style.inset = \"0\";\n canvas.style.width = \"100%\";\n canvas.style.height = \"100%\";\n canvas.style.display = \"block\";\n container.appendChild(canvas);\n container.style.backgroundColor = state.settings.backgroundColor;\n const offscreen = canvas.transferControlToOffscreen();\n this.transport.postMessage(\n {type: \"init\", canvas: offscreen, width, height, dpr: this.dpr, settings: state.settings},\n [offscreen],\n );\n\n this.interactionHandler = new InteractionHandler(container, this.camera, state, {\n clientToMapPoint: (cx, cy) => this.camera.clientToMapPoint(cx, cy, container.getBoundingClientRect()),\n pickAtPoint: (x, y) => this.hitTester.pick(x, y),\n }, this.events);\n }\n\n this.cameraChangeHandler = () => this.onCameraChange();\n this.camera.on(\"change\", this.cameraChangeHandler);\n\n this.applyStyleTransforms();\n this.subscribeToState(state);\n\n // Seed the worker with the current camera so it paints the background\n // before the first scene arrives.\n this.postCamera();\n }\n\n get coordinateTransform(): CoordFn {\n return this._coordinateTransform;\n }\n\n // --- Messaging ---\n\n private post(message: MainToWorkerMessage, transfer?: Transferable[]): void {\n if (this.destroyed || !this.transport) return;\n this.transport.postMessage(message, transfer);\n }\n\n private postSettings(): void {\n this.post({type: \"settings\", settings: this.state.settings});\n }\n\n private postCamera(): void {\n this.post({\n type: \"camera\",\n camera: {scale: this.camera.getScale(), offsetX: this.camera.position.x, offsetY: this.camera.position.y},\n viewport: this.camera.getViewportBounds(),\n width: this.camera.width,\n height: this.camera.height,\n });\n }\n\n private postScene(): void {\n const result = this.lastResult;\n if (!result) {\n this.post({\n type: \"scene\",\n link: {shapes: [], bounds: []},\n room: {shapes: [], bounds: []},\n topLabel: [],\n transform: serializeTransform(this.currentStyle),\n });\n return;\n }\n const ctx = this.styleContext();\n this.post({\n type: \"scene\",\n link: this.styleLayer(result.sceneShapes.link, ctx),\n room: this.styleLayer(result.sceneShapes.room, ctx),\n topLabel: this.styleShapes(result.sceneShapes.topLabel, ctx),\n transform: serializeTransform(this.currentStyle),\n });\n }\n\n private postOverlays(): void {\n const ctx = this.styleContext();\n const out: Shape[] = [];\n for (const s of this.buildCurrentRoomOverlayShapes()) out.push(...this.styleOne(s, ctx, false));\n for (const s of buildBuiltInOverlayShapes(this.state)) out.push(...this.styleOne(s, ctx, false));\n for (const overlay of this.sceneOverlays.values()) {\n const rendered = overlay.render(this.state, this.camera.getViewportBounds());\n if (!rendered) continue;\n const shapes = Array.isArray(rendered) ? rendered : [rendered];\n for (const s of shapes) out.push(...this.styleOne(s, ctx, overlay.sceneSpace ?? false));\n }\n this.post({type: \"overlays\", shapes: out});\n }\n\n // --- Styling helpers ---\n\n private styleContext(): StyleContext {\n return {scale: this.camera.getScale(), roomSize: this.state.settings.roomSize};\n }\n\n private styleOne(shape: Shape, ctx: StyleContext, bypass: boolean): Shape[] {\n if (bypass || this.currentStyle === identityStyle) return [shape];\n return applyStyleToShapes([shape], this.currentStyle, ctx);\n }\n\n private styleShapes(shapes: Shape[], ctx: StyleContext): Shape[] {\n if (this.currentStyle === identityStyle) return shapes;\n return applyStyleToShapes(shapes, this.currentStyle, ctx);\n }\n\n /** Style a scene layer, carrying each shape's world-space cull bounds through. */\n private styleLayer(shapes: Shape[], ctx: StyleContext): LayerPayload {\n const outShapes: Shape[] = [];\n const outBounds: Array<Bounds | null> = [];\n for (const shape of shapes) {\n const b = this.boundsByShape.get(shape) ?? null;\n const styled = this.currentStyle === identityStyle ? [shape] : applyStyleToShapes([shape], this.currentStyle, ctx);\n for (const s of styled) {\n outShapes.push(s);\n outBounds.push(b);\n }\n }\n return {shapes: outShapes, bounds: outBounds};\n }\n\n // --- Scene build ---\n\n refresh(): void {\n const {currentAreaInstance, currentZIndex, positionRoomId} = this.state;\n if (!currentAreaInstance || currentZIndex === undefined) return;\n const plane = currentAreaInstance.getPlane(currentZIndex);\n if (!plane) {\n this.lastResult = undefined;\n this.lastHitShapes = [];\n this.boundsByShape.clear();\n this.hitTester.clear();\n this.postSettings();\n this.postScene();\n this.postOverlays();\n this.postCamera();\n return;\n }\n\n const result = this.pipeline.buildScene(currentAreaInstance, plane, currentZIndex, this.state.lens);\n this.lastResult = result;\n this.lastHitShapes = result.hitShapes;\n this.boundsByShape = this.buildBoundsMap(result);\n this.hitTester.build(this.lastHitShapes, this.state.settings.roomSize, this._coordinateTransform, this.coordinateLayerOffset);\n\n if (this.container) this.container.style.backgroundColor = this.state.settings.backgroundColor;\n\n this.postSettings();\n this.postScene();\n this.postOverlays();\n this.postCamera();\n\n // Position marker handled inside postOverlays; nothing else needed.\n void positionRoomId;\n }\n\n private buildBoundsMap(result: SceneBuildResult): Map<Shape, Bounds> {\n const map = new Map<Shape, Bounds>();\n const half = this.state.settings.roomSize / 2;\n for (const {room, shape} of result.roomShapeRefs.values()) {\n map.set(shape, {x: room.x - half, y: room.y - half, width: this.state.settings.roomSize, height: this.state.settings.roomSize});\n }\n for (const {shape, bounds} of result.standaloneExitShapeRefs) map.set(shape, bounds);\n for (const {shape, bounds} of result.labelShapeRefs) map.set(shape, bounds);\n for (const {shape, bounds} of result.specialExitShapeRefs) map.set(shape, bounds);\n for (const {shape, bounds} of result.stubShapeRefs) map.set(shape, bounds);\n for (const {shape, bounds} of result.areaExitLabelShapeRefs) map.set(shape, bounds);\n return map;\n }\n\n /** Port of {@link KonvaRenderBackend.updateCurrentRoomOverlay} returning shapes. */\n private buildCurrentRoomOverlayShapes(): Shape[] {\n const state = this.state;\n const roomId = state.positionRoomId;\n if (roomId === undefined) return [];\n const room = state.mapReader.getRoom(roomId);\n if (!room) return [];\n if (room.area !== state.currentArea || room.z !== state.currentZIndex) return [];\n const settings = state.settings;\n if (!settings.highlightCurrentRoom) return [];\n\n const out: Shape[] = [];\n const exitRenderer = this.pipeline.exitRenderer;\n const lens = state.lens;\n const roomsToRedraw = new Map<number, MapData.Room>();\n roomsToRedraw.set(room.id, room);\n\n if (state.currentAreaInstance && state.currentZIndex !== undefined) {\n const exits = state.currentAreaInstance\n .getLinkExits(state.currentZIndex)\n .filter(exit => exit.a === room.id || exit.b === room.id);\n for (const exit of exits) {\n const data = exitRenderer.renderDataWithColor(exit, currentRoomColor, state.currentZIndex);\n if (data) out.push(this.pipeline.buildExitShape(data));\n }\n }\n for (const se of computeSpecialExits(room, settings, currentRoomColor)) out.push(specialExitToShape(se, room.id));\n for (const stub of computeStubs(room, settings, currentRoomColor)) out.push(stubToShape(stub));\n\n [...Object.values(room.exits), ...Object.values(room.specialExits)].forEach(id => {\n const other = state.mapReader.getRoom(id as number);\n if (other && other.area === state.currentArea && other.z === state.currentZIndex && lens.isVisible(other)) {\n roomsToRedraw.set(other.id, other);\n }\n });\n\n roomsToRedraw.forEach((roomToRedraw, id) => {\n const isCurrent = id === room.id;\n const overlayShape: GroupShape = layoutRoom(roomToRedraw, state.mapReader, settings, {\n strokeOverride: isCurrent ? currentRoomColor : settings.lineColor,\n flatPipeline: true,\n });\n overlayShape.children.push(...layoutInnerExits(roomToRedraw, state.mapReader, settings));\n out.push(overlayShape);\n });\n\n return out;\n }\n\n // --- Style transform (mirrors KonvaRenderBackend.applyStyleTransforms) ---\n\n setStyle(style: Style): void {\n this.currentStyle = style;\n this.lastHitShapes = [];\n this.hitTester.clear();\n this.applyStyleTransforms();\n this.refresh();\n }\n\n private applyStyleTransforms(): void {\n const style = this.currentStyle;\n const forward: CoordFn = style.worldToScene ? (x, y) => style.worldToScene!(x, y) : IDENTITY_TRANSFORM;\n const newInverse: CoordFn = style.sceneToWorld ? (x, y) => style.sceneToWorld!(x, y) : IDENTITY_TRANSFORM;\n const oldInverse = this.coordinateInverse;\n const layerOffset: LayerOffset | undefined = style.sceneLayerOffset ? (layer) => style.sceneLayerOffset!(layer) : undefined;\n\n this._coordinateTransform = forward;\n this.coordinateInverse = newInverse;\n this.coordinateLayerOffset = layerOffset;\n this.culling.setCoordinateTransform(forward);\n if (this.lastHitShapes.length > 0) {\n this.hitTester.build(this.lastHitShapes, this.state.settings.roomSize, forward, layerOffset);\n }\n\n // Keep the same map point centred when the projection changes.\n const scale = this.camera.getScale();\n const screenCX = this.camera.width / 2;\n const screenCY = this.camera.height / 2;\n const oldRX = (screenCX - this.camera.position.x) / scale;\n const oldRY = (screenCY - this.camera.position.y) / scale;\n const map = oldInverse(oldRX, oldRY);\n const nr = forward(map.x, map.y);\n this.camera.position = {x: screenCX - nr.x * scale, y: screenCY - nr.y * scale};\n // position assignment does not notify; the upcoming refresh posts camera.\n }\n\n // --- Camera ---\n\n private onCameraChange(): void {\n this.postCamera();\n const vpBounds = this.camera.getViewportBounds();\n this.events.emit(\"pan\", vpBounds);\n for (const cb of this.viewportSubscribers) cb();\n if (this.liveEffectStage) {\n this.syncEffectStage();\n const scale = this.camera.getScale();\n for (const effect of this.liveEffects.values()) {\n effect.updateViewport(vpBounds, scale, this._coordinateTransform);\n }\n }\n }\n\n // --- State subscriptions ---\n\n private subscribeToState(state: MapState): void {\n state.events.on(\"area\", () => this.refresh());\n state.events.on(\"position\", ({roomId, center, areaChanged}) => this.onPositionChanged(roomId, center, areaChanged));\n state.events.on(\"center\", ({roomId, instant}) => {\n const room = state.mapReader.getRoom(roomId);\n if (room) {\n const p = this._coordinateTransform(room.x, room.y);\n this.camera.panToMapPointAnimated(p.x, p.y, instant || this.state.settings.instantMapMove);\n }\n });\n state.events.on(\"highlight\", () => this.postOverlays());\n state.events.on(\"path\", () => this.postOverlays());\n state.events.on(\"clear\", () => this.postOverlays());\n state.events.on(\"lens\", () => this.refresh());\n }\n\n private onPositionChanged(roomId: number | undefined, center: boolean, instant: boolean): void {\n if (roomId !== undefined && center) {\n const room = this.state.mapReader.getRoom(roomId);\n if (room) {\n const p = this._coordinateTransform(room.x, room.y);\n this.camera.panToMapPointAnimated(p.x, p.y, instant || this.state.settings.instantMapMove);\n }\n }\n this.postOverlays();\n }\n\n // --- Background ---\n\n updateBackground(): void {\n if (this.container) this.container.style.backgroundColor = this.state.settings.backgroundColor;\n this.postSettings();\n this.postCamera();\n }\n\n // --- Scene overlays ---\n\n addSceneOverlay(id: string, overlay: SceneOverlay): void {\n const existing = this.sceneOverlays.get(id);\n if (existing) existing.detach?.();\n this.sceneOverlays.set(id, overlay);\n overlay.attach?.(this.createOverlayContext(id, overlay));\n this.postOverlays();\n }\n\n removeSceneOverlay(id: string): void {\n const overlay = this.sceneOverlays.get(id);\n if (!overlay) return;\n overlay.detach?.();\n this.sceneOverlays.delete(id);\n this.postOverlays();\n }\n\n getSceneOverlays(): Iterable<SceneOverlay> {\n return this.sceneOverlays.values();\n }\n\n private createOverlayContext(id: string, overlay: SceneOverlay): SceneOverlayContext {\n return {\n state: this.state,\n onViewportChange: (cb) => {\n this.viewportSubscribers.add(cb);\n return () => this.viewportSubscribers.delete(cb);\n },\n invalidate: () => {\n if (this.sceneOverlays.get(id) !== overlay) return;\n this.postOverlays();\n },\n };\n }\n\n // --- Live effects (main-thread Konva overlay above the worker canvas) ---\n\n private ensureEffectStage(): void {\n if (this.liveEffectStage || !this.container) return;\n const host = document.createElement(\"div\");\n host.style.position = \"absolute\";\n host.style.inset = \"0\";\n host.style.pointerEvents = \"none\"; // never intercept interaction\n this.container.appendChild(host);\n const stage = new Konva.Stage({\n container: host,\n width: this.camera.width,\n height: this.camera.height,\n listening: false,\n });\n const layer = new Konva.Layer({listening: false});\n stage.add(layer);\n this.liveEffectHost = host;\n this.liveEffectStage = stage;\n this.liveEffectLayer = layer;\n this.syncEffectStage();\n }\n\n /** Mirror the camera transform onto the effect stage so effects align with the map. */\n private syncEffectStage(): void {\n const stage = this.liveEffectStage;\n if (!stage) return;\n if (stage.width() !== this.camera.width || stage.height() !== this.camera.height) {\n stage.width(this.camera.width);\n stage.height(this.camera.height);\n }\n const scale = this.camera.getScale();\n stage.scale({x: scale, y: scale});\n stage.position(this.camera.position);\n stage.batchDraw();\n }\n\n addLiveEffect(id: string, effect: LiveEffect): void {\n this.removeLiveEffect(id);\n this.ensureEffectStage();\n if (!this.liveEffectLayer) return; // headless / no container\n effect.attach(this.liveEffectLayer);\n this.liveEffects.set(id, effect);\n this.syncEffectStage();\n effect.updateViewport(this.camera.getViewportBounds(), this.camera.getScale(), this._coordinateTransform);\n }\n\n removeLiveEffect(id: string): void {\n const effect = this.liveEffects.get(id);\n if (!effect) return;\n effect.destroy();\n this.liveEffects.delete(id);\n this.liveEffectLayer?.batchDraw();\n }\n\n // --- Drawn-geometry snapshots (synchronous, from the last main-thread build) ---\n\n getDrawnExits(): readonly DrawnExitEntry[] {\n return this.lastResult?.drawnExits ?? [];\n }\n\n getDrawnSpecialExits(): readonly DrawnSpecialExitEntry[] {\n return this.lastResult?.drawnSpecialExits ?? [];\n }\n\n getDrawnStubs(): readonly DrawnStubEntry[] {\n return this.lastResult?.drawnStubs ?? [];\n }\n\n // --- Export ---\n\n /**\n * Not supported with the worker backend — the live canvas is owned by the\n * worker and cannot be read synchronously here. Use the headless\n * `CanvasExporter` / `PngBytesExporter` (they rebuild from state), or the\n * async {@link captureViewport} for a live snapshot.\n */\n exportCanvas(): ExportCanvas | undefined {\n return undefined;\n }\n\n /** Async live-viewport snapshot via a worker round-trip. */\n captureViewport(options?: {pixelRatio?: number}): Promise<ImageBitmap> {\n if (!this.transport) return Promise.reject(new Error(\"No worker transport\"));\n const requestId = ++this.exportSeq;\n return new Promise<ImageBitmap>((resolve) => {\n this.pendingExports.set(requestId, resolve);\n this.post({type: \"export\", requestId, pixelRatio: options?.pixelRatio ?? this.dpr});\n });\n }\n\n private handleWorkerMessage(message: WorkerToMainMessage): void {\n if (message.type === \"export\") {\n const resolve = this.pendingExports.get(message.requestId);\n if (resolve) {\n this.pendingExports.delete(message.requestId);\n resolve(message.bitmap);\n }\n }\n // 'ready' is informational; the worker buffers state until init.\n }\n\n // --- Teardown ---\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.state.events.removeAllListeners();\n this.interactionHandler?.destroy();\n\n for (const effect of this.liveEffects.values()) effect.destroy();\n this.liveEffects.clear();\n this.liveEffectStage?.destroy();\n this.liveEffectStage = undefined;\n this.liveEffectLayer = undefined;\n this.liveEffectHost?.remove();\n this.liveEffectHost = undefined;\n\n for (const overlay of this.sceneOverlays.values()) overlay.detach?.();\n this.sceneOverlays.clear();\n this.viewportSubscribers.clear();\n this.pendingExports.clear();\n\n this.camera.cancelAnimation();\n if (this.cameraChangeHandler) {\n this.camera.off(\"change\", this.cameraChangeHandler);\n this.cameraChangeHandler = undefined;\n }\n\n this.post({type: \"destroy\"});\n this.transport?.terminate?.();\n\n this.events.removeAllListeners();\n }\n}\n","/**\n * Opt-in OffscreenCanvas backend entry point.\n *\n * Renders the map in a Web Worker via `OffscreenCanvas`, moving the per-frame\n * rasterisation off the main thread. The default Konva backend is untouched —\n * you only get this when you wire it in explicitly:\n *\n * ```ts\n * import { MapRenderer } from \"mudlet-map-renderer\";\n * import { createOffscreenBackend } from \"mudlet-map-renderer/offscreen\";\n *\n * const renderer = new MapRenderer(reader, settings, container, createOffscreenBackend(container));\n * ```\n *\n * Note the `container` is passed twice: `MapRenderer`'s `backendFactory` hook\n * receives only the `MapState`, so the container is closed over by the factory.\n *\n * Supports image labels, the ambient-light overlay, and live effects (the last\n * via a main-thread Konva overlay stage; the map still rasterises off-thread).\n * The one limitation: `renderer.exportCanvas()` returns `undefined` (the live\n * canvas lives in the worker) — use the headless `CanvasExporter` /\n * `PngBytesExporter` exporters, or `backend.captureViewport()`.\n */\n\nimport type {MapState} from \"../../MapState\";\nimport type {InteractiveBackend} from \"../MapRenderer\";\nimport {OffscreenCanvasBackend, type OffscreenBackendOptions, type WorkerTransport} from \"./OffscreenCanvasBackend\";\nimport OffscreenWorker from \"./worker?worker&inline\";\n\nexport {OffscreenCanvasBackend} from \"./OffscreenCanvasBackend\";\nexport type {OffscreenBackendOptions, WorkerTransport} from \"./OffscreenCanvasBackend\";\nexport type {MainToWorkerMessage, WorkerToMainMessage, SerializableTransform} from \"./protocol\";\n\n/**\n * Build a backend factory for {@link MapRenderer}'s `backendFactory` parameter.\n * Pass the same `container` you give `MapRenderer`.\n */\nexport function createOffscreenBackend(\n container?: HTMLDivElement,\n options: OffscreenBackendOptions = {},\n): (state: MapState) => InteractiveBackend {\n return (state: MapState) =>\n new OffscreenCanvasBackend(state, container, {\n ...options,\n createTransport: options.createTransport ?? (() => new OffscreenWorker() as unknown as WorkerTransport),\n });\n}\n"],"mappings":"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"}
|
|
@@ -43,6 +43,18 @@ export interface SceneOverlayContext {
|
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
45
|
export interface SceneOverlay {
|
|
46
|
+
/**
|
|
47
|
+
* Optional. When `true`, {@link render} returns shapes already in
|
|
48
|
+
* **rendered/scene space** (i.e. post-Style projection), so the active
|
|
49
|
+
* {@link Style} transform is skipped for this overlay. Use this for
|
|
50
|
+
* overlays that visualise data the renderer has already projected — e.g.
|
|
51
|
+
* a hit-area debug overlay built from {@link HitTester} geometry, which is
|
|
52
|
+
* stored in rendered space. Without it, coordinate-warping styles
|
|
53
|
+
* (Isometric) would project the geometry a second time, offsetting it.
|
|
54
|
+
*
|
|
55
|
+
* Defaults to `false`: shapes are world-space and pass through the Style.
|
|
56
|
+
*/
|
|
57
|
+
readonly sceneSpace?: boolean;
|
|
46
58
|
/**
|
|
47
59
|
* Optional. Called once when the overlay is registered with an interactive
|
|
48
60
|
* renderer. Subscribe to events here and call `ctx.invalidate()` when the
|
|
@@ -60,9 +72,10 @@ export interface SceneOverlay {
|
|
|
60
72
|
* Contribute geometry to the scene. Called on register, on invalidate, and
|
|
61
73
|
* by every exporter.
|
|
62
74
|
*
|
|
63
|
-
* @returns one or more world-space {@link Shape}s
|
|
64
|
-
*
|
|
65
|
-
*
|
|
75
|
+
* @returns one or more world-space {@link Shape}s (or rendered-space when
|
|
76
|
+
* {@link sceneSpace} is `true`), or `void` to emit nothing this frame.
|
|
77
|
+
* Shapes carry their own {@link Shape.layer} hint; leaving it unset
|
|
78
|
+
* routes them to the overlay layer.
|
|
66
79
|
*/
|
|
67
80
|
render(state: MapState, bounds: ViewportBounds): Shape | Shape[] | void;
|
|
68
81
|
}
|
|
@@ -60,6 +60,7 @@ export declare class KonvaRenderBackend implements InteractiveBackend {
|
|
|
60
60
|
private destroyed;
|
|
61
61
|
private _coordinateTransform;
|
|
62
62
|
private coordinateInverse;
|
|
63
|
+
private coordinateLayerOffset;
|
|
63
64
|
get coordinateTransform(): CoordFn;
|
|
64
65
|
private liveEffects;
|
|
65
66
|
private sceneOverlays;
|
|
@@ -102,6 +103,9 @@ export declare class KonvaRenderBackend implements InteractiveBackend {
|
|
|
102
103
|
* relationship between input shape and tracked handle, so callers that cache
|
|
103
104
|
* the return value (position marker, scene overlays, highlights, current-room
|
|
104
105
|
* overlay, paths) can destroy the entire expansion through that one handle.
|
|
106
|
+
*
|
|
107
|
+
* `bypassStyle` skips the Style transform entirely — used for overlays whose
|
|
108
|
+
* geometry is already in rendered space (e.g. hit-area debug visualisation).
|
|
105
109
|
*/
|
|
106
110
|
private addStyledShape;
|
|
107
111
|
/**
|
|
@@ -54,6 +54,14 @@ export interface InteractiveBackend {
|
|
|
54
54
|
getDrawnSpecialExits(): readonly DrawnSpecialExitEntry[];
|
|
55
55
|
/** Companion to {@link getDrawnExits} for one-way stub indicators. */
|
|
56
56
|
getDrawnStubs(): readonly DrawnStubEntry[];
|
|
57
|
+
/**
|
|
58
|
+
* Register an interactive-only animated effect. Optional: backends that
|
|
59
|
+
* cannot host animated effects omit it (the facade then no-ops). Both the
|
|
60
|
+
* Konva and OffscreenCanvas backends implement it.
|
|
61
|
+
*/
|
|
62
|
+
addLiveEffect?(id: string, effect: LiveEffect): void;
|
|
63
|
+
/** Companion to {@link addLiveEffect}. */
|
|
64
|
+
removeLiveEffect?(id: string): void;
|
|
57
65
|
destroy(): void;
|
|
58
66
|
}
|
|
59
67
|
/**
|
|
@@ -145,9 +153,10 @@ export declare class MapRenderer {
|
|
|
145
153
|
addSceneOverlay(id: string, overlay: SceneOverlay): void;
|
|
146
154
|
removeSceneOverlay(id: string): void;
|
|
147
155
|
/**
|
|
148
|
-
* Register an interactive-only animated effect.
|
|
149
|
-
*
|
|
150
|
-
* {@link addSceneOverlay} for
|
|
156
|
+
* Register an interactive-only animated effect. Supported by the Konva and
|
|
157
|
+
* OffscreenCanvas backends; no-ops on backends that don't host effects.
|
|
158
|
+
* Does not appear in SVG/PNG exports — use {@link addSceneOverlay} for
|
|
159
|
+
* overlays that must appear in exports.
|
|
151
160
|
*
|
|
152
161
|
* ```ts
|
|
153
162
|
* renderer.addLiveEffect('rain', new RainEffect());
|