Aşağıdaki gibi bir SVG haritanız olduğunu varsayalım:
Yukarıdaki harita Japonya'nın illerini gösteriyor. Ancak tüm iller aynı rengi paylaştığı için görünmüyor. Hadi her ile farklı bir renk verelim:
Şimdi daha iyi görünüyor, değil mi?
Ancak hangi rengin hangi ili temsil ettiğini hala bilmiyoruz, bu yüzden bir açıklama ekleyelim:
Tamam, şimdi Japonya'nın tüm illerinin nerede olduğunu görebiliyoruz. Ama bir adım daha ileri gidelim.
Ayrı bir açıklama yerine, bu sıkıcı ve çok yer kaplıyor, bir hover işlevi ekleyelim, böylece bir ilin üzerine geldiğinizde adı bir araç ipucunda gösterilsin.
Çok daha iyi değil mi?
Japonya'nın illerinin SVG haritasının bu GitHub deposundan alındığını unutmayın. Svelte kullanarak SVG ile dinamik çalışmak veya araç ipucu eklemek beklediğim kadar kolay olmadı. Yukarıdaki yapıları oluşturmanın 30 dakika süreceğini düşünmüştüm, ancak yaklaşık 2 saat sürdü.
Örneğin, SVG içindeki g öğeleri hover olaylarını kabul etmez. Ayrıca, yukarıdaki haritalar için dosyamda SVG'yi 3 kez çoğaltmak istemedim, bu yüzden SVG'yi ayrı bir Svelte dosyasına taşıdım, bir kez içe aktardım ve haritaları oluştururken o SVG dosyasını klonladım. Bu, kodu çok daha temiz hale getiriyor.
Aşağıdaki kodu referans alabilirsiniz:
<script>
import { onMount } from 'svelte';
// Get the SVG file from GitHub repo: https://github.com/geolonia/japanese-prefectures/blob/master/map-full.svg
import Prefectures from './Prefectures.svelte';
function getUniqueColor(n) {
const rgb = [0, 0, 0];
for (let i = 0; i < 24; i++) {
rgb[i % 3] <<= 1;
rgb[i % 3] |= n & 0x01;
n >>= 1;
}
return '#' + rgb.reduce((a, c) => (c > 0x0f ? c.toString(16) : '0' + c.toString(16)) + a, '');
}
let container, svg, colorfulSvg, tooltipSvg, tooltip;
$: tooltip = null;
let prefectures = [];
let noOfPefectures = 47;
let randomColors = Array.from({ length: noOfPefectures }, (_, index) => index)
.map((value) => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => getUniqueColor(value));
onMount(() => {
svg = container.firstChild;
colorfulSvg = svg.cloneNode(true);
colorfulSvg.getElementById('prefectures').childNodes.forEach((node, index) => {
let color = randomColors[index];
let code = node.getAttribute('data-code');
let titleText = node.getElementsByTagName('title')[0].textContent;
let title = {
en: titleText.split('/')[1].trim(),
tr: titleText.split('/')[1].trim(),
jp: titleText.split('/')[0].trim()
};
prefectures = [...prefectures, { color, title, code }];
node.setAttribute('fill', randomColors[index]);
});
document.getElementById('colorfulContainer').appendChild(colorfulSvg);
tooltipSvg = colorfulSvg.cloneNode(true);
tooltipSvg.getElementById('prefectures').childNodes.forEach((node, index) => {
let span = document.createElement('span');
span.classList.add('tooltiptext');
span.innerHTML = prefectures[index].title[$language];
node.classList.add('tooltip');
node.appendChild(span);
});
document.getElementById('tooltipContainer').appendChild(tooltipSvg);
document.addEventListener('mouseover', function (e) {
if (!e.target.closest('#tooltip')) {
tooltip.style.visibility = 'hidden';
}
let target = e.target.closest('#tooltipContainer #prefectures g');
if (target) {
let elemRect = target.getBoundingClientRect();
let bodyRect = document.getElementById('tooltipContainer').getBoundingClientRect();
tooltip.style.top = `${elemRect.top - bodyRect.top}px`;
tooltip.style.left = `${elemRect.left - bodyRect.left}px`;
tooltip.style.visibility = 'visible';
let titleText = target.getElementsByTagName('title')[0].textContent;
tooltip.textContent =
$language == 'jp' ? titleText.split('/')[0].trim() : titleText.split('/')[1].trim();
}
});
});
</script>
<div id="mainContainer" class="flex gap-4 flex-col relative">
<p>Original MAP</p>
<div class="flex justify-center" bind:this={container}><Prefectures /></div>
<p>Colorful MAP</p>
<div class="flex justify-center" id="colorfulContainer"></div>
<p>Legend</p>
{#key prefectures}
<div class="flex flex-wrap gap-2">
{#each prefectures.sort((a, b) => a.code - b.code) as pref}
<span
class="text-sm text-white px-2 py-1 rounded-full"
style="background-color: {pref.color}">{pref.title[$language]}</span
>
{/each}
</div>
{/key}
<p>Tooltipped MAP</p>
<div class="flex justify-center relative" id="tooltipContainer">
<span
style="visiblity:hidden;"
bind:this={tooltip}
id="tooltip"
class="absolute px-2 py-1 rounded bg-white/[0.9]"
></span>
</div>
</div>
Bir sonraki blog yazısında, bir ile tıkladığınızda bazı istatistikleri gösterelim.
O zamana kadar, mutlu kodlamalar!