diff --git a/PANDUAN_FITUR.md b/PANDUAN_FITUR.md new file mode 100644 index 0000000..ff1229e --- /dev/null +++ b/PANDUAN_FITUR.md @@ -0,0 +1,385 @@ +# π PANDUAN FITUR GIS PONTIANAK + +## Setup Awal + +### 1. Inisialisasi Database + +```bash +# Buka di browser: +http://localhost/web-gis/create_tables.php +``` + +**Respons berhasil:** + +```json +{ + "status": "success", + "message": "Tabel berhasil dibuat atau sudah ada" +} +``` + +Ini akan membuat 3 tabel baru: + +- `rumah_ibadah` - Lokasi tempat ibadah +- `penduduk_miskin` - Lokasi keluarga kurang mampu +- `jalan_rusak` - Laporan jalan rusak + +--- + +## Fitur 1: RUMAH IBADAH (Tempat Ibadah) + +### Cara Menggunakan: + +**Step 1:** Buka GIS Interface + +``` +http://localhost/web-gis/index.html +``` + +**Step 2:** Klik tombol "Rumah Ibadah" di toolbar + +- Ikon: ποΈ (bangunan dengan tanda plus) +- Di toolbar utama sebelah atas map + +**Step 3:** Klik di mana saja di peta + +- Status akan berubah: "Klik Peta untuk menambah lokasi..." +- Modal dialog akan muncul + +**Step 4:** Isi form: + +``` +βββββββββββββββββββββββββββββββββββββββ +β INPUT RUMAH IBADAH β +βββββββββββββββββββββββββββββββββββββββ€ +β Nama : [Masjid Al-Nur] β +β Alamat : [Auto-fill] β β Otomatis dari koordinat +β PIC (Nama) : [Pengurus] β +β Radius Pencarian: [1000] meter β β Geser slider +β Koordinat : -0.1234, 109.3456 β +β β +β [SIMPAN] [BATAL] β +βββββββββββββββββββββββββββββββββββββββ +``` + +**Field Penjelasan:** + +- **Nama:** Nama tempat ibadah (Masjid/Gereja/dll) +- **Alamat:** Otomatis terisi pakai Nominatim (Reverse Geocoding) + - Tunggu pesan "Mencari alamat..." hingga selesai +- **PIC:** Nama Pengurus/Koordinator +- **Radius:** Jarak pencarian untuk keluarga miskin sekitar (default 1000m) + +**Step 5:** Klik "SIMPAN" + +- Marker teal + lingkaran akan muncul di peta +- Data tersimpan di database + +### Interaksi Lanjutan: + +**Edit:** + +1. Klik marker di peta +2. Popup muncul β Klik "Edit" +3. Modal akan terbuka dengan data lama +4. Ubah dan klik "Simpan" + +**Hapus:** + +1. Klik marker +2. Popup β Klik "Hapus" +3. Konfirmasi β Data terhapus + +**Cari:** + +- Gunakan Registry Drawer (kanan peta) +- Filter: Input Type = "Rumah Ibadah" +- Cari nama atau ketik untuk filter + +--- + +## Fitur 2: PENDUDUK MISKIN (Keluarga Kurang Mampu) + +### Cara Menggunakan: + +**Step 1:** Klik tombol "Penduduk Miskin" di toolbar + +- Ikon: π€ (orang dengan tanda plus) + +**Step 2:** Klik di peta untuk lokasi keluarga miskin + +**Step 3:** Isi form: + +``` +βββββββββββββββββββββββββββββββββββββββββββββββ +β INPUT PENDUDUK MISKIN β +βββββββββββββββββββββββββββββββββββββββββββββββ€ +β Nama Ketua KK : [Nama Kepala Keluarga]β +β Jumlah Anggota : [5] β +β Rumah Ibadah Terdekat: [OTOMATIS] β +β Nama : Masjid Al-Nur β β Sistem mencari +β Jarak : 234 meter β otomatis +β Koordinat : -0.1234, 109.3456 β +β β +β [SIMPAN] [BATAL] β +βββββββββββββββββββββββββββββββββββββββββββββββ +``` + +**Field Penjelasan:** + +- **Nama Ketua KK:** Nama kepala keluarga yang bertanggung jawab +- **Jumlah Anggota:** Total orang dalam keluarga termasuk ketua +- **Rumah Ibadah Terdekat:** Sistem otomatis menemukan tempat ibadah terdekat + - Nama dan jarak ditampilkan (berdasarkan radius yang Anda set di rumah ibadah) + - TIDAK perlu isi manual + +**Step 4:** Klik "SIMPAN" + +- Marker merah akan muncul +- Data tersimpan beserta referensi rumah ibadah terdekat + +### Fitur Khusus: Pencarian Miskin Sekitar Rumah Ibadah + +**Gunakan tombol di popup Rumah Ibadah:** + +1. Klik marker Rumah Ibadah di peta +2. Di popup klik: **"Cari Miskin"** +3. Semua keluarga miskin dalam radius akan ter-zoom +4. Map akan fit ke cluster keluarga miskin + +--- + +## Fitur 3: CHOROPLETH KECAMATAN (Peta Populasi) + +### Cara Menggunakan: + +**Step 1:** Klik tombol "Choropleth" di toolbar + +- Ikon: πΊοΈ (peta) + +**Step 2:** Peta akan berubah + +- Menampilkan 6 kecamatan Pontianak +- Warna berbeda sesuai populasi + +**Gradasi Warna:** + +``` +π΄ Merah Tua = Populasi > 120,000 jiwa +π₯ Merah Terang = Populasi > 100,000 jiwa +π¨ Merah Muda = Populasi > 80,000 jiwa +π§ Merah Pucat = Populasi β€ 80,000 jiwa +``` + +**Step 3:** Klik salah satu kecamatan + +- Panel di kanan bawah muncul: + +``` +ββββββββββββββββββββββββββββββββββββ +β Choropleth Kecamatan Pontianak β +ββββββββββββββββββββββββββββββββββββ€ +β PONTIANAK BARAT β +β 148,800 jiwa β +β β +β Kepadatan: 2,500 jiwa/kmΒ² β +ββββββββββββββββββββββββββββββββββββ +``` + +**Data Populasi (BPS 2025):** + +| # | Kecamatan | Populasi | Warna | +| --- | ------------------ | -------- | ----- | +| 1 | Pontianak Barat | 148,800 | π΄ | +| 2 | Pontianak Selatan | 133,600 | π΄ | +| 3 | Pontianak Utara | 129,200 | π΄ | +| 4 | Pontianak Timur | 121,500 | π΄ | +| 5 | Pontianak Kota | 98,500 | π₯ | +| 6 | Pontianak Tenggara | 52,900 | π§ | + +**Fitur Interaksi:** + +- **Hover:** Kecamatan akan highlight +- **Klik:** Info populasi muncul di panel +- **Keluar Mode:** Klik tombol lain atau click tombol Choropleth lagi + +--- + +## Layer Control (Kontrol Visibilitas) + +### Tombol Layer (atas kiri map): + +Klik ikon **β°** untuk membuka layer control. + +``` +β Choropleth Kecamatan +β Rumah Ibadah +β Penduduk Miskin +β Jalan Rusak +β Lokasi SPBU + ... (layer lainnya) +``` + +**Toggle on/off:** + +- Centang untuk tampilkan layer +- Uncheck untuk sembunyikan + +**Catatan:** Saat aktif mode Choropleth, layer lain otomatis disembunyikan untuk fokus pada peta kecamatan. + +--- + +## Registry / Pencarian + +### Buka Registry Drawer: + +Klik tombol **π** di toolbar atau panel kanan. + +### Cara Mencari: + +**1. Filter by Type (Dropdown atas):** + +``` +Input Type: + βΌ Semua + β‘ Point + β‘ Polyline + β‘ Polygon + β‘ Rumah Ibadah β Pilih ini + β‘ Penduduk Miskin β atau ini + β‘ Jalan Rusak +``` + +**2. Filter by Registry (Dropdown bawah):** + +``` +Registry Type: + βΌ Semua + β‘ Jalan Nasional + β‘ Parkir + β‘ Rumah Ibadah + β‘ Penduduk Miskin +``` + +**3. Cari (Kolom input):** + +``` +Cari nama: [Masjid] π + +Hasil: +βββββββββββββββββββββββββββββββ +β β Masjid Al-Nur β +β Rumah Ibadah β +β -0.1234, 109.3456 β +βββββββββββββββββββββββββββββββ€ +β β Masjid Besar Pontianak β +β Rumah Ibadah β +β -0.1245, 109.3467 β +βββββββββββββββββββββββββββββββ +``` + +**Klik hasil β Map akan:** + +- Zoom ke lokasi +- Buka popup +- Highlight marker + +--- + +## Troubleshooting + +### β Tombol tidak muncul + +**Solusi:** + +- Refresh browser (Ctrl+F5) +- Clear cache +- Cek console (F12) untuk error + +### β Alamat tidak terisi (Reverse Geocode gagal) + +**Penyebab:** Tidak ada koneksi internet atau Nominatim API timeout +**Solusi:** + +- Pastikan internet terhubung +- Coba refresh modal +- Manual isi alamat + +### β Rumah Ibadah tidak ditemukan saat input miskin + +**Penyebab:** Belum ada data rumah ibadah, atau lokasi terlalu jauh +**Solusi:** + +- Tambahkan rumah ibadah terlebih dahulu di mode Rumah Ibadah +- Pastikan radius rumah ibadah cukup besar + +### β Choropleth tidak tampil + +**Penyebab:** File GeoJSON tidak ditemukan +**Solusi:** + +- Cek file ada di: `data/pontianak-kecamatan.geojson` +- Cek console untuk error message + +### β Database error + +**Solusi:** + +- Jalankan ulang `create_tables.php` +- Cek koneksi database di `db_config.php` + +--- + +## Tips & Trik + +### π‘ Shortcut + +- **Double-click** marker untuk langsung edit +- **Scroll zoom** di map untuk zoom in/out +- **Drag** untuk geser peta +- **Ctrl+A** di search untuk select all results + +### π Export Data + +Semua data tersimpan di database MySQL. Untuk export: + +```sql +SELECT * FROM rumah_ibadah; +SELECT * FROM penduduk_miskin; +``` + +### π¨ Customize Warna + +Edit di `index.html` function: + +- `getPopulationFill()` - Ubah warna choropleth +- `createRumahIbadahIcon()` - Ubah marker rumah ibadah +- `createPendudukMiskinIcon()` - Ubah marker miskin + +--- + +## File Penting + +``` +web-gis/ +βββ index.html β Main GIS Interface +βββ create_tables.php β Init database +βββ db_config.php β Database config +β +βββ api/ +β βββ save_rumah_ibadah.php +β βββ get_rumah_ibadah.php +β βββ delete_rumah_ibadah.php +β βββ save_penduduk_miskin.php +β βββ get_penduduk_miskin.php +β βββ delete_penduduk_miskin.php +β +βββ data/ + βββ pontianak-kecamatan.geojson β Choropleth data + βββ Export_Output_2.json β Road network data +``` + +--- + +**Versi:** 2025-04-20 +**Status:** Production Ready β diff --git a/create_tables.php b/create_tables.php index 6d44224..c6851e0 100644 --- a/create_tables.php +++ b/create_tables.php @@ -1,8 +1,9 @@ query($sql) === TRUE) { - echo json_encode(['status' => 'success', 'message' => 'Tabel jalan_rusak berhasil dibuat atau sudah ada']); -} else { - echo json_encode(['status' => 'error', 'message' => $conn->error]); +foreach ($statements as $sql) { + if ($conn->query($sql) !== TRUE) { + echo json_encode(['status' => 'error', 'message' => $conn->error]); + $conn->close(); + exit; + } } +$alterStatements = [ + "ALTER TABLE penduduk_miskin ADD COLUMN bantuan_status VARCHAR(20) NOT NULL DEFAULT 'belum' AFTER jarak_ke_rumah_ibadah_m", + "ALTER TABLE penduduk_miskin ADD COLUMN bantuan_catatan TEXT DEFAULT NULL AFTER bantuan_status", + "ALTER TABLE penduduk_miskin ADD COLUMN bantuan_updated_at TIMESTAMP NULL DEFAULT NULL AFTER bantuan_catatan" +]; + +foreach ($alterStatements as $alterSql) { + $conn->query($alterSql); +} + +echo json_encode(['status' => 'success', 'message' => 'Tabel berhasil dibuat atau sudah ada']); $conn->close(); ?> diff --git a/delete_penduduk_miskin.php b/delete_penduduk_miskin.php new file mode 100644 index 0000000..cdd0b98 --- /dev/null +++ b/delete_penduduk_miskin.php @@ -0,0 +1,26 @@ + 'error', 'message' => 'ID tidak valid']); + $conn->close(); + exit; + } + + $stmt = $conn->prepare("DELETE FROM penduduk_miskin WHERE id = ?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => 'success', 'message' => 'Data penduduk miskin dihapus']); + } else { + echo json_encode(['status' => 'error', 'message' => $stmt->error]); + } + + $stmt->close(); +} +$conn->close(); +?> \ No newline at end of file diff --git a/delete_rumah_ibadah.php b/delete_rumah_ibadah.php new file mode 100644 index 0000000..81a5a6d --- /dev/null +++ b/delete_rumah_ibadah.php @@ -0,0 +1,26 @@ + 'error', 'message' => 'ID tidak valid']); + $conn->close(); + exit; + } + + $stmt = $conn->prepare("DELETE FROM rumah_ibadah WHERE id = ?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => 'success', 'message' => 'Rumah ibadah dihapus']); + } else { + echo json_encode(['status' => 'error', 'message' => $stmt->error]); + } + + $stmt->close(); +} +$conn->close(); +?> \ No newline at end of file diff --git a/get_penduduk_miskin.php b/get_penduduk_miskin.php new file mode 100644 index 0000000..0342fca --- /dev/null +++ b/get_penduduk_miskin.php @@ -0,0 +1,34 @@ +query($sql); +$data = []; + +if (!$result) { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]); + $conn->close(); + exit; +} + +if ($result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $row['latitude'] = (float)$row['latitude']; + $row['longitude'] = (float)$row['longitude']; + $row['jumlah_anggota'] = (int)$row['jumlah_anggota']; + $row['rumah_ibadah_id'] = $row['rumah_ibadah_id'] !== null ? (int)$row['rumah_ibadah_id'] : null; + $row['jarak_ke_rumah_ibadah_m'] = $row['jarak_ke_rumah_ibadah_m'] !== null ? (float)$row['jarak_ke_rumah_ibadah_m'] : null; + $row['bantuan_status'] = $row['bantuan_status'] ?: 'belum'; + $row['bantuan_catatan'] = $row['bantuan_catatan'] ?? ''; + $data[] = $row; + } +} + +echo json_encode($data); +$conn->close(); +?> \ No newline at end of file diff --git a/get_rumah_ibadah.php b/get_rumah_ibadah.php new file mode 100644 index 0000000..7f016d8 --- /dev/null +++ b/get_rumah_ibadah.php @@ -0,0 +1,30 @@ +query($sql); +$data = []; + +if (!$result) { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]); + $conn->close(); + exit; +} + +if ($result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $row['latitude'] = (float)$row['latitude']; + $row['longitude'] = (float)$row['longitude']; + $row['radius_m'] = (int)$row['radius_m']; + $data[] = $row; + } +} + +echo json_encode($data); +$conn->close(); +?> \ No newline at end of file diff --git a/index.html b/index.html index e926a03..3885645 100644 --- a/index.html +++ b/index.html @@ -31,6 +31,68 @@ .leaflet-popup-content-wrapper { border-radius: 12px; padding: 0; overflow: hidden; } .leaflet-popup-content { margin: 0; width: 280px !important; } .leaflet-draw-toolbar a { background-color: white; } + .leaflet-control-layers { + max-height: calc(100vh - 8rem); + overflow-y: auto; + width: 190px; + font-size: 12px; + } + .leaflet-control-layers-toggle { + width: 30px !important; + height: 30px !important; + background-size: 18px 18px !important; + } + .leaflet-control-layers-overlays label, + .leaflet-control-layers-list label { + margin-bottom: 0.15rem; + line-height: 1.2; + } + .leaflet-control-layers input { + margin-top: 0.15rem; + } + .leaflet-draw-toolbar a { + width: 32px !important; + height: 32px !important; + line-height: 32px !important; + background-size: 18px 18px !important; + background-repeat: no-repeat !important; + background-position: center center !important; + } + .leaflet-draw-toolbar .leaflet-draw-draw-marker { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='9' r='2.5'/%3E%3Cpath d='M12 2C8.13 2 5 5.13 5 9c0 5 7 13 7 13s7-8 7-13c0-3.87-3.13-7-7-7Z'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-draw-polyline { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 18l6-6 4 4 6-8'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-draw-polygon { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2l8 5v10l-8 5-8-5V7z'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-draw-rectangle { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='5' width='14' height='14' rx='1'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-draw-circle { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='7'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-edit-edit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-edit-remove { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M8 6V4h8v2'/%3E%3Cpath d='M6 6l1 14h10l1-14'/%3E%3Cpath d='M10 11v6'/%3E%3Cpath d='M14 11v6'/%3E%3C/svg>") !important; + } + .leaflet-draw-toolbar .leaflet-draw-draw-polygon, + .leaflet-draw-toolbar .leaflet-draw-draw-polyline, + .leaflet-draw-toolbar .leaflet-draw-edit-edit, + .leaflet-draw-toolbar .leaflet-draw-edit-remove { + margin-bottom: 0; + } + .leaflet-draw-section { + margin-bottom: 2px; + } + .leaflet-top.leaflet-left .leaflet-control-layers, + .leaflet-top.leaflet-left .leaflet-bar, + .leaflet-top.leaflet-left .leaflet-draw { + margin-top: 0.35rem; + } /* CSS Tambahan agar ikon SVG tidak terpotong atau memiliki background */ .custom-marker { background: transparent !important; border: none !important; } @@ -44,7 +106,11 @@ .registry-item:hover { transform: translateY(-1px); box-shadow: 0 12px 28px rgba(15, 23, 42, 0.1); } .registry-chip { display: inline-flex; align-items: center; gap: .35rem; border-radius: 9999px; padding: .25rem .6rem; font-size: .7rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; } #registryDrawer { transition: transform .24s ease, opacity .24s ease; } - #registryDrawer.hidden-drawer { transform: translateX(-12px); opacity: 0; pointer-events: none; } + #registryDrawer.hidden-drawer { transform: translateX(18px); opacity: 0; pointer-events: none; } + #bantuanDrawer { transition: transform .24s ease, opacity .24s ease; } + #bantuanDrawer.hidden-drawer { transform: translateX(18px); opacity: 0; pointer-events: none; } + #layerDrawer { transition: transform .24s ease, opacity .24s ease; } + #layerDrawer.hidden-drawer { transform: translateX(-18px); opacity: 0; pointer-events: none; }
@@ -80,6 +146,12 @@ + + @@ -131,6 +203,9 @@ + + +Kelola bantuan untuk penduduk miskin per wilayah rumah ibadah.
+Dropdown semua layer.
+