second commit

This commit is contained in:
2026-06-11 13:17:12 +07:00
parent a7cb1f2de0
commit 69c15319dd
9 changed files with 478 additions and 133 deletions
+19 -13
View File
@@ -1,5 +1,11 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/helpers.php';
@@ -36,6 +42,13 @@ switch ($method) {
$body = getRequestBody();
$point_id = (int)($body['point_id'] ?? 0);
$jenis_bantuan = (!empty($body['jenis_bantuan'])) ? $body['jenis_bantuan'] : '';
$nominal = (isset($body['nominal']) && $body['nominal'] !== '') ? (float)$body['nominal'] : null;
$tanggal_bantuan = (!empty($body['tanggal_bantuan'])) ? $body['tanggal_bantuan'] : null;
$instansi_pemberi = (!empty($body['instansi_pemberi'])) ? $body['instansi_pemberi'] : null;
$keterangan = (!empty($body['keterangan'])) ? $body['keterangan'] : null;
$stmt = $db->prepare(
"INSERT INTO bantuan
(
@@ -51,19 +64,12 @@ switch ($method) {
);
$stmt->execute([
$body['point_id'],
$body['jenis_bantuan'],
$body['nominal'],
$body['tanggal_bantuan'],
$body['instansi_pemberi'],
$body['keterangan']
$point_id,
$jenis_bantuan,
$nominal,
$tanggal_bantuan,
$instansi_pemberi,
$keterangan
]);
jsonResponse([
+21 -7
View File
@@ -1,5 +1,11 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/helpers.php';
@@ -44,6 +50,14 @@ switch ($method) {
$body = getRequestBody();
$nama_pelapor = (!empty($body['nama_pelapor'])) ? $body['nama_pelapor'] : '';
$no_hp = (!empty($body['no_hp'])) ? $body['no_hp'] : null;
$nama_warga = (!empty($body['nama_warga'])) ? $body['nama_warga'] : '';
$alamat = (!empty($body['alamat'])) ? $body['alamat'] : null;
$latitude = (isset($body['latitude']) && $body['latitude'] !== '') ? (float)$body['latitude'] : null;
$longitude = (isset($body['longitude']) && $body['longitude'] !== '') ? (float)$body['longitude'] : null;
$keterangan = (!empty($body['keterangan'])) ? $body['keterangan'] : null;
$stmt = $db->prepare(
"INSERT INTO laporan_masyarakat
(
@@ -61,13 +75,13 @@ switch ($method) {
);
$stmt->execute([
$body['nama_pelapor'] ?? '',
$body['no_hp'] ?? '',
$body['nama_warga'] ?? '',
$body['alamat'] ?? '',
$body['latitude'] ?? null,
$body['longitude'] ?? null,
$body['keterangan'] ?? '',
$nama_pelapor,
$no_hp,
$nama_warga,
$alamat,
$latitude,
$longitude,
$keterangan,
'Menunggu Verifikasi'
]);
+7
View File
@@ -1,3 +1,10 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
// ============================================================
// api/parcels.php — CRUD for land parcel polygons
+47 -20
View File
@@ -1,9 +1,18 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
// ============================================================
// api/points.php — CRUD for point features
// Supports: SPBU, Mosque, Poor Population
// ============================================================
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/helpers.php';
@@ -93,6 +102,16 @@ switch ($method) {
jsonResponse(['error' => 'Invalid category'], 422);
}
$subtype = (!empty($body['subtype'])) ? $body['subtype'] : null;
$description = (!empty($body['description'])) ? $body['description'] : null;
$tanggal_lahir = (!empty($body['tanggal_lahir'])) ? $body['tanggal_lahir'] : null;
$pendidikan = (!empty($body['pendidikan'])) ? $body['pendidikan'] : null;
$pekerjaan = (!empty($body['pekerjaan'])) ? $body['pekerjaan'] : null;
$jumlah_tanggungan = (isset($body['jumlah_tanggungan']) && $body['jumlah_tanggungan'] !== '') ? (int)$body['jumlah_tanggungan'] : null;
$riwayat_penyakit = (!empty($body['riwayat_penyakit'])) ? $body['riwayat_penyakit'] : null;
$alamat = (!empty($body['alamat'])) ? $body['alamat'] : null;
$status_verifikasi = (!empty($body['status_verifikasi'])) ? $body['status_verifikasi'] : 'Menunggu Verifikasi';
$stmt = $db->prepare(
'INSERT INTO points (
name,
@@ -114,20 +133,19 @@ switch ($method) {
$stmt->execute([
$body['name'],
$body['category'],
$body['subtype'] ?? null,
$subtype,
(float)$body['latitude'],
(float)$body['longitude'],
$body['description'] ?? null,
$description,
$body['tanggal_lahir'] ?? null,
$body['pendidikan'] ?? null,
$body['pekerjaan'] ?? null,
$body['jumlah_tanggungan'] ?? null,
$body['riwayat_penyakit'] ?? null,
$body['alamat'] ?? null,
$tanggal_lahir,
$pendidikan,
$pekerjaan,
$jumlah_tanggungan,
$riwayat_penyakit,
$alamat,
$body['status_verifikasi']
?? 'Menunggu Verifikasi'
$status_verifikasi
]);
$id = (int)$db->lastInsertId();
@@ -154,6 +172,16 @@ switch ($method) {
jsonResponse(['error' => 'Point not found'], 404);
}
$subtype = (!empty($body['subtype'])) ? $body['subtype'] : null;
$description = (!empty($body['description'])) ? $body['description'] : null;
$tanggal_lahir = (!empty($body['tanggal_lahir'])) ? $body['tanggal_lahir'] : null;
$pendidikan = (!empty($body['pendidikan'])) ? $body['pendidikan'] : null;
$pekerjaan = (!empty($body['pekerjaan'])) ? $body['pekerjaan'] : null;
$jumlah_tanggungan = (isset($body['jumlah_tanggungan']) && $body['jumlah_tanggungan'] !== '') ? (int)$body['jumlah_tanggungan'] : null;
$riwayat_penyakit = (!empty($body['riwayat_penyakit'])) ? $body['riwayat_penyakit'] : null;
$alamat = (!empty($body['alamat'])) ? $body['alamat'] : null;
$status_verifikasi = (!empty($body['status_verifikasi'])) ? $body['status_verifikasi'] : 'Menunggu Verifikasi';
$stmt = $db->prepare(
'UPDATE points SET
name=?,
@@ -174,22 +202,21 @@ switch ($method) {
$stmt->execute([
$body['name'] ?? '',
$body['category'] ?? 'spbu',
$body['subtype'] ?? null,
$subtype,
(float)($body['latitude'] ?? 0),
(float)($body['longitude'] ?? 0),
$body['description'] ?? null,
$description,
$body['tanggal_lahir'] ?? null,
$body['pendidikan'] ?? null,
$body['pekerjaan'] ?? null,
$body['jumlah_tanggungan'] ?? null,
$body['riwayat_penyakit'] ?? null,
$body['alamat'] ?? null,
$tanggal_lahir,
$pendidikan,
$pekerjaan,
$jumlah_tanggungan,
$riwayat_penyakit,
$alamat,
$body['status_verifikasi']
?? 'Menunggu Verifikasi',
$status_verifikasi,
$id
]);
+7
View File
@@ -1,3 +1,10 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
// ============================================================
// api/roads.php — CRUD for road polylines
+20 -9
View File
@@ -223,7 +223,7 @@ function enableLaporanAdd() {
openLaporanModal(e.latlng);
map.off('click', laporanClickHandler);
disableLaporanAdd();
};
map.once('click', laporanClickHandler);
@@ -238,6 +238,13 @@ function disablePointAdd() {
updateDrawModeUI();
}
function disableLaporanAdd() {
if (laporanClickHandler) {
map.off('click', laporanClickHandler);
laporanClickHandler = null;
}
}
/* Load all points from API */
async function loadPoints() {
const res = await fetch(API.points);
@@ -504,6 +511,7 @@ function showModal(type, data, extra) {
<textarea id="f-alamat">${data?.alamat || ''}</textarea>
</div>
<input type="hidden" id="f-status-verifikasi" value="${data?.status_verifikasi || 'Menunggu Verifikasi'}">
</div>
<div class="btn-row">
<button class="btn btn-primary btn-full" onclick="savePoint(${data?.id || 'null'}, ${latlng?.lat}, ${latlng?.lng})">
@@ -749,7 +757,7 @@ async function savePoint(id, lat, lng) {
document.getElementById('f-alamat')?.value || null,
status_verifikasi:
'Menunggu Verifikasi'
id ? (document.getElementById('f-status-verifikasi')?.value || 'Menunggu Verifikasi') : 'Menunggu Verifikasi'
};
try {
let res;
@@ -1334,6 +1342,7 @@ document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
stopDraw();
disablePointAdd();
disableLaporanAdd();
closeModal();
}
});
@@ -1347,13 +1356,15 @@ function updateMarkerColors() {
poorMarkers.forEach(marker => {
let distance = map.distance(selectedCenter, marker.getLatLng());
if (distance <= radius) {
marker.getElement().style.filter = "hue-rotate(0deg)";
inside++;
} else {
marker.getElement().style.filter = "hue-rotate(120deg)";
outside++;
const el = marker.getElement();
if (el) {
if (distance <= radius) {
el.style.filter = "hue-rotate(0deg)";
inside++;
} else {
el.style.filter = "hue-rotate(120deg)";
outside++;
}
}
});
+49 -9
View File
@@ -12,15 +12,55 @@ USE webgis_db;
-- Stores all point-type features (SPBU, Mosque, Poor Population)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS points (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
category ENUM('spbu','mosque','poor') NOT NULL COMMENT 'spbu=Gas Station, mosque=Mosque, poor=Poor Population',
subtype VARCHAR(100) DEFAULT NULL COMMENT 'For SPBU: 24hours or not24hours',
latitude DECIMAL(10,8) NOT NULL,
longitude DECIMAL(11,8) NOT NULL,
description TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
category ENUM('spbu','mosque','poor') NOT NULL COMMENT 'spbu=Gas Station, mosque=Mosque, poor=Poor Population',
subtype VARCHAR(100) DEFAULT NULL COMMENT 'For SPBU: 24hours or not24hours',
latitude DECIMAL(10,8) NOT NULL,
longitude DECIMAL(11,8) NOT NULL,
description TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
tanggal_lahir DATE DEFAULT NULL,
pendidikan VARCHAR(100) DEFAULT NULL,
pekerjaan VARCHAR(100) DEFAULT NULL,
jumlah_tanggungan INT DEFAULT NULL,
riwayat_penyakit TEXT DEFAULT NULL,
alamat TEXT DEFAULT NULL,
status_verifikasi ENUM('Menunggu Verifikasi','Layak','Tidak Layak','Perlu Verifikasi Ulang') DEFAULT 'Menunggu Verifikasi'
) ENGINE=InnoDB;
-- ------------------------------------------------------------
-- TABLE: laporan_masyarakat
-- Stores reports submitted by citizens about poor populations
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS laporan_masyarakat (
id INT AUTO_INCREMENT PRIMARY KEY,
nama_pelapor VARCHAR(100) NOT NULL,
no_hp VARCHAR(20) DEFAULT NULL,
nama_warga VARCHAR(100) NOT NULL,
alamat TEXT DEFAULT NULL,
latitude DECIMAL(10,8) DEFAULT NULL,
longitude DECIMAL(11,8) DEFAULT NULL,
keterangan TEXT DEFAULT NULL,
status ENUM('Menunggu Verifikasi','Disetujui','Ditolak') DEFAULT 'Menunggu Verifikasi',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- ------------------------------------------------------------
-- TABLE: bantuan
-- Stores aid distribution records for poor populations
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS bantuan (
id INT AUTO_INCREMENT PRIMARY KEY,
point_id INT NOT NULL,
jenis_bantuan VARCHAR(100) NOT NULL,
nominal DECIMAL(12,2) DEFAULT NULL,
tanggal_bantuan DATE DEFAULT NULL,
instansi_pemberi VARCHAR(100) DEFAULT NULL,
keterangan TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (point_id) REFERENCES points (id) ON DELETE CASCADE
) ENGINE=InnoDB;
-- ------------------------------------------------------------
+49 -9
View File
@@ -12,15 +12,55 @@ USE webgis_db;
-- Stores all point-type features (SPBU, Mosque, Poor Population)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS points (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
category ENUM('spbu','mosque','poor') NOT NULL COMMENT 'spbu=Gas Station, mosque=Mosque, poor=Poor Population',
subtype VARCHAR(100) DEFAULT NULL COMMENT 'For SPBU: 24hours or not24hours',
latitude DECIMAL(10,8) NOT NULL,
longitude DECIMAL(11,8) NOT NULL,
description TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
category ENUM('spbu','mosque','poor') NOT NULL COMMENT 'spbu=Gas Station, mosque=Mosque, poor=Poor Population',
subtype VARCHAR(100) DEFAULT NULL COMMENT 'For SPBU: 24hours or not24hours',
latitude DECIMAL(10,8) NOT NULL,
longitude DECIMAL(11,8) NOT NULL,
description TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
tanggal_lahir DATE DEFAULT NULL,
pendidikan VARCHAR(100) DEFAULT NULL,
pekerjaan VARCHAR(100) DEFAULT NULL,
jumlah_tanggungan INT DEFAULT NULL,
riwayat_penyakit TEXT DEFAULT NULL,
alamat TEXT DEFAULT NULL,
status_verifikasi ENUM('Menunggu Verifikasi','Layak','Tidak Layak','Perlu Verifikasi Ulang') DEFAULT 'Menunggu Verifikasi'
) ENGINE=InnoDB;
-- ------------------------------------------------------------
-- TABLE: laporan_masyarakat
-- Stores reports submitted by citizens about poor populations
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS laporan_masyarakat (
id INT AUTO_INCREMENT PRIMARY KEY,
nama_pelapor VARCHAR(100) NOT NULL,
no_hp VARCHAR(20) DEFAULT NULL,
nama_warga VARCHAR(100) NOT NULL,
alamat TEXT DEFAULT NULL,
latitude DECIMAL(10,8) DEFAULT NULL,
longitude DECIMAL(11,8) DEFAULT NULL,
keterangan TEXT DEFAULT NULL,
status ENUM('Menunggu Verifikasi','Disetujui','Ditolak') DEFAULT 'Menunggu Verifikasi',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- ------------------------------------------------------------
-- TABLE: bantuan
-- Stores aid distribution records for poor populations
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS bantuan (
id INT AUTO_INCREMENT PRIMARY KEY,
point_id INT NOT NULL,
jenis_bantuan VARCHAR(100) NOT NULL,
nominal DECIMAL(12,2) DEFAULT NULL,
tanggal_bantuan DATE DEFAULT NULL,
instansi_pemberi VARCHAR(100) DEFAULT NULL,
keterangan TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (point_id) REFERENCES points (id) ON DELETE CASCADE
) ENGINE=InnoDB;
-- ------------------------------------------------------------
+259 -66
View File
@@ -3,18 +3,250 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SinergiSpasial | WebGIS Pontianak</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #00d2ff;
--secondary: #3a7bd5;
--bg-dark: #0b0f19;
--surface: rgba(20, 27, 45, 0.6);
--surface-border: rgba(255, 255, 255, 0.1);
--text-main: #f8fafc;
--text-muted: #94a3b8;
}
<title>SinergiSpasial</title>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
scroll-behavior: smooth;
}
<link rel="stylesheet" href="assets/css/style.css">
body {
background-color: var(--bg-dark);
color: var(--text-main);
/* Membuat efek grid khas peta digital/GIS */
background-image:
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
background-size: 30px 30px;
overflow-x: hidden;
}
/* --- Header & Nav (Glassmorphism) --- */
header {
position: fixed;
top: 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 5%;
background: rgba(11, 15, 25, 0.8);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--surface-border);
z-index: 1000;
}
.logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary);
text-shadow: 0 0 10px rgba(0, 210, 255, 0.4);
display: flex;
align-items: center;
gap: 10px;
}
nav a {
color: var(--text-main);
text-decoration: none;
margin-left: 30px;
font-size: 0.9rem;
font-weight: 400;
transition: color 0.3s;
}
nav a:hover {
color: var(--primary);
}
/* --- Global Section --- */
.section {
padding: 100px 5%;
text-align: center;
}
h2 {
font-size: 2.5rem;
margin-bottom: 20px;
background: -webkit-linear-gradient(right, var(--primary), var(--secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* --- Hero Section --- */
.hero {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
padding: 0 5%;
}
/* Efek cahaya radial di background Hero */
.hero::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(58, 123, 213, 0.15) 0%, transparent 70%);
z-index: -1;
}
.hero-content {
max-width: 800px;
}
.hero h1 {
font-size: 3.5rem;
line-height: 1.2;
margin-bottom: 20px;
}
.hero p {
font-size: 1.1rem;
color: var(--text-muted);
margin-bottom: 40px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.btn {
display: inline-block;
padding: 15px 35px;
font-size: 1rem;
font-weight: 600;
color: #fff;
text-decoration: none;
background: linear-gradient(45deg, var(--secondary), var(--primary));
border-radius: 30px;
box-shadow: 0 10px 20px rgba(0, 210, 255, 0.3);
transition: transform 0.3s, box-shadow 0.3s;
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 15px 25px rgba(0, 210, 255, 0.5);
}
/* --- Cards (Fitur) --- */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
margin-top: 40px;
}
.card {
background: var(--surface);
backdrop-filter: blur(10px);
border: 1px solid var(--surface-border);
padding: 40px 20px;
border-radius: 20px;
transition: transform 0.3s, border-color 0.3s;
text-align: left;
}
.card:hover {
transform: translateY(-10px);
border-color: var(--primary);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.card h3 {
font-size: 1.5rem;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 10px;
}
.card p {
color: var(--text-muted);
font-size: 0.95rem;
line-height: 1.6;
}
/* --- Preview --- */
.preview {
width: 100%;
max-width: 900px;
border-radius: 15px;
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
border: 1px solid var(--surface-border);
margin-top: 30px;
}
/* --- Flow (Alur Analisis) --- */
.flow {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 15px;
margin-top: 40px;
}
.flow-item {
background: var(--surface);
border: 1px solid var(--surface-border);
padding: 15px 25px;
border-radius: 30px;
font-weight: 600;
color: var(--primary);
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.flow-arrow {
color: var(--text-muted);
font-size: 1.2rem;
}
/* --- Footer --- */
footer {
text-align: center;
padding: 30px;
background: rgba(11, 15, 25, 0.9);
border-top: 1px solid var(--surface-border);
color: var(--text-muted);
font-size: 0.9rem;
}
/* Responsiveness */
@media (max-width: 768px) {
.hero h1 { font-size: 2.5rem; }
.flow { flex-direction: column; }
.flow-arrow { transform: rotate(90deg); }
nav { display: none; } /* Bisa ditambah hamburger menu nanti */
}
</style>
</head>
<body>
<header>
<div class="logo">
🕌 SinergiSpasial
🗺️ SinergiSpasial
</div>
<nav>
<a href="#tentang">Tentang</a>
<a href="#fitur">Fitur</a>
@@ -23,109 +255,70 @@
</header>
<section class="hero">
<div class="hero-content">
<h1>
Sistem Informasi Geografis
Berbasis Web untuk Analisis
Sistem Informasi Geografis<br>
Berbasis Web untuk Analisis<br>
Sebaran Kemiskinan
</h1>
<p>
Membantu identifikasi wilayah bantuan
berdasarkan jangkauan masjid
di Kota Pontianak.
Membantu identifikasi wilayah bantuan berdasarkan jangkauan radius masjid di Kota Pontianak dengan pendekatan presisi geospasial.
</p>
<a href="dashboard.html" class="btn">
Masuk ke Sistem
Masuk ke Dashboard GIS
</a>
</div>
</section>
<section id="tentang" class="section">
<h2>Tentang Sistem</h2>
<p>
SinergiSpasial merupakan WebGIS yang
dirancang untuk membantu visualisasi
dan analisis sebaran penduduk miskin
menggunakan pendekatan geospasial
berbasis radius jangkauan masjid.
<p style="color: var(--text-muted); max-width: 700px; margin: 0 auto; line-height: 1.8;">
SinergiSpasial merupakan WebGIS yang dirancang untuk membantu visualisasi dan analisis sebaran penduduk miskin menggunakan pendekatan geospasial berbasis radius jangkauan masjid.
</p>
</section>
<section id="fitur" class="section">
<h2>Fitur Unggulan</h2>
<div class="cards">
<div class="card">
<h3>🕌 Data Masjid</h3>
<p>Manajemen lokasi masjid sebagai pusat bantuan.</p>
<p>Manajemen titik koordinat dan lokasi masjid sebagai titik pusat distribusi bantuan.</p>
</div>
<div class="card">
<h3>👨‍👩‍👧‍👦 Data Penduduk</h3>
<p>Pemetaan penduduk miskin berbasis lokasi.</p>
<p>Pemetaan data demografi penduduk miskin secara akurat berbasis lokasi (Point of Interest).</p>
</div>
<div class="card">
<h3>📍 Analisis Radius</h3>
<p>Menentukan jangkauan bantuan secara otomatis.</p>
<p>Pemrosesan buffer/radius secara otomatis untuk menentukan area jangkauan bantuan yang optimal.</p>
</div>
</div>
</section>
<section id="preview" class="section">
<h2>Preview Sistem</h2>
<img src="assets/img/preview.png"
alt="Preview Dashboard"
class="preview">
<div style="width: 100%; max-width: 900px; height: 500px; background: var(--surface); margin: 30px auto 0; border-radius: 15px; border: 1px solid var(--surface-border); display: flex; align-items: center; justify-content: center; color: var(--text-muted);">
[ Area Gambar Preview Map / Dashboard ]
</div>
</section>
<section class="section">
<h2>Alur Analisis</h2>
<h2>Alur Analisis Geospasial</h2>
<div class="flow">
<div>Pilih Masjid</div>
<div></div>
<div>Tentukan Radius</div>
<div></div>
<div>Hitung Jarak</div>
<div></div>
<div>Identifikasi Penduduk</div>
<div></div>
<div>Rekomendasi Bantuan</div>
<div class="flow-item">Pilih Masjid</div>
<div class="flow-arrow"></div>
<div class="flow-item">Tentukan Radius</div>
<div class="flow-arrow"></div>
<div class="flow-item">Hitung Intersect Jarak</div>
<div class="flow-arrow"></div>
<div class="flow-item">Identifikasi Penduduk</div>
<div class="flow-arrow"></div>
<div class="flow-item">Rekomendasi Bantuan</div>
</div>
</section>
<footer>
<p>
© 2026 SinergiSpasial
Sistem Informasi Geografis Kota Pontianak
</p>
<p>© 2026 SinergiSpasial Sistem Informasi Geografis Kota Pontianak</p>
</footer>
</body>