SVG-Icons in MapLibre: Pixel und Symbolgröße prüfen
Dekodiere eigene SVG-Grafik für eine MapLibre-Symbolebene, steuere Bilddichte und Icongröße und behalte eine bearbeitbare Masterdatei. Prüfe dargestellte Form und Öffnung.
Auf dieser Seite
Um ein SVG-Iconbild in MapLibre GL JS zu verwenden, dekodiere das SVG mit einem Browser-Image, übergib dieses Bild an addImage und referenziere seine ID in icon-image einer Symbolebene. Behalte das Quell-SVG separat. Das registrierte Stilbild liefert Pixel für die Darstellung statt bearbeitbarer SVG-Pfadobjekte.
Das aktuelle offizielle SVG-Symbolbeispiel zeigt diesen Dekodierungsweg. Die pauschale Aussage, MapLibre könne keine SVG-Grafik anzeigen, würde ihn übersehen. Unser Beispiel legt Version 6.12.0 fest und testet ein selbst erstelltes hohles Emblem auf einer leeren Karte ohne Token.
Halte Quelle und registriertes Bild getrennt
Die aufbewahrte Quelle enthält einen zusammengesetzten Rautenpfad mit innerer Öffnung. Seine viewBox bleibt 0 0 64 64. Wir erzeugen zwei Kopien mit ausdrücklich festgelegter Breite und Höhe von 64 oder 128. Die Pfaddaten bleiben identisch.
Die Browserdekodierung macht jede Kopie zu einem Bild mit den angegebenen Abmessungen. MapLibres addImage-API akzeptiert Bildobjekte wie HTMLImageElement und ImageData. Sie akzeptiert keinen SVG-Pfad als Geometrieanweisung für ein Symbol.
Dieser Unterschied zählt, wenn du Farbe oder Kontur änderst. Bearbeite die SVG-Masterdatei, dekodiere das überarbeitete Bild und aktualisiere das Kartenbild über die passende API. Das Prüfen der registrierten Pixel stellt die ursprüngliche Pfadkonstruktion nicht wieder her. Unser Leitfaden zu SVGs mit eingebetteten Rasterbildern erklärt den grundsätzlichen Unterschied zwischen SVG-Container und bearbeitbarer Geometrie.

Wähle Bilddichte und Icongröße gemeinsam
Zwei Einstellungen beeinflussen den nominellen Bildrahmen unseres Symbols. Das pixelRatio des Bilds beschreibt seine Dichte; icon-size der Ebene skaliert das entstandene Icon. Siehe die aktuellen Stilbildmetadaten und die Spezifikation zum Symbollayout.
Für unser zentriertes, nicht gedrehtes Symbol ohne Textanpassung lautet der nominelle Rahmen:
logical width = decoded width / image pixelRatio * icon-size
logical height = decoded height / image pixelRatio * icon-sizeEin 128×128 großes Bild, das mit Verhältnis 2 registriert wird, ergibt denselben nominellen Rahmen von 64×64 wie ein 64×64 großes Bild mit Verhältnis 1, wenn icon-size gleich 1 ist. Änderst du das erste Verhältnis zu 1, verdoppelt sich sein Rahmen. Ein höheres icon-size von 1.5 macht aus einem logischen Bildrahmen von 64×64 einen von 96×96.
Dieser Rahmen schließt Quellleerraum ein. Wirkt das Emblem darin zu klein, prüfe die SVG-Grenzen, bevor du jedes Symbol vergrößerst. Ein größeres dekodiertes Bild bei gleichem Verhältnis macht auch das Symbol größer. Eingabeabmessungen allein sind keine Dichtestrategie.
Das Kartencanvas besitzt ein eigenes Pixelverhältnis. Es ist vom an addImage übergebenen Verhältnis getrennt. Unsere Messtestdatei setzt das Canvas-Verhältnis über die dokumentierten Map-Optionen ausdrücklich auf 1. Das Geräte-Pixelverhältnis des Browsers war 2. So werden die folgenden Vergleiche isoliert, statt Gerätepixel eines Screenshots als CSS-Abmessungen zu behandeln.
Vergleiche die tatsächlich bemalte Fläche
Wir renderten fünf Symbolfälle in Chrome mit WebGL 2. Jede Karte hatte einen Punkt, denselben hellen Hintergrund, keine Kacheln und keinen Token. Beide SVG-Quellen hatten einen identischen Pfad und kein eingebettetes Bild.
Um die terrakottafarbene Grafik zu messen, durchsuchte unsere Auslesung die tatsächlichen WebGL-Pixel nach rotdominierter Farbe: Rot größer als das 1.35-Fache von Grün und das 1.6-Fache von Blau. Die erkannten Begrenzungsrahmenabmessungen teilten wir durch das Verhältnis zwischen internem Canvas-Puffer und CSS-Größe. Das misst einen anhand eines Schwellenwerts erkannten Farbbereich, nicht den gesamten Bildrahmen.
| Dekodiertes Bild | Bildverhältnis | icon-size | Nomineller Rahmen | Beobachtete Farbgrenzen |
|---|---|---|---|---|
| 64×64 | 1 | 1 | 64×64 | 62×62 CSS px |
| 128×128 | 1 | 1 | 128×128 | 126×126 CSS px |
| 128×128 | 2 | 1 | 64×64 | 62×62 CSS px |
| 64×64 | 1 | 1.5 | 96×96 | 94×94 CSS px |
| 128×128 | 2 | 1.5 | 96×96 | 94×94 CSS px |
Nicht alle Kantenpixel überschreiten diesen Farbschwellenwert. Deshalb sind die gemessenen Farbgrenzen kleiner als die nominellen Rahmen. Die Paare zeigen die beabsichtigte Größenbeziehung in dieser Testdatei. Sie beweisen keine identische Pixelqualität bei jeder Dichte oder Zoomstufe.
Das Alpha in der Mitte des registrierten Bilds war in jedem Fall null. Auf der gerenderten Karte zeigte diese Stelle die Hintergrundfarbe (244, 242, 232) mit Alpha 255, weil die Hintergrundebene selbst undurchsichtig war. Undurchsichtige Kartenpixel durch die Öffnung zu sehen bedeutet nicht, dass das Icon seine Transparenz verloren hat.
Diese Beobachtungen sind auf unsere Quelle, den Browser, die Canvas-Einstellungen und den Schwellenwert begrenzt. Teste die ausgelieferte Grafik bei ihren vorgesehenen Darstellungsgrößen, besonders bei dünnen Konturen oder kleinen Öffnungen.
Kopiere eine Symbolvorlage ohne Token
Speichere dieses vollständige HTML und stelle es über einen lokalen Webserver bereit. Für die festgelegte Bibliothek und CSS ist Internetzugriff erforderlich. Die Karte verwendet weder Kacheldienst noch API-Schlüssel. Das SVG ist als Text eingebettet und in eine Daten-URL kodiert.
Das Beispiel wartet auf image.decode(), sodass die Registrierung nach erfolgreicher Dekodierung erfolgt. Es registriert das bekannte Bild nach dem Laden des Stils. Für dieses einzelne feste Emblem benötigt es nicht die Auflösung fehlender Bilder aus dem offiziellen Beispiel.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>MapLibre decoded SVG symbol</title>
<link rel="stylesheet"
href="https://unpkg.com/maplibre-gl@6.12.0/dist/maplibre-gl.css">
<style>#map { width: 360px; height: 280px; }</style>
<div id="map"></div>
<pre id="status">Loading…</pre>
<script type="module">
import * as ml from
'https://unpkg.com/maplibre-gl@6.12.0/dist/maplibre-gl.mjs';
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 64 64"><path fill="#c45b39" fill-rule="evenodd" d="M32 0 L64 32 L32 64 L0 32 Z M32 16 L16 32 L32 48 L48 32 Z"/></svg>`;
const image = new Image();
image.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
try {
await image.decode();
const ratio = 2;
const iconSize = 1;
const map = new ml.Map({
container: 'map', center: [0, 0], zoom: 2, interactive: false,
attributionControl: false, fadeDuration: 0,
style: { version: 8, sources: {}, layers: [{
id: 'background', type: 'background',
paint: { 'background-color': '#f4f2e8' }
}] }
});
map.on('error', e => {
document.querySelector('#status').textContent = e.error.message;
});
await map.once('load');
map.addImage('emblem', image, { pixelRatio: ratio });
map.addSource('point', { type: 'geojson', data: {
type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] },
properties: {}
} });
map.addLayer({ id: 'emblem', type: 'symbol', source: 'point', layout: {
'icon-image': 'emblem', 'icon-size': iconSize, 'icon-overlap': 'always'
} });
await map.once('idle');
const registered = map.getImage('emblem');
document.querySelector('#status').textContent = JSON.stringify({
version: ml.getVersion(),
decoded: [image.naturalWidth, image.naturalHeight],
registered: [registered.data.width, registered.data.height],
imagePixelRatio: registered.pixelRatio,
logicalFrame: [image.naturalWidth / ratio * iconSize,
image.naturalHeight / ratio * iconSize]
}, null, 2);
} catch (error) {
document.querySelector('#status').textContent = String(error);
}
</script>
</html>Der Status sollte dekodierte und registrierte Abmessungen von [128, 128], das Bildverhältnis 2 und den logischen Rahmen [64, 64] zeigen. Dieser Status meldet den nominellen Rahmen, keinen gemessenen Farbbegrenzungsrahmen. Ändere iconSize für einen 96×96 großen Rahmen zu 1.5. Für den Vergleich mit der Eingabe niedriger Dichte ändere SVG-Breite und -Höhe zu 64 und ratio zu 1. Pfad und viewBox bleiben gleich.
Halte icon-image identisch mit der registrierten ID. Erscheint ein Icon nicht, bestätige erfolgreiche Dekodierung und Registrierung. Prüfe dann Quelle, Ebene, Sichtbarkeit und Platzierungseinstellungen. Unser Einzelpunktbeispiel verwendet icon-overlap: 'always', um den Vergleich unabhängig von Kollisionen mit anderen Symbolen zu machen. Dein Produktionsstil braucht möglicherweise anderes Kollisionsverhalten.
Verwende einen DOM-Marker, wenn das zum Ausgabemodell passt
MapLibre dokumentiert auch eigene Icons mit DOM-Markern. Dieser Weg kapselt ein HTML-Element, statt ein Stilbild zu registrieren. Wähle ihn, wenn der elementbasierte Markerablauf zur Anwendung passt, und prüfe Browserstile und Platzierung anschließend separat.
Übertrage keine Aussagen aus Mapbox Studios Vektoricon-Funktionen oder einem MapTiler-SDK-Beispiel auf diese MapLibre-Stilbildpipeline. Auch ein gewöhnliches vollfarbiges SVG-Bild wird nicht allein durch Ändern des sdf-Flags zu einem vorzeichenbehafteten Distanzfeld. Dichteinstellungen steuern, wie das Bild interpretiert und angezeigt wird. Sie machen aus seinen Pixeln keine bearbeitbaren Konturen.
Braucht ein Ziel eine PNG-Datei, behandelt unser Leitfaden zum SVG-Rendering mit Sharp die Vorbereitung einer Raster-Ausgabekopie. Behalte die gewöhnliche SVG-Masterdatei zum Bearbeiten. Auch Inline-SVG und Bildausgabe haben unterschiedliche Interaktionsmodelle.
Liegt dein Icon nur als PNG oder JPG vor und brauchst du bearbeitbare Grafik, stelle SVG-Konturen mit PerfectVector wieder her. Prüfe Außenform und Öffnung und behalte diese Masterdatei, bevor du das Kartenbild dekodierst. Der Kartencode steuert weiterhin Dichte, Symbolgröße und geografische Position. Ein vorhandenes sauberes SVG kann direkt durch den Dekodierungsablauf gehen. Der Vektorisierungsleitfaden erklärt, wann eine Rasterkonvertierung sinnvoll ist.
Häufige Fragen
Kann MapLibre GL JS SVG-Grafik als Symbol anzeigen? Ja. Das aktuelle offizielle Beispiel dekodiert SVG-Text mit einem Browser-Image und registriert dieses Bild für eine Symbolebene. Behalte das ursprüngliche SVG getrennt vom registrierten Bild.
Warum hat eine größere Eingabe mein Icon vergrößert? Größere dekodierte Abmessungen bei unverändertem Bild-Pixelverhältnis und icon-size vergrößern den nominellen Rahmen. Stimme Bilddichte und Darstellungsskalierung bewusst aufeinander ab.
Erhält pixelRatio bearbeitbare SVG-Pfade im Symbol? Nein. Es beschreibt die Bilddichte. Behalte und bearbeite das Quell-SVG und dekodiere anschließend die überarbeitete Grafik für die Karte.
Warum ist der Kartenpixel im Loch meines Icons undurchsichtig? Eine undurchsichtige Hintergrundebene kann durch die transparente Iconöffnung sichtbar sein. Prüfe das Alpha des registrierten Bilds getrennt vom vollständig zusammengesetzten Kartencanvas.
Quellen
- MapLibre – Ein entferntes SVG-Symbol anzeigen – Der aktuelle Weg über SVG-Text, Browserbild und addImage.
- MapLibre – Map-API – Akzeptierte Bildobjekte und Bildregistrierung zur Laufzeit.
- MapLibre – StyleImageMetadata – Bilddichte und Metadaten zur SDF-Interpretation.
- MapLibre – Symbollayout-Spezifikation – Iconskalierung und Kollisionsverhalten.
- MapLibre – MapOptions – Canvas-Optionen zur Kontrolle der Messtestdatei.
- MDN – HTMLImageElement.decode – Auf Browserbilddekodierung warten und Fehler behandeln.
- MapLibre – Eigene Icons mit Markers hinzufügen – Separater Markerablauf mit HTML-Elementen.
Mehr aus dem Blog

SVG-Logos in Satori: Grafik in einer Markenkarte erhalten
Bette ein SVG-Logo mit festen Abmessungen und eigenständigen Bilddaten in eine Satori-Karte ein. Prüfe die verschachtelte Grafik und rendere eine separate PNG-Ausgabedatei.

SVG auf Canvas: Grafik vor dem PNG-Export laden
Lade ein vollständiges SVG mit Image.decode, zeichne es in gewählter Bitmapgröße, prüfe CORS und PNG-Auslesung und halte die bearbeitbare Quelle von exportierten Pixeln getrennt.
