mudlet-map-renderer 0.24.0-konva → 0.26.0-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.
@@ -74,7 +74,7 @@ export declare class AreaMapRenderer {
74
74
  constructor(container: HTMLDivElement, mapReader: MapReader, settings?: AreaMapSettings);
75
75
  private initResize;
76
76
  private initScaling;
77
- setZoom(zoom: number): void;
77
+ setZoom(zoom: number): boolean;
78
78
  getZoom(): number;
79
79
  setDomainInfo(domainInfo: Record<number, AreaDomainInfo>): void;
80
80
  setDomainFilter(filter: DomainFilter): void;
@@ -0,0 +1,76 @@
1
+ import { default as MapReader } from './reader/MapReader';
2
+ import { Settings } from './Renderer';
3
+ export type CanvasExportOverlays = {
4
+ position?: {
5
+ roomId: number;
6
+ };
7
+ highlights?: Array<{
8
+ roomId: number;
9
+ color: string;
10
+ }>;
11
+ paths?: Array<{
12
+ locations: number[];
13
+ color: string;
14
+ }>;
15
+ };
16
+ export type CanvasExportOptions = {
17
+ /** Width of the output image in pixels. */
18
+ width: number;
19
+ /** Height of the output image in pixels. */
20
+ height: number;
21
+ /** Room ID to center the export on. If omitted, exports the full area. */
22
+ roomId?: number;
23
+ /** Padding in map units around the exported region. Default: 3 */
24
+ padding?: number;
25
+ /** Overlay data (position marker, highlights, paths). */
26
+ overlays?: CanvasExportOverlays;
27
+ };
28
+ /**
29
+ * Renders map data directly to a Canvas2D context.
30
+ * Works in both browser (OffscreenCanvas / regular Canvas) and Node.js (with the 'canvas' npm package).
31
+ *
32
+ * Usage (Node.js):
33
+ * ```
34
+ * import { createCanvas } from 'canvas';
35
+ * const canvas = createCanvas(width, height);
36
+ * const exporter = new CanvasExporter(mapReader, settings);
37
+ * exporter.render(canvas.getContext('2d'), areaId, zIndex, { width, height });
38
+ * const buffer = canvas.toBuffer('image/png');
39
+ * ```
40
+ *
41
+ * Usage (Browser):
42
+ * ```
43
+ * const canvas = new OffscreenCanvas(width, height);
44
+ * const exporter = new CanvasExporter(mapReader, settings);
45
+ * exporter.render(canvas.getContext('2d'), areaId, zIndex, { width, height });
46
+ * const blob = await canvas.convertToBlob({ type: 'image/png' });
47
+ * ```
48
+ */
49
+ export declare class CanvasExporter {
50
+ private readonly mapReader;
51
+ private readonly settings;
52
+ private readonly exitRenderer;
53
+ constructor(mapReader: MapReader, settings: Settings);
54
+ private getSymbolColor;
55
+ /**
56
+ * Render the map area to a Canvas2D context.
57
+ * The caller creates the canvas and context; this method draws to it.
58
+ */
59
+ render(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, areaId: number, zIndex: number, options: CanvasExportOptions): void;
60
+ private computeBounds;
61
+ private getEffectiveBounds;
62
+ private getRoomEdgePoint;
63
+ private renderGrid;
64
+ private renderLabels;
65
+ private renderLinkExits;
66
+ private drawExitData;
67
+ private renderStubs;
68
+ private renderSpecialExits;
69
+ private renderRooms;
70
+ private roundRect;
71
+ private renderInnerExits;
72
+ private drawTriangle;
73
+ private renderPathOverlay;
74
+ private renderHighlightOverlay;
75
+ private renderPositionMarker;
76
+ }
@@ -34,12 +34,14 @@ export type ExitDrawData = {
34
34
  width: number;
35
35
  height: number;
36
36
  };
37
+ /** Set when this exit leads to a room in a different area (cross-area exit). */
38
+ targetRoomId?: number;
37
39
  };
38
40
  export default class ExitRenderer {
39
41
  private mapReader;
40
42
  private mapRenderer;
41
43
  private readonly settings;
42
- constructor(mapReader: MapReader, mapRenderer: Renderer, settings: Settings);
44
+ constructor(mapReader: MapReader, mapRenderer: Renderer | null, settings: Settings);
43
45
  /**
44
46
  * Get the edge point of a room based on its shape
45
47
  */
@@ -54,6 +56,18 @@ export default class ExitRenderer {
54
56
  private renderOneWayExit;
55
57
  renderAreaExit(room: MapData.Room, dir: MapData.direction, color?: string): import('konva/lib/shapes/Arrow').Arrow;
56
58
  renderSpecialExits(room: MapData.Room, overrideColor?: string): (import('konva/lib/shapes/Arrow').Arrow | import('konva/lib/shapes/Rect').Rect | import('konva/lib/shapes/Line').Line<import('konva/lib/shapes/Line').LineConfig>)[];
59
+ /**
60
+ * Returns hit-zone bounds for special exits (custom lines) that lead to rooms in another area.
61
+ */
62
+ getSpecialExitAreaTargets(room: MapData.Room): {
63
+ bounds: {
64
+ x: number;
65
+ y: number;
66
+ width: number;
67
+ height: number;
68
+ };
69
+ targetRoomId: number;
70
+ }[];
57
71
  renderStubs(room: MapData.Room, color?: string): import('konva/lib/shapes/Line').Line<{
58
72
  points: number[];
59
73
  stroke: string;
@@ -61,6 +75,7 @@ export default class ExitRenderer {
61
75
  perfectDrawEnabled: false;
62
76
  listening: false;
63
77
  }>[];
78
+ private getSymbolColor;
64
79
  renderInnerExits(room: MapData.Room): import('konva/lib/Group').Group[];
65
80
  renderDoor(points: number[], type: 1 | 2 | 3): import('konva/lib/shapes/Rect').Rect;
66
81
  }
@@ -0,0 +1,63 @@
1
+ import { default as MapReader } from './reader/MapReader';
2
+ import { default as Area } from './reader/Area';
3
+ import { Settings } from './Renderer';
4
+ import { MapRenderer } from './MapRenderer';
5
+ import { SvgExportOptions } from './SvgExporter';
6
+ import { CanvasExportOptions, CanvasExportOverlays } from './CanvasExporter';
7
+ /**
8
+ * A headless (no DOM / no Konva) renderer for server-side and backend use.
9
+ * Provides the same stateful API as the browser Renderer for area display,
10
+ * position tracking, path rendering, and highlights — then exports to SVG or
11
+ * renders to a caller-provided Canvas2D context for PNG output.
12
+ *
13
+ * Usage:
14
+ * ```
15
+ * const renderer = new HeadlessRenderer(mapReader, settings);
16
+ * renderer.drawArea(areaId, 0);
17
+ * renderer.setPosition(playerRoomId);
18
+ * renderer.renderPath([roomA, roomB, roomC], '#ff0000');
19
+ *
20
+ * // SVG export (always available)
21
+ * const svg = renderer.exportSvg({ padding: 5 });
22
+ *
23
+ * // PNG export (Node.js with 'canvas' package)
24
+ * import { createCanvas } from 'canvas';
25
+ * const canvas = createCanvas(1920, 1080);
26
+ * renderer.renderToCanvas(canvas.getContext('2d'), { width: 1920, height: 1080 });
27
+ * fs.writeFileSync('map.png', canvas.toBuffer('image/png'));
28
+ * ```
29
+ */
30
+ export declare class HeadlessRenderer implements MapRenderer {
31
+ private readonly mapReader;
32
+ readonly settings: Settings;
33
+ private currentArea?;
34
+ private currentAreaInstance?;
35
+ private currentZIndex?;
36
+ private positionRoomId?;
37
+ private highlights;
38
+ private paths;
39
+ constructor(mapReader: MapReader, settings?: Settings);
40
+ drawArea(id: number, zIndex: number): void;
41
+ getCurrentArea(): Area | undefined;
42
+ setPosition(roomId: number): void;
43
+ clearPosition(): void;
44
+ renderPath(locations: number[], color?: string): void;
45
+ clearPaths(): void;
46
+ renderHighlight(roomId: number, color: string): void;
47
+ removeHighlight(roomId: number): void;
48
+ hasHighlight(roomId: number): boolean;
49
+ clearHighlights(): void;
50
+ /**
51
+ * Export the current area as an SVG string.
52
+ */
53
+ exportSvg(options?: SvgExportOptions): string | undefined;
54
+ /**
55
+ * Render the current area to a Canvas2D context (for PNG export).
56
+ * The caller provides the canvas and context — works with `canvas` npm package (Node.js)
57
+ * or OffscreenCanvas (browser).
58
+ */
59
+ renderToCanvas(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, options: Omit<CanvasExportOptions, 'overlays'> & {
60
+ overlays?: CanvasExportOverlays;
61
+ }): void;
62
+ private buildOverlays;
63
+ }
@@ -0,0 +1,32 @@
1
+ import { default as Area } from './reader/Area';
2
+ import { Settings } from './Renderer';
3
+ import { SvgExportOptions } from './SvgExporter';
4
+ /**
5
+ * Environment-agnostic interface for map rendering.
6
+ *
7
+ * Both the browser {@link Renderer} (Konva.js, requires DOM) and
8
+ * {@link HeadlessRenderer} (no DOM, export-only) implement this interface.
9
+ *
10
+ * Use this type to write code that works in both environments:
11
+ * ```typescript
12
+ * function setupMap(renderer: MapRenderer) {
13
+ * renderer.drawArea(1, 0);
14
+ * renderer.setPosition(42);
15
+ * renderer.renderHighlight(100, '#ff0000');
16
+ * }
17
+ * ```
18
+ */
19
+ export interface MapRenderer {
20
+ readonly settings: Settings;
21
+ drawArea(id: number, zIndex: number): void;
22
+ getCurrentArea(): Area | undefined;
23
+ setPosition(roomId: number): void;
24
+ clearPosition(): void;
25
+ renderPath(locations: number[], color?: string): void;
26
+ clearPaths(): void;
27
+ renderHighlight(roomId: number, color: string): void;
28
+ removeHighlight(roomId: number): void;
29
+ hasHighlight(roomId: number): boolean;
30
+ clearHighlights(): void;
31
+ exportSvg(options?: SvgExportOptions): string | undefined;
32
+ }
@@ -0,0 +1,18 @@
1
+ import { default as MapReader } from './reader/MapReader';
2
+ import { Settings } from './Renderer';
3
+ export interface PathSegment {
4
+ points: number[];
5
+ }
6
+ export interface PathInnerMarker {
7
+ room: MapData.Room;
8
+ direction: MapData.direction;
9
+ }
10
+ export interface PathCustomLine {
11
+ points: number[];
12
+ }
13
+ export interface PathResult {
14
+ segments: PathSegment[];
15
+ innerMarkers: PathInnerMarker[];
16
+ customLines: PathCustomLine[];
17
+ }
18
+ export declare function computePathData(mapReader: MapReader, settings: Settings, locations: number[], currentArea: number, currentZIndex: number): PathResult;
@@ -7,17 +7,8 @@ export default class PathRenderer {
7
7
  private readonly settings;
8
8
  private paths;
9
9
  constructor(mapReader: MapReader, overlayLayer: Konva.Layer, settings: Settings);
10
- private getRoomEdgePoint;
11
- private findConnection;
12
- private findExitDirection;
13
10
  private createStrokedLine;
14
11
  private renderInnerExitMarker;
15
12
  renderPath(locations: number[], currentArea?: number, currentZIndex?: number, color?: string): import('konva/lib/Group').Group | import('konva/lib/Shape').Shape<import('konva/lib/Shape').ShapeConfig> | undefined;
16
- private addRegularConnectionPoints;
17
- private addSpecialConnectionPoints;
18
- private renderInnerConnection;
19
13
  clearPaths(): void;
20
- private isRoomVisible;
21
- private getExitToRoom;
22
- private getDirectionTowards;
23
14
  }
@@ -1,5 +1,8 @@
1
1
  import { default as MapReader } from './reader/MapReader';
2
2
  import { default as Area } from './reader/Area';
3
+ import { SvgExportOptions } from './SvgExporter';
4
+ import { MapRenderer } from './MapRenderer';
5
+ export declare function colorLightness(color: string): number;
3
6
  export type PerfSnapshot = {
4
7
  /** Total updateRoomCulling time in ms */
5
8
  cullingMs: number;
@@ -14,7 +17,7 @@ export type PerfSnapshot = {
14
17
  /** Estimated FPS based on time between culling calls */
15
18
  fps: number;
16
19
  };
17
- export type LabelRenderMode = "image" | "data";
20
+ export type LabelRenderMode = "image" | "data" | "none";
18
21
  export type CullingMode = "none" | "basic" | "indexed";
19
22
  export type RoomShape = "rectangle" | "circle" | "roundedRectangle";
20
23
  export type RoomContextMenuEventDetail = {
@@ -34,6 +37,20 @@ export type RoomClickEventDetail = {
34
37
  export type ZoomChangeEventDetail = {
35
38
  zoom: number;
36
39
  };
40
+ export type AreaExitClickEventDetail = {
41
+ targetRoomId: number;
42
+ position: {
43
+ x: number;
44
+ y: number;
45
+ };
46
+ };
47
+ export type ViewportBounds = {
48
+ minX: number;
49
+ maxX: number;
50
+ minY: number;
51
+ maxY: number;
52
+ };
53
+ export type PanEventDetail = ViewportBounds;
37
54
  /**
38
55
  * Style configuration for the player position marker.
39
56
  * The player marker is a circle that indicates the current player position on the map.
@@ -129,10 +146,22 @@ export type Settings = {
129
146
  gridLineWidth: number;
130
147
  /** Performance monitoring callback, or null to disable. */
131
148
  perfCallback: ((stats: PerfSnapshot) => void) | null;
149
+ /** Whether to draw borders (strokes) on rooms. Default: true */
150
+ borders: boolean;
151
+ /** When true, rooms use frame rendering: fill=backgroundColor, stroke=envColor. Default: false */
152
+ frameMode: boolean;
153
+ /** When true, rooms display a 3D emboss effect (rectangle/roundedRectangle only). Default: false */
154
+ emboss: boolean;
155
+ /** When true, displays the area name as a header text on the map. Default: false */
156
+ areaName: boolean;
157
+ /** Font family for the area name header. Default: 'sans-serif' */
158
+ fontFamily: string;
159
+ /** When true, uses bounds from all z-levels for viewport sizing, not just the current level. Default: false */
160
+ uniformLevelSize: boolean;
132
161
  };
133
162
  /** Creates a new Settings object with default values. */
134
163
  export declare function createSettings(): Settings;
135
- export declare class Renderer {
164
+ export declare class Renderer implements MapRenderer {
136
165
  private readonly stage;
137
166
  private readonly gridLayer;
138
167
  private readonly roomLayer;
@@ -140,7 +169,7 @@ export declare class Renderer {
140
169
  private readonly overlayLayer;
141
170
  private readonly positionLayer;
142
171
  private mapReader;
143
- private readonly settings;
172
+ readonly settings: Settings;
144
173
  private exitRenderer;
145
174
  private pathRenderer;
146
175
  private highlights;
@@ -156,6 +185,8 @@ export declare class Renderer {
156
185
  private roomNodes;
157
186
  /** When true, resizing the container will center on the current room. Set to false for static map views. */
158
187
  centerOnResize: boolean;
188
+ /** Minimum zoom level, updated by fitArea() to prevent zooming out beyond the full area view. */
189
+ minZoom: number;
159
190
  private standaloneExitNodes;
160
191
  private spatialBucketSize;
161
192
  private roomSpatialIndex;
@@ -170,6 +201,7 @@ export declare class Renderer {
170
201
  private cullingScheduled;
171
202
  private perfMonitor;
172
203
  private exitBatchShape?;
204
+ private areaExitHitZones;
173
205
  private visibleExitDrawData;
174
206
  private cachedGridBounds;
175
207
  constructor(container: HTMLDivElement, mapReader: MapReader, settings?: Settings);
@@ -179,6 +211,28 @@ export declare class Renderer {
179
211
  private onResize;
180
212
  private initScaling;
181
213
  drawArea(id: number, zIndex: number): void;
214
+ /**
215
+ * Export the currently displayed area as an SVG string.
216
+ * @param options - Optional room focus and padding
217
+ * @returns SVG string, or undefined if no area is displayed
218
+ */
219
+ exportSvg(options?: SvgExportOptions): string | undefined;
220
+ /**
221
+ * Export the currently displayed canvas as a PNG data URL.
222
+ * @param options - pixelRatio for resolution (default 1), mimeType override
223
+ * @returns data URL string, or undefined if no area is displayed
224
+ */
225
+ exportPng(options?: {
226
+ pixelRatio?: number;
227
+ }): string | undefined;
228
+ /**
229
+ * Export the currently displayed canvas as a PNG Blob.
230
+ * @param options - pixelRatio for resolution (default 1)
231
+ * @returns Promise resolving to a Blob, or undefined if no area is displayed
232
+ */
233
+ exportPngBlob(options?: {
234
+ pixelRatio?: number;
235
+ }): Promise<Blob> | undefined;
182
236
  private computeSpatialBucketSize;
183
237
  private getBucketKey;
184
238
  private forEachBucket;
@@ -189,7 +243,11 @@ export declare class Renderer {
189
243
  private refreshStandaloneExitBoundsIfNeeded;
190
244
  private emitRoomContextEvent;
191
245
  private emitRoomClickEvent;
246
+ private findAreaExitAtClientPoint;
247
+ private emitAreaExitClickEvent;
192
248
  private emitZoomChangeEvent;
249
+ private emitPanEvent;
250
+ private emitMapClickEvent;
193
251
  setZoom(zoom: number): boolean;
194
252
  /**
195
253
  * Zooms relative to the center of the viewport.
@@ -197,6 +255,21 @@ export declare class Renderer {
197
255
  */
198
256
  zoomToCenter(zoom: number): boolean;
199
257
  getZoom(): number;
258
+ /**
259
+ * Returns the current viewport bounds in map coordinates.
260
+ */
261
+ getViewportBounds(): ViewportBounds;
262
+ /**
263
+ * Returns the bounds of the current area in map coordinates.
264
+ * Accounts for area name overhead if enabled.
265
+ */
266
+ getAreaBounds(): ViewportBounds | null;
267
+ /**
268
+ * Fit the entire current area into the viewport.
269
+ * Calculates the zoom level needed to show all rooms (and labels) and centers the view.
270
+ * Call after drawArea() to show the whole area without needing a position room.
271
+ */
272
+ fitArea(): void;
200
273
  setCullingMode(mode: CullingMode): void;
201
274
  getCullingMode(): CullingMode;
202
275
  getCurrentArea(): Area | undefined;
@@ -221,7 +294,8 @@ export declare class Renderer {
221
294
  */
222
295
  updatePositionMarker(roomId: number): void;
223
296
  setPosition(roomId: number, center?: boolean): void;
224
- centerOn(roomId: number): void;
297
+ clearPosition(): void;
298
+ centerOn(roomId: number, instant?: boolean): void;
225
299
  renderPath(locations: number[], color?: string): import('konva/lib/Group').Group | import('konva/lib/Shape').Shape<import('konva/lib/Shape').ShapeConfig> | undefined;
226
300
  clearPaths(): void;
227
301
  renderHighlight(roomId: number, color: string): import('konva/lib/Shape').Shape<import('konva/lib/Shape').ShapeConfig> | undefined;
@@ -232,6 +306,8 @@ export declare class Renderer {
232
306
  private createHighlightShape;
233
307
  private centerOnRoom;
234
308
  private centerOnRoomView;
309
+ private getEffectiveBounds;
310
+ private renderAreaName;
235
311
  private renderRooms;
236
312
  private scheduleRoomCulling;
237
313
  private updateRoomCulling;
@@ -241,6 +317,7 @@ export declare class Renderer {
241
317
  private clearCurrentRoomOverlay;
242
318
  private updateCurrentRoomOverlay;
243
319
  private createOverlayRoomGroup;
320
+ private getSymbolColor;
244
321
  private renderSymbol;
245
322
  private renderExits;
246
323
  private drawExitData;
@@ -0,0 +1,51 @@
1
+ import { default as MapReader } from './reader/MapReader';
2
+ import { Settings } from './Renderer';
3
+ export type SvgOverlays = {
4
+ position?: {
5
+ roomId: number;
6
+ };
7
+ highlights?: Array<{
8
+ roomId: number;
9
+ color: string;
10
+ }>;
11
+ paths?: Array<{
12
+ locations: number[];
13
+ color: string;
14
+ }>;
15
+ };
16
+ export type SvgExportOptions = {
17
+ /** Room ID to center the export on. If omitted, exports the full area. */
18
+ roomId?: number;
19
+ /** Padding in map units around the exported region. Default: 3 */
20
+ padding?: number;
21
+ /** Overlay data (position marker, highlights, paths) to include in the export. */
22
+ overlays?: SvgOverlays;
23
+ };
24
+ export declare class SvgExporter {
25
+ private readonly mapReader;
26
+ private readonly settings;
27
+ private readonly exitRenderer;
28
+ constructor(mapReader: MapReader, settings: Settings);
29
+ private getSymbolColor;
30
+ export(areaId: number, zIndex: number, options?: SvgExportOptions): string;
31
+ private computeBounds;
32
+ private getEffectiveBounds;
33
+ private getRoomEdgePoint;
34
+ private renderGrid;
35
+ private renderLabels;
36
+ private labelColor;
37
+ private renderLinkExits;
38
+ private renderExitData;
39
+ private renderSvgLine;
40
+ private renderSvgArrow;
41
+ private renderSvgDoor;
42
+ private renderStubs;
43
+ private renderSpecialExits;
44
+ private renderRooms;
45
+ private renderInnerExits;
46
+ private svgTriangle;
47
+ private renderPathOverlay;
48
+ private innerExitRotation;
49
+ private renderHighlightOverlay;
50
+ private renderPositionMarker;
51
+ }