Ícones SVG no MapLibre: pixels e tamanho do símbolo
Decodifique arte SVG para uma camada de símbolos MapLibre, controle densidade e tamanho do ícone e mantenha um original editável. Verifique a forma e a abertura exibidas.
Nesta página
Para usar uma imagem de ícone SVG no MapLibre GL JS, decodifique o SVG com um Image do navegador, passe essa imagem para addImage e referencie seu ID no icon-image de uma camada de símbolos. Mantenha o SVG de origem separado: a imagem registrada no estilo fornece pixels para renderização, em vez de objetos de caminhos SVG editáveis.
O exemplo oficial atual de símbolo SVG demonstra essa rota de decodificação. Afirmar de forma geral que o MapLibre não consegue exibir arte SVG ignoraria esse exemplo. Nosso exemplo fixa a versão 6.12.0 e testa um emblema vazado original em um mapa vazio sem token.
Separe a origem da imagem registrada
A origem mantida contém um caminho losangular composto com abertura interna. Seu viewBox continua 0 0 64 64. Produzimos duas cópias com largura e altura explícitas de 64 ou 128; os dados do caminho continuam idênticos.
A decodificação do navegador transforma cada cópia em uma imagem nas dimensões declaradas. A API addImage do MapLibre aceita objetos de imagem como HTMLImageElement e ImageData. Não aceita um caminho SVG como instrução de geometria de símbolo.
Essa distinção importa ao mudar uma cor ou contorno. Edite o original SVG, decodifique a imagem revisada e atualize a imagem do mapa pela API adequada. Examinar os pixels registrados não recupera a construção original dos caminhos. Nosso guia de SVG com raster incorporado explica a diferença mais ampla entre um contêiner SVG e geometria editável.

Escolha densidade da imagem e tamanho do ícone juntos
Duas configurações afetam o quadro nominal de imagem do símbolo. O pixelRatio da imagem descreve sua densidade; o icon-size da camada redimensiona o ícone resultante. Veja os metadados atuais de imagem de estilo e a especificação de layout de símbolos.
Para nosso símbolo centralizado, sem rotação e sem ajuste ao texto, o quadro nominal é:
logical width = decoded width / image pixelRatio * icon-size
logical height = decoded height / image pixelRatio * icon-sizeUma imagem 128×128 registrada com razão 2 fornece o mesmo quadro nominal 64×64 de uma imagem 64×64 com razão 1 quando icon-size é 1. Mudar a primeira razão para 1 dobra o quadro. Aumentar icon-size para 1.5 transforma um quadro lógico 64×64 em 96×96.
Esse quadro inclui o espaço vazio da origem. Se o emblema parece pequeno demais dentro dele, examine os limites SVG antes de aumentar todos os símbolos. Uma imagem decodificada maior com a mesma razão também aumenta o símbolo; dimensões de entrada, sozinhas, não são uma estratégia de densidade.
O Canvas do mapa tem sua própria razão de pixels. Ela é separada da razão passada a addImage. Nosso arquivo de medição define explicitamente a razão do Canvas como 1 usando as opções Map documentadas; a razão de pixels do dispositivo no navegador era 2. Isso isola as comparações abaixo em vez de tratar pixels de dispositivo de uma captura como dimensões CSS.
Compare a área realmente pintada
Renderizamos cinco casos de símbolos no Chrome com WebGL 2. Cada mapa tinha um ponto, o mesmo fundo claro, nenhum mosaico e nenhum token. As duas origens SVG tinham um caminho idêntico e nenhuma imagem incorporada.
Para medir a arte terracota, nossa leitura percorreu os pixels WebGL reais procurando cor com predominância de vermelho: vermelho maior que 1.35 vezes verde e 1.6 vezes azul. Dividimos as dimensões da caixa delimitadora detectada pela razão entre o buffer do Canvas e o CSS. Isso mede uma região pintada com limiar, não o quadro inteiro da imagem.
| Imagem decodificada | Razão da imagem | icon-size | Quadro nominal | Limites pintados observados |
|---|---|---|---|---|
| 64×64 | 1 | 1 | 64×64 | 62×62 px CSS |
| 128×128 | 1 | 1 | 128×128 | 126×126 px CSS |
| 128×128 | 2 | 1 | 64×64 | 62×62 px CSS |
| 64×64 | 1 | 1.5 | 96×96 | 94×94 px CSS |
| 128×128 | 2 | 1.5 | 96×96 | 94×94 px CSS |
Nem todos os pixels de borda passam nesse limiar de cor, o que explica os limites pintados medidos menores que os quadros nominais. Os pares mostram a relação pretendida de tamanho neste arquivo; não provam qualidade de pixels idêntica em toda densidade ou zoom.
O alfa central da imagem registrada era zero em todos os casos. No mapa renderizado, esse local mostrava a cor de fundo (244, 242, 232) com alfa 255, porque a própria camada de fundo era opaca. Ver pixels opacos do mapa pela abertura não significa que o ícone perdeu a transparência.
São observações limitadas à nossa origem, navegador, configurações de Canvas e limiar. Teste sua arte entregue nos tamanhos de exibição pretendidos, especialmente se contiver traços finos ou aberturas pequenas.
Copie um exemplo inicial de símbolo sem token
Salve este HTML completo e sirva em um servidor web local. É necessário acesso à internet para a biblioteca fixada e o CSS; o mapa não usa serviço de mosaicos nem chave de API. O SVG é incorporado como texto e codificado em uma URL de dados.
O exemplo aguarda image.decode(), portanto o registro vem após decodificação bem-sucedida. Ele registra a imagem conhecida depois que o estilo carrega; não precisa do resolvedor de imagem ausente do exemplo oficial para este único emblema fixo.
<!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>O estado deve mostrar dimensões decodificadas e registradas de [128, 128], razão de imagem 2 e quadro lógico [64, 64]. Esse estado informa o quadro nominal, não uma caixa delimitadora pintada medida. Mude iconSize para 1.5 para obter quadro 96×96. Para comparar a entrada de baixa densidade, mude largura e altura do SVG para 64 e ratio para 1, mantendo caminho e viewBox iguais.
Mantenha icon-image igual ao ID registrado. Se um ícone não aparecer, confirme decodificação e registro bem-sucedidos; depois examine origem, camada, visibilidade e configurações de posição. Nosso exemplo de um ponto usa icon-overlap: 'always' para tornar a comparação independente de colisões com outros símbolos. Seu estilo de produção pode exigir outro comportamento de colisão.
Use um marcador DOM quando esse for o modelo de entrega
O MapLibre também documenta ícones personalizados com DOM Markers. Essa rota envolve um elemento HTML em vez de registrar uma imagem de estilo. Escolha-a quando o fluxo de marcador baseado em elemento combinar com a aplicação; depois examine separadamente seus estilos e posição no navegador.
Não transfira afirmações sobre recursos de ícones vetoriais do Mapbox Studio ou um exemplo do MapTiler SDK para esse processo de imagens de estilo do MapLibre. Uma imagem SVG comum em cores também não se torna um campo de distância com sinal só por mudar a flag sdf. Configurações de densidade controlam como essa imagem é interpretada e exibida; não transformam seus pixels em contornos editáveis.
Se um destino precisa de PNG, nosso guia de renderização SVG com Sharp cobre a preparação de uma cópia raster de entrega. Mantenha o original SVG comum para edições; SVG inline e entrega por imagem também têm modelos de interação diferentes.
Se seu ícone existe só como PNG ou JPG e você precisa de arte editável, recupere contornos SVG com o PerfectVector, examine a forma externa e a abertura e mantenha esse original antes de decodificar a imagem do mapa. O código do mapa ainda controla densidade, tamanho do símbolo e posição geográfica. Um SVG limpo existente pode ir direto pela rota de decodificação; o guia de vetorização explica quando uma conversão raster é útil.
Perguntas frequentes
O MapLibre GL JS pode exibir arte SVG como símbolo? Sim. Seu exemplo oficial atual decodifica texto SVG com um Image do navegador e registra essa imagem para uma camada de símbolos. Mantenha o SVG original separado da imagem registrada.
Por que uma entrada maior aumentou meu ícone? Aumentar as dimensões decodificadas e manter a mesma razão de pixels da imagem e icon-size aumenta o quadro nominal. Combine densidade de imagem e escala de exibição deliberadamente.
pixelRatio preserva caminhos SVG editáveis no símbolo? Não. Ele descreve a densidade da imagem. Mantenha e edite o SVG de origem, depois decodifique a arte revisada para o mapa.
Por que o pixel do mapa dentro do furo do ícone é opaco? Uma camada de fundo opaca pode aparecer por uma abertura transparente do ícone. Examine o alfa da imagem registrada separadamente do Canvas do mapa totalmente composto.
Fontes
- MapLibre — Exibir um símbolo SVG remoto — A rota atual de texto SVG, imagem do navegador e addImage.
- MapLibre — API Map — Objetos de imagem aceitos e registro de imagem em execução.
- MapLibre — StyleImageMetadata — Metadados de densidade de imagem e interpretação SDF.
- MapLibre — Especificação de layout de símbolos — Escala de ícones e comportamento de colisão.
- MapLibre — MapOptions — Opções de Canvas usadas para controlar o arquivo de medição.
- MDN — HTMLImageElement.decode — Aguardar a decodificação de imagem no navegador e tratar falhas.
- MapLibre — Adicionar ícones personalizados com Markers — O fluxo separado de marcadores com elementos HTML.
Mais do blog

Logos SVG no Satori: preserve a arte no cartão da marca
Incorpore um logo SVG em um cartão Satori com dimensões explícitas e dados independentes. Examine a arte aninhada e renderize um PNG separado para entrega.

SVG para Canvas: carregue a arte antes de exportar PNG
Carregue um SVG inteiro com Image.decode, desenhe no tamanho de bitmap escolhido, teste CORS e leitura PNG e separe a origem editável dos pixels exportados.
