svg ile interaktif harita yapımı — html css js ile harita yapımı
Merhabalar, bir projede interaktif bölgesel haritaya ihtiyaç duyduk. Kaynak araştırdım fakat Türkçe içerik bulamadım, bende kaleme alıp anlatmak istedim.
Bu yazıda sizlere interaktif bölgesel bir harita nasıl yapılır göstermek istiyorum. İhtiyacımız olan materyaller interaktif hale getirmek istediğimiz haritanın SVG hali. Bizim projemizde bir tasarımcı çizdiği için biz ondan ilerlemiştik sizlerin de çizim yaptıracak imkanı varsa direkt #3.0 aşamaya geçebilirsiniz.
1.0 Harita oluşturma #
Bunun için değişik araçlar mevcut fakat ben Figma kullandığım için eklentisi de olan https://vector.mapcraft.biz/constructor/ aracını kullanmayı tercih ettim.
Örnek olarak: Akdeniz Bölgesi
(Kaynak: wikipedia)
- Adana, Antalya, Burdur, Hatay, Isparta, Mersin, Osmaniye, Konya, Kahramanmaraş, Karaman, Afyonkarahisar, Denizli, Gaziantep, Niğde
vector.mapcraft.biz/constructor
Seçim sonrası “Download SVG” diyoruz. Düzenleme yapacaksanız; dosyayı Figma ile açıp düzenleyebilirsiniz.
Özelleştirmek istemiyorsanız direk #1.2 adıma geçebilirsiniz.
1.1 Haritayı özelleştirelim #
(Opsiyon)
İndirdiğiniz SVG dosyasını Figma ile açarak düzenleme yapabilirsiniz. Katmanlara çift tıka girerek çizgi ve şekil renklerini değiştirebilirsiniz. Şehirleri renk-renk özelleştirmek isterseniz bu yöntemi seçebilirsiniz.
Veya sonraki aşamada göstereceğim css de ile aktiflik durumu hariç tek tip renk ile görünüm kazandırabilirsiniz.
1.2 Haritayı Kod Satırına Ekleme #
- Figma’da düzenleme sonrası; katmanlarda gruba sağ tıklayıp “Copy/Paste > Copy as SVG” adımlarını izleyebiliriz.
- Düzenleme yapmadıysanız indirdiğiniz dosyayı editör ile açıyoruz ve kodları projemize dahil ediyoruz.
2.0 Haritayı işaretleme #
SVG path değerlerine class verelim aktif ve üzerine gelme durumunda renk olayını css ile ayarlamak için class tanımlayalım ve aktif classı belirleyelim.
(Anlatım boyunca scss yazıyor olacağız.)
<path class="region" d="..."></path>
Eğer başlangıçta bir il aktif gelsin istersek:
<path class="region on" d="..."></path>
2.1 CSS ile harita aktif ve üzerine gelince durumlarını ayarlama #
.region {
fill: #8C5423;
stroke: #ccc;
stroke-linejoin: round;
fill-rule: evenodd;
clip-rule: evenodd;
stroke-width: 1;
transition: fill 300ms;
&:hover {
fill: #A67449;
}
&.on {
fill: #733E1F;
}
}
2.2 Şehir üzerine gelince açılacak bilgi kartı
İsteğimiz görünümü elde ettik şimdi etkileşim için JavaScript zamanı.
2.2 Şehir üzerine gelince açılacak bilgi kartı #
<div class="map-of-regions">
<ul class="list-of-regions">
<li data-state="mersin" class="region-card on">
<div class="region-image">
<img src="url" alt="Şehir" class="rounded-start">
</div>
<div class="region-content">
<div class="fs-6 title">Şehir İsmi</div>
<div class="desc">
<p>
Lorem ipsum.
</p>
</div>
</div>
</li>
...
</ul>
...
svg
...
</div>
Açılacak kartımızı özelleştirelim.
.map-of-regions {
position: relative;
.list-of-regions {
list-style: none;
position: absolute;
margin: 0;
padding: 0;
top: 0;
left: 40px;
.region-card {
display: none;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, .125);
border-radius: 0.25rem;
box-shadow: rgba(0, 0, 0, .1) 0 4px 12px;
padding: 0;
&.on {
display: flex;
}
.region-image {
width: 100px;
height: 100px;
&.rounded-start {
border-radius: .25rem 0 0 .25rem;
}
}
.region-content {
padding: 10px;
.title {
font-weight: 600;
&.fs-6 {
font-size: 1rem;
}
}
}
}
}
}
3.0 JavaScript ile etkileşim kazandırma #
JavaScript tarafında yakalamak için her bir şehrin koduna id veriyoruz.
Ben şehir ismi tercih ettim.
<path id="kahramanmaras" d="..."></path>
3.1 Üzerine gelince açılacak bilgi kartları için JavaScript yazalım. #
const regionsCards = document.querySelector(".list-of-regions");
const regionsCard = document.querySelectorAll(".list-of-regions li");
const generalRegions = document.querySelector('#regions');
const svgPathRegions = document.querySelectorAll("#regions > *");
const regionActiveCard = document.querySelector('[data-state=mersin]');
const regionActivePath = document.querySelector('#mersin');
function removeAllOn() {
regionsCard.forEach(function (el) {
el.classList.remove("on");
});
svgPathRegions.forEach(function (el) {
el.classList.remove("on");
});
}
function addOnFromState(el) {
const stateId = el.getAttribute("id");
const wordState = document.querySelector("[data-state='" + stateId + "']");
wordState.classList.add("on");
el.classList.add("on");
mediterraneanRegions();
}
const mediterraneanRegions = function () {
generalRegions.addEventListener('mousemove', (event) => {
regionsCards.style.top = event.clientY + -120 + 'px';
regionsCards.style.left = event.clientX + 20 + 'px';
regionsCards.style.position = 'fixed';
});
}
svgPathRegions.forEach((el) => {
el.addEventListener("mouseenter", () => {
removeAllOn();
addOnFromState(el);
});
el.addEventListener("mouseleave", () => {
removeAllOn();
});
el.addEventListener("touchstart", () => {
removeAllOn();
addOnFromState(el);
});
});
3.3 Seçim olmaması durumunda aktif şehir #
/* active city in case of not election */
generalRegions.addEventListener("mouseleave", () => {
setTimeout(() => {
if(![...regionsCard].filter(e=>e.classList.contains("on")).length){
regionActiveCard.classList.add("on");
regionActivePath.classList.add("on")
regionsCards.setAttribute("style", "position:absolute");
}
}, 1000);
})
Herkese iyi çalışmalar.