PerfectVector
Oleh Irene Kim

Ikon SVG MapLibre: Periksa Piksel dan Ukuran Simbol

Dekode gambar SVG khusus untuk layer simbol MapLibre, kendalikan kepadatan gambar dan ukuran ikon, serta simpan master yang bisa diedit. Verifikasi bentuk dan bukaan yang ditampilkan.

8 menit baca
Di halaman ini

Untuk memakai gambar ikon SVG di MapLibre GL JS, dekode SVG dengan Image peramban, teruskan gambar itu ke addImage, dan rujuk ID-nya dalam icon-image layer simbol. Simpan SVG sumber secara terpisah: gambar gaya yang didaftarkan menyediakan piksel untuk rendering, bukan objek path SVG yang bisa diedit.

Contoh simbol SVG resmi saat ini mendemonstrasikan jalur dekode ini. Klaim menyeluruh bahwa MapLibre tidak bisa menampilkan gambar SVG akan melewatkannya. Contoh kami mengunci 6.12.0 dan menguji lambang berlubang asli dalam peta kosong tanpa token.

Pisahkan sumber dari gambar yang didaftarkan

Sumber yang disimpan berisi satu path wajik majemuk dengan bukaan dalam. viewBox-nya tetap 0 0 64 64. Kami membuat dua salinan dengan lebar dan tinggi eksplisit 64 atau 128; data path tetap identik.

Dekode peramban mengubah setiap salinan menjadi gambar pada dimensi yang dinyatakan. API addImage MapLibre menerima objek gambar seperti HTMLImageElement dan ImageData. API ini tidak menerima path SVG sebagai instruksi geometri simbol.

Perbedaan itu penting ketika Anda mengubah warna atau kontur. Edit master SVG, dekode gambar yang direvisi, lalu perbarui gambar peta melalui API yang sesuai. Memeriksa piksel yang didaftarkan tidak akan memulihkan konstruksi path asli. Panduan SVG dengan raster tertanam kami menjelaskan perbedaan lebih luas antara wadah SVG dan geometri yang bisa diedit.

Gambar sumber dan pewarnaan simbol
Ilustrasi konseptual lambang wajik berlubang sebagai kontur yang bisa diedit dan salinan tampilan berbasis piksel
Ilustrasi: pertahankan SVG yang bisa diedit sambil mengendalikan ukuran tampilan gambar hasil dekode. Pengukuran WebGL di bawah berasal dari spesimen peramban yang dibuat terpisah.

Pilih kepadatan gambar dan ukuran ikon bersama-sama

Dua pengaturan memengaruhi bingkai gambar nominal simbol kami. pixelRatio gambar mendeskripsikan kepadatannya; icon-size layer menskalakan ikon hasilnya. Lihat metadata gambar gaya dan spesifikasi tata letak simbol saat ini.

Untuk simbol terpusat tanpa rotasi dan tanpa penyesuaian teks kami, bingkai nominalnya adalah:

logical width = decoded width / image pixelRatio * icon-size
logical height = decoded height / image pixelRatio * icon-size

Gambar 128×128 yang didaftarkan pada rasio 2 memberikan bingkai nominal 64×64 yang sama dengan gambar 64×64 pada rasio 1 ketika icon-size bernilai 1. Mengubah rasio pertama menjadi 1 menggandakan bingkainya. Menaikkan icon-size ke 1,5 membuat bingkai gambar logis 64×64 menjadi 96×96.

Bingkai ini menyertakan ruang kosong sumber. Jika lambang terlihat terlalu kecil di dalamnya, periksa batas SVG sebelum memperbesar semua simbol. Gambar hasil dekode yang lebih besar dengan rasio sama juga memperbesar simbol; dimensi masukan saja bukan strategi kepadatan.

Kanvas peta memiliki rasio piksel sendiri. Itu terpisah dari rasio yang diteruskan ke addImage. Contoh pengukuran kami secara eksplisit menetapkan rasio kanvas ke 1 menggunakan opsi Map yang didokumentasikan; rasio piksel perangkat peramban adalah 2. Ini mengisolasi perbandingan berikut alih-alih menganggap piksel perangkat dalam tangkapan layar sebagai dimensi CSS.

Bandingkan jejak pewarnaan sebenarnya

Kami merender lima kasus simbol di Chrome dengan WebGL 2. Setiap peta memiliki satu titik, latar terang yang sama, tanpa tile, dan tanpa token. Kedua sumber SVG memiliki satu path identik tanpa gambar tertanam.

Untuk mengukur gambar terakota, pembacaan kami memindai piksel WebGL sebenarnya untuk warna dominan merah: merah lebih besar dari 1,35 kali hijau dan 1,6 kali biru. Kami membagi dimensi kotak pembatas yang terdeteksi dengan rasio backing kanvas terhadap CSS. Ini mengukur wilayah pewarnaan berdasarkan ambang, bukan seluruh bingkai gambar.

Gambar hasil dekodeRasio gambaricon-sizeBingkai nominalBatas pewarnaan yang diamati
64×641164×6462×62 px CSS
128×12811128×128126×126 px CSS
128×1282164×6462×62 px CSS
64×6411.596×9694×94 px CSS
128×12821.596×9694×94 px CSS

Tidak semua piksel tepi lolos ambang warna tersebut, yang menjelaskan mengapa batas pewarnaan terukur lebih kecil daripada bingkai nominal. Pasangan itu menunjukkan hubungan ukuran yang dimaksud dalam contoh uji ini; pasangan itu tidak membuktikan kualitas piksel identik pada setiap kepadatan atau zoom.

Alfa tengah gambar yang didaftarkan bernilai nol dalam setiap kasus. Pada peta yang dirender, lokasi itu menunjukkan warna latar (244, 242, 232) dengan alfa 255 karena layer latar itu sendiri buram. Melihat piksel peta buram melalui bukaan tidak berarti ikon kehilangan transparansinya.

Ini pengamatan terbatas atas sumber, peramban, pengaturan kanvas, dan ambang kami. Uji gambar yang diserahkan pada ukuran tampilan yang dimaksud, terutama jika memiliki stroke tipis atau bukaan kecil.

Salin kode awal simbol tanpa token

Simpan HTML lengkap ini dan sajikan dari server web lokal. Akses internet diperlukan untuk pustaka versi terkunci dan CSS; peta tidak memakai layanan tile atau API key. SVG disematkan sebagai teks dan dikodekan menjadi data URL.

Contoh menunggu image.decode(), sehingga pendaftaran mengikuti keberhasilan dekode. Contoh mendaftarkan gambar yang diketahui setelah gaya dimuat; tidak diperlukan resolver gambar hilang milik contoh resmi untuk satu lambang tetap ini.

<!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>

Status seharusnya menunjukkan dimensi hasil dekode dan terdaftar [128, 128], rasio gambar 2, dan bingkai logis [64, 64]. Status ini melaporkan bingkai nominal, bukan kotak pembatas pewarnaan yang diukur. Ubah iconSize menjadi 1,5 untuk bingkai 96×96. Untuk membandingkan masukan berkepadatan rendah, ubah lebar dan tinggi SVG menjadi 64 serta ratio menjadi 1 sambil mempertahankan path dan viewBox yang sama.

Jaga icon-image sama dengan ID yang didaftarkan. Jika ikon tidak muncul, pastikan dekode dan pendaftaran berhasil, lalu periksa sumber, layer, visibilitas, dan pengaturan penempatan. Contoh satu titik kami memakai icon-overlap: 'always' agar perbandingan tidak bergantung pada tabrakan dengan simbol lain. Gaya produksi Anda mungkin membutuhkan perilaku tabrakan berbeda.

Gunakan marker DOM jika itu model penyerahannya

MapLibre juga mendokumentasikan ikon khusus dengan DOM Marker. Jalur itu membungkus elemen HTML alih-alih mendaftarkan gambar gaya. Pilih ketika alur marker berbasis elemen sesuai dengan aplikasi, lalu periksa gaya peramban dan penempatannya secara terpisah.

Jangan memindahkan klaim fitur ikon vektor Mapbox Studio atau contoh MapTiler SDK ke rangkaian gambar gaya MapLibre ini. Gambar SVG penuh warna biasa juga tidak menjadi signed distance field hanya dengan mengubah flag sdf. Pengaturan kepadatan mengendalikan cara gambar ini ditafsirkan dan ditampilkan; pengaturan itu tidak mengubah pikselnya menjadi kontur yang bisa diedit.

Jika tujuan membutuhkan berkas PNG, panduan rendering SVG Sharp kami membahas penyiapan salinan raster untuk diserahkan. Simpan master SVG biasa untuk pengeditan; SVG inline dan penyerahan gambar juga memiliki model interaksi berbeda.

Jika ikon hanya tersedia sebagai PNG atau JPG dan Anda membutuhkan gambar yang bisa diedit, pulihkan kontur SVG dengan PerfectVector, periksa bentuk luar dan bukaan, serta simpan master itu sebelum mendekode gambar peta. Kode peta tetap mengendalikan kepadatan, ukuran simbol, dan posisi geografis. SVG bersih yang sudah ada bisa langsung melalui alur dekode; panduan vektorisasi menjelaskan kapan konversi raster berguna.

Pertanyaan umum

Bisakah MapLibre GL JS menampilkan gambar SVG sebagai simbol? Bisa. Contoh resmi saat ini mendekode teks SVG dengan Image peramban dan mendaftarkan gambar itu untuk layer simbol. Pisahkan SVG asli dari gambar yang didaftarkan.

Mengapa masukan lebih besar membuat ikon saya lebih besar? Menaikkan dimensi hasil dekode sambil mempertahankan rasio piksel gambar dan icon-size yang sama memperbesar bingkai nominal. Pasangkan kepadatan gambar dan skala tampilan dengan sengaja.

Apakah pixelRatio mempertahankan path SVG yang bisa diedit dalam simbol? Tidak. Itu mendeskripsikan kepadatan gambar. Simpan dan edit SVG sumber, lalu dekode gambar yang direvisi untuk peta.

Mengapa piksel peta di dalam lubang ikon saya buram? Layer latar buram dapat terlihat melalui bukaan ikon transparan. Periksa alfa gambar yang didaftarkan secara terpisah dari kanvas peta yang sudah dikomposisikan sepenuhnya.

Sumber

  1. MapLibre — Menampilkan simbol SVG jarak jauh — Jalur teks SVG, gambar peramban, dan addImage saat ini.
  2. MapLibre — API Map — Objek gambar yang diterima dan pendaftaran gambar saat runtime.
  3. MapLibre — StyleImageMetadata — Metadata kepadatan gambar dan interpretasi SDF.
  4. MapLibre — Spesifikasi tata letak simbol — Penskalaan ikon dan perilaku tabrakan.
  5. MapLibre — MapOptions — Opsi kanvas yang dipakai untuk mengendalikan contoh pengukuran.
  6. MDN — HTMLImageElement.decode — Menunggu dekode gambar peramban dan menangani kegagalan.
  7. MapLibre — Menambahkan ikon khusus dengan Marker — Alur marker elemen HTML yang terpisah.

Lebih banyak dari blog

PerfectVector

Mulai dengan SVG yang lebih rapi
dan lebih mudah diedit

Tanpa kartu kredit