Skip to content

versatiles-org/versatiles-svg-renderer

Repository files navigation

NPM version NPM downloads Code coverage CI status License

VersaTiles SVG Renderer

Renders vector maps as SVG.

Example: rendered map view

Download SVG

Supported layer types: background, fill, line, circle, symbol, and raster.

Installation

npm install @versatiles/svg-renderer

Usage

Node.js

import { renderToSVG } from '@versatiles/svg-renderer';
import { styles } from '@versatiles/style';
import { writeFileSync } from 'node:fs';

const svg = await renderToSVG({
	style: styles.colorful(),
	width: 800,
	height: 600,
	lon: 13.4,
	lat: 52.5,
	zoom: 10,
});

writeFileSync('map.svg', svg);

Browser

import { renderToSVG } from '@versatiles/svg-renderer';

const svg = await renderToSVG({
	style: await fetch('https://tiles.versatiles.org/assets/styles/colorful/style.json').then((r) =>
		r.json(),
	),
	width: 800,
	height: 600,
	lon: 13.4,
	lat: 52.5,
	zoom: 10,
});

document.body.innerHTML = svg;

MapLibre Plugin

The package includes an SVGExportControl that adds an export button to any MapLibre GL JS map.

<!DOCTYPE html>
<html>
	<head>
		<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.css" />
		<script src="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.js"></script>
		<script src="https://unpkg.com/@versatiles/svg-renderer/dist/maplibre.umd.js"></script>
	</head>
	<body>
		<div id="map"></div>
		<script>
			const map = new maplibregl.Map({
				container: 'map',
				style: 'https://tiles.versatiles.org/assets/styles/colorful/style.json',
				center: [13.4, 52.5],
				zoom: 10,
			});
			map.addControl(new VersaTilesSVG.SVGExportControl(), 'top-right');
		</script>
	</body>
</html>

The control opens a panel where the user can set width, height, and scale, preview the SVG, download it, or open it in a new tab. Map interactions are disabled while the panel is open.

Options:

new SVGExportControl({
	defaultWidth: 1024, // default: 1024
	defaultHeight: 1024, // default: 1024
	defaultScale: 1, // default: 1
});

API

renderToSVG(options): Promise<string>

Option Type Default Description
style StyleSpecification (required) MapLibre style specification
width number 1024 Output width in pixels
height number 1024 Output height in pixels
lon number 0 Center longitude
lat number 0 Center latitude
zoom number 2 Zoom level
renderLabels boolean false Enable rendering of text labels and icons

About renderLabels

When renderLabels is set to true, symbol layers are rendered, including text labels and sprite-based icons. By default, this option is disabled.

Warning

The rendering of labels and icons is experimental and may produce imperfect results. Since we cannot use the original layouting engine of MapLibre GL JS, there are known limitations:

  • No collision detection: Text labels are rendered without collision detection, so labels may overlap.
  • Simplified text placement: Labels can not be positioned along lines.

E2E Visual Comparison

A visual comparison report between the SVG renderer and MapLibre GL JS is published to GitHub Pages:

View Report

Dependency Graph

---
config:
  layout: elk
---
flowchart TB

subgraph 0["src"]
1["demo.ts"]
2["index.ts"]
subgraph 3["pipeline"]
4["render.ts"]
E["style_layer.ts"]
end
subgraph 5["sources"]
6["index.ts"]
7["geojson.ts"]
9["merge.ts"]
A["raster.ts"]
B["tiles.ts"]
C["sprite.ts"]
D["vector.ts"]
end
8["geometry.ts"]
subgraph F["renderer"]
G["svg.ts"]
H["color.ts"]
I["svg_path.ts"]
N["types.ts"]
end
subgraph J["maplibre"]
K["control.ts"]
L["panel_css.ts"]
M["index.ts"]
end
end
1-->2
2-->4
2-->G
4-->6
4-->C
4-->E
6-->7
6-->9
6-->A
6-->C
6-->D
7-->8
9-->8
A-->B
B-->8
D-->8
D-->B
G-->H
G-->I
K-->2
K-->L
M-->2
M-->K

class 0,3,5,F,J subgraphs;
classDef subgraphs fill-opacity:0.1, fill:#888, color:#888, stroke:#888;
Loading