PerfectVector
Yazan Irene Kim

Leaflet SVG İşaretçileri: Ucu iconAnchor ile Hizalayın

Görünür ucu iconAnchor'a eşleyerek Leaflet'te özel SVG işaretçilerini konumlandırın. viewBox boşluğunu, en boy oranı sığdırmasını ve simge boyutu değişikliklerini hesaba katın.

8 dk okuma
Bu sayfada

Leaflet özel SVG işaretçisi için iconSize değerini gösterilen görsel boyutlarına, iconAnchor değerini ise görsel içindeki görünür ucun piksel konumuna ayarlayın. Görselin sol üst köşesinden ölçün. Saydam SVG kenar boşlukları bu boyutlara dâhildir; bu nedenle genişliğin yarısı ve yüksekliğin tamamı, asimetrik veya boşluklu bir iğnenin ucunu kaçırabilir.

Bu kılavuz, ucu gövdesinin merkezinin sağında bulunan özgün bir iğne kullanır. Döşemesiz tarayıcı haritasında iki kaynak çerçevesini iki simge boyutunda karşılaştırıyoruz. Temiz SVG çiziminiz zaten varsa doğrudan kullanın; bağlantı noktası yerleşimi vektörleştirme gerektirmez.

Çizimi, görsel kutusunu ve harita noktasını ayırın

Burada üç koordinat sistemi buluşur. SVG yolu çizimi kaynak birimleriyle tanımlar. iconSize, gösterilen görsel kutusunu piksel cinsinden belirler. Leaflet, bu kutu içinde iconAnchor ile belirtilen noktayı işaretçinin coğrafi konumuna yerleştirir. Icon başvurusu, bu seçenekleri ve sol üst bağlantı noktası başlangıcını tanımlar.

Geleneksel iğne alt kenarın ortasına uzanabilir, ancak çiziminiz başka yerde bitebilir. Leaflet'in belgelenen varsayılanı, boyut belirtildiğinde ortalanmış bağlantı noktasıdır. Deneyimizdeki alt orta değerleri bu varsayılan değil, sınadığımız açık bir varsayımdır.

Resmî özel simge öğreticisi, L.icon örneğini işaretçiye aktarmayı gösterir. İçe aktarılan çizim için ek iş, görsel içinde harita koordinatına değmesi gereken noktayı bulmaktır.

Görünür uç ve bağlantı noktası
Boşluklu tuval içindeki asimetrik konum iğnesinin, ucu artı işaretinden kaymışken ve sonra ona değmişken kavramsal karşılaştırması
İllüstrasyon: görünür ucu konumlandırırken görsel çerçevesinin tamamını hesaba katın. Aşağıdaki ölçülmüş tarayıcı deneyi ayrı oluşturulmuş SVG dosyaları kullanır.

Kaynak ucu simge piksellerine eşleyin

İğnemizin ucu kaynak koordinatı (40, 80) konumundadır. Sıkı çerçevesi viewBox="0 0 60 80" değerindedir. Boşluklu sürüm yalnızca çerçeveyi viewBox="-20 -10 100 120" yapar; iki dosya aynı yolu ve saydam açıklığı korur.

viewBox başvurusu bu kaynak dikdörtgenini açıklar. İçindeki boş alan çizimle birlikte taşınır. SVG sınırlama kutusu kılavuzumuz, tuval ve boyalı şeklin neden farklı sınırlara sahip olabileceğini açıklar.

İki sürüm de açıkça preserveAspectRatio="xMidYMid meet" kullanır. Bu, çerçeveyi görüntü alanına tekdüze sığdırır ve artan alanı ortalar. Ayarlar için MDN preserveAspectRatio başvurusuna bakın.

Bu sığdırma modunda W ve H simge boyutları, (minX, minY, vbW, vbH) viewBox ve (tipX, tipY) kaynak uç olsun:

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 + offsetY

Boşluklu 60×80 simgede s, 0.6 olur. 100×120 kaynak çerçevesi 60×72 piksel kaplar; üstte ve altta dörder piksel bırakır. Uç, bu dikey ofset dâhil [36, 58] olur. Her boyutun oranını ayrı almak tekdüze sığdırma adımını kaçırır.

Kaynak çerçevesiSimge boyutuHesaplanan uç bağlantı noktası
Sıkı, 0 0 60 8060×80[40, 80]
Sıkı, 0 0 60 8090×120[60, 120]
Boşluklu, -20 -10 100 12060×80[36, 58]
Boşluklu, -20 -10 100 12090×120[54, 87]

Bu hesaplar, dönüştürülmemiş görselimiz ve açık ortalanmış meet ayarı için geçerlidir. Farklı hizalama, slice veya none için uygun koordinat eşlemesi gerekir. En boy oranı kılavuzumuz bu seçenekleri ele alır. İşaretçi görselindeki ek CSS dönüşümleri de ayrı inceleme gerektirir.

Döşemesiz haritada yerleşimi kontrol edin

Resmî indirme sayfasında kararlı sürüm olarak belirtilen Leaflet 1.9.4'ü kullandık. Deney, sürümü sabitlenmiş JavaScript ve CSS'yi yerel yükler, döşeme katmanı eklemez. Her harita [0, 0] koordinatını mavi artı işaretine yansıtır; bu referans noktasının yanında bir SVG görsel gösterir.

Kaynak incelemesi, her SVG'de özdeş tek bileşik yol ve sıfır gömülü raster görsel buldu. Tarayıcı görsel boyutları istendiği gibi 60×80 ve 90×120 pikseldi. Her görselin gözlenen dikdörtgenini kullanarak eşlenen uç konumunu yansıtılan coğrafi noktayla karşılaştırdık:

KaynakSimge boyutuAlt orta bağlantı noktası varsayımıyla hataHesaplanan uç bağlantı noktasıyla hata
Sıkı60×8010 px sağa0 px
Sıkı90×12015 px sağa0 px
Boşluklu60×806 px sağa, 22 px yukarı0 px
Boşluklu90×1209 px sağa, 33 px yukarı0 px

Artı işareti düzeltilmiş iğne uçlarına görsel olarak da değdi. Bunlar tek Chrome tarayıcısında özgün testimizin gözlemleridir; her SVG, tarayıcı veya harita entegrasyonu için garanti değildir. Boşluklu iğne, bağlantı noktası düzeltildikten sonra aynı görsel kutusunda daha küçük kalır. Yerleşim ve çizim boyutu ayrı kararlardır.

Çalışan işaretçi başlangıcını kopyalayın

Bu eksiksiz HTML'yi marker.html olarak kaydedip yerel web sunucusundan sunun. Leaflet indirme sayfasının bağladığı CDN'den sabitlenmiş Leaflet dosyalarını yükler. SVG görsel URL'sine kodlandığından örnek simge dosyası veya döşeme hizmeti gerektirmez. İki kütüphane dosyası için internet erişimi gerekir.

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

Gösterilen durum anchor: [36, 58], görsel boyutu [60, 80] ve sıfır yer değiştirme bildirmelidir. size değerini [90, 120] yapın; aynı hesap [54, 87] verir. Sıkı çerçeveyi kullanmak için SVG'nin viewBox değerini ve JavaScript viewBox dizisini 0 0 60 80 olarak değiştirin. İkisini tutarlı tutun.

Yol, fill-rule="evenodd" içeren dairesel iç konturla gerçek açıklık oluşturur. MDN fill-rule başvurusu kuralı açıklar. Örnek harita kapsayıcısına kenarlık veya dönüşüm eklemez; bunlar görüntü alanı dikdörtgenlerini kapsayıcı koordinatlarıyla karşılaştırırken dikkat gerektirir.

Çizimi değiştirmeden önce hedefi inceleyin

İşaretçiniz koordinatını hâlâ kaçırıyorsa sırayla inceleyin:

  1. SVG görselin yüklendiğini ve işaretçi öğesinin amaçlanan piksel genişlik ve yüksekliğine sahip olduğunu doğrulayın.
  2. SVG içinde uygulanan dönüşümler dâhil gerçek kaynak ucu bulun.
  3. Tam viewBox'ı, en küçük koordinatlarını ve sığdırma modunu kontrol edin.
  4. Çerçeveyi veya simge boyutunu değiştirdiğinizde bağlantı noktasını yeniden hesaplayın.
  5. Sınarken ilgisiz CSS geçersiz kılmalarını kaldırın, ardından son stili ve amaçlanan görüntüleme boyutlarını tekrar kontrol edin.

Bu kontrolde coğrafi koordinatı sabit tutun. Görsel boşluğunu telafi etmek için koordinatı taşımak çizim yerleşimi hatasını gizler.

Bu bir tarayıcı işaretçisi iş akışıdır. QGIS SVG işaretçisi, kendi hedef denetimlerini ve parametreli boyama söz dizimini kullanır; genel tarayıcı teslimi için normal SVG ana dosyası koruyun.

Simgeniz yalnızca PNG veya JPG olarak mevcutsa ve düzenlenebilir konturlar gerekiyorsa çizimi PerfectVector ile dönüştürün, açıklığı ve ucu inceleyin, temiz SVG ana dosyası kaydedin. Ardından Leaflet bağlantı noktasını son kaynak çerçevesinden hesaplayın. Vektörleştirme çizimi hazırlar; harita kodunuz konumları ve yerleşimi sağlar. Tek sorun mevcut SVG'deki ofsetse çerçevesini veya bağlantı noktasını doğrudan düzeltin. Görüntü vektörleştirme kılavuzu, raster kaynak dönüşümünün ne zaman yararlı olduğunu açıklar.

Sık sorulan sorular

iconAnchor enlem ve boylam mı? Hayır. Gösterilen simge görselinin içinde, sol üst köşesinden ölçülen piksel konumudur. İşaretçinin coğrafi konumu ayrı sağlanır.

Bağlantı noktasını düzeltince boşluklu SVG'm neden hâlâ küçük? Boş kaynak çerçevesi görsel kutusunun bir kısmını kaplamaya devam eder. Bağlantı noktasını düzeltmek ucu konumlandırır; boşluğu kaldırmaz veya boyalı şekli büyütmez.

Her zaman genişliğin yarısını ve yüksekliğin tamamını mı kullanmalıyım? Bu çifti yalnızca görünür tutunma noktası gerçekten oradaysa kullanın. Asimetrik iğnemiz ve boşluklu kaynağımız, ikisi de konum işaretçisi çizimi olsa da farklı değerler gerektirir.

PNG'yi SVG'ye dönüştürmek işaretçi konumunu düzeltir mi? Dönüşüm düzenlenebilir çizim sağlayabilir. İşaretçinin yerleşimini son kaynak çerçevesi, gösterilen boyutlar, bağlantı noktası ve harita koordinatları belirlemeye devam eder.

Kaynaklar

  1. Leaflet — Icon başvurusu — Piksel boyutları, bağlantı noktası başlangıcı, varsayılan ortalama ve coğrafi hizalama.
  2. Leaflet — Özel Simgeli İşaretçiler — Simge oluşturma ve işaretçiye atama.
  3. Leaflet — İndirme — Kararlı sürüm ve sabitlenmiş JavaScript ve CSS bağlantıları.
  4. MDN — viewBox — İki çerçevede kullanılan kaynak koordinat dikdörtgeni.
  5. MDN — preserveAspectRatio — xMidYMid meet için tekdüze sığdırma ve kalan alanı ortalama.
  6. MDN — fill-rule — Saydam açıklıkta kullanılan çift-tek kuralı.

Bloga daha fazlası

PerfectVector

Düzenlemesi daha kolay,
daha temiz bir SVG ile başlayın

Kredi kartı gerekmez