@versatiles/svg-renderer 1.2.0 → 2.0.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 +38 -78
- package/dist/index.d.ts +2665 -4
- package/dist/index.js +199 -124
- package/package.json +15 -92
- package/dist/index.cjs +0 -11623
- package/dist/maplibre-svg-export.d.ts +0 -42
- package/dist/maplibre-svg-export.js +0 -12072
- package/dist/maplibre-svg-export.umd.js +0 -12081
package/dist/index.js
CHANGED
|
@@ -8014,6 +8014,10 @@ class Color {
|
|
|
8014
8014
|
get rgb() {
|
|
8015
8015
|
return `#${d2h(this.values[0])}${d2h(this.values[1])}${d2h(this.values[2])}`;
|
|
8016
8016
|
}
|
|
8017
|
+
/** The red, green and blue components as bytes, for painting pixels directly. */
|
|
8018
|
+
get rgbBytes() {
|
|
8019
|
+
return [this.values[0], this.values[1], this.values[2]];
|
|
8020
|
+
}
|
|
8017
8021
|
get opacity() {
|
|
8018
8022
|
return this.values[3] / 255;
|
|
8019
8023
|
}
|
|
@@ -8232,6 +8236,133 @@ function formatNum(tenths) {
|
|
|
8232
8236
|
return (negative ? '-' : '') + String(whole) + '.' + String(frac);
|
|
8233
8237
|
}
|
|
8234
8238
|
|
|
8239
|
+
/**
|
|
8240
|
+
* Where a symbol sits relative to its point, shared by every backend so the two cannot
|
|
8241
|
+
* drift apart. The text vocabulary is SVG's (`text-anchor` / `dominant-baseline`); the
|
|
8242
|
+
* canvas backend translates it to `textAlign` / `textBaseline`.
|
|
8243
|
+
*/
|
|
8244
|
+
function mapTextAnchor(anchor) {
|
|
8245
|
+
switch (anchor) {
|
|
8246
|
+
case 'left':
|
|
8247
|
+
return ['start', 'central'];
|
|
8248
|
+
case 'right':
|
|
8249
|
+
return ['end', 'central'];
|
|
8250
|
+
case 'top':
|
|
8251
|
+
return ['middle', 'text-before-edge'];
|
|
8252
|
+
case 'bottom':
|
|
8253
|
+
return ['middle', 'text-after-edge'];
|
|
8254
|
+
case 'top-left':
|
|
8255
|
+
return ['start', 'text-before-edge'];
|
|
8256
|
+
case 'top-right':
|
|
8257
|
+
return ['end', 'text-before-edge'];
|
|
8258
|
+
case 'bottom-left':
|
|
8259
|
+
return ['start', 'text-after-edge'];
|
|
8260
|
+
case 'bottom-right':
|
|
8261
|
+
return ['end', 'text-after-edge'];
|
|
8262
|
+
default:
|
|
8263
|
+
return ['middle', 'central'];
|
|
8264
|
+
}
|
|
8265
|
+
}
|
|
8266
|
+
function mapIconAnchor(anchor, w, h) {
|
|
8267
|
+
switch (anchor) {
|
|
8268
|
+
case 'left':
|
|
8269
|
+
return [0, -h / 2];
|
|
8270
|
+
case 'right':
|
|
8271
|
+
return [-w, -h / 2];
|
|
8272
|
+
case 'top':
|
|
8273
|
+
return [-w / 2, 0];
|
|
8274
|
+
case 'bottom':
|
|
8275
|
+
return [-w / 2, -h];
|
|
8276
|
+
case 'top-left':
|
|
8277
|
+
return [0, 0];
|
|
8278
|
+
case 'top-right':
|
|
8279
|
+
return [-w, 0];
|
|
8280
|
+
case 'bottom-left':
|
|
8281
|
+
return [0, -h];
|
|
8282
|
+
case 'bottom-right':
|
|
8283
|
+
return [-w, -h];
|
|
8284
|
+
default:
|
|
8285
|
+
return [-w / 2, -h / 2];
|
|
8286
|
+
}
|
|
8287
|
+
}
|
|
8288
|
+
|
|
8289
|
+
/** Size of a raster tile image in user units, when drawn as a mesh of triangles on the globe. */
|
|
8290
|
+
const RASTER_TILE_UNITS = 256;
|
|
8291
|
+
/** How far (pixels) a raster tile image reaches beyond the tile border in the seam underlay. */
|
|
8292
|
+
const RASTER_TILE_BLEED_PX = 1;
|
|
8293
|
+
/** How far (pixels) each raster triangle is grown beyond its edges to overlap its neighbours. */
|
|
8294
|
+
const RASTER_TRIANGLE_OVERLAP_PX = 0.5;
|
|
8295
|
+
/**
|
|
8296
|
+
* The affine transform [a, b, c, d, e, f] mapping the source triangle (in tile units 0..1,
|
|
8297
|
+
* scaled to RASTER_TILE_UNITS) exactly onto the target triangle, or undefined if either is
|
|
8298
|
+
* degenerate.
|
|
8299
|
+
*/
|
|
8300
|
+
function affineFromTriangles(source, target) {
|
|
8301
|
+
const k = RASTER_TILE_UNITS;
|
|
8302
|
+
const [[u0, v0], [u1, v1], [u2, v2]] = source.map(([u, v]) => [u * k, v * k]);
|
|
8303
|
+
const [[x0, y0], [x1, y1], [x2, y2]] = target;
|
|
8304
|
+
const du1 = u1 - u0;
|
|
8305
|
+
const dv1 = v1 - v0;
|
|
8306
|
+
const du2 = u2 - u0;
|
|
8307
|
+
const dv2 = v2 - v0;
|
|
8308
|
+
const det = du1 * dv2 - du2 * dv1;
|
|
8309
|
+
if (Math.abs(det) < 1e-12)
|
|
8310
|
+
return undefined;
|
|
8311
|
+
const dx1 = x1 - x0;
|
|
8312
|
+
const dx2 = x2 - x0;
|
|
8313
|
+
const dy1 = y1 - y0;
|
|
8314
|
+
const dy2 = y2 - y0;
|
|
8315
|
+
// Screen area below a hundredth of a pixel: nothing to draw.
|
|
8316
|
+
if (Math.abs(dx1 * dy2 - dx2 * dy1) < 0.02)
|
|
8317
|
+
return undefined;
|
|
8318
|
+
const a = (dx1 * dv2 - dx2 * dv1) / det;
|
|
8319
|
+
const c = (du1 * dx2 - du2 * dx1) / det;
|
|
8320
|
+
const b = (dy1 * dv2 - dy2 * dv1) / det;
|
|
8321
|
+
const d = (du1 * dy2 - du2 * dy1) / det;
|
|
8322
|
+
return [a, b, c, d, x0 - a * u0 - c * v0, y0 - b * u0 - d * v0];
|
|
8323
|
+
}
|
|
8324
|
+
function isOnTileBorder(source) {
|
|
8325
|
+
return source.some(([u, v]) => u === 0 || u === 1 || v === 0 || v === 1);
|
|
8326
|
+
}
|
|
8327
|
+
/**
|
|
8328
|
+
* Moves the source corners of a triangle that lie on the tile border inwards, by the
|
|
8329
|
+
* equivalent of RASTER_TILE_BLEED_PX on screen, so that the image edge lies beyond the border.
|
|
8330
|
+
* (Used for the underlay that closes the seams between tiles, see `#drawRasterMeshes`.)
|
|
8331
|
+
*/
|
|
8332
|
+
function bleedAtTileBorder(source, target) {
|
|
8333
|
+
const [[u0, v0], [u1, v1], [u2, v2]] = source;
|
|
8334
|
+
const [[x0, y0], [x1, y1], [x2, y2]] = target;
|
|
8335
|
+
const sourceArea = Math.abs((u1 - u0) * (v2 - v0) - (u2 - u0) * (v1 - v0));
|
|
8336
|
+
const targetArea = Math.abs((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0));
|
|
8337
|
+
if (sourceArea === 0 || targetArea === 0)
|
|
8338
|
+
return source;
|
|
8339
|
+
// Pixels per tile unit, and the bleed in tile units, kept within the triangle.
|
|
8340
|
+
const scale = Math.sqrt(targetArea / sourceArea);
|
|
8341
|
+
const size = Math.max(Math.abs(u1 - u0), Math.abs(u2 - u0), Math.abs(v1 - v0), Math.abs(v2 - v0));
|
|
8342
|
+
const bleed = Math.min(RASTER_TILE_BLEED_PX / scale, size / 4);
|
|
8343
|
+
const inset = (t) => (t === 0 ? bleed : t === 1 ? 1 - bleed : t);
|
|
8344
|
+
return source.map(([u, v]) => [inset(u), inset(v)]);
|
|
8345
|
+
}
|
|
8346
|
+
/**
|
|
8347
|
+
* Moves every edge of a triangle outwards by `distance`, by scaling it around its incenter.
|
|
8348
|
+
* Growth is limited for very thin triangles, whose corners would otherwise shoot far out.
|
|
8349
|
+
*/
|
|
8350
|
+
function growTriangle(triangle, distance) {
|
|
8351
|
+
const [[x0, y0], [x1, y1], [x2, y2]] = triangle;
|
|
8352
|
+
const a = Math.hypot(x2 - x1, y2 - y1);
|
|
8353
|
+
const b = Math.hypot(x2 - x0, y2 - y0);
|
|
8354
|
+
const c = Math.hypot(x1 - x0, y1 - y0);
|
|
8355
|
+
const perimeter = a + b + c;
|
|
8356
|
+
const area = Math.abs((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)) / 2;
|
|
8357
|
+
if (perimeter === 0 || area === 0)
|
|
8358
|
+
return triangle;
|
|
8359
|
+
const inradius = (2 * area) / perimeter;
|
|
8360
|
+
const cx = (a * x0 + b * x1 + c * x2) / perimeter;
|
|
8361
|
+
const cy = (a * y0 + b * y1 + c * y2) / perimeter;
|
|
8362
|
+
const scale = 1 + distance / Math.max(inradius, 2 * distance);
|
|
8363
|
+
return triangle.map(([x, y]) => [cx + (x - cx) * scale, cy + (y - cy) * scale]);
|
|
8364
|
+
}
|
|
8365
|
+
|
|
8235
8366
|
// line-blur approximates MapLibre's edge-feather blur, which keeps an opaque core
|
|
8236
8367
|
// and feathers over ~`blur` px with a hard cutoff. feGaussianBlur alone conserves
|
|
8237
8368
|
// total ink and leaves soft, infinite tails, so we combine three corrections,
|
|
@@ -8805,82 +8936,6 @@ function strokeAttr(color, width) {
|
|
|
8805
8936
|
function formatScaled(v) {
|
|
8806
8937
|
return formatNum(Math.round(v * 10));
|
|
8807
8938
|
}
|
|
8808
|
-
/** Size of a raster tile image in user units, when drawn as a mesh of triangles on the globe. */
|
|
8809
|
-
const RASTER_TILE_UNITS = 256;
|
|
8810
|
-
/** How far (pixels) a raster tile image reaches beyond the tile border in the seam underlay. */
|
|
8811
|
-
const RASTER_TILE_BLEED_PX = 1;
|
|
8812
|
-
/** How far (pixels) each raster triangle is grown beyond its edges to overlap its neighbours. */
|
|
8813
|
-
const RASTER_TRIANGLE_OVERLAP_PX = 0.5;
|
|
8814
|
-
/**
|
|
8815
|
-
* The affine transform [a, b, c, d, e, f] mapping the source triangle (in tile units 0..1,
|
|
8816
|
-
* scaled to RASTER_TILE_UNITS) exactly onto the target triangle, or undefined if either is
|
|
8817
|
-
* degenerate.
|
|
8818
|
-
*/
|
|
8819
|
-
function affineFromTriangles(source, target) {
|
|
8820
|
-
const k = RASTER_TILE_UNITS;
|
|
8821
|
-
const [[u0, v0], [u1, v1], [u2, v2]] = source.map(([u, v]) => [u * k, v * k]);
|
|
8822
|
-
const [[x0, y0], [x1, y1], [x2, y2]] = target;
|
|
8823
|
-
const du1 = u1 - u0;
|
|
8824
|
-
const dv1 = v1 - v0;
|
|
8825
|
-
const du2 = u2 - u0;
|
|
8826
|
-
const dv2 = v2 - v0;
|
|
8827
|
-
const det = du1 * dv2 - du2 * dv1;
|
|
8828
|
-
if (Math.abs(det) < 1e-12)
|
|
8829
|
-
return undefined;
|
|
8830
|
-
const dx1 = x1 - x0;
|
|
8831
|
-
const dx2 = x2 - x0;
|
|
8832
|
-
const dy1 = y1 - y0;
|
|
8833
|
-
const dy2 = y2 - y0;
|
|
8834
|
-
// Screen area below a hundredth of a pixel: nothing to draw.
|
|
8835
|
-
if (Math.abs(dx1 * dy2 - dx2 * dy1) < 0.02)
|
|
8836
|
-
return undefined;
|
|
8837
|
-
const a = (dx1 * dv2 - dx2 * dv1) / det;
|
|
8838
|
-
const c = (du1 * dx2 - du2 * dx1) / det;
|
|
8839
|
-
const b = (dy1 * dv2 - dy2 * dv1) / det;
|
|
8840
|
-
const d = (du1 * dy2 - du2 * dy1) / det;
|
|
8841
|
-
return [a, b, c, d, x0 - a * u0 - c * v0, y0 - b * u0 - d * v0];
|
|
8842
|
-
}
|
|
8843
|
-
function isOnTileBorder(source) {
|
|
8844
|
-
return source.some(([u, v]) => u === 0 || u === 1 || v === 0 || v === 1);
|
|
8845
|
-
}
|
|
8846
|
-
/**
|
|
8847
|
-
* Moves the source corners of a triangle that lie on the tile border inwards, by the
|
|
8848
|
-
* equivalent of RASTER_TILE_BLEED_PX on screen, so that the image edge lies beyond the border.
|
|
8849
|
-
* (Used for the underlay that closes the seams between tiles, see `#drawRasterMeshes`.)
|
|
8850
|
-
*/
|
|
8851
|
-
function bleedAtTileBorder(source, target) {
|
|
8852
|
-
const [[u0, v0], [u1, v1], [u2, v2]] = source;
|
|
8853
|
-
const [[x0, y0], [x1, y1], [x2, y2]] = target;
|
|
8854
|
-
const sourceArea = Math.abs((u1 - u0) * (v2 - v0) - (u2 - u0) * (v1 - v0));
|
|
8855
|
-
const targetArea = Math.abs((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0));
|
|
8856
|
-
if (sourceArea === 0 || targetArea === 0)
|
|
8857
|
-
return source;
|
|
8858
|
-
// Pixels per tile unit, and the bleed in tile units, kept within the triangle.
|
|
8859
|
-
const scale = Math.sqrt(targetArea / sourceArea);
|
|
8860
|
-
const size = Math.max(Math.abs(u1 - u0), Math.abs(u2 - u0), Math.abs(v1 - v0), Math.abs(v2 - v0));
|
|
8861
|
-
const bleed = Math.min(RASTER_TILE_BLEED_PX / scale, size / 4);
|
|
8862
|
-
const inset = (t) => (t === 0 ? bleed : t === 1 ? 1 - bleed : t);
|
|
8863
|
-
return source.map(([u, v]) => [inset(u), inset(v)]);
|
|
8864
|
-
}
|
|
8865
|
-
/**
|
|
8866
|
-
* Moves every edge of a triangle outwards by `distance`, by scaling it around its incenter.
|
|
8867
|
-
* Growth is limited for very thin triangles, whose corners would otherwise shoot far out.
|
|
8868
|
-
*/
|
|
8869
|
-
function growTriangle(triangle, distance) {
|
|
8870
|
-
const [[x0, y0], [x1, y1], [x2, y2]] = triangle;
|
|
8871
|
-
const a = Math.hypot(x2 - x1, y2 - y1);
|
|
8872
|
-
const b = Math.hypot(x2 - x0, y2 - y0);
|
|
8873
|
-
const c = Math.hypot(x1 - x0, y1 - y0);
|
|
8874
|
-
const perimeter = a + b + c;
|
|
8875
|
-
const area = Math.abs((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)) / 2;
|
|
8876
|
-
if (perimeter === 0 || area === 0)
|
|
8877
|
-
return triangle;
|
|
8878
|
-
const inradius = (2 * area) / perimeter;
|
|
8879
|
-
const cx = (a * x0 + b * x1 + c * x2) / perimeter;
|
|
8880
|
-
const cy = (a * y0 + b * y1 + c * y2) / perimeter;
|
|
8881
|
-
const scale = 1 + distance / Math.max(inradius, 2 * distance);
|
|
8882
|
-
return triangle.map(([x, y]) => [cx + (x - cx) * scale, cy + (y - cy) * scale]);
|
|
8883
|
-
}
|
|
8884
8939
|
function formatUnit(v) {
|
|
8885
8940
|
return (Math.round(v * 100000) / 100000).toString();
|
|
8886
8941
|
}
|
|
@@ -8894,50 +8949,6 @@ function formatPoint(p) {
|
|
|
8894
8949
|
const [x, y] = roundXY(p[0], p[1]);
|
|
8895
8950
|
return formatNum(x) + ',' + formatNum(y);
|
|
8896
8951
|
}
|
|
8897
|
-
function mapTextAnchor(anchor) {
|
|
8898
|
-
switch (anchor) {
|
|
8899
|
-
case 'left':
|
|
8900
|
-
return ['start', 'central'];
|
|
8901
|
-
case 'right':
|
|
8902
|
-
return ['end', 'central'];
|
|
8903
|
-
case 'top':
|
|
8904
|
-
return ['middle', 'text-before-edge'];
|
|
8905
|
-
case 'bottom':
|
|
8906
|
-
return ['middle', 'text-after-edge'];
|
|
8907
|
-
case 'top-left':
|
|
8908
|
-
return ['start', 'text-before-edge'];
|
|
8909
|
-
case 'top-right':
|
|
8910
|
-
return ['end', 'text-before-edge'];
|
|
8911
|
-
case 'bottom-left':
|
|
8912
|
-
return ['start', 'text-after-edge'];
|
|
8913
|
-
case 'bottom-right':
|
|
8914
|
-
return ['end', 'text-after-edge'];
|
|
8915
|
-
default:
|
|
8916
|
-
return ['middle', 'central'];
|
|
8917
|
-
}
|
|
8918
|
-
}
|
|
8919
|
-
function mapIconAnchor(anchor, w, h) {
|
|
8920
|
-
switch (anchor) {
|
|
8921
|
-
case 'left':
|
|
8922
|
-
return [0, -h / 2];
|
|
8923
|
-
case 'right':
|
|
8924
|
-
return [-w, -h / 2];
|
|
8925
|
-
case 'top':
|
|
8926
|
-
return [-w / 2, 0];
|
|
8927
|
-
case 'bottom':
|
|
8928
|
-
return [-w / 2, -h];
|
|
8929
|
-
case 'top-left':
|
|
8930
|
-
return [0, 0];
|
|
8931
|
-
case 'top-right':
|
|
8932
|
-
return [-w, 0];
|
|
8933
|
-
case 'bottom-left':
|
|
8934
|
-
return [0, -h];
|
|
8935
|
-
case 'bottom-right':
|
|
8936
|
-
return [-w, -h];
|
|
8937
|
-
default:
|
|
8938
|
-
return [-w / 2, -h / 2];
|
|
8939
|
-
}
|
|
8940
|
-
}
|
|
8941
8952
|
function escapeXml(s) {
|
|
8942
8953
|
return s
|
|
8943
8954
|
.replace(/&/g, '&')
|
|
@@ -11358,7 +11369,13 @@ function resolveTokens(text, properties) {
|
|
|
11358
11369
|
return '';
|
|
11359
11370
|
});
|
|
11360
11371
|
}
|
|
11361
|
-
|
|
11372
|
+
/**
|
|
11373
|
+
* Draws the map described by `job` onto its renderer and returns that renderer, so a
|
|
11374
|
+
* caller can take the result in whatever form the backend provides (see
|
|
11375
|
+
* {@link renderMap} for the SVG string, or `renderToPNG` in `@versatiles/png-renderer` for
|
|
11376
|
+
* an image buffer).
|
|
11377
|
+
*/
|
|
11378
|
+
async function drawMap(job) {
|
|
11362
11379
|
job.projection ??= Projection.fromStyle({
|
|
11363
11380
|
width: job.renderer.width,
|
|
11364
11381
|
height: job.renderer.height,
|
|
@@ -11370,7 +11387,10 @@ async function renderMap(job) {
|
|
|
11370
11387
|
if (clipCircle)
|
|
11371
11388
|
job.renderer.setClipCircle?.(clipCircle);
|
|
11372
11389
|
await render(job);
|
|
11373
|
-
return job.renderer
|
|
11390
|
+
return job.renderer;
|
|
11391
|
+
}
|
|
11392
|
+
async function renderMap(job) {
|
|
11393
|
+
return (await drawMap(job)).getString();
|
|
11374
11394
|
}
|
|
11375
11395
|
function getFeatures(layerFeatures, layerStyle) {
|
|
11376
11396
|
return layerFeatures.get(layerStyle.sourceLayer) ?? layerFeatures.get(layerStyle.source);
|
|
@@ -11483,7 +11503,7 @@ async function render(job) {
|
|
|
11483
11503
|
case 'raster':
|
|
11484
11504
|
{
|
|
11485
11505
|
const tiles = await getRasterTiles(job, layerStyle.source);
|
|
11486
|
-
renderer.drawRasterTiles(layerId, tiles, {
|
|
11506
|
+
await renderer.drawRasterTiles(layerId, tiles, {
|
|
11487
11507
|
opacity: getPaint('raster-opacity'),
|
|
11488
11508
|
hueRotate: getPaint('raster-hue-rotate'),
|
|
11489
11509
|
brightnessMin: getPaint('raster-brightness-min'),
|
|
@@ -11535,7 +11555,7 @@ async function render(job) {
|
|
|
11535
11555
|
if (symbolFeatures.length === 0)
|
|
11536
11556
|
continue;
|
|
11537
11557
|
// Render icons first (underneath text)
|
|
11538
|
-
renderer.drawIcons(`${layerId}-icons`, symbolFeatures.flatMap((feature) => {
|
|
11558
|
+
await renderer.drawIcons(`${layerId}-icons`, symbolFeatures.flatMap((feature) => {
|
|
11539
11559
|
const iconImage = getLayout('icon-image', feature);
|
|
11540
11560
|
const iconName = iconImage != null
|
|
11541
11561
|
? resolveTokens(iconImage.toString(), feature.properties)
|
|
@@ -11599,6 +11619,61 @@ async function render(job) {
|
|
|
11599
11619
|
}
|
|
11600
11620
|
}
|
|
11601
11621
|
|
|
11622
|
+
/**
|
|
11623
|
+
* Renders a MapLibre style to an SVG image.
|
|
11624
|
+
*
|
|
11625
|
+
* Fetches the vector and raster tiles the view needs, then draws every layer as SVG
|
|
11626
|
+
* elements: fills and lines as paths, raster tiles and sprites as embedded images. The
|
|
11627
|
+
* result is a single self-contained SVG document — it references no external files, so
|
|
11628
|
+
* it can be saved, inlined into HTML or opened in a vector editor as is.
|
|
11629
|
+
*
|
|
11630
|
+
* Works in Node.js (22 or later) and in the browser. The same function is exported by
|
|
11631
|
+
* `@versatiles/svg-renderer`, `@versatiles/png-renderer` and
|
|
11632
|
+
* `@versatiles/maplibre-svg-export`; the examples import it from the first.
|
|
11633
|
+
*
|
|
11634
|
+
* @example Render a map in Node.js
|
|
11635
|
+
* ```ts
|
|
11636
|
+
* import { renderToSVG } from '@versatiles/svg-renderer';
|
|
11637
|
+
* import { inlineSources, osm } from '@versatiles/style';
|
|
11638
|
+
* import { writeFile } from 'node:fs/promises';
|
|
11639
|
+
*
|
|
11640
|
+
* // inlineSources() resolves the style's TileJSON sources into tile URLs,
|
|
11641
|
+
* // which the renderer needs. Without it the map comes out empty.
|
|
11642
|
+
* const style = await inlineSources(osm({ theme: 'colorful' }));
|
|
11643
|
+
*
|
|
11644
|
+
* const svg = await renderToSVG({
|
|
11645
|
+
* style,
|
|
11646
|
+
* width: 800,
|
|
11647
|
+
* height: 600,
|
|
11648
|
+
* lon: 13.4, // Berlin
|
|
11649
|
+
* lat: 52.52,
|
|
11650
|
+
* zoom: 12,
|
|
11651
|
+
* });
|
|
11652
|
+
*
|
|
11653
|
+
* await writeFile('berlin.svg', svg);
|
|
11654
|
+
* ```
|
|
11655
|
+
*
|
|
11656
|
+
* @example Render a hosted style in the browser
|
|
11657
|
+
* ```ts
|
|
11658
|
+
* import { renderToSVG } from '@versatiles/svg-renderer';
|
|
11659
|
+
*
|
|
11660
|
+
* // This hosted style already lists its tile URLs, so it can be used directly.
|
|
11661
|
+
* const style = await fetch(
|
|
11662
|
+
* 'https://tiles.versatiles.org/assets/styles/colorful/style.json',
|
|
11663
|
+
* ).then((response) => response.json());
|
|
11664
|
+
*
|
|
11665
|
+
* document.body.innerHTML = await renderToSVG({ style, width: 800, height: 600, zoom: 3 });
|
|
11666
|
+
* ```
|
|
11667
|
+
*
|
|
11668
|
+
* @example Include labels and icons
|
|
11669
|
+
* ```ts
|
|
11670
|
+
* const svg = await renderToSVG({ style, lon: 13.4, lat: 52.52, zoom: 14, renderLabels: true });
|
|
11671
|
+
* ```
|
|
11672
|
+
*
|
|
11673
|
+
* @param options - What to render and how large. Only `style` is required.
|
|
11674
|
+
* @returns The SVG document, as a string beginning with `<svg`.
|
|
11675
|
+
* @throws If `width` or `height` is not positive.
|
|
11676
|
+
*/
|
|
11602
11677
|
async function renderToSVG(options) {
|
|
11603
11678
|
const width = options.width ?? 1024;
|
|
11604
11679
|
const height = options.height ?? 1024;
|
package/package.json
CHANGED
|
@@ -1,118 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versatiles/svg-renderer",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Renders
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Renders MapLibre styles as SVG, in Node.js or the browser.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svg",
|
|
7
7
|
"map",
|
|
8
|
-
"
|
|
8
|
+
"maplibre",
|
|
9
9
|
"vector-tiles",
|
|
10
|
+
"renderer",
|
|
11
|
+
"export",
|
|
10
12
|
"versatiles"
|
|
11
13
|
],
|
|
12
|
-
"homepage": "https://github.com/versatiles-org/versatiles-svg-renderer",
|
|
14
|
+
"homepage": "https://github.com/versatiles-org/versatiles-svg-renderer/tree/main/packages/svg-renderer",
|
|
13
15
|
"bugs": "https://github.com/versatiles-org/versatiles-svg-renderer/issues",
|
|
14
16
|
"repository": {
|
|
15
17
|
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/versatiles-org/versatiles-svg-renderer.git"
|
|
18
|
+
"url": "git+https://github.com/versatiles-org/versatiles-svg-renderer.git",
|
|
19
|
+
"directory": "packages/svg-renderer"
|
|
17
20
|
},
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"unpkg": "dist/maplibre-svg-export.umd.js",
|
|
22
|
-
"jsdelivr": "dist/maplibre-svg-export.umd.js",
|
|
21
|
+
"author": "Michael Kreil <versatiles@michael-kreil.de>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"type": "module",
|
|
23
24
|
"exports": {
|
|
24
25
|
".": {
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
"default": "./dist/index.js"
|
|
28
|
-
},
|
|
29
|
-
"require": {
|
|
30
|
-
"types": "./dist/index.d.ts",
|
|
31
|
-
"default": "./dist/index.cjs"
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"./maplibre": {
|
|
35
|
-
"script": "./dist/maplibre-svg-export.umd.js",
|
|
36
|
-
"import": {
|
|
37
|
-
"types": "./dist/maplibre-svg-export.d.ts",
|
|
38
|
-
"default": "./dist/maplibre-svg-export.js"
|
|
39
|
-
}
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
40
28
|
}
|
|
41
29
|
},
|
|
42
30
|
"files": [
|
|
43
31
|
"dist",
|
|
44
32
|
"!dist/**/*.map"
|
|
45
33
|
],
|
|
46
|
-
"scripts": {
|
|
47
|
-
"build": "rm -rf dist && rollup -c rollup.config.ts --configPlugin @rollup/plugin-typescript && rm -rf dist/types",
|
|
48
|
-
"build-analyze": "npm run build && tsx scripts/analyze-bundle.ts",
|
|
49
|
-
"check": "npm run format && npm run lint && npm run typecheck && npm run build && npm run test && npm run test:e2e",
|
|
50
|
-
"demo": "tsx src/demo.ts",
|
|
51
|
-
"dev": "tsx dev/serve.ts",
|
|
52
|
-
"dev:render-comparison": "tsx dev/render-comparison.ts",
|
|
53
|
-
"doc:graph": "vrt deps-graph | vrt doc-insert README.md '## Dependency Graph'",
|
|
54
|
-
"doc:typescript": "npx vrt doc-typescript -f html -o ./doc-typescript",
|
|
55
|
-
"format": "prettier --write --log-level warn .",
|
|
56
|
-
"lint": "eslint --color .",
|
|
57
|
-
"prepack": "npm run doc:graph && npm run build",
|
|
58
|
-
"release": "npx vrt release-npm",
|
|
59
|
-
"start": "tsx src/index.ts",
|
|
60
|
-
"test": "vitest run",
|
|
61
|
-
"test:coverage": "vitest run --coverage",
|
|
62
|
-
"test:e2e:maplibre": "tsx e2e/maplibre-control.ts",
|
|
63
|
-
"test:e2e:screenshots": "tsx e2e/screenshots.ts",
|
|
64
|
-
"test:e2e": "vitest run --config vitest.e2e.config.ts && npm run test:e2e:maplibre && npm run test:e2e:screenshots",
|
|
65
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p e2e/tsconfig.json && tsc --noEmit -p dev/tsconfig.json",
|
|
66
|
-
"upgrade": "vrt deps-upgrade"
|
|
67
|
-
},
|
|
68
34
|
"sideEffects": false,
|
|
69
|
-
"type": "module",
|
|
70
|
-
"author": "Michael Kreil <versatiles@michael-kreil.de>",
|
|
71
|
-
"license": "MIT",
|
|
72
35
|
"engines": {
|
|
73
36
|
"node": ">= 22"
|
|
74
37
|
},
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
},
|
|
78
|
-
"peerDependenciesMeta": {
|
|
79
|
-
"maplibre-gl": {
|
|
80
|
-
"optional": true
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
"devDependencies": {
|
|
84
|
-
"@eslint/js": "^10.0.1",
|
|
85
|
-
"@mapbox/vector-tile": "^3.0.0",
|
|
86
|
-
"@maplibre/maplibre-gl-style-spec": "^26.4.4",
|
|
87
|
-
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
88
|
-
"@rollup/plugin-typescript": "^12.3.0",
|
|
89
|
-
"@types/node": "^26.6.2",
|
|
90
|
-
"@types/pbf": "^3.0.5",
|
|
91
|
-
"@types/pngjs": "^6.0.5",
|
|
92
|
-
"@versatiles/release-tool": "^2.15.0",
|
|
93
|
-
"@versatiles/style": "^6.0.0",
|
|
94
|
-
"@vitest/coverage-v8": "^5.0.1",
|
|
95
|
-
"eslint": "^10.11.0",
|
|
96
|
-
"geojson": "^0.5.0",
|
|
97
|
-
"jsdom": "^30.1.0",
|
|
98
|
-
"maplibre-gl": "^6.10.0",
|
|
99
|
-
"npm-check-updates": "^23.1.0",
|
|
100
|
-
"pbf": "^5.1.2",
|
|
101
|
-
"pixelmatch": "^7.2.0",
|
|
102
|
-
"playwright": "^1.63.0",
|
|
103
|
-
"pngjs": "^7.0.0",
|
|
104
|
-
"prettier": "^3.9.8",
|
|
105
|
-
"rollup": "^4.63.4",
|
|
106
|
-
"rollup-plugin-dts": "^6.5.1",
|
|
107
|
-
"rollup-plugin-visualizer": "^7.1.1",
|
|
108
|
-
"tslib": "^2.8.1",
|
|
109
|
-
"tsx": "^4.23.13",
|
|
110
|
-
"typescript": "^6.0.3",
|
|
111
|
-
"typescript-eslint": "^8.70.0",
|
|
112
|
-
"vitest": "^5.0.1"
|
|
113
|
-
},
|
|
114
|
-
"allowScripts": {
|
|
115
|
-
"esbuild": true,
|
|
116
|
-
"fsevents": true
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@types/geojson": "^7946.0.16"
|
|
117
40
|
}
|
|
118
41
|
}
|