Analisis Spasial Sisi Klien menggunakan Turf.js untuk Analisis Keadilan Akses Ruang Terbuka Hijau di Perkotaan
Ketika kota-kota besar di Indonesia terus berkembang, disparitas akses terhadap ruang terbuka hijau (RTH) menjadi isu kritis yang sering terabaikan. Masyarakat miskin dan marjinal cenderung tinggal di area dengan RTH minimal, sementara kawasan elite menikmati taman, city park, dan green corridor yang memadai. Analisis Spasial Sisi Klien menggunakan Turf.js menawarkan pendekatan revolusioner untuk mengukur, memvisualisasikan, dan mengkomunikasikan ketidakadilan spasial ini—langsung di browser, tanpa server GIS mahal, dan dengan privasi data komunitas terjaga.
Mengapa Keadilan Akses RTH Memerlukan Pendekatan Client-Side?
Analisis keadilan lingkungan (environmental justice) tradisional bergantung pada desktop GIS atau server PostGIS yang memerlukan keahlian teknis tinggi dan infrastruktur mahal. Hal ini menciptakan paradox: komunitas yang paling membutuhkan bukti spasial untuk advokasi justru tidak memiliki akses ke alat analisisnya. Dengan memindahkan komputasi geospasial ke sisi klien melalui Turf.js, kita mendemokratisasi analisis spasial:
- Zero infrastructure cost: Tidak perlu server, database spatial, atau lisensi ArcGIS Enterprise.
- Data sovereignty: Data sensus, survei komunitas, dan lokasi rumah warga tidak pernah meninggalkan browser.
- Real-time participatory mapping: Warga bisa mengubah parameter (jarak jalan kaki, definisi RTH, bobot indeks kemiskinan) dan langsung melihat dampaknya.
- Offline-capable: Penting untuk area perkotaan padat dengan konektivitas tidak stabil.
Arsitektur Teknis: Stack Ringan untuk Analisis Keadilan Spasial
1. Data Layer: Open Data & Crowdsourced
// Contoh sumber data gratis untuk kota Indonesia
const dataSources = {
rth: 'OpenStreetMap (leisure=park, landuse=forest, boundary=protected_area)',
admin: 'BPS / BIG - Batas kelurahan/kecamatan (GeoJSON)',
demografi: 'BPS - Penduduk per kelurahan + indeks kemiskinan',
jalan: 'OSM - highway=footway,path,pedestrian,residential',
bangunan: 'OSM - building=yes (untuk estimasi densitas)'
};
Semua layer diunduh sebagai GeoJSON statis atau via Overpass API, lalu disimpan di IndexedDB untuk akses offline.
2. Computation Layer: Turf.js Core Functions
Berikut fungsi-fungsi kunci Turf.js yang menjadi tulang punggung analisis keadilan akses RTH:
| Fungsi Turf.js | Peran dalam Analisis Keadilan |
|---|---|
turf.buffer |
Membuat zona akses jalan kaki 300m/500m/1000m dari setiap RTH |
turf.nearestPoint |
Menghitung jarak terdekat setiap titik centroid kelurahan ke RTH |
turf.distance |
Mengukur jarak Euclidean/geodesic untuk metrik aksesibilitas |
turf.intersect |
Menghitung overlap zona akses RTH dengan batas kelurahan |
turf.area |
Menghitung luas RTH per kapita per kelurahan |
turf.pointsWithinPolygon |
Menghitung jumlah titik rumah/penduduk dalam zona akses |
turf.hexGrid / turf.squareGrid |
Membuat grid analisis seragam untuk heatmap keadilan |
turf.collect |
Mengagregasi atribut demografi ke grid/kelurahan |
3. Indikator Keadilan Spasial yang Dihitung Client-Side
// Contoh implementasi indeks keadilan akses RTH
async function hitungIndeksKeadilan(rthLayer, kelurahanLayer, jalanLayer) {
// 1. Buat jaringan jalan kaki (simplified: buffer jalan)
const walkableNetwork = turf.buffer(jalanLayer, 0.0015, { units: 'kilometers' });
// 2. Zona akses RTH via jalan kaki (300m = ~5 menit jalan kaki)
const rthAccessZones = turf.buffer(rthLayer, 0.3, { units: 'kilometers' });
// 3. Intersect dengan area jalan kaki
const accessibleRTH = turf.intersect(rthAccessZones, walkableNetwork);
// 4. Hitung metrik per kelurahan
const results = kelurahanLayer.features.map(kel => {
const kelArea = turf.area(kel);
const pop = kel.properties.penduduk || 0;
const povertyIdx = kel.properties.indeks_kemiskinan || 0;
// RTH dalam batas kelurahan
const rthInKel = turf.featureCollection(
rthLayer.features.filter(r => turf.booleanWithin(r, kel))
);
const totalRTHArea = rthInKel.features.reduce((sum, r) => sum + turf.area(r), 0);
// Zona akses yang overlap dengan kelurahan
const accessInKel = turf.featureCollection(
accessibleRTH.features.filter(z => turf.booleanOverlap(z, kel))
);
const accessArea = accessInKel.features.reduce((sum, z) => sum + turf.area(z), 0);
// Persentase area kelurahan terlayani
const pctServed = (accessArea / kelArea) * 100;
// RTH per kapita (m2/orang)
const rthPerCapita = pop > 0 ? totalRTHArea / pop : 0;
// Skor keadilan: kombinasi akses + kebutuhan (kemiskinan)
const equityScore = (pctServed * 0.6) + ((100 - povertyIdx) * 0.4); // invert kemiskinan
return {
kelurahan: kel.properties.nama,
kode: kel.properties.kode,
penduduk: pop,
kemiskinan: povertyIdx,
rth_total_m2: totalRTHArea,
rth_per_capita: rthPerCapita,
pct_area_terlayani: pctServed,
equity_score: equityScore,
priority: equityScore < 40 ? 'Tinggi' : equityScore < 70 ? 'Sedang' : 'Rendah'
};
});
return results;
}
Studi Kasus: Analisis Keadilan RTH di Kota Bandung
Profil Data
- Unit analisis: 151 kelurahan
- Data RTH: 342 poligon dari OSM (taman kota, hutan kota, Taman Nasional, green belt)
- Data demografi: BPS 2023 – penduduk per kelurahan + persentase miskin
- Jaringan jalan kaki: 2.847 segmen dari OSM (footway, path, pedestrian, residential)
Temuan Kunci
- Disparitas ekstrem: Kelurahan di utara Bandung (Coblong, Cidadas) memiliki RTH per kapita >15 m²/orang, sementara kelurahan padat di selatan (Bojongloa, Cibangkong) <1 m²/orang.
- Keadilan akses jalan kaki: 68% kelurahan memiliki <30% area terlayani zona akses 300m dari RTH via jalan kaki.
- Korelasi kemiskinan-akses: Koefisien korelasi Pearson -0.62 (p<0.001) antara indeks kemiskinan dan persentase area terlayani RTH.
- Prioritas intervensi: 23 kelurahan dikategorikan “Prioritas Tinggi” (equity score <40), mencakup 412.000 penduduk (18% total kota).
- Choropleth Equity Index: Warna merah-hijau berdasarkan equity score per kelurahan.
- Isochrone Walkability: Layer polygon zona akses 5/10/15 menit jalan kaki dari setiap RTH.
- Gap Analysis Map: Overlay kepadatan penduduk miskin dengan area tidak terlayani RTH (hotspot keadilan).
- GeoJSON untuk dikirim ke DPRD/Dinas LH
- CSV metrik per kelurahan untuk analisis statistik lanjutan
- PNG/PDF peta siap cetak untuk rapat musyawarah
- Link shareable (URL dengan parameter query) untuk kolaborasi remote
- Network-based accessibility: Ganti buffer Euclidean dengan routing graph jalan kaki nyata (integrasi OSRM client-side via
osrm-text-instructions). - Multi-kriteria decision analysis (MCDA): Bobotkan faktor: kepadatan, kemiskinan, rentan banjir, kualitas udara, kerentanan panas.
- Time-series analysis: Bandingkan akses RTH 2015 vs 2020 vs 2024 menggunakan data OSM historical.
- 3D visibility analysis: Gunakan
turf-tin+ DEM untuk analisis viewshed ke RTH dari area kumuh. - Integration dengan e-Musrenbang: Export otomatis proposal prioritas RTH ke sistem perencanaan partisipatif pemerintah.
Visualisasi Interaktif yang Dihasilkan
Aplikasi client-side menghasilkan tiga visualisasi utama yang bisa diekspor sebagai PNG/GeoJSON untuk advokasi:
Optimasi Performa untuk Dataset Kota Besar
Ketika menganalisis 150+ kelurahan dengan ribuan fitur OSF, performa browser menjadi kritis. Berikut strategi optimasi yang terbukti efektif:
1. Web Worker untuk Komputasi Berat
// main.js
const worker = new Worker('equity-worker.js');
worker.postMessage({ rth, kelurahan, jalan, params });
worker.onmessage = (e) => {
if (e.data.type === 'progress') updateProgressBar(e.data.pct);
if (e.data.type === 'result') renderResults(e.data.payload);
};
// equity-worker.js
importScripts('https://cdn.jsdelivr.net/npm/@turf/turf@6/turf.min.js');
self.onmessage = async (e) => {
const { rth, kelurahan, jalan, params } = e.data;
const steps = [
() => bufferJalan(jalan),
() => bufferRTH(rth),
() => intersectZones(),
() => hitungPerKelurahan()
];
for (let i = 0; i < steps.length; i++) {
const partial = await steps[i]();
self.postMessage({ type: 'progress', pct: ((i+1)/steps.length)*100 });
}
self.postMessage({ type: 'result', payload: finalResult });
};
2. Simplifikasi Geometri Adaptif
function simplifyAdaptive(geojson, zoomLevel) {
// Toleransi berdasarkan zoom: semakin jauh, semakin sederhana
const tolerance = Math.max(0.0001, 0.001 * Math.pow(2, 12 - zoomLevel));
return geojson.features.map(f => ({
...f,
geometry: turf.simplify(f.geometry, { tolerance, highQuality: true })
}));
}
3. Chunking & RequestIdleCallback
async function processInChunks(features, processor, chunkSize = 50) {
const results = [];
for (let i = 0; i requestIdleCallback(r));
}
return results;
}
4. IndexedDB Caching untuk Data Berulang
async function getCachedOrFetch(key, fetcher, ttlHours = 24) {
const db = await openDB('rth-equity-cache', 1);
const cached = await db.get('layers', key);
const now = Date.now();
if (cached && (now - cached.timestamp) < ttlHours * 3600 * 1000) {
return cached.data;
}
const fresh = await fetcher();
await db.put('layers', { key, data: fresh, timestamp: now });
return fresh;
}
Integrasi dengan Alat Advokasi Komunitas
Keunggulan pendekatan client-side adalah kemampuan mengintegrasikan langsung dengan workflow advokasi warga:
1. Participatory Scenario Builder
Warga bisa mensimulasikan “What-if”: “Bagaimana kalau lahan kosong di jalan X dijadikan taman?”
function simulasiTambahRTH(existingRTH, proposedSites, kelurahanLayer) {
const combinedRTH = turf.featureCollection([
...existingRTH.features,
...proposedSites.map(s => turf.polygon(s.coordinates, { proposed: true }))
]);
return hitungIndeksKeadilan(combinedRTH, kelurahanLayer, jalanLayer);
}
2. Export untuk Laporan Resmi
3. Real-time Feedback Loop
Komunitas bisa melaporkan kondisi aktual RTH (rusak, dijual, fungsional) via form sederhana yang update layer lokal tanpa server backend.
Tantangan & Solusi Praktis
| Tantangan | Solusi Client-Side |
|---|---|
| Data OSM tidak lengkap/akurat | Layer koreksi crowdsourced + validasi ground-truthing komunitas |
| Jalan kaki tidak terhubung (putus) | Graph-based routing (Turf + Dijkstra sederhana) bukan buffer Euclidean |
| Performa mobile lambat | Progressive loading: render kelurahan dulu, hitung metrik di background |
| Definisi RTH bervariasi | UI toggle: hanya taman formal / termasuk green belt / termasuk pekarangan |
| Data kemiskinan usang | Integrasi survei RT/RW real-time via form offline-first |
Perbandingan: Client-Side vs Server-Side untuk Keadilan Spasial
| Aspek | Server-Side (PostGIS/GeoServer) | Client-Side (Turf.js) |
|---|---|---|
| Biaya infrastruktur | Bulan $50-500+ | $0 (static hosting) |
| Keahlian teknis diperlukan | DBA, DevOps, GIS Specialist | Frontend Developer + Domain Expert |
| Privasi data warga | Risiko kebocoran server | Data tidak pernah keluar device |
| Iterasi partisipatif | Menit-jam (request ke admin) | Detik (interaksi langsung) |
| Skalabilitas komputasi | Tinggi (cluster) | Terbatas (RAM/CPU device) |
| Offline capability | Tidak | Ya (Service Worker + IndexedDB) |
Roadmap Pengembangan Lanjutan
Kesimpulan: Memberdayakan Advokasi Berbasis Bukti
Analisis Spasial Sisi Klien menggunakan Turf.js bukan sekadar alternatif teknis—ia merupakan enabler fundamental untuk keadilan spasial. Dengan menempatkan kekuatan analisis geospasial di tangan komunitas yang paling terdampak, kita mengubah narasi dari “warga sebagai objek data” menjadi “warga sebagai analis dan advokat”.
Kota-kota Indonesia membutuhkan ribuan analis spasial komunitas, bukan segelintir pakar GIS di kantor pusat. Turf.js di browser adalah alat yang memungkinkan transformasi ini terjadi—sekali klik, satu kelurahan, satu kota pada satu waktu.
FAQ
Apakah Turf.js bisa menangani data skala kota penuh (100k+ fitur)?
Ya, dengan optimasi Web Worker, chunking, dan simplifikasi geometri adaptif, Turf.js bisa memproses 50.000-100.000 fitur di desktop modern dalam 2-5 detik. Untuk mobile, rekomendasi batas ~20.000 fitur dengan progressive loading.
Bagaimana cara memvalidasi akurasi analisis client-side?
Lakukan ground-truthing sampel acak (min 30 titik per kota) bandingkan hasil Turf.js dengan pengukuran manual GPS/tape. Docakkan parameter buffer jalan kaki (default 1.5m) berdasarkan kondisi trotoar nyata.
Apakah data BPS/Big bisa langsung digunakan tanpa preprocessing?
Biasanya perlu harmonisasi kode wilayah (KODE_WILAYAH BPS vs KECAMATAN/KELURAHAN OSM). Gunakan turf.join atau join berbasis atribut nama setelah pembersihan string (case-insensitive, hapus titik/tanda baca).
Bisakah aplikasi ini di-host gratis?
Ya. GitHub Pages, Netlify, Vercel, atau Cloudflare Pages mendukung static site hosting gratis dengan custom domain, HTTPS, dan CDN global. Ukuran bundle <500KB gzipped.
Bagaimana menangani RTH yang status hukumnya争议 (sengketa lahan)?
Tambahkan properti status_hukum: 'resmi' | 'sengketa' | 'informal' | 'rencana' pada layer RTH. UI menyediakan filter layer sehingga analisis bisa dijalankan skenario: “hanya resmi” vs “semua inklusif informal”.