up
This commit is contained in:
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
|
||||||
|
|
||||||
if ($id <= 0) {
|
|
||||||
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = "DELETE FROM spbu WHERE id=$id";
|
|
||||||
|
|
||||||
if ($conn->query($sql)) {
|
|
||||||
echo json_encode(["status" => "success"]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(["status" => "error", "message" => $conn->error]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
|
||||||
|
|
||||||
if ($id <= 0) {
|
|
||||||
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = "DELETE FROM jalan WHERE id=$id";
|
|
||||||
|
|
||||||
if ($conn->query($sql)) {
|
|
||||||
echo json_encode(["status" => "success"]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(["status" => "error", "message" => $conn->error]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
|
||||||
|
|
||||||
if ($id <= 0) {
|
|
||||||
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = "DELETE FROM parsil WHERE id=$id";
|
|
||||||
|
|
||||||
if ($conn->query($sql)) {
|
|
||||||
echo json_encode(["status" => "success"]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(["status" => "error", "message" => $conn->error]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$sql = "SELECT * FROM spbu";
|
|
||||||
$result = $conn->query($sql);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
echo json_encode([
|
|
||||||
"status" => "error",
|
|
||||||
"message" => "Gagal membaca tabel spbu",
|
|
||||||
"detail" => $conn->error
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
while($row = $result->fetch_assoc()){
|
|
||||||
$data[] = $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode($data);
|
|
||||||
?>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$sql = "SELECT * FROM jalan";
|
|
||||||
$result = $conn->query($sql);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
echo json_encode([
|
|
||||||
"status" => "error",
|
|
||||||
"message" => "Gagal membaca tabel jalan",
|
|
||||||
"detail" => $conn->error
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
while($row = $result->fetch_assoc()){
|
|
||||||
$data[] = $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode($data);
|
|
||||||
?>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$sql = "SELECT * FROM parsil";
|
|
||||||
$result = $conn->query($sql);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
echo json_encode([
|
|
||||||
"status" => "error",
|
|
||||||
"message" => "Gagal membaca tabel parsil",
|
|
||||||
"detail" => $conn->error
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
while($row = $result->fetch_assoc()){
|
|
||||||
$data[] = $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode($data);
|
|
||||||
?>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?php
|
|
||||||
ini_set('display_errors', 0);
|
|
||||||
error_reporting(0);
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
include "db_config.php";
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$raw = file_get_contents("php://input");
|
|
||||||
$data = json_decode($raw, true);
|
|
||||||
|
|
||||||
$nama = $data['nama'] ?? '';
|
|
||||||
$no = $data['no'] ?? '';
|
|
||||||
$status = $data['status'] ?? 'Tidak';
|
|
||||||
$lat = floatval($data['lat'] ?? 0);
|
|
||||||
$lng = floatval($data['lng'] ?? 0);
|
|
||||||
|
|
||||||
if(!$nama || !$no) {
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status" => "error", "message" => "Data tidak lengkap"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $conn->prepare("INSERT INTO spbu (nama,no,status,lat,lng) VALUES (?,?,?,?,?)");
|
|
||||||
if(!$stmt) {
|
|
||||||
$err = $conn->error;
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " SPBU PREPARE ERR: $err\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"prepare","message"=>$err]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt->bind_param("sssdd", $nama, $no, $status, $lat, $lng);
|
|
||||||
|
|
||||||
if($stmt->execute()){
|
|
||||||
$id = $stmt->insert_id;
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"success","id"=>$id]);
|
|
||||||
} else {
|
|
||||||
$err = $stmt->error;
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " SPBU EXEC ERR: $err | Payload: $raw\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"execute","message"=>$err]);
|
|
||||||
}
|
|
||||||
$stmt->close();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$err = $e->getMessage();
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " SPBU EXCEPTION: $err | Payload: $raw\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"exception","message"=>$err]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
ini_set('display_errors', 0);
|
|
||||||
error_reporting(0);
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
include "db_config.php";
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$raw = file_get_contents("php://input");
|
|
||||||
$data = json_decode($raw, true);
|
|
||||||
|
|
||||||
$nama = $data['nama'] ?? '';
|
|
||||||
$status = $data['status'] ?? 'Kabupaten';
|
|
||||||
$panjang = floatval($data['panjang'] ?? 0);
|
|
||||||
$koordinatInput = $data['koordinat'] ?? [];
|
|
||||||
|
|
||||||
if (is_string($koordinatInput)) {
|
|
||||||
$decoded = json_decode($koordinatInput, true);
|
|
||||||
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
|
||||||
} else {
|
|
||||||
$koordinat = json_encode($koordinatInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$nama) {
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status" => "error", "message" => "Nama tidak boleh kosong"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $conn->prepare("INSERT INTO jalan (nama,status,panjang,koordinat) VALUES (?,?,?,?)");
|
|
||||||
if(!$stmt) {
|
|
||||||
$err = $conn->error;
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " JALAN PREPARE ERR: $err\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"prepare","message"=>$err]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt->bind_param("ssds", $nama, $status, $panjang, $koordinat);
|
|
||||||
|
|
||||||
if($stmt->execute()){
|
|
||||||
$id = $stmt->insert_id;
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"success","id"=>$id]);
|
|
||||||
} else {
|
|
||||||
$err = $stmt->error;
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " JALAN EXEC ERR: $err | Payload: $raw\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"execute","message"=>$err]);
|
|
||||||
}
|
|
||||||
$stmt->close();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$err = $e->getMessage();
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " JALAN EXCEPTION: $err | Payload: $raw\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"exception","message"=>$err]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
ini_set('display_errors', 0);
|
|
||||||
error_reporting(0);
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
include "db_config.php";
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$raw = file_get_contents("php://input");
|
|
||||||
$data = json_decode($raw, true);
|
|
||||||
|
|
||||||
$nama = $data['nama'] ?? '';
|
|
||||||
$pemilik = $data['pemilik'] ?? '';
|
|
||||||
$status = $data['status'] ?? 'SHM';
|
|
||||||
$luas = floatval($data['luas'] ?? 0);
|
|
||||||
$koordinatInput = $data['koordinat'] ?? [];
|
|
||||||
|
|
||||||
if (is_string($koordinatInput)) {
|
|
||||||
$decoded = json_decode($koordinatInput, true);
|
|
||||||
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
|
||||||
} else {
|
|
||||||
$koordinat = json_encode($koordinatInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$nama) {
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status" => "error", "message" => "Nama tidak boleh kosong"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $conn->prepare("INSERT INTO parsil (nama, pemilik, status, luas, koordinat) VALUES (?,?,?,?,?)");
|
|
||||||
if(!$stmt) {
|
|
||||||
$err = $conn->error;
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " PARSIL PREPARE ERR: $err\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"prepare","message"=>$err]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt->bind_param("sssds", $nama, $pemilik, $status, $luas, $koordinat);
|
|
||||||
|
|
||||||
if($stmt->execute()){
|
|
||||||
$id = $stmt->insert_id;
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"success","id"=>$id]);
|
|
||||||
} else {
|
|
||||||
$err = $stmt->error;
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " PARSIL EXEC ERR: $err | Payload: $raw\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"execute","message"=>$err]);
|
|
||||||
}
|
|
||||||
$stmt->close();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$err = $e->getMessage();
|
|
||||||
file_put_contents('error_log.txt', date('[Y-m-d H:i:s]') . " PARSIL EXCEPTION: $err | Payload: $raw\n", FILE_APPEND);
|
|
||||||
ob_clean();
|
|
||||||
echo json_encode(["status"=>"error","step"=>"exception","message"=>$err]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
|
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
|
||||||
$nama = $conn->real_escape_string($data['nama'] ?? '');
|
|
||||||
$no = $conn->real_escape_string($data['no'] ?? '');
|
|
||||||
$status = $conn->real_escape_string($data['status'] ?? 'Tidak');
|
|
||||||
$lat = isset($data['lat']) ? floatval($data['lat']) : 0;
|
|
||||||
$lng = isset($data['lng']) ? floatval($data['lng']) : 0;
|
|
||||||
|
|
||||||
if ($id <= 0 || $nama === '' || $no === '') {
|
|
||||||
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = "UPDATE spbu SET nama='$nama', no='$no', status='$status', lat='$lat', lng='$lng' WHERE id=$id";
|
|
||||||
|
|
||||||
if ($conn->query($sql)) {
|
|
||||||
echo json_encode(["status" => "success"]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(["status" => "error", "message" => $conn->error]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
|
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
|
||||||
$nama = $conn->real_escape_string($data['nama'] ?? '');
|
|
||||||
$status = $conn->real_escape_string($data['status'] ?? 'Kabupaten');
|
|
||||||
$panjang = isset($data['panjang']) ? floatval($data['panjang']) : 0;
|
|
||||||
$koordinatInput = $data['koordinat'] ?? [];
|
|
||||||
|
|
||||||
if ($id <= 0 || $nama === '') {
|
|
||||||
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($koordinatInput)) {
|
|
||||||
$decoded = json_decode($koordinatInput, true);
|
|
||||||
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
|
||||||
} else {
|
|
||||||
$koordinat = json_encode($koordinatInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
$koordinat = $conn->real_escape_string($koordinat);
|
|
||||||
|
|
||||||
$sql = "UPDATE jalan SET nama='$nama', status='$status', panjang='$panjang', koordinat='$koordinat' WHERE id=$id";
|
|
||||||
|
|
||||||
if ($conn->query($sql)) {
|
|
||||||
echo json_encode(["status" => "success"]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(["status" => "error", "message" => $conn->error]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
include "db_config.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
|
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
|
||||||
$nama = $conn->real_escape_string($data['nama'] ?? '');
|
|
||||||
$pemilik = $conn->real_escape_string($data['pemilik'] ?? '');
|
|
||||||
$status = $conn->real_escape_string($data['status'] ?? 'SHM');
|
|
||||||
$luas = isset($data['luas']) ? floatval($data['luas']) : 0;
|
|
||||||
$koordinatInput = $data['koordinat'] ?? [];
|
|
||||||
|
|
||||||
if ($id <= 0 || $nama === '') {
|
|
||||||
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($koordinatInput)) {
|
|
||||||
$decoded = json_decode($koordinatInput, true);
|
|
||||||
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
|
||||||
} else {
|
|
||||||
$koordinat = json_encode($koordinatInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
$koordinat = $conn->real_escape_string($koordinat);
|
|
||||||
|
|
||||||
$sql = "UPDATE parsil SET nama='$nama', pemilik='$pemilik', status='$status', luas='$luas', koordinat='$koordinat' WHERE id=$id";
|
|
||||||
|
|
||||||
if ($conn->query($sql)) {
|
|
||||||
echo json_encode(["status" => "success"]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(["status" => "error", "message" => $conn->error]);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
+28
-734
@@ -2950,10 +2950,7 @@
|
|||||||
}
|
}
|
||||||
.pf h4 i { font-size: 15px !important; opacity: .9; }
|
.pf h4 i { font-size: 15px !important; opacity: .9; }
|
||||||
/* Color the h4 based on icon color */
|
/* Color the h4 based on icon color */
|
||||||
.pf h4:has(.fa-gas-pump) { background: linear-gradient(135deg,#064e3b,#059669); }
|
|
||||||
.pf h4:has(.fa-road) { background: linear-gradient(135deg,#1e3a8a,#2563eb); }
|
|
||||||
.pf h4:has(.fa-vector-square){ background: linear-gradient(135deg,#78350f,#d97706); }
|
|
||||||
|
|
||||||
.pf label {
|
.pf label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 10px !important;
|
font-size: 10px !important;
|
||||||
@@ -3284,10 +3281,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="list-masjid" style="display:none;"><span id="cnt-masjid">0</span></div>
|
<div id="list-masjid" style="display:none;"><span id="cnt-masjid">0</span></div>
|
||||||
<div id="list-kemiskinan" style="display:none;"><span id="cnt-kemiskinan">0</span></div>
|
<div id="list-kemiskinan" style="display:none;"><span id="cnt-kemiskinan">0</span></div>
|
||||||
<div id="list-spbu" style="display:none;"><span id="cnt-spbu">0</span></div>
|
</div>
|
||||||
<div id="list-jalan" style="display:none;"><span id="cnt-jalan">0</span></div>
|
|
||||||
<div id="list-parsil" style="display:none;"><span id="cnt-parsil">0</span></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="leg-sec">
|
<div class="leg-sec">
|
||||||
<div class="sec-lbl" style="margin-bottom:10px">Legenda Peta</div>
|
<div class="sec-lbl" style="margin-bottom:10px">Legenda Peta</div>
|
||||||
@@ -3341,20 +3335,7 @@
|
|||||||
<span>Rumah Ibadah <small>Tambah lokasi ibadah</small></span>
|
<span>Rumah Ibadah <small>Tambah lokasi ibadah</small></span>
|
||||||
</div>
|
</div>
|
||||||
<div style="height:1px;background:#e2e8f0;margin:4px 4px"></div>
|
<div style="height:1px;background:#e2e8f0;margin:4px 4px"></div>
|
||||||
<div style="padding:6px 10px 2px;font-size:10px;font-weight:800;color:#94a3b8;text-transform:uppercase;letter-spacing:.6px">Opsional</div>
|
|
||||||
<div class="add-item" onclick="setMode('spbu');closeAddMenu()">
|
|
||||||
<span class="ai-icon" style="background:#dcfce7;color:#16a34a"><i class="fas fa-gas-pump"></i></span>
|
|
||||||
<span>SPBU <small>Tambah titik SPBU</small></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="add-item" onclick="setMode('jalan');closeAddMenu()">
|
|
||||||
<span class="ai-icon" style="background:#dbeafe;color:#2563eb"><i class="fas fa-road"></i></span>
|
|
||||||
<span>Jalan <small>Gambar ruas jalan</small></span>
|
|
||||||
</div>
|
|
||||||
<div class="add-item" onclick="setMode('parsil');closeAddMenu()">
|
|
||||||
<span class="ai-icon" style="background:#fef3c7;color:#d97706"><i class="fas fa-vector-square"></i></span>
|
|
||||||
<span>Parsil / Lahan <small>Gambar area persil</small></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Icon buttons -->
|
<!-- Icon buttons -->
|
||||||
@@ -3523,10 +3504,10 @@
|
|||||||
|
|
||||||
/* STATE */
|
/* STATE */
|
||||||
const state = {
|
const state = {
|
||||||
mode: null, spbu: [], jalan: [], parsil: [], kemiskinan: [], masjid: [],
|
mode: null, kemiskinan: [], masjid: [],
|
||||||
featureRefs: { spbu: {}, jalan: {}, parsil: {}, kemiskinan: {}, masjid: {} },
|
featureRefs: { kemiskinan: {}, masjid: {} },
|
||||||
kkLayerRefs: {}, blankRefs: {}, useSatellite: false, geometryEdit: null, activeCard: null,
|
kkLayerRefs: {}, blankRefs: {}, useSatellite: false, geometryEdit: null, activeCard: null,
|
||||||
spbuFilterVis: { open24: true, non24: true }, drawingLine: false, drawingPoly: false,
|
drawingLine: false, drawingPoly: false,
|
||||||
tempPoints: [], tempMarkers: [], tempPolyline: null, tempPolygon: null
|
tempPoints: [], tempMarkers: [], tempPolyline: null, tempPolygon: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3542,22 +3523,12 @@
|
|||||||
const layers = {
|
const layers = {
|
||||||
kemiskinan: L.layerGroup().addTo(map),
|
kemiskinan: L.layerGroup().addTo(map),
|
||||||
masjid: L.layerGroup().addTo(map),
|
masjid: L.layerGroup().addTo(map),
|
||||||
blankspot: L.layerGroup().addTo(map),
|
blankspot: L.layerGroup().addTo(map),};
|
||||||
// Layer opsional — OFF by default (tidak .addTo(map))
|
|
||||||
spbu24: L.layerGroup(),
|
|
||||||
spbuNon24: L.layerGroup(),
|
|
||||||
jalan: L.layerGroup(),
|
|
||||||
parsil: L.layerGroup()
|
|
||||||
};
|
|
||||||
const layersControl = L.control.layers(null, {
|
const layersControl = L.control.layers(null, {
|
||||||
'<span class="lc-item"><span class="lc-dot lc-dot-kemiskinan"></span><span class="lc-text"><strong>Kemiskinan</strong><small>Data KK miskin</small></span></span>': layers.kemiskinan,
|
'<span class="lc-item"><span class="lc-dot lc-dot-kemiskinan"></span><span class="lc-text"><strong>Kemiskinan</strong><small>Data KK miskin</small></span></span>': layers.kemiskinan,
|
||||||
'<span class="lc-item"><span class="lc-dot lc-dot-masjid"></span><span class="lc-text"><strong>Rumah Ibadah</strong><small>Fasilitas ibadah</small></span></span>': layers.masjid,
|
'<span class="lc-item"><span class="lc-dot lc-dot-masjid"></span><span class="lc-text"><strong>Rumah Ibadah</strong><small>Fasilitas ibadah</small></span></span>': layers.masjid,
|
||||||
'<span class="lc-item"><span class="lc-dot" style="background:#64748b"></span><span class="lc-text"><strong>Blank Spot</strong><small>Di luar radius rumah ibadah</small></span></span>': layers.blankspot,
|
'<span class="lc-item"><span class="lc-dot" style="background:#64748b"></span><span class="lc-text"><strong>Blank Spot</strong><small>Di luar radius rumah ibadah</small></span></span>': layers.blankspot,
|
||||||
'<span class="lc-item"><span class="lc-dot" style="background:#16a34a"></span><span class="lc-text"><strong>SPBU 24 Jam</strong><small>Buka 24 jam</small></span></span>': layers.spbu24,
|
}, { collapsed: false, position: 'topright' }).addTo(map);
|
||||||
'<span class="lc-item"><span class="lc-dot" style="background:#dc2626"></span><span class="lc-text"><strong>SPBU Non-24</strong><small>Tidak 24 jam</small></span></span>': layers.spbuNon24,
|
|
||||||
'<span class="lc-item"><span class="lc-dot" style="background:#2563eb"></span><span class="lc-text"><strong>Jalan</strong><small>Jaringan jalan</small></span></span>': layers.jalan,
|
|
||||||
'<span class="lc-item"><span class="lc-dot" style="background:#d97706"></span><span class="lc-text"><strong>Parsil / Lahan</strong><small>Data persil tanah</small></span></span>': layers.parsil,
|
|
||||||
}, { collapsed: false, position: 'topright' }).addTo(map);
|
|
||||||
decorateLayersControl();
|
decorateLayersControl();
|
||||||
function decorateLayersControl() {
|
function decorateLayersControl() {
|
||||||
const container = layersControl.getContainer();
|
const container = layersControl.getContainer();
|
||||||
@@ -3565,7 +3536,7 @@
|
|||||||
const overlays = container.querySelector('.leaflet-control-layers-overlays');
|
const overlays = container.querySelector('.leaflet-control-layers-overlays');
|
||||||
if (!overlays) return;
|
if (!overlays) return;
|
||||||
const labels = Array.from(overlays.querySelectorAll('label'));
|
const labels = Array.from(overlays.querySelectorAll('label'));
|
||||||
if (labels.length < 6) return;
|
if (labels.length < 3) return;
|
||||||
overlays.innerHTML = '';
|
overlays.innerHTML = '';
|
||||||
const addGroup = (title, items, color) => {
|
const addGroup = (title, items, color) => {
|
||||||
const head = document.createElement('div');
|
const head = document.createElement('div');
|
||||||
@@ -3613,7 +3584,7 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
addGroup('Tematik Utama', [labels[0], labels[1], labels[2]]);
|
addGroup('Tematik Utama', [labels[0], labels[1], labels[2]]);
|
||||||
addGroup('Opsional', [labels[3], labels[4], labels[5], labels[6]], '#64748b');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusStoreKey = 'gis-kemiskinan-status';
|
const statusStoreKey = 'gis-kemiskinan-status';
|
||||||
@@ -3897,18 +3868,6 @@
|
|||||||
const fWarga = state.kemiskinan.find(d => (`${d.nama_kk} ${d.alamat}`).toLowerCase().includes(q));
|
const fWarga = state.kemiskinan.find(d => (`${d.nama_kk} ${d.alamat}`).toLowerCase().includes(q));
|
||||||
if (fWarga) return focusFeature('kemiskinan', fWarga.id);
|
if (fWarga) return focusFeature('kemiskinan', fWarga.id);
|
||||||
|
|
||||||
// 3. Cari SPBU
|
|
||||||
const fSpbu = state.spbu.find(d => (d.nama || '').toLowerCase().includes(q));
|
|
||||||
if (fSpbu) return focusFeature('spbu', fSpbu.id);
|
|
||||||
|
|
||||||
// 4. Cari Jalan
|
|
||||||
const fJalan = state.jalan.find(d => (d.nama || '').toLowerCase().includes(q));
|
|
||||||
if (fJalan) return focusFeature('jalan', fJalan.id);
|
|
||||||
|
|
||||||
// 5. Cari Parsil
|
|
||||||
const fParsil = state.parsil.find(d => (`${d.nama} ${d.pemilik}`).toLowerCase().includes(q));
|
|
||||||
if (fParsil) return focusFeature('parsil', fParsil.id);
|
|
||||||
|
|
||||||
// Jika tidak ketemu
|
// Jika tidak ketemu
|
||||||
alert('Data "' + q + '" tidak ditemukan.');
|
alert('Data "' + q + '" tidak ditemukan.');
|
||||||
}
|
}
|
||||||
@@ -4124,7 +4083,7 @@
|
|||||||
function setMode(m) {
|
function setMode(m) {
|
||||||
cancelDrawing();
|
cancelDrawing();
|
||||||
state.mode = state.mode === m ? null : m;
|
state.mode = state.mode === m ? null : m;
|
||||||
['kemiskinan', 'masjid', 'spbu', 'jalan', 'parsil'].forEach(x => {
|
['kemiskinan', 'masjid'].forEach(x => {
|
||||||
const el = document.getElementById('btn-' + x);
|
const el = document.getElementById('btn-' + x);
|
||||||
if (el) el.className = 'mbtn';
|
if (el) el.className = 'mbtn';
|
||||||
});
|
});
|
||||||
@@ -4134,11 +4093,6 @@
|
|||||||
const msgs = {
|
const msgs = {
|
||||||
kemiskinan: 'Klik peta untuk menambah data Kemiskinan',
|
kemiskinan: 'Klik peta untuk menambah data Kemiskinan',
|
||||||
masjid: 'Klik peta untuk menambah titik Rumah Ibadah',
|
masjid: 'Klik peta untuk menambah titik Rumah Ibadah',
|
||||||
spbu: 'Klik peta untuk menambah titik SPBU',
|
|
||||||
jalan: 'Klik untuk gambar jalan — klik ganda untuk selesai',
|
|
||||||
parsil: 'Klik untuk gambar parsil — klik titik awal atau dbl-klik selesai',
|
|
||||||
line: 'Klik untuk gambar jalan — klik ganda untuk selesai',
|
|
||||||
poly: 'Klik untuk gambar parsil — klik titik awal atau dbl-klik selesai',
|
|
||||||
};
|
};
|
||||||
hint.textContent = msgs[m] || 'Klik peta';
|
hint.textContent = msgs[m] || 'Klik peta';
|
||||||
hint.classList.add('show');
|
hint.classList.add('show');
|
||||||
@@ -4157,14 +4111,9 @@
|
|||||||
if (!state.mode) return;
|
if (!state.mode) return;
|
||||||
if (state.mode === 'kemiskinan') handleKemiskinanClick(e);
|
if (state.mode === 'kemiskinan') handleKemiskinanClick(e);
|
||||||
else if (state.mode === 'masjid') handleMasjidClick(e);
|
else if (state.mode === 'masjid') handleMasjidClick(e);
|
||||||
else if (state.mode === 'spbu') handlePointClick(e);
|
|
||||||
else if (state.mode === 'jalan') handleLineClick(e);
|
|
||||||
else if (state.mode === 'parsil') handlePolyClick(e);
|
|
||||||
});
|
});
|
||||||
map.on('dblclick', function (e) {
|
map.on('dblclick', function (e) {
|
||||||
if ((state.mode === 'jalan' || state.mode === 'line') && state.drawingLine) finishLine(e);
|
|
||||||
if ((state.mode === 'parsil' || state.mode === 'poly') && state.drawingPoly) finishPoly(e);
|
|
||||||
if (['jalan','parsil','line','poly'].includes(state.mode)) L.DomEvent.stopPropagation(e);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ── MODERN MARKER ICON ── */
|
/* ── MODERN MARKER ICON ── */
|
||||||
@@ -4229,102 +4178,9 @@
|
|||||||
window._tmpM = tmpM;
|
window._tmpM = tmpM;
|
||||||
}
|
}
|
||||||
|
|
||||||
function savePoint() {
|
|
||||||
|
|
||||||
const nama = document.getElementById('p-nama').value.trim();
|
|
||||||
const no = document.getElementById('p-no').value.trim();
|
|
||||||
const status = document.getElementById('p-status').value;
|
|
||||||
const lat = parseFloat(document.getElementById('p-lat').value);
|
|
||||||
const lng = parseFloat(document.getElementById('p-lng').value);
|
|
||||||
|
|
||||||
if (!nama || !no) {
|
|
||||||
alert('Lengkapi nama dan nomor SPBU!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("api/save_data.php", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
nama: nama,
|
|
||||||
no: no,
|
|
||||||
status: status,
|
|
||||||
lat: lat,
|
|
||||||
lng: lng
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(response => {
|
|
||||||
|
|
||||||
if (response.status == "success") {
|
|
||||||
|
|
||||||
const d = {
|
|
||||||
id: response.id || Date.now(),
|
|
||||||
nama,
|
|
||||||
no,
|
|
||||||
status,
|
|
||||||
lat,
|
|
||||||
lng
|
|
||||||
};
|
|
||||||
|
|
||||||
state.spbu.push(d);
|
|
||||||
|
|
||||||
renderSPBU(d);
|
|
||||||
|
|
||||||
updateCount('spbu', state.spbu.length);
|
|
||||||
|
|
||||||
addCard(
|
|
||||||
'spbu',
|
|
||||||
d.id,
|
|
||||||
nama,
|
|
||||||
'No: ' + no,
|
|
||||||
status === 'Ya' ? 'Buka 24 Jam' : 'Tidak Buka 24 Jam',
|
|
||||||
status === 'Ya' ? '#1a6b3c' : '#b93328'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (window._tmpM) {
|
|
||||||
map.closePopup();
|
|
||||||
map.removeLayer(window._tmpM);
|
|
||||||
window._tmpM = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
setMode(null);
|
|
||||||
ensureLayerVisible('spbu', d.id);
|
|
||||||
focusFeature('spbu', d.id);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
alert("Gagal menyimpan: " + (response.message || "Periksa database"));
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
alert("Terjadi error jaringan");
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSPBU(d) {
|
|
||||||
const color = d.status === 'Ya' ? '#10b981' : '#ef4444';
|
|
||||||
const icon = createModernMarker(color, 'fas fa-gas-pump', d.nama);
|
|
||||||
const m = L.marker([d.lat, d.lng], { icon, draggable: true });
|
|
||||||
m.bindPopup(`<div class="pi">
|
|
||||||
<h4><i class="fas fa-gas-pump" style="color:${color}"></i>${d.nama}<button class="pi-close-alt" onclick="map.closePopup()"><i class="fas fa-times"></i></button></h4>
|
|
||||||
<div class="pi-body">
|
|
||||||
<div class="pi-row"><span class="pi-k">No. SPBU</span><span class="pi-v">${d.no}</span></div>
|
|
||||||
<div class="pi-row"><span class="pi-k">Status</span><span class="pi-v" style="color:${color}">${d.status === 'Ya' ? '✔ Buka 24 Jam' : '✖ Tidak Buka 24 Jam'}</span></div>
|
|
||||||
<div class="pi-row"><span class="pi-k">Koordinat</span><span class="pi-v" style="font-size:11px;font-family:monospace">${d.lat.toFixed(5)}, ${d.lng.toFixed(5)}</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="act-row">
|
|
||||||
<button class="pbtn pbtn-y" onclick="openEditSpbu(${d.id})">Edit</button>
|
|
||||||
<button class="pbtn pbtn-r" onclick="deleteFeature('spbu',${d.id})">Hapus</button>
|
|
||||||
</div>
|
|
||||||
</div>`, { autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] });
|
|
||||||
m.addTo(d.status === 'Ya' ? layers.spbu24 : layers.spbuNon24);
|
|
||||||
state.featureRefs.spbu[String(d.id)] = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── JALAN ── */
|
/* ── JALAN ── */
|
||||||
function handleLineClick(e) {
|
function handleLineClick(e) {
|
||||||
@@ -4337,231 +4193,14 @@
|
|||||||
document.getElementById('hint').textContent = `📍 ${state.tempPoints.length} titik — klik ganda untuk selesai`;
|
document.getElementById('hint').textContent = `📍 ${state.tempPoints.length} titik — klik ganda untuk selesai`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishLine(e) {
|
|
||||||
if (state.tempPoints.length < 2) { alert('Minimal 2 titik!'); return; }
|
|
||||||
const pts = [...state.tempPoints];
|
|
||||||
const len = calcLen(pts);
|
|
||||||
window._tempLinePts = pts;
|
|
||||||
window._tempLineLen = len;
|
|
||||||
clearTemp();
|
|
||||||
L.popup({ closeOnClick: false, keepInView: true, autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] })
|
|
||||||
.setLatLng(pts[Math.floor(pts.length / 2)])
|
|
||||||
.setContent(`<div class="pf">
|
|
||||||
<h4><i class="fas fa-road"></i> Tambah Jalan</h4>
|
|
||||||
<label>Nama Jalan</label>
|
|
||||||
<input id="j-nama" placeholder="Jl. Ahmad Yani">
|
|
||||||
<label>Status Jalan</label>
|
|
||||||
<select id="j-status">
|
|
||||||
<option value="Nasional">Jalan Nasional</option>
|
|
||||||
<option value="Provinsi">Jalan Provinsi</option>
|
|
||||||
<option value="Kabupaten" selected>Jalan Kabupaten</option>
|
|
||||||
</select>
|
|
||||||
<div style="display:flex;align-items:center;gap:10px;margin:10px 16px 4px;padding:9px 12px;background:#eff6ff;border-radius:9px;border:1px solid #dbeafe">
|
|
||||||
<i class="fas fa-ruler-horizontal" style="color:#2563eb;font-size:13px"></i>
|
|
||||||
<span style="font-size:11px;color:#64748b;font-weight:600">Panjang terukur:</span>
|
|
||||||
<span style="font-size:14px;font-weight:800;color:#1d4ed8;margin-left:auto">${fmtLen(len)}</span>
|
|
||||||
</div>
|
|
||||||
<button class="pbtn pbtn-b" onclick="saveLine()">Simpan Jalan</button>
|
|
||||||
</div>`).addTo(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveLine() {
|
|
||||||
const pts = window._tempLinePts || [];
|
|
||||||
const len = window._tempLineLen || 0;
|
|
||||||
|
|
||||||
const nama = document.getElementById('j-nama').value.trim();
|
|
||||||
const status = document.getElementById('j-status').value;
|
|
||||||
|
|
||||||
if (!nama) {
|
|
||||||
alert('Isi nama jalan!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("api/save_jalan.php", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
nama: nama,
|
|
||||||
status: status,
|
|
||||||
panjang: len,
|
|
||||||
koordinat: pts
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(response => {
|
|
||||||
|
|
||||||
if (response.status == "success") {
|
|
||||||
|
|
||||||
const d = {
|
|
||||||
id: response.id || Date.now(),
|
|
||||||
nama,
|
|
||||||
status,
|
|
||||||
pts,
|
|
||||||
len
|
|
||||||
};
|
|
||||||
|
|
||||||
state.jalan.push(d);
|
|
||||||
|
|
||||||
renderJalan(d);
|
|
||||||
|
|
||||||
updateCount('jalan', state.jalan.length);
|
|
||||||
|
|
||||||
addCard(
|
|
||||||
'jalan',
|
|
||||||
d.id,
|
|
||||||
nama,
|
|
||||||
status + ' · ' + fmtLen(len),
|
|
||||||
status,
|
|
||||||
jColor[status]
|
|
||||||
);
|
|
||||||
|
|
||||||
map.closePopup();
|
|
||||||
setMode(null);
|
|
||||||
ensureLayerVisible('jalan', d.id);
|
|
||||||
focusFeature('jalan', d.id);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// log removed
|
|
||||||
alert("Gagal simpan jalan");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
// log removed
|
|
||||||
alert("Error simpan jalan");
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
function renderJalan(d) {
|
|
||||||
|
|
||||||
const pts = normalizeLinePoints(d.pts);
|
|
||||||
if (pts.length < 2) {
|
|
||||||
// log removed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const c = jColor[d.status] || '#ef4444';
|
|
||||||
|
|
||||||
const w =
|
|
||||||
d.status === 'Nasional' ? 6 :
|
|
||||||
d.status === 'Provinsi' ? 5 : 4;
|
|
||||||
|
|
||||||
const line = L.polyline(pts, {
|
|
||||||
color: c,
|
|
||||||
weight: w,
|
|
||||||
opacity: 0.95,
|
|
||||||
lineCap: 'round',
|
|
||||||
lineJoin: 'round',
|
|
||||||
className: 'path-glow'
|
|
||||||
})
|
|
||||||
.bindPopup(`
|
|
||||||
<div class="pi">
|
|
||||||
<h4><i class="fas fa-road" style="color:${c}"></i>${d.nama}<button class="pi-close-alt" onclick="map.closePopup()"><i class="fas fa-times"></i></button></h4>
|
|
||||||
|
|
||||||
<div class="pi-body">
|
|
||||||
<div class="pi-row">
|
|
||||||
<span class="pi-k">Status</span>
|
|
||||||
<span class="pi-v">${d.status}</span>
|
|
||||||
</div>
|
|
||||||
<div class="pi-row">
|
|
||||||
<span class="pi-k">Panjang</span>
|
|
||||||
<span class="pi-v">${fmtLen(d.len)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="act-row">
|
|
||||||
<button class="pbtn pbtn-y" onclick="openEditJalan(${d.id})">Edit</button>
|
|
||||||
<button class="pbtn pbtn-r" onclick="deleteFeature('jalan',${d.id})">Hapus</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
`, { autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] })
|
|
||||||
.addTo(layers.jalan);
|
|
||||||
|
|
||||||
state.featureRefs.jalan[String(d.id)] = line;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeLinePoints(raw) {
|
|
||||||
|
|
||||||
let pts = raw;
|
|
||||||
|
|
||||||
if (typeof pts === 'string') {
|
|
||||||
try {
|
|
||||||
pts = JSON.parse(pts);
|
|
||||||
} catch (_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kompatibilitas data lama: koordinat sempat tersimpan sebagai JSON string di dalam JSON string.
|
|
||||||
if (typeof pts === 'string') {
|
|
||||||
try {
|
|
||||||
pts = JSON.parse(pts);
|
|
||||||
} catch (_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(pts) || pts.length === 0) return [];
|
|
||||||
|
|
||||||
if (Array.isArray(pts[0])) {
|
|
||||||
return pts
|
|
||||||
.map(p => [parseFloat(p[0]), parseFloat(p[1])])
|
|
||||||
.filter(p => Number.isFinite(p[0]) && Number.isFinite(p[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pts[0] && typeof pts[0] === 'object' && pts[0].lat !== undefined) {
|
|
||||||
return pts
|
|
||||||
.map(p => [parseFloat(p.lat), parseFloat(p.lng)])
|
|
||||||
.filter(p => Number.isFinite(p[0]) && Number.isFinite(p[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizePolyPoints(raw) {
|
|
||||||
|
|
||||||
let pts = raw;
|
|
||||||
|
|
||||||
if (typeof pts === 'string') {
|
|
||||||
try {
|
|
||||||
pts = JSON.parse(pts);
|
|
||||||
} catch (_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof pts === 'string') {
|
|
||||||
try {
|
|
||||||
pts = JSON.parse(pts);
|
|
||||||
} catch (_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(pts) || pts.length === 0) return [];
|
|
||||||
|
|
||||||
if (Array.isArray(pts[0])) {
|
|
||||||
return pts
|
|
||||||
.map(p => [parseFloat(p[0]), parseFloat(p[1])])
|
|
||||||
.filter(p => Number.isFinite(p[0]) && Number.isFinite(p[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pts[0] && typeof pts[0] === 'object' && pts[0].lat !== undefined) {
|
|
||||||
return pts
|
|
||||||
.map(p => [parseFloat(p.lat), parseFloat(p.lng)])
|
|
||||||
.filter(p => Number.isFinite(p[0]) && Number.isFinite(p[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── PARSIL ── */
|
/* ── PARSIL ── */
|
||||||
function handlePolyClick(e) {
|
function handlePolyClick(e) {
|
||||||
@@ -4585,160 +4224,11 @@
|
|||||||
`🗺️ ${state.tempPoints.length} titik — klik titik awal atau dbl-klik selesai`;
|
`🗺️ ${state.tempPoints.length} titik — klik titik awal atau dbl-klik selesai`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishPoly(e) {
|
|
||||||
if (state.tempPoints.length < 3) { alert('Minimal 3 titik!'); return; }
|
|
||||||
const pts = [...state.tempPoints];
|
|
||||||
const area = calcArea(pts);
|
|
||||||
window._tempPolyPts = pts;
|
|
||||||
window._tempPolyArea = area;
|
|
||||||
clearTemp();
|
|
||||||
const center = L.polygon(pts).getBounds().getCenter();
|
|
||||||
L.popup({ closeOnClick: false, keepInView: true, autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] })
|
|
||||||
.setLatLng(center)
|
|
||||||
.setContent(`<div class="pf">
|
|
||||||
<h4><i class="fas fa-vector-square"></i> Tambah Parsil / Lahan</h4>
|
|
||||||
<label>Nama / ID Parsil</label>
|
|
||||||
<input id="ps-nama" placeholder="Parsil A-01">
|
|
||||||
<label>Pemilik</label>
|
|
||||||
<input id="ps-pemilik" placeholder="Nama pemilik">
|
|
||||||
<label>Status Sertifikat</label>
|
|
||||||
<select id="ps-status">
|
|
||||||
<option value="SHM">SHM — Hak Milik</option>
|
|
||||||
<option value="HGB">HGB — Hak Guna Bangunan</option>
|
|
||||||
<option value="Sewa">Sewa / Kontrak</option>
|
|
||||||
<option value="Lainnya">Lainnya</option>
|
|
||||||
</select>
|
|
||||||
<div style="display:flex;align-items:center;gap:10px;margin:10px 16px 4px;padding:9px 12px;background:#fffbeb;border-radius:9px;border:1px solid #fde68a">
|
|
||||||
<i class="fas fa-ruler-combined" style="color:#d97706;font-size:13px"></i>
|
|
||||||
<span style="font-size:11px;color:#64748b;font-weight:600">Luas terukur:</span>
|
|
||||||
<span style="font-size:14px;font-weight:800;color:#d97706;margin-left:auto">${fmtArea(area)}</span>
|
|
||||||
</div>
|
|
||||||
<button class="pbtn pbtn-y" onclick="saveParsil()">Simpan Parsil</button>
|
|
||||||
</div>`).addTo(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveParsil() {
|
|
||||||
const pts = window._tempPolyPts || [];
|
|
||||||
const area = window._tempPolyArea || 0;
|
|
||||||
|
|
||||||
const nama = document.getElementById('ps-nama').value.trim();
|
|
||||||
const pemilik = document.getElementById('ps-pemilik').value.trim();
|
|
||||||
const status = document.getElementById('ps-status').value;
|
|
||||||
|
|
||||||
if (!nama) {
|
|
||||||
alert('Isi nama parsil!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("api/save_parsil.php", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
nama: nama,
|
|
||||||
pemilik: pemilik,
|
|
||||||
status: status,
|
|
||||||
luas: area,
|
|
||||||
koordinat: pts
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(response => {
|
|
||||||
|
|
||||||
if (response.status == "success") {
|
|
||||||
|
|
||||||
const parsil = {
|
|
||||||
id: response.id || Date.now(),
|
|
||||||
nama,
|
|
||||||
pemilik,
|
|
||||||
status,
|
|
||||||
pts,
|
|
||||||
area
|
|
||||||
};
|
|
||||||
|
|
||||||
state.parsil.push(parsil);
|
|
||||||
|
|
||||||
renderParsil(parsil);
|
|
||||||
|
|
||||||
updateCount('parsil', state.parsil.length);
|
|
||||||
|
|
||||||
addCard(
|
|
||||||
'parsil',
|
|
||||||
parsil.id,
|
|
||||||
parsil.nama,
|
|
||||||
parsil.status,
|
|
||||||
parsil.status,
|
|
||||||
'#1a5276'
|
|
||||||
);
|
|
||||||
|
|
||||||
map.closePopup();
|
|
||||||
setMode(null);
|
|
||||||
ensureLayerVisible('parsil', parsil.id);
|
|
||||||
focusFeature('parsil', parsil.id);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
// log removed
|
|
||||||
alert("Gagal simpan parsil");
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(err => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderParsil(d) {
|
|
||||||
|
|
||||||
const pts = normalizePolyPoints(d.pts);
|
|
||||||
if (pts.length < 3) {
|
|
||||||
// log removed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const c = pColor[d.status];
|
|
||||||
|
|
||||||
const poly = L.polygon(pts, {
|
|
||||||
color: c,
|
|
||||||
fillColor: c,
|
|
||||||
fillOpacity: 0.25,
|
|
||||||
weight: 3,
|
|
||||||
dashArray: '8, 6',
|
|
||||||
lineCap: 'round',
|
|
||||||
lineJoin: 'round',
|
|
||||||
className: 'parsil-glow'
|
|
||||||
})
|
|
||||||
.bindPopup(`
|
|
||||||
<div class="pi">
|
|
||||||
<h4><i class="fas fa-draw-polygon" style="color:${c}"></i>${d.nama}<button class="pi-close-alt" onclick="map.closePopup()"><i class="fas fa-times"></i></button></h4>
|
|
||||||
|
|
||||||
<div class="pi-body">
|
|
||||||
<div class="pi-row">
|
|
||||||
<span class="pi-k">Pemilik</span>
|
|
||||||
<span class="pi-v">${d.pemilik || '-'}</span>
|
|
||||||
</div>
|
|
||||||
<div class="pi-row">
|
|
||||||
<span class="pi-k">Status</span>
|
|
||||||
<span class="pi-v">${d.status}</span>
|
|
||||||
</div>
|
|
||||||
<div class="pi-row">
|
|
||||||
<span class="pi-k">Luas</span>
|
|
||||||
<span class="pi-v">${fmtArea(d.area)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="act-row">
|
|
||||||
<button class="pbtn pbtn-y" onclick="openEditParsil(${d.id})">Edit</button>
|
|
||||||
<button class="pbtn pbtn-r" onclick="deleteFeature('parsil',${d.id})">Hapus</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
`)
|
|
||||||
.addTo(layers.parsil);
|
|
||||||
|
|
||||||
state.featureRefs.parsil[String(d.id)] = poly;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getById(type, id) {
|
function getById(type, id) {
|
||||||
return state[type].find(x => String(x.id) === String(id));
|
return state[type].find(x => String(x.id) === String(id));
|
||||||
@@ -4911,11 +4401,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function refreshType(type) {
|
function refreshType(type) {
|
||||||
if (state.geometryEdit && state.geometryEdit.type === type) stopGeometryEdit();
|
if (state.geometryEdit && state.geometryEdit.type === type) stopGeometryEdit(); else {
|
||||||
if (type === 'spbu') {
|
|
||||||
layers.spbu24.clearLayers();
|
|
||||||
layers.spbuNon24.clearLayers();
|
|
||||||
} else {
|
|
||||||
layers[type].clearLayers();
|
layers[type].clearLayers();
|
||||||
}
|
}
|
||||||
state.featureRefs[type] = {};
|
state.featureRefs[type] = {};
|
||||||
@@ -4952,31 +4438,7 @@
|
|||||||
renderDashboard();
|
renderDashboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditSpbu(id) {
|
|
||||||
const d = getById('spbu', id);
|
|
||||||
if (!d) return;
|
|
||||||
const ref = state.featureRefs.spbu[String(id)];
|
|
||||||
const ll = ref && ref.getLatLng ? ref.getLatLng() : { lat: d.lat, lng: d.lng };
|
|
||||||
const html = `<div class="pf">
|
|
||||||
<h4><i class="fas fa-edit" style="color:var(--amber)"></i> Edit SPBU</h4>
|
|
||||||
<label>Nama SPBU</label>
|
|
||||||
<input id="e-spbu-nama" value="${(d.nama || '').replace(/"/g, '"')}">
|
|
||||||
<label>Nomor SPBU</label>
|
|
||||||
<input id="e-spbu-no" value="${(d.no || '').replace(/"/g, '"')}">
|
|
||||||
<label>Status Operasional</label>
|
|
||||||
<select id="e-spbu-status">
|
|
||||||
<option value="Ya" ${d.status === 'Ya' ? 'selected' : ''}>Buka 24 Jam</option>
|
|
||||||
<option value="Tidak" ${d.status === 'Tidak' ? 'selected' : ''}>Tidak Buka 24 Jam</option>
|
|
||||||
</select>
|
|
||||||
<label>Latitude</label>
|
|
||||||
<input id="e-spbu-lat" value="${Number(ll.lat).toFixed(6)}">
|
|
||||||
<label>Longitude</label>
|
|
||||||
<input id="e-spbu-lng" value="${Number(ll.lng).toFixed(6)}">
|
|
||||||
<button class="pbtn pbtn-y" onclick="saveEditSpbu(${id})">Simpan Perubahan</button>
|
|
||||||
</div>`;
|
|
||||||
map.closePopup();
|
|
||||||
L.popup({ maxWidth: 290, autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] }).setLatLng([ll.lat, ll.lng]).setContent(html).openOn(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveEditSpbu(id) {
|
function saveEditSpbu(id) {
|
||||||
const nama = document.getElementById('e-spbu-nama').value.trim();
|
const nama = document.getElementById('e-spbu-nama').value.trim();
|
||||||
@@ -5011,33 +4473,7 @@
|
|||||||
.catch(() => alert('Error update SPBU'));
|
.catch(() => alert('Error update SPBU'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditJalan(id) {
|
|
||||||
if (state.geometryEdit && (state.geometryEdit.type !== 'jalan' || String(state.geometryEdit.id) !== String(id))) {
|
|
||||||
stopGeometryEdit();
|
|
||||||
}
|
|
||||||
const d = getById('jalan', id);
|
|
||||||
if (!d) return;
|
|
||||||
const pts = normalizeLinePoints(d.pts);
|
|
||||||
const ref = state.featureRefs.jalan[String(id)];
|
|
||||||
const center = ref && ref.getBounds ? ref.getBounds().getCenter() : map.getCenter();
|
|
||||||
const html = `<div class="pf" style="width:290px">
|
|
||||||
<h4><i class="fas fa-edit" style="color:var(--amber)"></i> Edit Jalan</h4>
|
|
||||||
<label>Nama Jalan</label>
|
|
||||||
<input id="e-jalan-nama" value="${(d.nama || '').replace(/"/g, '"')}">
|
|
||||||
<label>Status Jalan</label>
|
|
||||||
<select id="e-jalan-status">
|
|
||||||
<option value="Nasional" ${d.status === 'Nasional' ? 'selected' : ''}>Jalan Nasional</option>
|
|
||||||
<option value="Provinsi" ${d.status === 'Provinsi' ? 'selected' : ''}>Jalan Provinsi</option>
|
|
||||||
<option value="Kabupaten" ${d.status === 'Kabupaten' ? 'selected' : ''}>Jalan Kabupaten</option>
|
|
||||||
</select>
|
|
||||||
<label>Koordinat Lokasi (satu baris: lat,lng)</label>
|
|
||||||
<textarea id="e-jalan-pts">${pointsToText(pts)}</textarea>
|
|
||||||
<button class="pbtn pbtn-b" onclick="startGeometryEdit('jalan',${id})">Edit Vertex / Drag di Peta</button>
|
|
||||||
<button class="pbtn pbtn-y" onclick="saveEditJalan(${id})">Simpan Perubahan</button>
|
|
||||||
</div>`;
|
|
||||||
map.closePopup();
|
|
||||||
L.popup({ maxWidth: 330, autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] }).setLatLng(center).setContent(html).openOn(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveEditJalan(id) {
|
function saveEditJalan(id) {
|
||||||
if (state.geometryEdit && state.geometryEdit.type === 'jalan' && String(state.geometryEdit.id) === String(id)) {
|
if (state.geometryEdit && state.geometryEdit.type === 'jalan' && String(state.geometryEdit.id) === String(id)) {
|
||||||
@@ -5075,36 +4511,7 @@
|
|||||||
.catch(() => alert('Error update jalan'));
|
.catch(() => alert('Error update jalan'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditParsil(id) {
|
|
||||||
if (state.geometryEdit && (state.geometryEdit.type !== 'parsil' || String(state.geometryEdit.id) !== String(id))) {
|
|
||||||
stopGeometryEdit();
|
|
||||||
}
|
|
||||||
const d = getById('parsil', id);
|
|
||||||
if (!d) return;
|
|
||||||
const pts = normalizePolyPoints(d.pts);
|
|
||||||
const ref = state.featureRefs.parsil[String(id)];
|
|
||||||
const center = ref && ref.getBounds ? ref.getBounds().getCenter() : map.getCenter();
|
|
||||||
const html = `<div class="pf" style="width:290px">
|
|
||||||
<h4><i class="fas fa-edit" style="color:var(--amber)"></i> Edit Parsil</h4>
|
|
||||||
<label>Nama / ID Parsil</label>
|
|
||||||
<input id="e-parsil-nama" value="${(d.nama || '').replace(/"/g, '"')}">
|
|
||||||
<label>Pemilik</label>
|
|
||||||
<input id="e-parsil-pemilik" value="${(d.pemilik || '').replace(/"/g, '"')}">
|
|
||||||
<label>Status Sertifikat</label>
|
|
||||||
<select id="e-parsil-status">
|
|
||||||
<option value="SHM" ${d.status === 'SHM' ? 'selected' : ''}>SHM – Hak Milik</option>
|
|
||||||
<option value="HGB" ${d.status === 'HGB' ? 'selected' : ''}>HGB – Hak Guna Bangunan</option>
|
|
||||||
<option value="HGU" ${d.status === 'HGU' ? 'selected' : ''}>HGU – Hak Guna Usaha</option>
|
|
||||||
<option value="HP" ${d.status === 'HP' ? 'selected' : ''}>HP – Hak Pakai</option>
|
|
||||||
</select>
|
|
||||||
<label>Koordinat Lokasi (satu baris: lat,lng)</label>
|
|
||||||
<textarea id="e-parsil-pts">${pointsToText(pts)}</textarea>
|
|
||||||
<button class="pbtn pbtn-b" onclick="startGeometryEdit('parsil',${id})">Edit Vertex / Drag di Peta</button>
|
|
||||||
<button class="pbtn pbtn-y" onclick="saveEditParsil(${id})">Simpan Perubahan</button>
|
|
||||||
</div>`;
|
|
||||||
map.closePopup();
|
|
||||||
L.popup({ maxWidth: 330, autoPanPaddingTopLeft: [0, 80], autoPanPaddingBottomRight: [0, 20] }).setLatLng(center).setContent(html).openOn(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveEditParsil(id) {
|
function saveEditParsil(id) {
|
||||||
if (state.geometryEdit && state.geometryEdit.type === 'parsil' && String(state.geometryEdit.id) === String(id)) {
|
if (state.geometryEdit && state.geometryEdit.type === 'parsil' && String(state.geometryEdit.id) === String(id)) {
|
||||||
@@ -5290,10 +4697,6 @@
|
|||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
loadSPBU();
|
|
||||||
loadJalan();
|
|
||||||
loadParsil();
|
|
||||||
|
|
||||||
// Kemiskinan butuh data Masjid untuk hitung Blank Spot (merah/hijau)
|
// Kemiskinan butuh data Masjid untuk hitung Blank Spot (merah/hijau)
|
||||||
// Jadi pastikan loadMasjid selesai dulu baru loadKemiskinan
|
// Jadi pastikan loadMasjid selesai dulu baru loadKemiskinan
|
||||||
loadMasjid().then(() => {
|
loadMasjid().then(() => {
|
||||||
@@ -5302,120 +4705,11 @@
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadSPBU() {
|
|
||||||
|
|
||||||
fetch("api/read_data.php")
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => {
|
|
||||||
|
|
||||||
data.forEach(d => {
|
|
||||||
|
|
||||||
const spbu = {
|
|
||||||
id: d.id,
|
|
||||||
nama: d.nama,
|
|
||||||
no: d.no,
|
|
||||||
status: d.status,
|
|
||||||
lat: parseFloat(d.lat),
|
|
||||||
lng: parseFloat(d.lng)
|
|
||||||
};
|
|
||||||
|
|
||||||
state.spbu.push(spbu);
|
|
||||||
|
|
||||||
renderSPBU(spbu);
|
|
||||||
|
|
||||||
updateCount('spbu', state.spbu.length);
|
|
||||||
|
|
||||||
addCard(
|
|
||||||
'spbu',
|
|
||||||
spbu.id,
|
|
||||||
spbu.nama,
|
|
||||||
'No: ' + spbu.no,
|
|
||||||
spbu.status === 'Ya' ? 'Buka 24 Jam' : 'Tidak Buka 24 Jam',
|
|
||||||
spbu.status === 'Ya' ? '#1a6b3c' : '#b93328'
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(err => {});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadJalan() {
|
|
||||||
|
|
||||||
fetch("api/read_jalan.php")
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => {
|
|
||||||
|
|
||||||
data.forEach(d => {
|
|
||||||
|
|
||||||
const jalan = {
|
|
||||||
id: d.id,
|
|
||||||
nama: d.nama,
|
|
||||||
status: d.status,
|
|
||||||
len: parseFloat(d.panjang),
|
|
||||||
pts: d.koordinat
|
|
||||||
};
|
|
||||||
|
|
||||||
state.jalan.push(jalan);
|
|
||||||
|
|
||||||
renderJalan(jalan);
|
|
||||||
|
|
||||||
updateCount('jalan', state.jalan.length);
|
|
||||||
|
|
||||||
addCard(
|
|
||||||
'jalan',
|
|
||||||
jalan.id,
|
|
||||||
jalan.nama,
|
|
||||||
jalan.status,
|
|
||||||
jalan.status,
|
|
||||||
'#e74c3c'
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(err => {});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadParsil() {
|
|
||||||
|
|
||||||
fetch("api/read_parsil.php")
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => {
|
|
||||||
|
|
||||||
data.forEach(d => {
|
|
||||||
|
|
||||||
const parsil = {
|
|
||||||
id: d.id,
|
|
||||||
nama: d.nama,
|
|
||||||
pemilik: d.pemilik,
|
|
||||||
status: d.status,
|
|
||||||
area: parseFloat(d.luas),
|
|
||||||
pts: d.koordinat
|
|
||||||
};
|
|
||||||
|
|
||||||
state.parsil.push(parsil);
|
|
||||||
|
|
||||||
renderParsil(parsil);
|
|
||||||
|
|
||||||
updateCount('parsil', state.parsil.length);
|
|
||||||
|
|
||||||
addCard(
|
|
||||||
'parsil',
|
|
||||||
parsil.id,
|
|
||||||
parsil.nama,
|
|
||||||
parsil.status,
|
|
||||||
parsil.status,
|
|
||||||
'#1a5276'
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(err => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── KEMISKINAN ── */
|
/* ── KEMISKINAN ── */
|
||||||
function getKemiskinanDraft() {
|
function getKemiskinanDraft() {
|
||||||
|
|||||||
+7482
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user