mudlet-map-renderer 0.33.0-konva → 0.34.1-konva
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 +141 -21
- package/dist/ExitRenderer.d.ts +44 -0
- package/dist/ScenePipeline.d.ts +15 -2
- package/dist/Viewport.d.ts +12 -0
- package/dist/backend/DrawingBackend.d.ts +49 -6
- package/dist/export/CanvasExporter.d.ts +67 -0
- package/dist/export/Exporter.d.ts +57 -0
- package/dist/export/PngExporter.d.ts +23 -0
- package/dist/export/SvgExporter.d.ts +15 -0
- package/dist/export/canvasToBytes.d.ts +19 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +19 -17
- package/dist/index.mjs +1184 -1109
- package/dist/index.mjs.map +1 -1
- package/dist/overlay/AmbientLightOverlay.d.ts +32 -0
- package/dist/overlay/LiveEffect.d.ts +33 -0
- package/dist/overlay/SceneOverlay.d.ts +63 -0
- package/dist/rendering/KonvaRenderBackend.d.ts +31 -9
- package/dist/rendering/MapRenderer.d.ts +64 -36
- package/dist/scene/AmbientLightStyle.d.ts +7 -2
- package/dist/{backend/BlueprintBackend.d.ts → style/BlueprintStyle.d.ts} +2 -12
- package/dist/{backend/IsometricBackend.d.ts → style/IsometricStyle.d.ts} +5 -6
- package/dist/{backend/NeonBackend.d.ts → style/NeonStyle.d.ts} +2 -12
- package/dist/{backend/ParchmentBackend.d.ts → style/ParchmentStyle.d.ts} +6 -16
- package/dist/{backend/SketchyBackend.d.ts → style/SketchyStyle.d.ts} +4 -13
- package/dist/style/index.d.ts +32 -0
- package/dist/types/Settings.d.ts +3 -17
- package/package.json +1 -1
- package/dist/HeadlessRenderer.d.ts +0 -64
- package/dist/MapRenderer.d.ts +0 -23
- package/dist/Renderer.d.ts +0 -56
- package/dist/rendering/SvgRenderBackend.d.ts +0 -21
- package/dist/types/OverlayPlugin.d.ts +0 -44
package/README.md
CHANGED
|
@@ -186,37 +186,97 @@ For large maps, spatial culling hides off-screen rooms for better performance:
|
|
|
186
186
|
renderer.setCullingMode('indexed');
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
###
|
|
189
|
+
### Styles
|
|
190
|
+
|
|
191
|
+
A `Style` is a target-agnostic visual transformer. One style drives the
|
|
192
|
+
interactive canvas *and* every exporter — set it once and it applies to SVG,
|
|
193
|
+
PNG, and anything else you export.
|
|
190
194
|
|
|
191
195
|
```ts
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
196
|
+
import {
|
|
197
|
+
compose, identityStyle,
|
|
198
|
+
Parchment, Blueprint, Neon, Sketchy, Isometric,
|
|
199
|
+
} from 'mudlet-map-renderer';
|
|
200
|
+
|
|
201
|
+
// Single style
|
|
202
|
+
renderer.setStyle(Parchment);
|
|
203
|
+
|
|
204
|
+
// Compose a chain (left → right = inner → outer)
|
|
205
|
+
renderer.setStyle(compose(
|
|
206
|
+
Parchment,
|
|
207
|
+
Sketchy({ jitter: 0.012, color: '#4a3728' }),
|
|
208
|
+
Isometric({ rotation: 30, depth: 0.18 }),
|
|
209
|
+
));
|
|
210
|
+
|
|
211
|
+
// Clear the current style
|
|
212
|
+
renderer.setStyle(identityStyle);
|
|
213
|
+
// or
|
|
214
|
+
renderer.clearStyle();
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Built-in styles:
|
|
218
|
+
|
|
219
|
+
| Style | Effect |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `Parchment` | Warm sepia / aged-paper palette |
|
|
222
|
+
| `Blueprint` | White lines on deep blue |
|
|
223
|
+
| `Neon` | Glowing neon outlines on dark background |
|
|
224
|
+
| `Sketchy({ jitter, color })` | Hand-drawn pencil wobble |
|
|
225
|
+
| `Isometric({ rotation?, depth? })` | 2:1 iso projection with optional cubes |
|
|
226
|
+
|
|
227
|
+
Custom styles extend `BaseStyle<Inner>` and override only the draw calls they
|
|
228
|
+
transform — see the built-ins for examples.
|
|
229
|
+
|
|
230
|
+
### Export
|
|
195
231
|
|
|
196
|
-
|
|
197
|
-
|
|
232
|
+
Exporters are plug-ins: a new output format is a new `Exporter<T>` class,
|
|
233
|
+
not a new `MapRenderer` method.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
import {
|
|
237
|
+
SvgExporter, PngExporter, PngBlobExporter, CanvasExporter,
|
|
238
|
+
} from 'mudlet-map-renderer';
|
|
239
|
+
|
|
240
|
+
// SVG (string)
|
|
241
|
+
const svg = renderer.export(new SvgExporter());
|
|
242
|
+
const svgCentered = renderer.export(new SvgExporter({ roomId: 1234, padding: 5 }));
|
|
243
|
+
const svgTyped = renderer.export(new SvgExporter({
|
|
198
244
|
overlays: {
|
|
199
245
|
position: { roomId: 1234 },
|
|
200
246
|
highlights: [{ roomId: 100, color: '#ff0000' }],
|
|
201
247
|
paths: [{ locations: [101, 102, 103], color: '#00ff00' }],
|
|
202
248
|
},
|
|
203
|
-
});
|
|
249
|
+
}));
|
|
204
250
|
|
|
205
|
-
// PNG
|
|
206
|
-
const
|
|
251
|
+
// PNG data URL
|
|
252
|
+
const pngUrl = renderer.export(new PngExporter({ pixelRatio: 2 }));
|
|
207
253
|
|
|
208
|
-
// PNG
|
|
209
|
-
const blob = await renderer.
|
|
254
|
+
// PNG as Blob
|
|
255
|
+
const blob = await renderer.export(new PngBlobExporter({ pixelRatio: 2 }));
|
|
210
256
|
|
|
211
|
-
//
|
|
212
|
-
const
|
|
257
|
+
// Headless PNG bytes at a specific size (portable — works in browser + Node)
|
|
258
|
+
const png = renderer.export(new PngBytesExporter({
|
|
213
259
|
width: 1920,
|
|
214
260
|
height: 1080,
|
|
215
261
|
roomId: 1234,
|
|
216
262
|
padding: 5,
|
|
217
|
-
});
|
|
263
|
+
}));
|
|
264
|
+
// fs.writeFileSync('out.png', png!); // Node
|
|
265
|
+
// new Blob([png!], { type: 'image/png' }); // Browser
|
|
266
|
+
|
|
267
|
+
// Canvas handle (if you need to draw more on it, attach to DOM, etc.)
|
|
268
|
+
const canvas = renderer.export(new CanvasExporter({
|
|
269
|
+
width: 1920,
|
|
270
|
+
height: 1080,
|
|
271
|
+
}));
|
|
218
272
|
```
|
|
219
273
|
|
|
274
|
+
Style + export compose: the style currently applied with `setStyle` is passed
|
|
275
|
+
to every exporter, so the SVG, the PNG, and the on-screen canvas stay in sync.
|
|
276
|
+
|
|
277
|
+
Writing a new exporter — e.g. PDF — means shipping a class that implements
|
|
278
|
+
`Exporter<Uint8Array>`. No changes to `MapRenderer`.
|
|
279
|
+
|
|
220
280
|
### Headless rendering (no DOM)
|
|
221
281
|
|
|
222
282
|
For server-side or offscreen rendering, omit the container argument:
|
|
@@ -225,10 +285,45 @@ For server-side or offscreen rendering, omit the container argument:
|
|
|
225
285
|
const renderer = new MapRenderer(mapReader, createSettings());
|
|
226
286
|
|
|
227
287
|
renderer.drawArea(42, 0);
|
|
228
|
-
renderer.
|
|
288
|
+
renderer.state.positionRoomId = 1234; // mark player position without auto-centering
|
|
229
289
|
|
|
230
|
-
const svg = renderer.
|
|
231
|
-
const
|
|
290
|
+
const svg = renderer.export(new SvgExporter({ padding: 5 }));
|
|
291
|
+
const png = renderer.export(new PngBytesExporter({ width: 1920, height: 1080 }));
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Overlays
|
|
295
|
+
|
|
296
|
+
Two kinds, picked by what you need:
|
|
297
|
+
|
|
298
|
+
- **`SceneOverlay`** — target-agnostic, appears in every output (interactive
|
|
299
|
+
canvas + every exporter). Use for static scene content (badges, annotations).
|
|
300
|
+
- **`LiveEffect`** — interactive canvas only, receives a Konva layer and
|
|
301
|
+
viewport updates for animation. Skipped by exporters.
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import type { SceneOverlay, LiveEffect } from 'mudlet-map-renderer';
|
|
305
|
+
|
|
306
|
+
// Scene overlay — uses target-agnostic draw primitives
|
|
307
|
+
class BadgeOverlay implements SceneOverlay {
|
|
308
|
+
render(target, state, bounds) {
|
|
309
|
+
const g = target.createGroup(0, 0);
|
|
310
|
+
target.addCircle(g, { cx: 5, cy: 5, radius: 0.4, fill: '#ff0' });
|
|
311
|
+
return g;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
renderer.addSceneOverlay('badge', new BadgeOverlay());
|
|
316
|
+
renderer.removeSceneOverlay('badge');
|
|
317
|
+
|
|
318
|
+
// Live effect — gets a Konva layer, interactive only
|
|
319
|
+
class Pulse implements LiveEffect {
|
|
320
|
+
attach(layer) { /* add Konva shapes */ }
|
|
321
|
+
updateViewport(bounds, scale) { /* react to pan/zoom */ }
|
|
322
|
+
destroy() { /* cleanup */ }
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
renderer.addLiveEffect('pulse', new Pulse());
|
|
326
|
+
renderer.removeLiveEffect('pulse');
|
|
232
327
|
```
|
|
233
328
|
|
|
234
329
|
### Cleanup
|
|
@@ -360,16 +455,41 @@ MudletMapReader.exportJson(map, 'map.json');
|
|
|
360
455
|
| `setZoom(zoom)` | Set zoom level |
|
|
361
456
|
| `zoomToCenter(zoom)` | Zoom keeping center fixed |
|
|
362
457
|
| `fitArea()` | Fit the full area in view |
|
|
363
|
-
| `
|
|
364
|
-
| `
|
|
365
|
-
| `
|
|
366
|
-
| `
|
|
458
|
+
| `setStyle(style)` | Apply a visual style (interactive + exporters) |
|
|
459
|
+
| `clearStyle()` | Remove the current style |
|
|
460
|
+
| `export(exporter)` | Run an `Exporter<T>` and return its output |
|
|
461
|
+
| `addSceneOverlay(id, overlay)` | Add a target-agnostic overlay |
|
|
462
|
+
| `removeSceneOverlay(id)` | Remove a scene overlay |
|
|
463
|
+
| `addLiveEffect(id, effect)` | Add an interactive-only animated effect |
|
|
464
|
+
| `removeLiveEffect(id)` | Remove a live effect |
|
|
367
465
|
| `refresh()` | Force a full re-render |
|
|
368
466
|
| `on(event, handler)` | Subscribe to an event |
|
|
369
467
|
| `off(event, handler)` | Unsubscribe from an event |
|
|
370
468
|
| `setCullingMode(mode)` | Set culling strategy |
|
|
371
469
|
| `destroy()` | Release all resources |
|
|
372
470
|
|
|
471
|
+
### Exporters
|
|
472
|
+
|
|
473
|
+
| Exporter | Output |
|
|
474
|
+
|---|---|
|
|
475
|
+
| `SvgExporter({ roomId?, padding?, overlays? })` | `string` — SVG document |
|
|
476
|
+
| `PngExporter({ pixelRatio? })` | `string` — PNG data URL (current viewport) |
|
|
477
|
+
| `PngBlobExporter({ pixelRatio? })` | `Promise<Blob>` — PNG Blob (browser only) |
|
|
478
|
+
| `PngBytesExporter({ width, height, roomId?, padding?, overlays?, mimeType?, quality? })` | `Uint8Array` — headless PNG/JPEG bytes; portable (browser + Node) |
|
|
479
|
+
| `CanvasExporter({ width, height, roomId?, padding?, overlays? })` | `ExportCanvas` — canvas handle; reframes to fit |
|
|
480
|
+
|
|
481
|
+
### Styles
|
|
482
|
+
|
|
483
|
+
| Style | Constructor / Usage |
|
|
484
|
+
|---|---|
|
|
485
|
+
| `Parchment` | `setStyle(Parchment)` |
|
|
486
|
+
| `Blueprint` | `setStyle(Blueprint)` |
|
|
487
|
+
| `Neon` | `setStyle(Neon)` |
|
|
488
|
+
| `Sketchy(opts)` | `setStyle(Sketchy({ jitter, color }))` |
|
|
489
|
+
| `Isometric(opts)` | `setStyle(Isometric({ rotation?, depth? }))` |
|
|
490
|
+
| `compose(...)` | Chain multiple styles into one |
|
|
491
|
+
| `identityStyle` | Pass-through; equivalent to `clearStyle()` |
|
|
492
|
+
|
|
373
493
|
### `PathFinder`
|
|
374
494
|
|
|
375
495
|
| Method | Description |
|
package/dist/ExitRenderer.d.ts
CHANGED
|
@@ -36,6 +36,18 @@ export type ExitDrawData = {
|
|
|
36
36
|
};
|
|
37
37
|
/** Set when this exit leads to a room in a different area (cross-area exit). */
|
|
38
38
|
targetRoomId?: number;
|
|
39
|
+
/** Source room center in map coords — used to compute label direction. */
|
|
40
|
+
from?: {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
};
|
|
44
|
+
/** Arrow tip / far endpoint in map coords — anchor for placed labels. */
|
|
45
|
+
tip?: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
};
|
|
49
|
+
/** Stroke colour of the rendered arrow — used to colour area-exit labels. */
|
|
50
|
+
arrowColor?: string;
|
|
39
51
|
};
|
|
40
52
|
export default class ExitRenderer {
|
|
41
53
|
private mapReader;
|
|
@@ -53,6 +65,29 @@ export default class ExitRenderer {
|
|
|
53
65
|
/**
|
|
54
66
|
* Returns hit-zone bounds for special exits (custom lines) that lead to rooms in another area.
|
|
55
67
|
*/
|
|
68
|
+
/**
|
|
69
|
+
* Hit zones for cross-area inner exits (up/down/in/out). These are drawn as
|
|
70
|
+
* triangles inside the room, not through the exit pipeline, so they need
|
|
71
|
+
* their own plumbing for area-exit labelling and clickability.
|
|
72
|
+
*/
|
|
73
|
+
getInnerExitAreaTargets(room: MapData.Room): {
|
|
74
|
+
bounds: {
|
|
75
|
+
x: number;
|
|
76
|
+
y: number;
|
|
77
|
+
width: number;
|
|
78
|
+
height: number;
|
|
79
|
+
};
|
|
80
|
+
targetRoomId: number;
|
|
81
|
+
from: {
|
|
82
|
+
x: number;
|
|
83
|
+
y: number;
|
|
84
|
+
};
|
|
85
|
+
tip: {
|
|
86
|
+
x: number;
|
|
87
|
+
y: number;
|
|
88
|
+
};
|
|
89
|
+
arrowColor: string;
|
|
90
|
+
}[];
|
|
56
91
|
getSpecialExitAreaTargets(room: MapData.Room): {
|
|
57
92
|
bounds: {
|
|
58
93
|
x: number;
|
|
@@ -61,5 +96,14 @@ export default class ExitRenderer {
|
|
|
61
96
|
height: number;
|
|
62
97
|
};
|
|
63
98
|
targetRoomId: number;
|
|
99
|
+
from: {
|
|
100
|
+
x: number;
|
|
101
|
+
y: number;
|
|
102
|
+
};
|
|
103
|
+
tip: {
|
|
104
|
+
x: number;
|
|
105
|
+
y: number;
|
|
106
|
+
};
|
|
107
|
+
arrowColor: string;
|
|
64
108
|
}[];
|
|
65
109
|
}
|
package/dist/ScenePipeline.d.ts
CHANGED
|
@@ -24,6 +24,18 @@ export type StandaloneExitEntry = {
|
|
|
24
24
|
export type AreaExitHitZone = {
|
|
25
25
|
bounds: Bounds;
|
|
26
26
|
targetRoomId: number;
|
|
27
|
+
/** Source room center — used to compute arrow direction for labels. Optional for back-compat. */
|
|
28
|
+
from?: {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
};
|
|
32
|
+
/** Arrow tip / far endpoint — anchor for placed labels. Optional for back-compat. */
|
|
33
|
+
tip?: {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
};
|
|
37
|
+
/** Stroke colour of the rendered arrow — used to colour area-exit labels. */
|
|
38
|
+
arrowColor?: string;
|
|
27
39
|
};
|
|
28
40
|
export type SceneBuildResult = {
|
|
29
41
|
roomNodes: Map<number, RoomNodeEntry>;
|
|
@@ -34,8 +46,8 @@ export type SceneBuildResult = {
|
|
|
34
46
|
* Backend-agnostic scene composition pipeline.
|
|
35
47
|
* Drives a DrawingBackend + LayerNode to render the full map scene.
|
|
36
48
|
*
|
|
37
|
-
* Both KonvaRenderBackend and
|
|
38
|
-
* with their respective DrawingBackend
|
|
49
|
+
* Both the interactive KonvaRenderBackend and exporters (SvgExporter,
|
|
50
|
+
* CanvasExporter, …) drive this pipeline with their respective DrawingBackend.
|
|
39
51
|
*/
|
|
40
52
|
export declare class ScenePipeline {
|
|
41
53
|
private readonly mapReader;
|
|
@@ -70,6 +82,7 @@ export declare class ScenePipeline {
|
|
|
70
82
|
renderExitData(data: ExitDrawData): GroupNode;
|
|
71
83
|
private renderArrow;
|
|
72
84
|
private renderLabels;
|
|
85
|
+
private renderAreaExitLabels;
|
|
73
86
|
private renderAreaName;
|
|
74
87
|
}
|
|
75
88
|
export {};
|
package/dist/Viewport.d.ts
CHANGED
|
@@ -52,6 +52,18 @@ export declare class Viewport {
|
|
|
52
52
|
* Center on a map coordinate, with optional animation.
|
|
53
53
|
*/
|
|
54
54
|
panToMapPointAnimated(x: number, y: number, instant: boolean): void;
|
|
55
|
+
/**
|
|
56
|
+
* Compute the zoom level that would fit the given map bounds in the current
|
|
57
|
+
* viewport (with the same padding/insets as {@link fitToMapBounds}). Useful
|
|
58
|
+
* for updating `minZoom` to lock zoom-out to an area without changing the
|
|
59
|
+
* current zoom or position.
|
|
60
|
+
*/
|
|
61
|
+
computeFitZoom(minX: number, maxX: number, minY: number, maxY: number, insets?: {
|
|
62
|
+
top?: number;
|
|
63
|
+
right?: number;
|
|
64
|
+
bottom?: number;
|
|
65
|
+
left?: number;
|
|
66
|
+
}): number;
|
|
55
67
|
/**
|
|
56
68
|
* Fit the viewport to show the given map bounds with padding.
|
|
57
69
|
* Optional `insets` (screen pixels) reserve space at each edge — content
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Low-level drawing primitives. A {@link DrawingBackend} is a thin abstraction
|
|
3
|
+
* over per-node draw calls. Leaf implementations target a specific rendering
|
|
4
|
+
* engine (Konva, raw Canvas2D, SVG strings, …); decorator implementations
|
|
5
|
+
* ({@link BaseStyle}) wrap another backend and transform the calls.
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
+
* End users should rarely touch this directly — prefer {@link Style} factories
|
|
8
|
+
* (Parchment, Sketchy(…), …) with {@link MapRenderer.setStyle}, and
|
|
9
|
+
* {@link Exporter} implementations with {@link MapRenderer.export}.
|
|
7
10
|
*/
|
|
8
11
|
export interface GroupNode {
|
|
9
12
|
setVisible(visible: boolean): void;
|
|
@@ -119,11 +122,51 @@ export interface DrawingBackend {
|
|
|
119
122
|
};
|
|
120
123
|
/**
|
|
121
124
|
* Map-space → render-space transform. Identity for flat backends; non-identity
|
|
122
|
-
* for
|
|
125
|
+
* for styles that warp coordinates (e.g. `IsometricStyle`).
|
|
123
126
|
* Decorators delegate to their inner backend.
|
|
124
|
-
* MapRenderer auto-applies this to culling and grid rendering when the backend is set.
|
|
125
127
|
*/
|
|
126
128
|
getTransform(): CoordFn;
|
|
127
129
|
/** Inverse of {@link getTransform}. */
|
|
128
130
|
getInverseTransform(): CoordFn;
|
|
129
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Abstract base for style (decorator) backends. Forwards every
|
|
134
|
+
* {@link DrawingBackend} method to `this.inner` by default; subclasses override
|
|
135
|
+
* only the methods they transform. Generic over the wrapped inner type so
|
|
136
|
+
* tooling preserves specific types through chains where useful.
|
|
137
|
+
*/
|
|
138
|
+
export declare abstract class BaseStyle<Inner extends DrawingBackend = DrawingBackend> implements DrawingBackend {
|
|
139
|
+
protected readonly inner: Inner;
|
|
140
|
+
constructor(inner: Inner);
|
|
141
|
+
createGroup(x: number, y: number): GroupNode;
|
|
142
|
+
addRect(parent: GroupNode, config: RectConfig): void;
|
|
143
|
+
addCircle(parent: GroupNode, config: CircleConfig): void;
|
|
144
|
+
addLine(parent: GroupNode, config: LineConfig): void;
|
|
145
|
+
addPolygon(parent: GroupNode, config: PolygonConfig): void;
|
|
146
|
+
addText(parent: GroupNode, config: TextConfig): void;
|
|
147
|
+
addImage(parent: GroupNode, config: ImageConfig): void;
|
|
148
|
+
supportsBatchExitRendering(): boolean;
|
|
149
|
+
getExitDepthOffset(): {
|
|
150
|
+
x: number;
|
|
151
|
+
y: number;
|
|
152
|
+
};
|
|
153
|
+
getTransform(): CoordFn;
|
|
154
|
+
getInverseTransform(): CoordFn;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* A {@link Style} is a target-agnostic transformer: given a {@link DrawingBackend}
|
|
158
|
+
* it returns a decorated one. The same style drives interactive canvas, SVG
|
|
159
|
+
* export, and any future target.
|
|
160
|
+
*
|
|
161
|
+
* Compose via {@link compose}; built-in styles live in `src/style`.
|
|
162
|
+
*/
|
|
163
|
+
export type Style = (target: DrawingBackend) => DrawingBackend;
|
|
164
|
+
/** Identity style — passes the target through unchanged. Useful as a default. */
|
|
165
|
+
export declare const identityStyle: Style;
|
|
166
|
+
/**
|
|
167
|
+
* Compose a chain of {@link Style}s into a single Style.
|
|
168
|
+
*
|
|
169
|
+
* `compose(Parchment, Sketchy)` wraps with Parchment first, then Sketchy —
|
|
170
|
+
* Sketchy is the outermost decorator, i.e. its methods run first during rendering.
|
|
171
|
+
*/
|
|
172
|
+
export declare function compose(...styles: Style[]): Style;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Exporter, ExportContext, ExportCanvas } from './Exporter';
|
|
2
|
+
export interface CanvasExportOptions {
|
|
3
|
+
/** Width of the output image in pixels. */
|
|
4
|
+
width: number;
|
|
5
|
+
/** Height of the output image in pixels. */
|
|
6
|
+
height: number;
|
|
7
|
+
/** Room ID to center the export on. If omitted, exports the full area. */
|
|
8
|
+
roomId?: number;
|
|
9
|
+
/** Padding in map units around the exported region. Default: 3 */
|
|
10
|
+
padding?: number;
|
|
11
|
+
/** Overlays to render over the scene (position marker, highlights, paths). */
|
|
12
|
+
overlays?: {
|
|
13
|
+
position?: {
|
|
14
|
+
roomId: number;
|
|
15
|
+
};
|
|
16
|
+
highlights?: Array<{
|
|
17
|
+
roomId: number;
|
|
18
|
+
color: string;
|
|
19
|
+
}>;
|
|
20
|
+
paths?: Array<{
|
|
21
|
+
locations: number[];
|
|
22
|
+
color: string;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Renders the current scene into a canvas at the requested width/height,
|
|
28
|
+
* reframing the viewport to fit the area (or a specific room) with padding.
|
|
29
|
+
*
|
|
30
|
+
* The returned {@link ExportCanvas} is the node-canvas-compatible object
|
|
31
|
+
* produced by Konva. Serialize with `.toBuffer('image/png')` in Node or
|
|
32
|
+
* `.toDataURL('image/png')` / `.toBlob(cb)` in the browser.
|
|
33
|
+
*
|
|
34
|
+
* Unlike {@link PngExporter} (which rasterizes the current on-screen viewport),
|
|
35
|
+
* `CanvasExporter` is the headless/programmatic path.
|
|
36
|
+
*/
|
|
37
|
+
export declare class CanvasExporter implements Exporter<ExportCanvas | undefined> {
|
|
38
|
+
private readonly options;
|
|
39
|
+
constructor(options: CanvasExportOptions);
|
|
40
|
+
render({ backend }: ExportContext): ExportCanvas | undefined;
|
|
41
|
+
}
|
|
42
|
+
export interface PngBytesExportOptions extends CanvasExportOptions {
|
|
43
|
+
/** MIME type to encode. Defaults to `'image/png'`. */
|
|
44
|
+
mimeType?: string;
|
|
45
|
+
/** Encoder quality (0..1). Only used for lossy formats like `'image/jpeg'`. */
|
|
46
|
+
quality?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Headless PNG/JPEG bytes at a specific width × height.
|
|
50
|
+
*
|
|
51
|
+
* Composes {@link CanvasExporter} with a portable `toDataURL` → `Uint8Array`
|
|
52
|
+
* decode, so callers get bytes directly without touching a canvas or casting
|
|
53
|
+
* to platform-specific types:
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* const png = renderer.export(new PngBytesExporter({ width: 1920, height: 1080 }));
|
|
57
|
+
* fs.writeFileSync('out.png', png!); // Node
|
|
58
|
+
* new Blob([png!], { type: 'image/png' }); // Browser
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* For JPEG: `new PngBytesExporter({ width, height, mimeType: 'image/jpeg', quality: 0.9 })`.
|
|
62
|
+
*/
|
|
63
|
+
export declare class PngBytesExporter implements Exporter<Uint8Array | undefined> {
|
|
64
|
+
private readonly options;
|
|
65
|
+
constructor(options: PngBytesExportOptions);
|
|
66
|
+
render(context: ExportContext): Uint8Array | undefined;
|
|
67
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { MapState } from '../MapState';
|
|
2
|
+
import { Style } from '../backend/DrawingBackend';
|
|
3
|
+
import { SceneOverlay } from '../overlay/SceneOverlay';
|
|
4
|
+
import { InteractiveBackend } from '../rendering/MapRenderer';
|
|
5
|
+
/**
|
|
6
|
+
* Context handed to every {@link Exporter} by {@link MapRenderer.export}.
|
|
7
|
+
* Exporters pull whatever they need — state + style for SVG, backend for
|
|
8
|
+
* canvas/PNG rasterization — so callers never have to wire `renderer.backend`
|
|
9
|
+
* (or any other internal) into an exporter themselves.
|
|
10
|
+
*/
|
|
11
|
+
export interface ExportContext {
|
|
12
|
+
readonly state: MapState;
|
|
13
|
+
readonly backend: InteractiveBackend;
|
|
14
|
+
readonly style: Style;
|
|
15
|
+
readonly sceneOverlays: Iterable<SceneOverlay>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Pluggable output format. An {@link Exporter} consumes an {@link ExportContext}
|
|
19
|
+
* and returns an output of type `T` (a string, a Blob promise, a canvas, bytes…).
|
|
20
|
+
*
|
|
21
|
+
* Adding a new output format means implementing `Exporter<T>`. `MapRenderer`'s
|
|
22
|
+
* surface does not change — users just pass the new exporter to `renderer.export`.
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* renderer.export(new SvgExporter({ padding: 5 })); // string
|
|
26
|
+
* renderer.export(new PngExporter({ pixelRatio: 2 })); // string (data URL)
|
|
27
|
+
* renderer.export(new CanvasExporter({ width, height })); // ExportCanvas
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface Exporter<T> {
|
|
31
|
+
render(context: ExportContext): T;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Canvas returned by {@link InteractiveBackend.toCanvas} and
|
|
35
|
+
* {@link CanvasExporter}. Describes the portable surface common to the
|
|
36
|
+
* browser `HTMLCanvasElement` and the `canvas` package's Node-side Canvas:
|
|
37
|
+
*
|
|
38
|
+
* - Portable: `width`, `height`, `getContext`, `toDataURL`.
|
|
39
|
+
* - Browser: `toBlob(cb)` (optional here; use when serializing to a Blob).
|
|
40
|
+
*
|
|
41
|
+
* Platform-specific serializers (e.g. node-canvas's `toBuffer`) are intentionally
|
|
42
|
+
* not part of this interface. Cast when you need them:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* import type { Canvas } from 'canvas';
|
|
46
|
+
* const canvas = renderer.export(new CanvasExporter({width, height})) as unknown as Canvas;
|
|
47
|
+
* const png = canvas.toBuffer('image/png');
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export interface ExportCanvas {
|
|
51
|
+
readonly width: number;
|
|
52
|
+
readonly height: number;
|
|
53
|
+
getContext(contextId: '2d', options?: any): CanvasRenderingContext2D | null;
|
|
54
|
+
toDataURL(type?: string, quality?: any): string;
|
|
55
|
+
/** Browser only; undefined in Node. */
|
|
56
|
+
toBlob?(callback: (blob: Blob | null) => void, type?: string, quality?: any): void;
|
|
57
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Exporter, ExportContext } from './Exporter';
|
|
2
|
+
export interface PngExportOptions {
|
|
3
|
+
pixelRatio?: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Exports the current interactive canvas as a PNG data URL. Rasterizes the
|
|
7
|
+
* live Konva stage — whatever style the renderer currently has applied is
|
|
8
|
+
* what gets captured.
|
|
9
|
+
*
|
|
10
|
+
* For re-framing with an explicit width/height (e.g. server-side rendering),
|
|
11
|
+
* use {@link CanvasExporter} and serialize its output yourself.
|
|
12
|
+
*/
|
|
13
|
+
export declare class PngExporter implements Exporter<string | undefined> {
|
|
14
|
+
private readonly options;
|
|
15
|
+
constructor(options?: PngExportOptions);
|
|
16
|
+
render({ backend }: ExportContext): string | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** Companion to {@link PngExporter} that returns a Blob instead of a data URL. */
|
|
19
|
+
export declare class PngBlobExporter implements Exporter<Promise<Blob> | undefined> {
|
|
20
|
+
private readonly options;
|
|
21
|
+
constructor(options?: PngExportOptions);
|
|
22
|
+
render({ backend }: ExportContext): Promise<Blob> | undefined;
|
|
23
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SvgExportOptions } from '../SvgTypes';
|
|
2
|
+
import { Exporter, ExportContext } from './Exporter';
|
|
3
|
+
/**
|
|
4
|
+
* Renders the current scene as an SVG string through the shared
|
|
5
|
+
* {@link ScenePipeline}. The context's style is applied so styled exports
|
|
6
|
+
* match the on-screen canvas; {@link SceneOverlay}s from the context are
|
|
7
|
+
* rendered into the SVG alongside the scene. `LiveEffect`s are intentionally
|
|
8
|
+
* ignored by design.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SvgExporter implements Exporter<string | undefined> {
|
|
11
|
+
private readonly options;
|
|
12
|
+
constructor(options?: SvgExportOptions);
|
|
13
|
+
render({ state, style, sceneOverlays }: ExportContext): string | undefined;
|
|
14
|
+
private renderBuiltInOverlays;
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ExportCanvas } from './Exporter';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize an {@link ExportCanvas} to raw bytes, synchronously, using the
|
|
4
|
+
* portable `toDataURL` API. Works identically in the browser and in Node.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const canvas = renderer.export(new CanvasExporter({ width, height }));
|
|
8
|
+
* const png = canvasToBytes(canvas); // Uint8Array
|
|
9
|
+
* fs.writeFileSync('out.png', png); // Node
|
|
10
|
+
* // or: new Blob([png], { type: 'image/png' }) — browser
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @param canvas Canvas produced by {@link CanvasExporter} or the
|
|
14
|
+
* interactive backend's `exportCanvas`.
|
|
15
|
+
* @param mimeType Output format. Defaults to `'image/png'`. Pass `'image/jpeg'`
|
|
16
|
+
* + `quality` (0..1) for JPEG.
|
|
17
|
+
* @param quality JPEG quality (ignored for PNG).
|
|
18
|
+
*/
|
|
19
|
+
export declare function canvasToBytes(canvas: ExportCanvas, mimeType?: string, quality?: number): Uint8Array;
|