Dark Peta MapLibre ala Google Maps lewat Runtime Override
Fiord bikin peta gelap tapi datar. Saya mutasi style JSON-nya langsung di runtime: brightness ladder per layer, label terang ber-halo, plus guard anti-flash.
Ringkasan
Fiord dark mode bikin jalan semua abu-abu sama, susah dibaca. Akhirnya fetch JSON Fiord, ubah paint 28 layer bikin tingkatan kecerahan jalan plus label pake halo gelap biar kelihatan kaya Google Maps. Pake cache, show peta dulu baru upgrade style, plus guard biar toggle cepat nggak bikin peta acak-acakan.
[unverified-own-experience] Peta pindah ke fiord kemarin sorenya langsung saya buka lagi. Gelap, finally. Tapi terus mata saya mencoba mencari jalan raya di antara jalan kampung, dan nyaris gagal. Semua jalan rata satu nada abu-abu. Bukan kesan malam ala Google Maps mobile yang jalan utamanya menonjol, tapi lebih mirip peta yang ditutup kertas tracing abu-abu.
[unverified] Tebakan pertama saya: pasang CSS filter invert(1) waktu dark mode. Cepat, satu baris, selesai. Tebakan kedua: cari style dark lain yang lebih bagus. Dua-duanya mundur. Filter CSS ikut membalik marker dan label, dan style dark OpenFreeMap sendiri kemarin sudah saya buktikan kontrasnya 1,03:1, peta render tapi efektif tak terlihat. README OpenFreeMap-nya pun jujur: Dark dan Fiord diwarisi dari style OpenMapTiles yang upstream-nya sudah ditelantarkan [8], hanya Liberty yang dirawat aktif. Jadi menunggu style dark yang lebih bagus muncul sendiri? Bukan arah yang menjanjikan.
setStyle ternyata terima objek, bukan cuma URL
[unverified] Selama ini saya anggap map.setStyle() itu menerima string URL style, titik. Kalau mau tampilan sendiri, ya fork JSON-nya, hosting sendiri, arahkan URL ke repo sendiri. Repot untuk sesuatu yang cuma mau ganti warna.
Padahal di dokumentasi API-nya [3] tertulis parameter style itu bertipe string | StyleSpecification: objek JSON utuh yang mengikuti style spec, atau URL ke JSON itu. Pintu masuk resminya terbuka: fetch JSON fiord, timpa paint-nya per layer, lalu serahkan objeknya ke setStyle. Google Maps sendiri memakai pola yang sama untuk night mode, yaitu array JSON berisi warna per elemen peta [4]. Bedanya cuma Google punya stylers, saya punya layers[].paint.
Tangga kecerahan bukan sekadar gelap
[unverified] Saya fetch URL fiord sekali per sesi lewat Promise yang di-cache, lalu menimpa paint untuk sekitar 28 layer id yang saya verifikasi satu per satu terhadap JSON live. Kuncinya bukan "jadi hitam", tapi tangga kecerahan: background paling gelap #1b1f27, jalan setapak #2a303c, jalan minor #333a48, jalan besar #4a5468, sampai jalan tol paling terang #5a6678. Jadi mata tetap bisa membaca hierarki jaringan jalan di atas navy near-black.
[unverified] Labelnya yang bikin hasil ini terasa ala Google Maps: nama kota #e8eaed dengan text-halo gelap #1b1f27 selebar 1, desa dan suburb agak redup #c7cbd1, nama jalan paling redup #9aa0a6. Halo gelap di belakang teks terang itu yang bikin label tetap terbaca di atas jalan mana pun.
Biar map langsung jalan dan tak flash saat toggle
[unverified] Kalau menunggu fetch selesai sebelum membuat map, pengguna menatap div kosong. Jadi komponen saya mem-paint URL fiord mentah dulu supaya peta langsung muncul, lalu begitu style hasil mutasi siap, baru di-upgrade lewat setStyle. Konsekuensinya ada jarak waktu antara fiord polos dan fiord versi malam, tapi itu imperceptible dibanding div kosong.
[unverified] Jebakan kedua: toggle dark-light yang diklik cepat. Promise lama bisa resolve setelah pengguna sudah balik ke light, dan setStyle dari resolusi itu menjadikan peta gelap pada mode terang. Guard-nya sederhana: sebelum setStyle, cek mapRef.current === map && styleRef.current === "dark". Kalau dunia sudah berubah, resolusi lama dibuang diam-diam. Kalau fetch-nya gagal? Tetap fiord polos, tanpa peta rusak. Kalau OpenFreeMap suatu hari me-rename layer-nya, override yang tak menemukan layer id-nya cuma jadi no-op. Failure mode terburuk dari seluruh rangkaian ini adalah peta kembali ke penampilan bawaan, dan itu justru yang saya mau.
[unverified] Yang berubah dari cara saya memandang style pihak ketiga: JSON style itu bahan mentah, bukan produk akhir. Spec-nya memang mendefinisikan style sebagai dokumen yang mendeskripsikan apa yang digambar dan bagaimana mewarnainya, dan karena dia cuma data, dia bisa dimutasi seperti data biasa [1]. Ada juga opsi resmi lain bernama transformStyle yang memodifikasi style setelah di-fetch tapi sebelum di-commit ke map, dan itu pilihan yang lebih idiomatik kalau mulai dari nol [7]. Untuk kasus saya yang butuh satu style gelap dipakai tiga komponen sekaligus, fetch sekali, mutasi sekali, share ke semua komponen tetap bentuk paling sederhana.