Marker SVG Leaflet: Sejajarkan Ujung dengan iconAnchor
Posisikan marker SVG khusus di Leaflet dengan memetakan ujung terlihat ke iconAnchor. Perhitungkan padding viewBox, penyesuaian rasio aspek, dan perubahan ukuran ikon.
Di halaman ini
Untuk marker SVG khusus Leaflet, tetapkan iconSize ke dimensi gambar yang ditampilkan dan iconAnchor ke posisi piksel ujung yang terlihat di dalam gambar tersebut. Ukur dari sudut kiri atas gambar. Margin SVG transparan ikut dihitung dalam dimensi itu, sehingga setengah lebar dan seluruh tinggi bisa meleset pada pin asimetris atau ber-padding.
Panduan ini memakai pin asli yang ujungnya berada di kanan pusat badannya. Kami membandingkan dua bingkai sumber pada dua ukuran ikon dalam peta peramban tanpa tile. Jika Anda sudah memiliki gambar SVG bersih, gunakan langsung; penempatan anchor tidak memerlukan vektorisasi.
Pisahkan gambar, kotak gambar, dan titik peta
Tiga sistem koordinat bertemu di sini. Path SVG mendeskripsikan gambar dalam satuan sumber. iconSize menetapkan kotak gambar yang ditampilkan dalam piksel. Leaflet menempatkan titik di dalam kotak yang ditentukan iconAnchor pada lokasi geografis marker. Referensi Icon mendefinisikan opsi ini dan origin anchor kiri atas.
Pin konvensional bisa mencapai tengah tepi bawah, tetapi gambar Anda bisa berakhir di tempat lain. Nilai bawaan Leaflet yang didokumentasikan adalah anchor terpusat ketika ukuran ditentukan. Nilai tengah bawah dalam eksperimen kami merupakan asumsi eksplisit yang diuji, bukan nilai bawaan tersebut.
Tutorial ikon khusus resmi menunjukkan cara meneruskan instans L.icon ke marker. Pekerjaan tambahan untuk gambar impor adalah menemukan titik di dalam gambar yang seharusnya menyentuh koordinat peta.

Petakan ujung sumber ke piksel ikon
Ujung pin kami berada pada koordinat sumber (40, 80). Bingkai rapatnya adalah viewBox="0 0 60 80". Versi ber-padding hanya mengubah bingkai menjadi viewBox="-20 -10 100 120"; kedua berkas mempertahankan path dan bukaan transparan yang sama.
Referensi viewBox menjelaskan persegi panjang sumber ini. Ruang kosong di dalamnya ikut bergerak bersama gambar. Panduan kotak pembatas SVG kami menjelaskan mengapa kanvas dan bentuk yang dicat bisa memiliki batas berbeda.
Kedua versi secara eksplisit memakai preserveAspectRatio="xMidYMid meet". Ini menyesuaikan bingkai secara seragam di dalam viewport dan memusatkan ruang tersisa. Lihat referensi preserveAspectRatio MDN untuk pengaturan tersebut.
Untuk mode penyesuaian ini, misalkan W dan H adalah dimensi ikon, (minX, minY, vbW, vbH) adalah viewBox, dan (tipX, tipY) adalah ujung sumber:
s = min(W / vbW, H / vbH)
offsetX = (W - vbW * s) / 2
offsetY = (H - vbH * s) / 2
anchorX = (tipX - minX) * s + offsetX
anchorY = (tipY - minY) * s + offsetYUntuk ikon ber-padding 60×80, s bernilai 0.6. Bingkai sumber 100×120 menempati 60×72 piksel, menyisakan empat piksel di atas dan bawah. Ujung menjadi [36, 58], termasuk offset vertikal itu. Sekadar mengambil pecahan masing-masing dimensi secara terpisah akan melewatkan tahap penyesuaian seragam.
| Bingkai sumber | Ukuran ikon | Anchor ujung yang dihitung |
|---|---|---|
| Rapat, 0 0 60 80 | 60×80 | [40, 80] |
| Rapat, 0 0 60 80 | 90×120 | [60, 120] |
| Ber-padding, -20 -10 100 120 | 60×80 | [36, 58] |
| Ber-padding, -20 -10 100 120 | 90×120 | [54, 87] |
Perhitungan ini berlaku pada gambar kami tanpa transformasi dan pengaturan meet terpusat eksplisit. Perataan berbeda, slice, atau none membutuhkan pemetaan koordinat yang sesuai. Panduan rasio aspek kami membahas pilihan tersebut. Transformasi CSS tambahan pada gambar marker juga perlu diperiksa secara terpisah.
Periksa penempatan dalam peta tanpa tile
Kami memakai Leaflet 1.9.4, rilis stabil yang disebut pada halaman unduhan resmi. Eksperimen memuat JavaScript dan CSS versi terkunci secara lokal tanpa menambahkan layer tile. Setiap peta memproyeksikan koordinat [0, 0] ke tanda bidik biru; peta menampilkan satu gambar SVG di samping titik acuan tersebut.
Pemeriksaan sumber menemukan satu path majemuk identik tanpa gambar raster tertanam dalam setiap SVG. Dimensi gambar peramban adalah 60×80 dan 90×120 piksel sesuai permintaan. Menggunakan persegi panjang yang diamati dari setiap gambar, kami membandingkan posisi ujung yang dipetakan dengan titik geografis yang diproyeksikan:
| Sumber | Ukuran ikon | Kesalahan dengan asumsi anchor tengah bawah | Kesalahan dengan anchor ujung yang dihitung |
|---|---|---|---|
| Rapat | 60×80 | 10 px ke kanan | 0 px |
| Rapat | 90×120 | 15 px ke kanan | 0 px |
| Ber-padding | 60×80 | 6 px ke kanan, 22 px ke atas | 0 px |
| Ber-padding | 90×120 | 9 px ke kanan, 33 px ke atas | 0 px |
Tanda bidik juga terlihat bertemu dengan ujung pin yang dikoreksi. Ini pengamatan atas contoh uji buatan sendiri dalam satu peramban Chrome, bukan jaminan untuk setiap SVG, peramban, atau integrasi peta. Pin ber-padding tetap lebih kecil di dalam kotak gambar yang sama setelah anchor dikoreksi. Penempatan dan ukuran gambar merupakan keputusan terpisah.
Salin kode awal marker yang berfungsi
Simpan HTML lengkap ini sebagai marker.html dan sajikan dari server web lokal. Kode memuat berkas Leaflet versi terkunci dari CDN yang ditautkan halaman unduhan Leaflet. SVG dikodekan menjadi URL gambar, sehingga contoh tidak membutuhkan berkas ikon atau layanan tile. Akses internet diperlukan untuk kedua berkas pustaka tersebut.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Leaflet SVG tip anchor</title>
<link rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<style>
#map { width: 360px; height: 300px; background: #edf3ef; }
.cross { position: absolute; z-index: 1000; pointer-events: none;
width: 24px; height: 24px; transform: translate(-50%, -50%); }
.cross::before, .cross::after { content: ""; position: absolute;
background: #006cbe; }
.cross::before { top: 12px; width: 24px; height: 1px; }
.cross::after { left: 12px; width: 1px; height: 24px; }
</style>
<div id="map"></div>
<pre id="status">Loading marker…</pre>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="60" height="80" viewBox="-20 -10 100 120" preserveAspectRatio="xMidYMid meet"><path fill="#bf593c" fill-rule="evenodd" d="M30 0 C46 0 60 12 60 28 C60 46 46 54 40 80 C30 62 0 46 0 28 C0 12 14 0 30 0 Z M40 26 A10 10 0 1 0 20 26 A10 10 0 1 0 40 26 Z"/></svg>`;
const size = [60, 80];
const viewBox = [-20, -10, 100, 120];
const sourceTip = [40, 80];
const scale = Math.min(size[0] / viewBox[2], size[1] / viewBox[3]);
const anchor = [
(sourceTip[0] - viewBox[0]) * scale
+ (size[0] - viewBox[2] * scale) / 2,
(sourceTip[1] - viewBox[1]) * scale
+ (size[1] - viewBox[3] * scale) / 2
];
const map = L.map("map", {
zoomControl: false, attributionControl: false,
dragging: false, scrollWheelZoom: false, doubleClickZoom: false,
boxZoom: false, keyboard: false, touchZoom: false
}).setView([0, 0], 2);
const position = [0, 0];
const icon = L.icon({
iconUrl: "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg),
iconSize: size,
iconAnchor: anchor
});
const marker = L.marker(position, { icon }).addTo(map);
const container = document.querySelector("#map");
const cross = document.createElement("span");
cross.className = "cross";
container.append(cross);
const point = map.latLngToContainerPoint(position);
cross.style.left = point.x + "px";
cross.style.top = point.y + "px";
(async () => {
const image = marker.getElement();
await image.decode();
const ir = image.getBoundingClientRect();
const mr = container.getBoundingClientRect();
const displacement = [
ir.left + anchor[0] - mr.left - point.x,
ir.top + anchor[1] - mr.top - point.y
];
document.querySelector("#status").textContent = JSON.stringify({
version: L.version, size, anchor,
observedImageSize: [ir.width, ir.height], displacement
}, null, 2);
})();
</script>
</html>Status yang ditampilkan seharusnya melaporkan anchor: [36, 58], ukuran gambar [60, 80], dan perpindahan nol. Ubah size menjadi [90, 120]; perhitungan yang sama memberi [54, 87]. Untuk memakai bingkai rapat, ubah viewBox SVG dan array viewBox JavaScript menjadi 0 0 60 80. Jaga keduanya konsisten.
Path menyertakan kontur dalam melingkar dengan fill-rule="evenodd", menciptakan bukaan sungguhan. Referensi fill-rule MDN menjelaskan aturannya. Contoh tidak menambahkan border atau transformasi ke wadah peta; keduanya memerlukan perhatian saat membandingkan persegi panjang viewport dengan koordinat wadah.
Periksa tujuan sebelum mengubah gambar
Jika marker masih meleset dari koordinatnya, periksa berurutan:
- Pastikan gambar SVG dimuat dan elemen marker memiliki lebar serta tinggi piksel yang dimaksud.
- Temukan ujung sumber sebenarnya, termasuk transformasi yang diterapkan di dalam SVG.
- Periksa seluruh viewBox, koordinat minimumnya, dan mode penyesuaiannya.
- Hitung ulang anchor setiap kali mengubah bingkai atau ukuran ikon.
- Hapus penimpaan CSS yang tidak terkait saat menguji, lalu periksa kembali gaya akhir dan ukuran tampilan yang dimaksud.
Pertahankan koordinat geografis saat pemeriksaan ini. Memindahkan koordinat untuk mengimbangi padding gambar akan menyembunyikan kesalahan penempatan gambar.
Ini alur marker peramban. Marker SVG QGIS memakai kontrol tujuan dan sintaks pewarnaan berparameter sendiri; pertahankan master SVG biasa untuk penyerahan peramban umum.
Jika ikon hanya tersedia sebagai PNG atau JPG dan Anda membutuhkan kontur yang bisa diedit, konversikan gambar dengan PerfectVector, periksa bukaan dan ujungnya, lalu simpan master SVG bersih. Kemudian hitung anchor Leaflet dari bingkai sumber akhir. Vektorisasi menyiapkan gambar; kode peta memasok lokasi dan penempatan. Jika satu-satunya masalah adalah offset pada SVG yang ada, perbaiki bingkai atau anchor langsung. Panduan vektorisasi gambar menjelaskan kapan konversi sumber raster berguna.
Pertanyaan umum
Apakah iconAnchor merupakan lintang dan bujur? Tidak. Itu posisi piksel di dalam gambar ikon yang ditampilkan, diukur dari sudut kiri atasnya. Posisi geografis marker diberikan terpisah.
Mengapa SVG ber-padding saya tetap kecil setelah anchor dikoreksi? Bingkai sumber kosong masih menempati sebagian kotak gambar. Koreksi anchor memosisikan ujung; tidak menghapus ruang kosong atau memperbesar bentuk yang dicat.
Haruskah saya selalu memakai setengah lebar dan seluruh tinggi? Gunakan pasangan itu hanya jika titik penempelan yang terlihat benar-benar berada di sana. Pin asimetris dan sumber ber-padding kami membutuhkan nilai berbeda, meski keduanya merupakan gambar marker lokasi.
Apakah mengonversi PNG menjadi SVG memperbaiki lokasi marker? Konversi dapat menyediakan gambar yang bisa diedit. Bingkai sumber akhir, dimensi tampilan, anchor, dan koordinat peta tetap menentukan penempatan marker.
Sumber
- Leaflet — Referensi Icon — Dimensi piksel, origin anchor, pemusatan bawaan, dan perataan geografis.
- Leaflet — Marker dengan Ikon Khusus — Membuat ikon dan menetapkannya ke marker.
- Leaflet — Unduhan — Rilis stabil dan tautan JavaScript serta CSS versi terkuncinya.
- MDN — viewBox — Persegi panjang koordinat sumber yang dipakai dalam kedua bingkai.
- MDN — preserveAspectRatio — Penyesuaian seragam dan pemusatan ruang tersisa untuk xMidYMid meet.
- MDN — fill-rule — Aturan genap-ganjil yang dipakai untuk bukaan transparan.
Lebih banyak dari blog

Gambar Node SVG Cytoscape.js: Atur Fit dan Padding
Pasang gambar SVG khusus dalam node Cytoscape.js dengan contoh yang berfungsi. Bandingkan ruang kosong sumber, contain dan cover, lalu periksa pemuatan serta penempatan label.

Ukur Panjang Jalur SVG Tanpa Keliru Skala
Ukur jalur SVG dalam satuan pengguna, perhitungkan transformasi dan ukuran nominal, serta bedakan total kontur, kalibrasi pathLength, dan gerak mesin.
