Overlay Animasi di Peta Statis Tanpa Library Peta
Peta kantor glowing plus garis ngalir tanpa Mapbox: satu SVG overlay viewBox 0-100, preserveAspectRatio none, animasi CSS yang aman buat reduced-motion.
Ringkasan
Daripada pasang Mapbox buat peta dekoratif, cukup tumpukin SVG overlay di atas next/image pakai viewBox "0 0 100 100" dan preserveAspectRatio="none", jadi koordinat titiknya persen dan ikut meregang pas resize. Garis alir sama denyut titik murni CSS, nol JavaScript. Kalau nanti butuh akurasi beneran, baru ganti ke library peta.
"Bisa nggak kita kasih titik-titik kantor yang glowing, terus ada garis putus-putus ngalir dari pusat ke cabang?" Desainer saya nunjuk peta raster statis Pulau Jawa di layar, ngarep sesuatu yang keliatan kayak dashboard logistik kelas atas.
Insting pertama saya langsung lari ke dua ekstrem. Pertama, hardcode koordinat pixel di atas gambar 1699x624. Itu bakal hancur pas layarnya di-resize. Kedua, pasang Mapbox atau Leaflet. Padahal kita cuma butuh gambar statis dengan beberapa titik animasi, bukan geocoding atau routing yang bikin bundle JavaScript bengkak.
Yang kejadian di commit ternyata jauh lebih sederhana. Saya numpuk elemen <svg> persis di atas next/image dalam kontainer relative, lalu ngunci semuanya di dua atribut: viewBox="0 0 100 100" dan preserveAspectRatio="none" [2].
Dengan viewBox segitu, satu unit user-space = satu persen dimensi kontainer [1]. Titik kantor tinggal ditulis sebagai koordinat persen di satu konstanta, hasil estimasi posisi geografis: Pusat di x 13.2 y 34, Bandung di x 17.5 y 60, Surabaya di x 69 y 33. Pas gambar ikut lebar layar, overlay ikut meregang non-uniform, persis kayak raster di bawahnya. Nol JavaScript, nol perhitungan ulang pas resize.
Satu catatan buat yang mau meniru: urutan layer itu penting. Cincin pulse digambar duluan biar kebagian di bawah, dot inti terakhir biar tetap tajam. Dan jangan hapus preserveAspectRatio="none" sekalian. Tanpa itu SVG-nya pindah ke mode meet dan overlay nggak nempel ke sudut gambar lagi; koordinat persen langsung meleset.
Nol JavaScript, murni CSS
Buat garis alir pusat-ke-cabang dan denyut titik, semua pakai animasi CSS: office-dot-pulse 2.4 detik buat opacity cincin luar, office-line-flow buat geser stroke-dashoffset. Warna pake var(--color-accent) biar kebawa tema.
<svg
viewBox="0 0 100 100"
preserveAspectRatio="none"
className="pointer-events-none absolute inset-0 h-full w-full"
aria-hidden="true"
>
{lines.map((l) => (
<g key={l.key}>
<line ... className="office-line-glow" />
<line ... strokeDasharray="0.6 0.4" className="office-line-dash" />
</g>
))}
</svg>
Hal kecil yang gampang terlewat: kode posisi kantor itu duplikat buat dua locale. Pusat dan Head Office punya koordinat identik, karena key-nya ikut teks konten. Ini trade-off yang saya terima; nambahin layer normalisasi ID buat sekedar dua bahasa itu overkill. Tapi kalau bahasa ketiga masuk, pindahin key-nya ke field netral di konten, jangan biarkan posisi geografis ikut-ikutan terjemahan.
Overlay di-skip dari interaksi dan pembaca layar: pointer-events-none bikin semua klik tembus ke elemen di bawahnya [4], dan aria-hidden="true" ngebuangnya dari accessibility tree karena nggak nyampein info baru [5].
Keputusan yang paling banyak debat di sini: koordinat persen itu estimasi tangan, bukan hasil proyeksi peta. Posisi kantor ditaruh manual sambil lihat peta sampai kerasa pas. Buat peta dekoratif di homepage, akurasi segitu udah cukup. Kalau nanti butuh akurat, saatnya ganti ke library peta beneran, bukan nambah rumit-Math di overlay.
Konsekuensi dari skema persen: radius r, stroke-width, sampai jarak stroke-dasharray ikut skala kontainer. Di layar lebar dash-nya lebih panjang, di mobile menyempit. Rasio gambar fix berarti skala X dan Y beda, jadi lingkaran sebenarnya oval tipis kalau dihitung matematis. Mata pengguna nggak akan pernah sadar, dan glow justru kerasa lebih organik.
Tiga lapis titik, dua lapis garis
Struktur SVG-nya sadar banget soal keterbatasan stroke-dasharray: pola putus-putus itu murni geometri, nggak bisa animasi glow-nya. Jadi tiap garis digambar dua kali dalam satu <g>: lapisan glow stroke-width 0.4 opacity 0.25 yang berdenyut lembut, plus lapisan inti stroke-width 0.15 berpola strokeDasharray="0.6 0.4" [7] yang dianimasikan stroke-dashoffset-nya supaya kerasa ngalir dari pusat ke cabang. Pola 0.6-0.4 ini juga yang bikin jarak lompatan animasi pendek: cukup geser 2 unit, arus udah keliatan loop mulus.
Titik kantornya tiga lapis: cincin denyar luar, glow tengah, dot inti, plus highlight putih kecil. Radiusnya skala viewBox: r 1.2 untuk kantor pusat, 0.8 buat cabang. Karena satuannya persen kontainer, proporsi dot konsisten di semua ukuran layar [1].
@media (prefers-reduced-motion: no-preference) {
.office-dot-pulse {
animation: office-dot-pulse 2.4s ease-in-out infinite;
}
.office-line-dash {
animation: office-line-flow 3s linear infinite;
}
}
Seluruh keyframe dibungkus prefers-reduced-motion: no-preference [3]. Media query ini dievaluasi ulang tiap perubahan nilai [8], jadi kalau pengguna nyalain reduce motion sambil halaman kebuka, animasinya mati sendiri tanpa reload. Catatan jujur: kalau prefers-contrast aktif, glow accent yang halus bisa kurang keliatan [6]. Saya milih nerima batasan ini daripada kasih outline tebal yang malah ngerusak peta statisnya.