Initial commit: Setup Landing Page dan file pertemuan
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
$tabel = isset($_POST['tabel']) ? trim($_POST['tabel']) : '';
|
||||
|
||||
if ($id <= 0) {
|
||||
http_response_code(400);
|
||||
echo "ID tidak valid!";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Allowed tables for security
|
||||
$allowed_tables = ['jalan', 'parsil'];
|
||||
|
||||
if (in_array($tabel, $allowed_tables)) {
|
||||
$stmt = $conn->prepare("DELETE FROM $tabel WHERE id = ?");
|
||||
$stmt->bind_param("i", $id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo "Data berhasil dihapus!";
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo "Gagal menghapus: " . $conn->error;
|
||||
}
|
||||
$stmt->close();
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo "Tabel tidak valid!";
|
||||
}
|
||||
$conn->close();
|
||||
} else {
|
||||
http_response_code(405);
|
||||
echo "Metode tidak diizinkan";
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
// Start session for standard PHP structure (if needed in future)
|
||||
session_start();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebGIS Pertemuan 1 — Pemetaan Jalan & Parsil</title>
|
||||
|
||||
<!-- Leaflet & Leaflet.draw CDN -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
|
||||
|
||||
<!-- Premium Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Custom CSS Styles -->
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ==============================
|
||||
HEADER BAR
|
||||
============================== -->
|
||||
<div class="webgis-header">
|
||||
<div class="header-brand">
|
||||
<div class="brand-icon">
|
||||
<!-- Map icon SVG -->
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="brand-name">WebGIS Spasial</div>
|
||||
<div class="brand-subtitle">Pertemuan 1</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-divider"></div>
|
||||
|
||||
<!-- SEARCH BAR -->
|
||||
<div class="search-wrapper">
|
||||
<div class="search-bar">
|
||||
<!-- Category Dropdown -->
|
||||
<div class="search-category-wrap" id="custom-select-wrap">
|
||||
<span class="search-category-icon">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 10h16M4 14h8" />
|
||||
</svg>
|
||||
</span>
|
||||
<div class="custom-select-trigger" id="custom-select-trigger">Semua Layer</div>
|
||||
<input type="hidden" id="search-category" value="Semua">
|
||||
<span class="category-arrow">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<div class="custom-select-options" id="custom-select-options">
|
||||
<div class="custom-option selected" data-value="Semua">Semua Layer</div>
|
||||
<div class="custom-option" data-value="Jalan">Jaringan Jalan</div>
|
||||
<div class="custom-option" data-value="Parsil">Parsil Lahan</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Input Pencarian -->
|
||||
<div class="search-input-wrap">
|
||||
<span class="search-icon">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
<input type="text" id="search-input" placeholder="Cari jalan atau pemilik parsil..."
|
||||
onkeyup="jalankanPencarian()" oninput="toggleClearBtn()" autocomplete="off">
|
||||
<button class="search-clear-btn" id="search-clear" onclick="clearSearch()" title="Hapus pencarian">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dropdown Hasil Pencarian -->
|
||||
<div class="search-results" id="search-results"></div>
|
||||
</div>
|
||||
|
||||
<!-- HEADER RIGHT TOOLS -->
|
||||
<div class="header-tools">
|
||||
<div class="tool-badge">Peta Aktif</div>
|
||||
<div class="tool-btn" title="Status Database">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
|
||||
</svg>
|
||||
<div class="status-dot"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==============================
|
||||
SIDEBAR INPUT DATA
|
||||
============================== -->
|
||||
<!-- Toggle Button -->
|
||||
<button class="sidebar-toggle" id="sidebar-toggle" title="Panel Input Data">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<span>Input Geometris</span>
|
||||
</button>
|
||||
|
||||
<!-- Sidebar Panel -->
|
||||
<div class="input-sidebar" id="input-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-title">
|
||||
<div class="sidebar-title-icon">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="sidebar-title-text">Panel Input Data</div>
|
||||
<div class="sidebar-title-sub">Tambah polygon & polyline</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="sidebar-close" id="sidebar-close" title="Tutup">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
<div class="sidebar-tabs">
|
||||
<button class="stab active" data-tab="jalan" onclick="switchSidebarTab('jalan')">
|
||||
<span class="stab-icon">🛣️</span>
|
||||
<span>Jalan (Polyline)</span>
|
||||
</button>
|
||||
<button class="stab" data-tab="parsil" onclick="switchSidebarTab('parsil')">
|
||||
<span class="stab-icon">🏘️</span>
|
||||
<span>Parsil (Polygon)</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Scrollable Content -->
|
||||
<div class="sidebar-body">
|
||||
|
||||
<!-- ===== TAB: JALAN (POLYLINE) ===== -->
|
||||
<div class="stab-content active" id="tab-jalan">
|
||||
<div class="step-guide">
|
||||
<div class="step-badge">Langkah 1</div>
|
||||
<p>Klik tombol <strong>Gambar Ruas Jalan</strong> di bawah, lalu buat garis di peta. Klik ganda titik akhir untuk menyelesaikan gambar.</p>
|
||||
</div>
|
||||
|
||||
<button class="btn-pick-location btn-draw" id="btn-draw-jalan" onclick="activateDrawMode('polyline')">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
||||
</svg>
|
||||
Gambar Ruas Jalan
|
||||
</button>
|
||||
|
||||
<div class="coords-display" id="coords-jalan">
|
||||
<span class="coords-label">Panjang Terhitung:</span>
|
||||
<span class="coords-value" id="coords-jalan-val">Belum digambar</span>
|
||||
</div>
|
||||
|
||||
<div class="step-guide">
|
||||
<div class="step-badge">Langkah 2</div>
|
||||
<p>Lengkapi atribut data jalan di bawah ini.</p>
|
||||
</div>
|
||||
|
||||
<div class="sfield">
|
||||
<label class="sfield-label">Nama Jalan <span class="required">*</span></label>
|
||||
<input type="text" id="sb_nama_jalan" class="sinput" placeholder="Contoh: Jl. Ahmad Yani">
|
||||
</div>
|
||||
|
||||
<div class="sfield">
|
||||
<label class="sfield-label">Status Administrasi</label>
|
||||
<select id="sb_status_jalan" class="sselect">
|
||||
<option value="Jalan Nasional">Jalan Nasional</option>
|
||||
<option value="Jalan Provinsi">Jalan Provinsi</option>
|
||||
<option value="Jalan Kabupaten">Jalan Kabupaten</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sfield">
|
||||
<label class="sfield-label">Panjang Terukur</label>
|
||||
<input type="text" id="sb_panjang_jalan" class="sinput" placeholder="Otomatis terhitung setelah menggambar" readonly>
|
||||
</div>
|
||||
|
||||
<button class="btn-save-sidebar" onclick="saveJalanSidebar()">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
Simpan Data Jalan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- ===== TAB: PARSIL (POLYGON) ===== -->
|
||||
<div class="stab-content" id="tab-parsil">
|
||||
<div class="step-guide">
|
||||
<div class="step-badge">Langkah 1</div>
|
||||
<p>Klik tombol <strong>Gambar Area Parsil</strong> di bawah, lalu tentukan batas area di peta. Klik ganda titik terakhir untuk menyelesaikan.</p>
|
||||
</div>
|
||||
|
||||
<button class="btn-pick-location" id="btn-draw-parsil" onclick="activateDrawMode('polygon')">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
|
||||
</svg>
|
||||
Gambar Area Parsil
|
||||
</button>
|
||||
|
||||
<div class="coords-display" id="coords-parsil">
|
||||
<span class="coords-label">Luas Terhitung:</span>
|
||||
<span class="coords-value" id="coords-parsil-val">Belum digambar</span>
|
||||
</div>
|
||||
|
||||
<div class="step-guide">
|
||||
<div class="step-badge">Langkah 2</div>
|
||||
<p>Lengkapi atribut parsil di bawah ini.</p>
|
||||
</div>
|
||||
|
||||
<div class="sfield">
|
||||
<label class="sfield-label">Nama Pemilik <span class="required">*</span></label>
|
||||
<input type="text" id="sb_nama_parsil" class="sinput" placeholder="Contoh: Haji Sudirman">
|
||||
</div>
|
||||
|
||||
<div class="sfield">
|
||||
<label class="sfield-label">Status Kepemilikan (Sertifikat)</label>
|
||||
<select id="sb_status_parsil" class="sselect">
|
||||
<option value="SHM">SHM (Sertifikat Hak Milik)</option>
|
||||
<option value="HGB">HGB (Hak Guna Bangunan)</option>
|
||||
<option value="HGU">HGU (Hak Guna Usaha)</option>
|
||||
<option value="HP">HP (Hak Pakai)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sfield">
|
||||
<label class="sfield-label">Luas Terukur</label>
|
||||
<input type="text" id="sb_luas_parsil" class="sinput" placeholder="Otomatis terhitung setelah menggambar" readonly>
|
||||
</div>
|
||||
|
||||
<button class="btn-save-sidebar" onclick="saveParsilSidebar()">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
Simpan Data Parsil
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div><!-- end sidebar-body -->
|
||||
</div><!-- end input-sidebar -->
|
||||
|
||||
<!-- Banner Info Mode Menggambar -->
|
||||
<div class="pick-mode-overlay" id="pick-overlay">
|
||||
<div class="pick-mode-banner">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5" />
|
||||
</svg>
|
||||
<span id="pick-overlay-text">Klik lokasi di peta...</span>
|
||||
<button onclick="deactivatePickMode()">Batal</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Container Peta -->
|
||||
<div id="map" style="padding-top: 60px; height: 100vh; box-sizing: border-box;"></div>
|
||||
|
||||
<!-- Scripts Leaflet, Leaflet.draw, Turf, dan script.js -->
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@6/turf.min.js"></script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
$host = "localhost";
|
||||
$user = "root";
|
||||
$pass = "";
|
||||
$db = "webgis_db_pertemuan1";
|
||||
|
||||
// Connect first without DB to ensure we can create it if missing
|
||||
$conn = new mysqli($host, $user, $pass);
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die("Koneksi gagal: " . $conn->connect_error);
|
||||
}
|
||||
|
||||
// Create database if not exists
|
||||
$conn->query("CREATE DATABASE IF NOT EXISTS `$db` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;");
|
||||
|
||||
// Select database
|
||||
$conn->select_db($db);
|
||||
|
||||
// Auto create tables if not exist
|
||||
// Table: jalan (for polyline data)
|
||||
$sql_jalan = "CREATE TABLE IF NOT EXISTS `jalan` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama_jalan` VARCHAR(255) NOT NULL,
|
||||
`status` VARCHAR(100) NOT NULL,
|
||||
`panjang` DECIMAL(10,2) NOT NULL,
|
||||
`koordinat` TEXT NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
|
||||
// Table: parsil (for polygon data)
|
||||
$sql_parsil = "CREATE TABLE IF NOT EXISTS `parsil` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`nama_pemilik` VARCHAR(255) NOT NULL,
|
||||
`status` VARCHAR(100) NOT NULL,
|
||||
`luas` DECIMAL(10,2) NOT NULL,
|
||||
`koordinat` TEXT NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
|
||||
if (!$conn->query($sql_jalan)) {
|
||||
die("Gagal membuat tabel jalan: " . $conn->error);
|
||||
}
|
||||
|
||||
if (!$conn->query($sql_parsil)) {
|
||||
die("Gagal membuat tabel parsil: " . $conn->error);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$jenis = isset($_GET['jenis']) ? $_GET['jenis'] : 'jalan';
|
||||
|
||||
if ($jenis == 'jalan') {
|
||||
$sql = "SELECT * FROM jalan";
|
||||
} else if ($jenis == 'parsil') {
|
||||
$sql = "SELECT * FROM parsil";
|
||||
} else {
|
||||
die(json_encode(["error" => "Jenis data tidak ditemukan"]));
|
||||
}
|
||||
|
||||
$result = $conn->query($sql);
|
||||
$data = array();
|
||||
|
||||
if ($result && $result->num_rows > 0) {
|
||||
while($row = $result->fetch_assoc()) {
|
||||
// Convert numbers correctly
|
||||
if (isset($row['panjang'])) {
|
||||
$row['panjang'] = floatval($row['panjang']);
|
||||
}
|
||||
if (isset($row['luas'])) {
|
||||
$row['luas'] = floatval($row['luas']);
|
||||
}
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$nama = isset($_POST['nama_jalan']) ? trim($_POST['nama_jalan']) : '';
|
||||
$status = isset($_POST['status']) ? trim($_POST['status']) : '';
|
||||
$panjang_raw = isset($_POST['panjang']) ? $_POST['panjang'] : '0';
|
||||
$koordinat = isset($_POST['koordinat']) ? $_POST['koordinat'] : '';
|
||||
|
||||
if (empty($nama) || empty($koordinat)) {
|
||||
http_response_code(400);
|
||||
echo "Nama jalan dan koordinat wajib diisi!";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Clean up " m" from length to get float value
|
||||
$panjang = floatval(preg_replace('/[^\d.]/', '', $panjang_raw));
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO jalan (nama_jalan, status, panjang, koordinat) VALUES (?, ?, ?, ?)");
|
||||
$stmt->bind_param("ssds", $nama, $status, $panjang, $koordinat);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo "Data Jalan berhasil disimpan!";
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo "Gagal menyimpan data: " . $conn->error;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
http_response_code(405);
|
||||
echo "Metode tidak diizinkan";
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$nama = isset($_POST['nama_pemilik']) ? trim($_POST['nama_pemilik']) : '';
|
||||
$status = isset($_POST['status']) ? trim($_POST['status']) : '';
|
||||
$luas_raw = isset($_POST['luas']) ? $_POST['luas'] : '0';
|
||||
$koordinat = isset($_POST['koordinat']) ? $_POST['koordinat'] : '';
|
||||
|
||||
if (empty($nama) || empty($koordinat)) {
|
||||
http_response_code(400);
|
||||
echo "Nama pemilik dan koordinat wajib diisi!";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Clean up " m²" or other characters to get float value
|
||||
$luas = floatval(preg_replace('/[^\d.]/', '', $luas_raw));
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO parsil (nama_pemilik, status, luas, koordinat) VALUES (?, ?, ?, ?)");
|
||||
$stmt->bind_param("ssds", $nama, $status, $luas, $koordinat);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo "Data Parsil berhasil disimpan!";
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo "Gagal menyimpan data: " . $conn->error;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
http_response_code(405);
|
||||
echo "Metode tidak diizinkan";
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,577 @@
|
||||
// ==========================================
|
||||
// 1. INISIALISASI PETA & LAYER
|
||||
// ==========================================
|
||||
var map = L.map('map', { zoomControl: false }).setView([-0.0227, 109.3425], 14);
|
||||
|
||||
// Zoom control di kanan bawah (tampilan modern)
|
||||
L.control.zoom({ position: 'bottomright' }).addTo(map);
|
||||
|
||||
// OpenStreetMap Tile Layer
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
// Layer Groups
|
||||
var jalanLayer = L.layerGroup().addTo(map);
|
||||
var parsilLayer = L.layerGroup().addTo(map);
|
||||
var drawnItems = new L.FeatureGroup().addTo(map);
|
||||
|
||||
// Layer Control (Checkbox di kanan atas)
|
||||
var overlayMaps = {
|
||||
"🛣️ Jaringan Jalan": jalanLayer,
|
||||
"🏘️ Parsil Bangunan": parsilLayer
|
||||
};
|
||||
L.control.layers(null, overlayMaps, { collapsed: true, position: 'bottomleft' }).addTo(map);
|
||||
|
||||
// Global Variables
|
||||
var databasePencarian = [];
|
||||
var sidebarDrawMode = null; // 'polyline' | 'polygon'
|
||||
var sidebarKoordinat = "";
|
||||
var sidebarDrawHandler = null;
|
||||
|
||||
// ==========================================
|
||||
// 2. FUNGSI LOAD DATA DARI DATABASE
|
||||
// ==========================================
|
||||
function loadJalan() {
|
||||
jalanLayer.clearLayers();
|
||||
|
||||
// Reset database pencarian khusus kategori Jalan
|
||||
databasePencarian = databasePencarian.filter(item => item.kategori !== 'Jalan');
|
||||
|
||||
fetch('load.php?jenis=jalan')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
data.forEach(item => {
|
||||
try {
|
||||
var geom = JSON.parse(item.koordinat);
|
||||
|
||||
// Warna berdasarkan status jalan
|
||||
var warna = item.status === 'Jalan Nasional' ? '#ef4444' // Red
|
||||
: item.status === 'Jalan Provinsi' ? '#fbbf24' // Yellow/Amber
|
||||
: '#10b981'; // Green (Kabupaten)
|
||||
|
||||
var viewHTML = `
|
||||
<div class="popup-container" id="popup-jalan-${item.id}">
|
||||
<div class="popup-header popup-header-jalan">
|
||||
<h4>${item.nama_jalan}</h4>
|
||||
<span class="popup-type-badge">🛣️ Jaringan Jalan</span>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
<div class="info-row">
|
||||
<span class="info-label">Status Jalan</span>
|
||||
<span class="info-value" style="color:${warna}; font-weight:600;">${item.status}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Panjang Terukur</span>
|
||||
<span class="info-value">${item.panjang} m</span>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-edit" onclick="formEditJalan('${item.id}', '${item.nama_jalan}', '${item.status}')">✏️ Edit</button>
|
||||
<button class="btn btn-delete" onclick="deleteData('jalan', '${item.id}')">🗑️ Hapus</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
var layerJalan = L.geoJSON(geom, {
|
||||
style: { color: warna, weight: 5, opacity: 0.85 }
|
||||
}).bindPopup(viewHTML).addTo(jalanLayer);
|
||||
|
||||
layerJalan.on('click', function () {
|
||||
map.fitBounds(layerJalan.getBounds(), { padding: [50, 50] });
|
||||
});
|
||||
|
||||
databasePencarian.push({
|
||||
namaLower: item.nama_jalan.toLowerCase(),
|
||||
namaAsli: item.nama_jalan,
|
||||
kategori: 'Jalan',
|
||||
ikon: '🛣️',
|
||||
tipe: 'area',
|
||||
layer: layerJalan
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error parse koordinat jalan ID: " + item.id, error);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(e => console.log('Belum ada data Jalan', e));
|
||||
}
|
||||
|
||||
function loadParsil() {
|
||||
parsilLayer.clearLayers();
|
||||
|
||||
// Reset database pencarian khusus kategori Parsil
|
||||
databasePencarian = databasePencarian.filter(item => item.kategori !== 'Parsil');
|
||||
|
||||
fetch('load.php?jenis=parsil')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
data.forEach(item => {
|
||||
try {
|
||||
var geom = JSON.parse(item.koordinat);
|
||||
|
||||
// Warna berdasarkan status sertifikat tanah
|
||||
var warna = item.status === 'SHM' ? '#10b981' // Green
|
||||
: item.status === 'HGB' ? '#3b82f6' // Blue
|
||||
: item.status === 'HGU' ? '#8b5cf6' // Purple
|
||||
: '#f59e0b'; // Orange (HP)
|
||||
|
||||
var viewHTML = `
|
||||
<div class="popup-container" id="popup-parsil-${item.id}">
|
||||
<div class="popup-header popup-header-parsil">
|
||||
<h4>${item.nama_pemilik}</h4>
|
||||
<span class="popup-type-badge">🏘️ Parsil Bangunan</span>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
<div class="info-row">
|
||||
<span class="info-label">Status Sertifikat</span>
|
||||
<span class="info-value" style="color:${warna}; font-weight:600;">${item.status}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Luas Terukur</span>
|
||||
<span class="info-value">${item.luas} m²</span>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-edit" onclick="formEditParsil('${item.id}', '${item.nama_pemilik}', '${item.status}')">✏️ Edit</button>
|
||||
<button class="btn btn-delete" onclick="deleteData('parsil', '${item.id}')">🗑️ Hapus</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
var layerParsil = L.geoJSON(geom, {
|
||||
style: { fillColor: warna, color: warna, weight: 2, fillOpacity: 0.45 }
|
||||
}).bindPopup(viewHTML).addTo(parsilLayer);
|
||||
|
||||
layerParsil.on('click', function () {
|
||||
map.fitBounds(layerParsil.getBounds(), { padding: [50, 50] });
|
||||
});
|
||||
|
||||
databasePencarian.push({
|
||||
namaLower: item.nama_pemilik.toLowerCase(),
|
||||
namaAsli: item.nama_pemilik,
|
||||
kategori: 'Parsil',
|
||||
ikon: '🏘️',
|
||||
tipe: 'area',
|
||||
layer: layerParsil
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error parse koordinat parsil ID: " + item.id, error);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(e => console.log('Belum ada data Parsil', e));
|
||||
}
|
||||
|
||||
// Load data awal
|
||||
loadJalan();
|
||||
loadParsil();
|
||||
|
||||
// ==========================================
|
||||
// 3. EDIT & UPDATE DATA
|
||||
// ==========================================
|
||||
function formEditJalan(id, nama, status) {
|
||||
setTimeout(function () {
|
||||
var container = document.getElementById(`popup-jalan-${id}`);
|
||||
if (!container) return;
|
||||
container.innerHTML = `
|
||||
<div class="popup-header popup-header-jalan" style="border-radius: 0;">
|
||||
<h4 style="margin:0;">Edit Detail Jalan</h4>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
<form onsubmit="updateData(event, 'jalan', '${id}')">
|
||||
<div class="sfield" style="margin-bottom:8px;">
|
||||
<span class="info-label">Nama Jalan</span>
|
||||
<input type="text" id="edit_nama" value="${nama}" required style="margin-bottom:0;">
|
||||
</div>
|
||||
<div class="sfield" style="margin-bottom:12px;">
|
||||
<span class="info-label">Status Jalan</span>
|
||||
<select id="edit_status" style="margin-bottom:0;">
|
||||
<option value="Jalan Nasional" ${status === 'Jalan Nasional' ? 'selected' : ''}>Jalan Nasional</option>
|
||||
<option value="Jalan Provinsi" ${status === 'Jalan Provinsi' ? 'selected' : ''}>Jalan Provinsi</option>
|
||||
<option value="Jalan Kabupaten" ${status === 'Jalan Kabupaten' ? 'selected' : ''}>Jalan Kabupaten</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="submit" class="btn btn-save">💾 Simpan</button>
|
||||
<button type="button" class="btn btn-delete" onclick="loadJalan();">Batal</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>`;
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function formEditParsil(id, nama, status) {
|
||||
setTimeout(function () {
|
||||
var container = document.getElementById(`popup-parsil-${id}`);
|
||||
if (!container) return;
|
||||
container.innerHTML = `
|
||||
<div class="popup-header popup-header-parsil" style="border-radius: 0;">
|
||||
<h4 style="margin:0;">Edit Detail Parsil</h4>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
<form onsubmit="updateData(event, 'parsil', '${id}')">
|
||||
<div class="sfield" style="margin-bottom:8px;">
|
||||
<span class="info-label">Nama Pemilik</span>
|
||||
<input type="text" id="edit_nama" value="${nama}" required style="margin-bottom:0;">
|
||||
</div>
|
||||
<div class="sfield" style="margin-bottom:12px;">
|
||||
<span class="info-label">Status Sertifikat</span>
|
||||
<select id="edit_status" style="margin-bottom:0;">
|
||||
<option value="SHM" ${status === 'SHM' ? 'selected' : ''}>SHM (Hak Milik)</option>
|
||||
<option value="HGB" ${status === 'HGB' ? 'selected' : ''}>HGB (Guna Bangunan)</option>
|
||||
<option value="HGU" ${status === 'HGU' ? 'selected' : ''}>HGU (Guna Usaha)</option>
|
||||
<option value="HP" ${status === 'HP' ? 'selected' : ''}>HP (Hak Pakai)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="submit" class="btn btn-save">💾 Simpan</button>
|
||||
<button type="button" class="btn btn-delete" onclick="loadParsil();">Batal</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>`;
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function updateData(e, tabel, id) {
|
||||
e.preventDefault();
|
||||
var formData = new FormData();
|
||||
formData.append('tabel', tabel);
|
||||
formData.append('id', id);
|
||||
|
||||
if (tabel === 'jalan') {
|
||||
formData.append('nama_jalan', document.getElementById('edit_nama').value);
|
||||
formData.append('status', document.getElementById('edit_status').value);
|
||||
} else if (tabel === 'parsil') {
|
||||
formData.append('nama_pemilik', document.getElementById('edit_nama').value);
|
||||
formData.append('status', document.getElementById('edit_status').value);
|
||||
}
|
||||
|
||||
fetch('update_data.php', { method: 'POST', body: formData })
|
||||
.then(r => r.text())
|
||||
.then(res => {
|
||||
alert(res);
|
||||
map.closePopup();
|
||||
if (tabel === 'jalan') loadJalan();
|
||||
if (tabel === 'parsil') loadParsil();
|
||||
})
|
||||
.catch(error => console.error("Error updating data:", error));
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 4. HAPUS DATA
|
||||
// ==========================================
|
||||
function deleteData(tabel, id) {
|
||||
if (confirm('Apakah Anda yakin ingin menghapus data ini secara permanen?')) {
|
||||
var formData = new FormData();
|
||||
formData.append('id', id);
|
||||
formData.append('tabel', tabel);
|
||||
|
||||
fetch('delete_data.php', { method: 'POST', body: formData })
|
||||
.then(r => r.text())
|
||||
.then(res => {
|
||||
alert(res);
|
||||
map.closePopup();
|
||||
if (tabel === 'jalan') loadJalan();
|
||||
if (tabel === 'parsil') loadParsil();
|
||||
})
|
||||
.catch(error => console.error("Error deleting data:", error));
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 5. SISTEM PENCARIAN & AUTOCMPLETE
|
||||
// ==========================================
|
||||
function jalankanPencarian() {
|
||||
var kataKunci = document.getElementById('search-input').value.toLowerCase();
|
||||
var kategori = document.getElementById('search-category').value;
|
||||
var wadahHasil = document.getElementById('search-results');
|
||||
|
||||
wadahHasil.innerHTML = '';
|
||||
|
||||
if (kataKunci.length < 2) {
|
||||
wadahHasil.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
var hasil = databasePencarian.filter(function (item) {
|
||||
var cocokNama = item.namaLower.includes(kataKunci);
|
||||
var cocokKategori = (kategori === 'Semua') || (item.kategori === kategori);
|
||||
return cocokNama && cocokKategori;
|
||||
});
|
||||
|
||||
if (hasil.length > 0) {
|
||||
wadahHasil.style.display = 'block';
|
||||
wadahHasil.innerHTML = `<div class="results-header">${hasil.length} hasil ditemukan</div>`;
|
||||
|
||||
hasil.forEach(function (item) {
|
||||
var badgeClass = item.kategori === 'Jalan' ? 'badge-Jalan' : 'badge-Parsil';
|
||||
var bgColors = item.kategori === 'Jalan' ? 'rgba(245,158,11,0.1)' : 'rgba(163,116,255,0.1)';
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.className = 'result-item';
|
||||
div.innerHTML = `
|
||||
<div class="result-item-icon" style="background: ${bgColors};">
|
||||
${item.ikon}
|
||||
</div>
|
||||
<div class="result-item-text">
|
||||
<div class="result-item-name">${item.namaAsli}</div>
|
||||
<div class="result-item-sub">Klik untuk zoom ke lokasi</div>
|
||||
</div>
|
||||
<span class="badge-kategori ${badgeClass}">${item.kategori}</span>`;
|
||||
|
||||
div.onclick = function () {
|
||||
map.fitBounds(item.layer.getBounds(), { padding: [50, 50] });
|
||||
item.layer.openPopup();
|
||||
wadahHasil.style.display = 'none';
|
||||
document.getElementById('search-input').value = item.namaAsli;
|
||||
toggleClearBtn();
|
||||
};
|
||||
wadahHasil.appendChild(div);
|
||||
});
|
||||
} else {
|
||||
wadahHasil.style.display = 'block';
|
||||
wadahHasil.innerHTML = `
|
||||
<div class="result-empty">
|
||||
<div class="result-item" style="color:#ef4444; justify-content:center;">Data tidak ditemukan</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleClearBtn() {
|
||||
var input = document.getElementById('search-input');
|
||||
var clearBtn = document.getElementById('search-clear');
|
||||
clearBtn.style.display = input.value.length > 0 ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
document.getElementById('search-input').value = '';
|
||||
document.getElementById('search-results').style.display = 'none';
|
||||
document.getElementById('search-clear').style.display = 'none';
|
||||
}
|
||||
|
||||
// Tutup hasil saat klik di luar
|
||||
document.addEventListener('click', function (e) {
|
||||
var wrapper = document.querySelector('.search-wrapper');
|
||||
if (wrapper && !wrapper.contains(e.target)) {
|
||||
document.getElementById('search-results').style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Shortcut Ctrl + K untuk fokus ke pencarian
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
document.getElementById('search-input').focus();
|
||||
}
|
||||
if (e.key === 'Escape') {
|
||||
clearSearch();
|
||||
document.getElementById('search-input').blur();
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 6. LOGIKA INPUT SIDEBAR & PROGRAMMATIC DRAW
|
||||
// ==========================================
|
||||
|
||||
// Buka/Tutup Sidebar
|
||||
document.getElementById('sidebar-toggle').addEventListener('click', function () {
|
||||
var sidebar = document.getElementById('input-sidebar');
|
||||
sidebar.classList.toggle('open');
|
||||
this.classList.toggle('open');
|
||||
});
|
||||
|
||||
document.getElementById('sidebar-close').addEventListener('click', function () {
|
||||
document.getElementById('input-sidebar').classList.remove('open');
|
||||
document.getElementById('sidebar-toggle').classList.remove('open');
|
||||
});
|
||||
|
||||
// Ganti Tab
|
||||
function switchSidebarTab(tabName) {
|
||||
document.querySelectorAll('.stab').forEach(function (t) { t.classList.remove('active'); });
|
||||
document.querySelectorAll('.stab-content').forEach(function (c) { c.classList.remove('active'); });
|
||||
document.querySelector('.stab[data-tab="' + tabName + '"]').classList.add('active');
|
||||
document.getElementById('tab-' + tabName).classList.add('active');
|
||||
|
||||
// Batalkan mode draw jika ganti tab
|
||||
deactivatePickMode();
|
||||
}
|
||||
|
||||
// Aktifkan mode gambar garis/poligon secara terprogram
|
||||
function activateDrawMode(type) {
|
||||
deactivatePickMode();
|
||||
sidebarDrawMode = type;
|
||||
|
||||
if (type === 'polyline') {
|
||||
sidebarDrawHandler = new L.Draw.Polyline(map, {
|
||||
shapeOptions: { color: '#6366f1', weight: 4 }
|
||||
});
|
||||
document.getElementById('coords-jalan-val').textContent = 'Sedang menggambar...';
|
||||
document.getElementById('btn-draw-jalan').classList.add('active-pick');
|
||||
} else if (type === 'polygon') {
|
||||
sidebarDrawHandler = new L.Draw.Polygon(map, {
|
||||
shapeOptions: { color: '#6366f1', fillColor: '#6366f1', fillOpacity: 0.3 }
|
||||
});
|
||||
document.getElementById('coords-parsil-val').textContent = 'Sedang menggambar...';
|
||||
document.getElementById('btn-draw-parsil').classList.add('active-pick');
|
||||
}
|
||||
|
||||
if (sidebarDrawHandler) sidebarDrawHandler.enable();
|
||||
document.getElementById('pick-overlay').classList.add('active');
|
||||
|
||||
var teks = {
|
||||
polyline: 'Klik titik-titik ruas jalan di peta. Klik dua kali titik terakhir untuk selesai.',
|
||||
polygon: 'Klik titik-titik batas lahan di peta. Klik dua kali titik terakhir untuk selesai.'
|
||||
};
|
||||
document.getElementById('pick-overlay-text').textContent = teks[type];
|
||||
map.getContainer().style.cursor = 'crosshair';
|
||||
}
|
||||
|
||||
// Batalkan mode draw
|
||||
function deactivatePickMode() {
|
||||
sidebarDrawMode = null;
|
||||
document.getElementById('pick-overlay').classList.remove('active');
|
||||
document.querySelectorAll('.btn-pick-location').forEach(function (b) { b.classList.remove('active-pick'); });
|
||||
map.getContainer().style.cursor = '';
|
||||
|
||||
if (sidebarDrawHandler) {
|
||||
try { sidebarDrawHandler.disable(); } catch (e) { }
|
||||
sidebarDrawHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Menangkap event Leaflet Draw CREATED
|
||||
map.on(L.Draw.Event.CREATED, function (e) {
|
||||
var type = e.layerType, layer = e.layer;
|
||||
var geojson = layer.toGeoJSON();
|
||||
|
||||
drawnItems.clearLayers();
|
||||
drawnItems.addLayer(layer);
|
||||
|
||||
if (sidebarDrawMode === 'polyline' && type === 'polyline') {
|
||||
// turf.length menghitung dalam KM, ubah ke meter
|
||||
var panjangMeter = (turf.length(geojson, { units: 'kilometers' }) * 1000).toFixed(2);
|
||||
sidebarKoordinat = JSON.stringify(geojson.geometry);
|
||||
|
||||
var el = document.getElementById('coords-jalan-val');
|
||||
el.textContent = panjangMeter + ' m';
|
||||
el.classList.add('has-coords');
|
||||
|
||||
document.getElementById('sb_panjang_jalan').value = panjangMeter + ' m';
|
||||
deactivatePickMode();
|
||||
} else if (sidebarDrawMode === 'polygon' && type === 'polygon') {
|
||||
// turf.area menghitung dalam meter persegi
|
||||
var luasMeter = turf.area(geojson).toFixed(2);
|
||||
sidebarKoordinat = JSON.stringify(geojson.geometry);
|
||||
|
||||
var el = document.getElementById('coords-parsil-val');
|
||||
el.textContent = luasMeter + ' m²';
|
||||
el.classList.add('has-coords');
|
||||
|
||||
document.getElementById('sb_luas_parsil').value = luasMeter + ' m²';
|
||||
deactivatePickMode();
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 7. SIMPAN DATA DARI SIDEBAR
|
||||
// ==========================================
|
||||
function saveJalanSidebar() {
|
||||
if (!sidebarKoordinat) {
|
||||
alert('Silakan gambar ruas jalan di peta terlebih dahulu!');
|
||||
return;
|
||||
}
|
||||
var nama = document.getElementById('sb_nama_jalan').value.trim();
|
||||
if (!nama) {
|
||||
alert('Nama jalan wajib diisi!');
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('nama_jalan', nama);
|
||||
formData.append('status', document.getElementById('sb_status_jalan').value);
|
||||
formData.append('panjang', document.getElementById('sb_panjang_jalan').value);
|
||||
formData.append('koordinat', sidebarKoordinat);
|
||||
|
||||
fetch('save_jalan.php', { method: 'POST', body: formData })
|
||||
.then(r => r.text())
|
||||
.then(res => {
|
||||
alert(res);
|
||||
document.getElementById('sb_nama_jalan').value = '';
|
||||
document.getElementById('sb_panjang_jalan').value = '';
|
||||
document.getElementById('coords-jalan-val').textContent = 'Belum digambar';
|
||||
document.getElementById('coords-jalan-val').classList.remove('has-coords');
|
||||
sidebarKoordinat = '';
|
||||
drawnItems.clearLayers();
|
||||
loadJalan();
|
||||
})
|
||||
.catch(e => console.error("Error saving jalan:", e));
|
||||
}
|
||||
|
||||
function saveParsilSidebar() {
|
||||
if (!sidebarKoordinat) {
|
||||
alert('Silakan gambar area parsil di peta terlebih dahulu!');
|
||||
return;
|
||||
}
|
||||
var nama = document.getElementById('sb_nama_parsil').value.trim();
|
||||
if (!nama) {
|
||||
alert('Nama pemilik wajib diisi!');
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('nama_pemilik', nama);
|
||||
formData.append('status', document.getElementById('sb_status_parsil').value);
|
||||
formData.append('luas', document.getElementById('sb_luas_parsil').value);
|
||||
formData.append('koordinat', sidebarKoordinat);
|
||||
|
||||
fetch('save_parsil.php', { method: 'POST', body: formData })
|
||||
.then(r => r.text())
|
||||
.then(res => {
|
||||
alert(res);
|
||||
document.getElementById('sb_nama_parsil').value = '';
|
||||
document.getElementById('sb_luas_parsil').value = '';
|
||||
document.getElementById('coords-parsil-val').textContent = 'Belum digambar';
|
||||
document.getElementById('coords-parsil-val').classList.remove('has-coords');
|
||||
sidebarKoordinat = '';
|
||||
drawnItems.clearLayers();
|
||||
loadParsil();
|
||||
})
|
||||
.catch(e => console.error("Error saving parsil:", e));
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 8. DROPDOWN KATEGORI DI HEADER
|
||||
// ==========================================
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var wrap = document.getElementById('custom-select-wrap');
|
||||
var trigger = document.getElementById('custom-select-trigger');
|
||||
var options = document.getElementById('custom-select-options');
|
||||
var hiddenInput = document.getElementById('search-category');
|
||||
var optionItems = document.querySelectorAll('.custom-option');
|
||||
|
||||
// Toggle dropdown
|
||||
wrap.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
options.classList.toggle('show');
|
||||
});
|
||||
|
||||
// Pilihan dropdown diklik
|
||||
optionItems.forEach(function (item) {
|
||||
item.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
optionItems.forEach(opt => opt.classList.remove('selected'));
|
||||
this.classList.add('selected');
|
||||
|
||||
trigger.textContent = this.textContent;
|
||||
hiddenInput.value = this.getAttribute('data-value');
|
||||
|
||||
options.classList.remove('show');
|
||||
jalankanPencarian();
|
||||
});
|
||||
});
|
||||
|
||||
// Tutup dropdown jika klik di luar
|
||||
document.addEventListener('click', function () {
|
||||
options.classList.remove('show');
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
$tabel = isset($_POST['tabel']) ? trim($_POST['tabel']) : '';
|
||||
$stmt = null;
|
||||
|
||||
if ($id <= 0) {
|
||||
http_response_code(400);
|
||||
echo "ID tidak valid!";
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($tabel == 'jalan') {
|
||||
$nama = isset($_POST['nama_jalan']) ? trim($_POST['nama_jalan']) : '';
|
||||
$status = isset($_POST['status']) ? trim($_POST['status']) : '';
|
||||
|
||||
if (empty($nama)) {
|
||||
http_response_code(400);
|
||||
echo "Nama jalan tidak boleh kosong!";
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("UPDATE jalan SET nama_jalan=?, status=? WHERE id=?");
|
||||
$stmt->bind_param("ssi", $nama, $status, $id);
|
||||
|
||||
} else if ($tabel == 'parsil') {
|
||||
$nama = isset($_POST['nama_pemilik']) ? trim($_POST['nama_pemilik']) : '';
|
||||
$status = isset($_POST['status']) ? trim($_POST['status']) : '';
|
||||
|
||||
if (empty($nama)) {
|
||||
http_response_code(400);
|
||||
echo "Nama pemilik tidak boleh kosong!";
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("UPDATE parsil SET nama_pemilik=?, status=? WHERE id=?");
|
||||
$stmt->bind_param("ssi", $nama, $status, $id);
|
||||
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo "Tabel tidak valid!";
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($stmt) {
|
||||
if ($stmt->execute()) {
|
||||
echo "Data berhasil diperbarui!";
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo "Gagal memperbarui: " . $conn->error;
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
} else {
|
||||
http_response_code(405);
|
||||
echo "Metode tidak diizinkan";
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user