1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
import { render } from "./renderer.js";
import { extendConfiguration } from "./configuration.js";
import { ImageType } from "./image_type.js";
import { StageType } from "./stage_type.js";
export { ImageType } from "./image_type.js";
export { StageType } from "./stage_type.js";
/**
* @typedef {import('./configuration.js').tConfiguration} tConfiguration
* @typedef {import('./image_type.js').ImageType} ImageType
* @typedef {import('./stage_type.js').StageType} StageType
* @typedef {import('wmap-parser').Map} ParsedMap
* @typedef {import('canvas').Canvas} Canvas
*/
/**
* Render a parsed Wardley map to a canvas element
* Works in both browser and Node.js environments
*
* @param {ParsedMap} map - Parsed map object from wmap-parser
* @param {HTMLCanvasElement|Canvas} canvas - Canvas element (browser) or Canvas instance (Node.js)
* @param {StageType} [stageType=StageType.ACTIVITIES] - The labels to use for each stage in the map.
* @param {tConfiguration} overrides - User configuration overrides
* @returns {Promise<void>}
*
* @example
* // Browser
* import { parse } from 'wmap-parser';
* import { renderToCanvas } from 'wmap-renderer-canvas';
*
* const map = parse(wmapSource);
* const canvas = document.getElementById('myCanvas');
* await renderToCanvas(map, canvas);
*
* @example
* // Node.js
* import { createCanvas } from 'canvas';
* import { parse } from 'wmap-parser';
* import { renderToCanvas } from 'wmap-renderer-canvas';
*
* const map = parse(wmapSource);
* const canvas = createCanvas(1384, 1084);
* await renderToCanvas(map, canvas);
*/
export async function renderToCanvas(
map,
canvas,
stageType = StageType.ACTIVITIES,
overrides = {},
) {
if (!map) {
throw new Error("Map object is required");
}
if (!canvas) {
throw new Error("Canvas is required");
}
const configuration = extendConfiguration(overrides);
const { mapWidth, mapHeight, padding } = configuration.theme.sizes;
const totalWidth = mapWidth + padding * 2;
const totalHeight = mapHeight + padding * 2;
if (canvas.width !== totalWidth || canvas.height !== totalHeight) {
canvas.width = totalWidth;
canvas.height = totalHeight;
}
const context = canvas.getContext("2d");
await render(map, context, stageType, configuration);
}
/**
* Render a parsed Wardley map to an image stream
* Only available in Node.js environments
*
* @param {ParsedMap} map - Parsed map object from wmap-parser
* @param {ImageType} imageType - Output image format ('png', 'jpeg', or 'pdf')
* @param {StageType} [stageType=StageType.ACTIVITIES] - The labels to use for each stage in the map.
* @param {tConfiguration} overrides - User configuration overrides
* @returns {Promise<Stream>} Stream of the rendered image
*
* @throws {Error} If not in Node.js environment
* @throws {Error} If canvas module is not available
* @throws {Error} If imageType is not supported
*
* @example
* import { parse } from 'wmap-parser';
* import { renderToImage, ImageType } from 'wmap-renderer-canvas';
* import fs from 'fs';
*
* const map = parse(wmapSource);
* const stream = await renderToImage(map, ImageType.PNG);
* const out = fs.createWriteStream('map.png');
* stream.pipe(out);
*/
export async function renderToImage(
map,
imageType = ImageType.PNG,
stageType = StageType.ACTIVITIES,
overrides = {},
) {
if (typeof window !== "undefined") {
throw new Error(
"renderToImage is only available in Node.js environments",
);
}
if (!map) {
throw new Error("Map object is required");
}
const validTypes = ["png", "jpeg", "pdf"];
if (!validTypes.includes(imageType)) {
throw new Error(
`Invalid image type. Must be one of: ${validTypes.join(", ")}`,
);
}
let createCanvas;
try {
const canvasModule = await import("canvas");
createCanvas =
canvasModule.default?.createCanvas || canvasModule.createCanvas;
} catch {
throw new Error("canvas module is required for renderToImage.");
}
const configuration = extendConfiguration(overrides);
const { mapWidth, mapHeight, padding } = configuration.theme.sizes;
const totalWidth = mapWidth + padding * 2;
const totalHeight = mapHeight + padding * 2;
const canvas =
imageType === "pdf"
? createCanvas(totalWidth, totalHeight, "pdf")
: createCanvas(totalWidth, totalHeight);
const ctx = canvas.getContext("2d");
await render(map, ctx, stageType, configuration);
switch (imageType) {
case "png":
return canvas.createPNGStream();
case "jpeg":
return canvas.createJPEGStream();
case "pdf":
return canvas.createPDFStream();
default:
throw new Error(`Unsupported image type: ${imageType}`);
}
}
|