Upload files to "/"
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
FROM php:8.2-apache
|
||||
|
||||
RUN docker-php-ext-install mysqli pdo pdo_mysql
|
||||
|
||||
COPY . /var/www/html/
|
||||
|
||||
RUN chown -R www-data:www-data /var/www/html
|
||||
|
||||
EXPOSE 80
|
||||
@@ -0,0 +1,47 @@
|
||||
CREATE TABLE IF NOT EXISTS spbu (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama VARCHAR(150) NOT NULL,
|
||||
hp VARCHAR(50) DEFAULT NULL,
|
||||
buka TINYINT(1) NOT NULL DEFAULT 1,
|
||||
lat DECIMAL(12,8) NOT NULL,
|
||||
lng DECIMAL(12,8) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS jalan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
status VARCHAR(100) NOT NULL,
|
||||
panjang DECIMAL(12,2) DEFAULT 0,
|
||||
koordinat LONGTEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tanah (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
status VARCHAR(100) NOT NULL,
|
||||
luas DECIMAL(12,2) DEFAULT 0,
|
||||
koordinat LONGTEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS populasi_kecamatan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
kecamatan VARCHAR(100) NOT NULL UNIQUE,
|
||||
populasi INT NOT NULL DEFAULT 0,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT INTO spbu (nama, hp, buka, lat, lng) VALUES
|
||||
('SPBU Ahmad Yani', '081234567890', 1, -0.05586000, 109.34725000),
|
||||
('SPBU Imam Bonjol', '081234567891', 0, -0.03372000, 109.34201000),
|
||||
('SPBU Sungai Raya Dalam', '081234567892', 1, -0.07043000, 109.37850000)
|
||||
ON DUPLICATE KEY UPDATE nama=VALUES(nama);
|
||||
|
||||
INSERT INTO populasi_kecamatan (kecamatan, populasi) VALUES
|
||||
('Pontianak Barat', 150000),
|
||||
('Pontianak Kota', 130000),
|
||||
('Pontianak Selatan', 95000),
|
||||
('Pontianak Tenggara', 53000),
|
||||
('Pontianak Timur', 104000),
|
||||
('Pontianak Utara', 128000)
|
||||
ON DUPLICATE KEY UPDATE populasi=VALUES(populasi);
|
||||
+33
-749
@@ -1,760 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>WebGIS Kota Pontianak - Pemetaan SPBU, Jalan, dan Tanah</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css" />
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Landing Page Tugas SIG - Pertemuan 1-4</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
||||
#map { height: 100vh; width: 100%; }
|
||||
|
||||
.leaflet-popup-content { min-width: 280px; }
|
||||
.popup-form { min-width: 260px; padding: 5px; }
|
||||
.popup-form h4 { margin: 0 0 12px 0; color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 5px; }
|
||||
.popup-form input, .popup-form select { width: 100%; margin-bottom: 12px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; font-size: 14px; }
|
||||
.popup-form button { width: 100%; background: #27ae60; color: white; border: none; padding: 10px; cursor: pointer; border-radius: 4px; font-weight: bold; font-size: 14px; }
|
||||
.popup-form button:hover { background: #219150; }
|
||||
.popup-form p { margin: 8px 0; font-size: 12px; color: #666; text-align: center; background: #f8f9fa; padding: 5px; border-radius: 4px; }
|
||||
|
||||
.legend { position: absolute; bottom: 20px; left: 20px; background: white; padding: 10px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 1000; font-size: 12px; pointer-events: none; }
|
||||
.legend span { display: inline-block; width: 20px; height: 20px; margin-right: 5px; vertical-align: middle; }
|
||||
.legend .spbu-icon { background: none; width: 20px; height: 20px; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; }
|
||||
|
||||
.population-panel { position: absolute; bottom: 20px; right: 20px; background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 900; width: 280px; max-height: 400px; overflow-y: auto; font-size: 13px; }
|
||||
.population-panel h3 { margin: 0 0 10px 0; color: #2c3e50; text-align: center; border-bottom: 2px solid #3498db; padding-bottom: 5px; }
|
||||
.population-item { padding: 8px; margin-bottom: 8px; background: #f8f9fa; border-radius: 6px; cursor: pointer; transition: all 0.2s; }
|
||||
.population-item:hover { background: #e9ecef; transform: translateX(-3px); }
|
||||
.population-item strong { color: #2c3e50; display: block; }
|
||||
.population-item .pop-value { color: #27ae60; font-weight: bold; font-size: 14px; }
|
||||
.total-pop { background: #2c3e50; color: white; padding: 10px; border-radius: 6px; text-align: center; margin-top: 10px; }
|
||||
.total-pop span { font-size: 18px; font-weight: bold; color: #f1c40f; }
|
||||
|
||||
.map-selector { position: absolute; top: 20px; left: 20px; background: white; padding: 10px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 1000; font-size: 12px; }
|
||||
.map-selector select { padding: 5px 10px; border-radius: 4px; border: 1px solid #ddd; margin-left: 5px; cursor: pointer; }
|
||||
|
||||
.toast-notification { position: fixed; bottom: 30px; right: 30px; background: #2c3e50; color: white; padding: 12px 20px; border-radius: 8px; z-index: 2000; animation: fadeOut 3s ease forwards; }
|
||||
@keyframes fadeOut { 0% { opacity: 1; } 70% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
|
||||
|
||||
.loading { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.8); color: white; padding: 15px 30px; border-radius: 8px; z-index: 3000; }
|
||||
.form-group { margin-bottom: 10px; }
|
||||
.form-group label { display: block; margin-bottom: 5px; font-weight: bold; font-size: 13px; }
|
||||
.btn-hapus { background: #e74c3c !important; width: 100% !important; }
|
||||
.btn-hapus:hover { background: #c0392b !important; }
|
||||
|
||||
.instruction-box {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
padding: 8px 15px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.spbu-marker {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.leaflet-control-layers {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
|
||||
}
|
||||
/* Styling untuk Layer Control */
|
||||
.leaflet-control-layers {
|
||||
max-width: 240px !important;
|
||||
font-size: 13px !important;
|
||||
z-index: 1010 !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.leaflet-control-layers-list {
|
||||
display: block !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.leaflet-control-layers-list label {
|
||||
display: block !important;
|
||||
margin-bottom: 8px !important;
|
||||
cursor: pointer !important;
|
||||
user-select: none;
|
||||
padding: 4px 2px !important;
|
||||
transition: all 0.2s ease;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.leaflet-control-layers-list label:hover {
|
||||
background-color: #f0f0f0 !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
/* PENTING: Pastikan checkbox FULLY VISIBLE */
|
||||
.leaflet-control-layers-list input[type="checkbox"],
|
||||
.leaflet-control-layers-list input[type="radio"] {
|
||||
display: inline-block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
margin-right: 8px !important;
|
||||
margin-left: 0 !important;
|
||||
cursor: pointer !important;
|
||||
accent-color: #27ae60 !important;
|
||||
vertical-align: middle !important;
|
||||
background: white !important;
|
||||
border: 1px solid #999 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.leaflet-control-layers-list input:checked {
|
||||
accent-color: #27ae60 !important;
|
||||
}
|
||||
.leaflet-control-layers-overlays {
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:Inter,Segoe UI,Arial,sans-serif;background:#f5f7fb;color:#1f2937;min-height:100vh}
|
||||
.hero{padding:52px 22px 28px;background:linear-gradient(135deg,#0f766e,#0ea5e9);color:white}
|
||||
.wrap{max-width:1080px;margin:auto}
|
||||
.badge{display:inline-block;background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.3);padding:8px 12px;border-radius:999px;margin-bottom:18px;font-size:14px}
|
||||
h1{font-size:clamp(30px,5vw,54px);line-height:1.05;margin-bottom:14px}
|
||||
.hero p{max-width:760px;font-size:17px;line-height:1.7;opacity:.95}
|
||||
main{max-width:1080px;margin:-18px auto 40px;padding:0 22px}
|
||||
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:18px}
|
||||
.card{background:white;border-radius:20px;padding:22px;border:1px solid #e5e7eb;box-shadow:0 12px 30px rgba(15,23,42,.08);display:flex;flex-direction:column;min-height:250px}
|
||||
.icon{width:48px;height:48px;border-radius:14px;display:grid;place-items:center;background:#ecfeff;font-size:24px;margin-bottom:15px}
|
||||
.card h2{font-size:20px;margin-bottom:8px;color:#0f172a}
|
||||
.card p{font-size:14px;color:#64748b;line-height:1.6;flex:1}
|
||||
a.btn{display:inline-block;text-decoration:none;background:#0f766e;color:white;padding:11px 14px;border-radius:12px;font-weight:700;text-align:center;margin-top:18px}
|
||||
a.btn:hover{background:#0d5f59}
|
||||
.note{background:white;border:1px solid #e5e7eb;border-radius:16px;padding:16px;margin-top:20px;color:#475569;line-height:1.6;font-size:14px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
|
||||
<div class="map-selector">
|
||||
<label>🗺️ Pilih Peta:</label>
|
||||
<select id="mapSelector">
|
||||
<option value="street">🌍 Street Map</option>
|
||||
<option value="satellite">🛰️ Satellite</option>
|
||||
<option value="osm">🗺️ OpenStreetMap</option>
|
||||
</select>
|
||||
<section class="hero">
|
||||
<div class="wrap">
|
||||
<div class="badge">Mata Kuliah SIG • Pertemuan 1-4</div>
|
||||
<h1>Kumpulan Tugas WebGIS</h1>
|
||||
<p>Landing page ini menampilkan seluruh tugas WebGIS yang dikerjakan pada pertemuan kelas. Klik salah satu kartu untuk membuka project sesuai topik.</p>
|
||||
</div>
|
||||
|
||||
<div class="population-panel" id="populationPanel">
|
||||
<h3>📊 POPULASI PER KECAMATAN</h3>
|
||||
<div id="populationList"><p style="text-align:center; color:#999;">Memuat data...</p></div>
|
||||
</section>
|
||||
<main>
|
||||
<div class="grid">
|
||||
<article class="card"><div class="icon">⛽</div><h2>Tugas 1</h2><p>WebGIS pemetaan lokasi SPBU di Kota Pontianak menggunakan marker Leaflet.</p><a class="btn" href="Tugas1/">Buka Tugas 1</a></article>
|
||||
<article class="card"><div class="icon">🛣️</div><h2>Tugas 2</h2><p>WebGIS manajemen data jalan berbentuk polyline dan data tanah berbentuk polygon.</p><a class="btn" href="Tugas2/">Buka Tugas 2</a></article>
|
||||
<article class="card"><div class="icon">🗂️</div><h2>Tugas 3</h2><p>Layer Groups dan Layers Control untuk menampilkan kategori SPBU buka 24 jam dan tidak 24 jam.</p><a class="btn" href="Tugas3/">Buka Tugas 3</a></article>
|
||||
<article class="card"><div class="icon">🏙️</div><h2>Tugas 4</h2><p>WebGIS GeoJSON kecamatan Kota Pontianak yang menampilkan nama kecamatan dan jumlah populasi.</p><a class="btn" href="Tugas4/">Buka Tugas 4</a></article>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<strong>Legenda</strong><br>
|
||||
<span class="spbu-icon">⛽</span> SPBU Buka 24 Jam<br>
|
||||
<span class="spbu-icon" style="filter: grayscale(0.5);">⛽</span> SPBU Tutup Malam<br>
|
||||
<span style="background: #e74c3c; height: 3px; display: inline-block;"></span> Jalan Nasional<br>
|
||||
<span style="background: #f39c12; height: 3px; display: inline-block;"></span> Jalan Provinsi<br>
|
||||
<span style="background: #3498db; height: 3px; display: inline-block;"></span> Jalan Kota<br>
|
||||
<span style="background: #e67e22;"></span> Bidang Tanah<br>
|
||||
<span style="background: #2c3e50; border: 1px dashed #2c3e50;"></span> Batas Kecamatan
|
||||
</div>
|
||||
<div class="instruction-box" id="instructionBox">
|
||||
💡 Petunjuk: Untuk menggambar, klik titik-titik di peta. Selesai = DOUBLE CLICK atau klik tombol ✅
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js"></script>
|
||||
<script src="https://unpkg.com/leaflet-geometryutil@0.3.0/src/leaflet.geometryutil.js"></script>
|
||||
|
||||
<script>
|
||||
// ==================== INISIALISASI ====================
|
||||
var map = L.map('map').setView([-0.0263, 109.3425], 12);
|
||||
|
||||
// Base Maps
|
||||
var baseMaps = {
|
||||
street: L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
|
||||
attribution: '© OSM & CartoDB', subdomains: 'abcd', maxZoom: 19
|
||||
}),
|
||||
satellite: L.tileLayer('https://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
|
||||
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'], attribution: '© Google Maps', maxZoom: 20
|
||||
}),
|
||||
osm: L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© OSM', maxZoom: 19
|
||||
})
|
||||
};
|
||||
baseMaps.street.addTo(map);
|
||||
|
||||
document.getElementById('mapSelector').addEventListener('change', function(e) {
|
||||
for (var key in baseMaps) map.removeLayer(baseMaps[key]);
|
||||
baseMaps[e.target.value].addTo(map);
|
||||
});
|
||||
|
||||
// ==================== LAYER GROUPS ====================
|
||||
// Layer group untuk SPBU Buka 24 Jam
|
||||
var spbuBukaLayer = L.layerGroup();
|
||||
// Layer group untuk SPBU Tutup Malam
|
||||
var spbuTutupLayer = L.layerGroup();
|
||||
// Layer group untuk Jalan
|
||||
var jalanLayer = L.layerGroup();
|
||||
// Layer group untuk Tanah
|
||||
var tanahLayer = L.layerGroup();
|
||||
// Layer group untuk Batas Kecamatan
|
||||
var kecamatanLayer = L.layerGroup();
|
||||
|
||||
// Tambahkan layer ke map (hanya layer yang ditampilkan default)
|
||||
spbuBukaLayer.addTo(map); // ✅ SPBU 24 Jam ditampilkan default
|
||||
// spbuTutupLayer.addTo(map); // ❌ SPBU Tutup Malam TIDAK ditampilkan default
|
||||
jalanLayer.addTo(map);
|
||||
tanahLayer.addTo(map);
|
||||
kecamatanLayer.addTo(map);
|
||||
|
||||
// Layer group untuk data yang digambar (drawing)
|
||||
var drawnItems = new L.FeatureGroup();
|
||||
map.addLayer(drawnItems);
|
||||
|
||||
// ==================== LAYER CONTROL ====================
|
||||
var overlayMaps = {
|
||||
"⛽ SPBU Buka 24 Jam": spbuBukaLayer,
|
||||
"🌙 SPBU Tutup Malam": spbuTutupLayer,
|
||||
"🛣️ Jalan": jalanLayer,
|
||||
"🏞️ Bidang Tanah": tanahLayer,
|
||||
"🏛️ Batas Kecamatan": kecamatanLayer
|
||||
};
|
||||
|
||||
// Tambahkan Layer Control ke map dengan opsi lebih baik
|
||||
var layerControl = L.control.layers(null, overlayMaps, {
|
||||
collapsed: false,
|
||||
position: 'topright'
|
||||
}).addTo(map);
|
||||
|
||||
// Tambahkan tooltip ke layer control dengan element event listener
|
||||
map.on('baselayerchange', function() {
|
||||
console.log('Layer control initialized');
|
||||
});
|
||||
|
||||
// Pastikan checkboxes visible ketika layer control fully loaded
|
||||
window.addEventListener('load', function() {
|
||||
var layerControlElement = document.querySelector('.leaflet-control-layers');
|
||||
if (layerControlElement) {
|
||||
// Add tooltip ke semua label
|
||||
var labels = layerControlElement.querySelectorAll('label');
|
||||
labels.forEach(function(label, index) {
|
||||
var inputs = label.querySelectorAll('input');
|
||||
if (inputs.length > 0) {
|
||||
var input = inputs[0];
|
||||
// Tampilkan checkbox explicitly
|
||||
input.style.display = 'inline-block';
|
||||
input.style.visibility = 'visible';
|
||||
input.style.opacity = '1';
|
||||
|
||||
// Tambahkan tooltip berdasarkan text content
|
||||
var text = label.textContent || '';
|
||||
if (text.includes('Buka 24')) {
|
||||
label.title = 'Tampilkan/Sembunyikan SPBU yang Buka 24 Jam';
|
||||
} else if (text.includes('Tutup')) {
|
||||
label.title = 'Tampilkan/Sembunyikan SPBU yang Tutup Malam';
|
||||
} else if (text.includes('Jalan')) {
|
||||
label.title = 'Tampilkan/Sembunyikan Data Jalan';
|
||||
} else if (text.includes('Tanah')) {
|
||||
label.title = 'Tampilkan/Sembunyikan Data Bidang Tanah';
|
||||
} else if (text.includes('Kecamatan')) {
|
||||
label.title = 'Tampilkan/Sembunyikan Batas-batas Kecamatan';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Data populasi
|
||||
var populasiData = {
|
||||
"Pontianak Timur": 0, "Pontianak Selatan": 0, "Pontianak Utara": 0,
|
||||
"Pontianak Barat": 0, "Pontianak Kota": 0, "Pontianak Tenggara": 0
|
||||
};
|
||||
|
||||
// Variabel pending data
|
||||
window.pendingJalan = null;
|
||||
window.pendingTanah = null;
|
||||
|
||||
function showToast(message) {
|
||||
var toast = document.createElement('div');
|
||||
toast.className = 'toast-notification';
|
||||
toast.innerHTML = message;
|
||||
document.body.appendChild(toast);
|
||||
setTimeout(function() { toast.remove(); }, 3000);
|
||||
}
|
||||
|
||||
function formatNumber(num) {
|
||||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
||||
}
|
||||
|
||||
// ==================== MEMBUAT IKON SPBU ====================
|
||||
function createSpbuIcon(isOpen) {
|
||||
var color = isOpen ? '#27ae60' : '#e74c3c';
|
||||
|
||||
var svgHtml = '<div style="position: relative;">' +
|
||||
'<svg width="32" height="42" viewBox="0 0 24 36" fill="none" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<path d="M12 0C5.37 0 0 5.37 0 12c0 9 12 24 12 24s12-15 12-24c0-6.63-5.37-12-12-12z" fill="' + color + '" stroke="#fff" stroke-width="1.5"/>' +
|
||||
'<circle cx="12" cy="12" r="5" fill="white" stroke="#333" stroke-width="0.5"/>' +
|
||||
'<text x="12" y="15" text-anchor="middle" font-size="9" font-weight="bold" fill="' + color + '" font-family="Arial">⛽</text>' +
|
||||
'</svg>' +
|
||||
'</div>';
|
||||
|
||||
return L.divIcon({
|
||||
className: 'spbu-marker',
|
||||
html: svgHtml,
|
||||
iconSize: [32, 42],
|
||||
iconAnchor: [16, 42],
|
||||
popupAnchor: [0, -38]
|
||||
});
|
||||
}
|
||||
|
||||
// Ikon default untuk draw marker
|
||||
var defaultSpbuIcon = createSpbuIcon(true);
|
||||
|
||||
// ==================== POPULASI & LOAD GEOJSON KECAMATAN ====================
|
||||
fetch('Admin_Kecamatan.json')
|
||||
.then(function(response) { return response.json(); })
|
||||
.then(function(data) {
|
||||
data.features.forEach(function(feature) {
|
||||
var namaKec = feature.properties.Ket || "Wilayah";
|
||||
var populasi = feature.properties.Populasi || 0;
|
||||
if (populasiData.hasOwnProperty(namaKec)) {
|
||||
populasiData[namaKec] = populasi;
|
||||
}
|
||||
});
|
||||
|
||||
updatePopulationPanel();
|
||||
|
||||
// Tampilkan ke peta - tambahkan ke kecamatanLayer
|
||||
L.geoJSON(data, {
|
||||
style: { color: "#2c3e50", weight: 2.5, fillOpacity: 0.15, dashArray: '5,5', fillColor: "#3498db" },
|
||||
onEachFeature: function(feature, layer) {
|
||||
var namaKec = feature.properties.Ket || "Wilayah";
|
||||
var pop = populasiData[namaKec] || 0;
|
||||
var luasKm2 = feature.properties.Plan_Area / 1000000;
|
||||
var kepadatan = luasKm2 > 0 ? (pop / luasKm2).toFixed(0) : 0;
|
||||
layer.bindPopup('<b>🏛️ KECAMATAN ' + namaKec + '</b><br>' +
|
||||
'<b>Luas:</b> ' + luasKm2.toFixed(2) + ' km²<br>' +
|
||||
'<b>👥 Populasi:</b> ' + formatNumber(pop) + ' jiwa<br>' +
|
||||
'<b>📈 Kepadatan:</b> ' + kepadatan + ' jiwa/km²');
|
||||
}
|
||||
}).addTo(kecamatanLayer);
|
||||
|
||||
fetch('api.php?action=get_populasi')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(dbData) {
|
||||
if (dbData.status === 'ok' && dbData.data && dbData.data.length > 0) {
|
||||
var updated = false;
|
||||
dbData.data.forEach(function(item) {
|
||||
if (populasiData.hasOwnProperty(item.kecamatan)) {
|
||||
populasiData[item.kecamatan] = parseInt(item.populasi);
|
||||
updated = true;
|
||||
}
|
||||
});
|
||||
if (updated) {
|
||||
updatePopulationPanel();
|
||||
console.log("Populasi diupdate dari database");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function(err) { console.error("Gagal load populasi dari DB:", err); });
|
||||
})
|
||||
.catch(function(err) { console.error("Gagal load GeoJSON:", err); });
|
||||
|
||||
function simpanPopulasi(kecamatan, populasi) {
|
||||
fetch('api.php?action=update_populasi', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ kecamatan: kecamatan, populasi: populasi })
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if(res.status === 'ok') {
|
||||
populasiData[kecamatan] = populasi;
|
||||
updatePopulationPanel();
|
||||
showToast('✅ Populasi ' + kecamatan + ' diupdate menjadi ' + formatNumber(populasi) + ' jiwa');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updatePopulationPanel() {
|
||||
var panel = document.getElementById('populationList');
|
||||
var total = 0;
|
||||
var html = '';
|
||||
var kecamatans = Object.keys(populasiData).sort();
|
||||
for (var i = 0; i < kecamatans.length; i++) {
|
||||
var kec = kecamatans[i];
|
||||
var pop = populasiData[kec] || 0;
|
||||
total += pop;
|
||||
html += '<div class="population-item" onclick="showEditPopup(\'' + kec + '\', ' + pop + ')">' +
|
||||
'<strong>🏘️ ' + kec + '</strong>' +
|
||||
'<div class="pop-value">👥 ' + formatNumber(pop) + ' jiwa</div>' +
|
||||
'</div>';
|
||||
}
|
||||
html += '<div class="total-pop">📊 TOTAL POPULASI<br><span>' + formatNumber(total) + ' jiwa</span></div>';
|
||||
panel.innerHTML = html;
|
||||
}
|
||||
|
||||
function showEditPopup(kecamatan, currentPop) {
|
||||
var form = '<div style="min-width:250px;padding:10px">' +
|
||||
'<h4 style="margin:0 0 10px 0">✏️ Edit Populasi</h4>' +
|
||||
'<b>Kecamatan:</b> ' + kecamatan + '<br><br>' +
|
||||
'<label>Jumlah Penduduk:</label>' +
|
||||
'<input type="number" id="edit_populasi" value="' + currentPop + '" min="0" style="width:100%;padding:8px;margin:8px 0;border:1px solid #ddd;border-radius:4px">' +
|
||||
'<button onclick="savePopulationEdit(\'' + kecamatan + '\')" style="width:100%;background:#27ae60;color:white;border:none;padding:8px;border-radius:4px;cursor:pointer">💾 Simpan</button>' +
|
||||
'</div>';
|
||||
L.popup().setLatLng(map.getCenter()).setContent(form).openOn(map);
|
||||
}
|
||||
|
||||
function savePopulationEdit(kecamatan) {
|
||||
var newPop = parseInt(document.getElementById('edit_populasi')?.value) || 0;
|
||||
map.closePopup();
|
||||
simpanPopulasi(kecamatan, newPop);
|
||||
}
|
||||
|
||||
// ==================== HAPUS DATA ====================
|
||||
function hapusData(type, id) {
|
||||
if (confirm('Apakah Anda yakin ingin menghapus data ini?')) {
|
||||
fetch('api.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action: 'delete_' + type, id: id })
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if(res.status === 'ok') {
|
||||
showToast('✅ Data berhasil dihapus!');
|
||||
loadData();
|
||||
map.closePopup();
|
||||
} else {
|
||||
alert('❌ Gagal hapus: ' + (res.msg || "Cek koneksi database"));
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert('❌ Error: ' + err.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== SIMPAN SPBU ====================
|
||||
function simpanSPBU(lat, lng) {
|
||||
var nama = document.getElementById('nama_spbu').value;
|
||||
var hp = document.getElementById('hp_spbu').value;
|
||||
var buka = document.getElementById('status_spbu').value;
|
||||
|
||||
if (!nama) {
|
||||
alert("Nama SPBU harus diisi!");
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('api.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'add_spbu', nama: nama, hp: hp, buka: parseInt(buka), lat: lat, lng: lng
|
||||
})
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if(res.status === 'ok') {
|
||||
showToast("✅ SPBU berhasil disimpan!");
|
||||
map.closePopup();
|
||||
loadData();
|
||||
} else {
|
||||
alert("❌ Gagal simpan: " + (res.msg || "Cek koneksi database"));
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("❌ Error: " + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== SIMPAN JALAN ====================
|
||||
window.simpanJalanBaru = function() {
|
||||
console.log("simpanJalanBaru dipanggil");
|
||||
|
||||
var statusSelect = document.getElementById('status_jalan');
|
||||
if (!statusSelect) {
|
||||
alert("Error: Form tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
var status = statusSelect.value;
|
||||
|
||||
if (!window.pendingJalan) {
|
||||
alert("Data koordinat tidak ditemukan! Silakan gambar ulang jalan.");
|
||||
return;
|
||||
}
|
||||
|
||||
var coords = window.pendingJalan.coords;
|
||||
var distance = window.pendingJalan.distance;
|
||||
|
||||
var cleanCoords = [];
|
||||
for (var i = 0; i < coords.length; i++) {
|
||||
cleanCoords.push([coords[i].lat, coords[i].lng]);
|
||||
}
|
||||
|
||||
console.log("Menyimpan jalan - titik: " + cleanCoords.length);
|
||||
|
||||
fetch('api.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'add_jalan', status: status, panjang: distance, koordinat: JSON.stringify(cleanCoords)
|
||||
})
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if(res.status === 'ok') {
|
||||
showToast("✅ Jalan berhasil disimpan!");
|
||||
map.closePopup();
|
||||
loadData();
|
||||
window.pendingJalan = null;
|
||||
} else {
|
||||
alert("❌ Gagal simpan: " + (res.msg || "Cek koneksi database"));
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("❌ Error: " + err.message);
|
||||
});
|
||||
};
|
||||
|
||||
// ==================== SIMPAN TANAH ====================
|
||||
window.simpanTanahBaru = function() {
|
||||
console.log("simpanTanahBaru dipanggil");
|
||||
|
||||
var statusSelect = document.getElementById('status_tanah');
|
||||
if (!statusSelect) {
|
||||
alert("Error: Form tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
var status = statusSelect.value;
|
||||
|
||||
if (!window.pendingTanah) {
|
||||
alert("Data koordinat tidak ditemukan! Silakan gambar ulang bidang tanah.");
|
||||
return;
|
||||
}
|
||||
|
||||
var coords = window.pendingTanah.coords;
|
||||
var area = window.pendingTanah.area;
|
||||
|
||||
var cleanCoords = [];
|
||||
for (var i = 0; i < coords.length; i++) {
|
||||
cleanCoords.push([coords[i].lat, coords[i].lng]);
|
||||
}
|
||||
|
||||
if (cleanCoords.length > 0) {
|
||||
var first = cleanCoords[0];
|
||||
var last = cleanCoords[cleanCoords.length - 1];
|
||||
if (first[0] !== last[0] || first[1] !== last[1]) {
|
||||
cleanCoords.push(first);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Menyimpan tanah - titik: " + cleanCoords.length);
|
||||
|
||||
fetch('api.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'add_tanah', status: status, luas: area, koordinat: JSON.stringify([cleanCoords])
|
||||
})
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if(res.status === 'ok') {
|
||||
showToast("✅ Bidang tanah berhasil disimpan!");
|
||||
map.closePopup();
|
||||
loadData();
|
||||
window.pendingTanah = null;
|
||||
} else {
|
||||
alert("❌ Gagal simpan: " + (res.msg || "Cek koneksi database"));
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("❌ Error: " + err.message);
|
||||
});
|
||||
};
|
||||
|
||||
// ==================== LOAD SEMUA DATA ====================
|
||||
function loadData() {
|
||||
console.log("Memuat data...");
|
||||
|
||||
// Kosongkan semua layer groups
|
||||
spbuBukaLayer.clearLayers();
|
||||
spbuTutupLayer.clearLayers();
|
||||
jalanLayer.clearLayers();
|
||||
tanahLayer.clearLayers();
|
||||
|
||||
// Load SPBU dan pisahkan berdasarkan status buka/tutup
|
||||
fetch('api.php?action=get_spbu')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(function(item) {
|
||||
var isOpen = (item.buka == 1);
|
||||
var icon = createSpbuIcon(isOpen);
|
||||
|
||||
var marker = L.marker([parseFloat(item.lat), parseFloat(item.lng)], {
|
||||
icon: icon
|
||||
});
|
||||
|
||||
marker.bindPopup('<b>⛽ SPBU</b><br><b>Nama:</b> ' + item.nama + '<br><b>HP:</b> ' + item.hp + '<br><b>Status:</b> ' + (isOpen ? '✅ Buka 24 Jam' : '🌙 Tutup Malam') + '<hr><button class="btn-hapus" onclick="hapusData(\'spbu\', ' + item.id + ')">🗑️ Hapus SPBU</button>');
|
||||
|
||||
if (isOpen) {
|
||||
marker.addTo(spbuBukaLayer);
|
||||
} else {
|
||||
marker.addTo(spbuTutupLayer);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function(err) { console.error("Gagal load SPBU:", err); });
|
||||
|
||||
// Load Jalan
|
||||
fetch('api.php?action=get_jalan')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(function(item) {
|
||||
try {
|
||||
var coords = JSON.parse(item.koordinat);
|
||||
var latlngs = [];
|
||||
for (var i = 0; i < coords.length; i++) {
|
||||
if (Array.isArray(coords[i]) && coords[i].length >= 2) {
|
||||
latlngs.push([coords[i][0], coords[i][1]]);
|
||||
}
|
||||
}
|
||||
|
||||
if (latlngs.length >= 2) {
|
||||
var warnaJalan = '#3498db';
|
||||
if (item.status === 'Nasional') {
|
||||
warnaJalan = '#e74c3c';
|
||||
} else if (item.status === 'Provinsi') {
|
||||
warnaJalan = '#f39c12';
|
||||
}
|
||||
|
||||
var polyline = L.polyline(latlngs, { color: warnaJalan, weight: 4, opacity: 0.8 });
|
||||
polyline.bindPopup('<b>🛣️ JALAN</b><br><b>Status:</b> ' + item.status + '<br><b>Panjang:</b> ' + parseFloat(item.panjang).toFixed(2) + ' meter<hr><button class="btn-hapus" onclick="hapusData(\'jalan\', ' + item.id + ')">🗑️ Hapus Jalan</button>');
|
||||
polyline.addTo(jalanLayer);
|
||||
}
|
||||
} catch(e) { console.error("Error jalan:", item.id, e); }
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function(err) { console.error("Gagal load Jalan:", err); });
|
||||
|
||||
// Load Tanah
|
||||
fetch('api.php?action=get_tanah')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(function(item) {
|
||||
try {
|
||||
var coords = JSON.parse(item.koordinat);
|
||||
var rings = [];
|
||||
if (Array.isArray(coords) && coords.length > 0) {
|
||||
if (coords.length > 0 && Array.isArray(coords[0]) && typeof coords[0][0] === 'number') {
|
||||
rings = [coords];
|
||||
} else {
|
||||
rings = coords;
|
||||
}
|
||||
}
|
||||
var latlngs = [];
|
||||
for (var r = 0; r < rings.length; r++) {
|
||||
var ring = rings[r];
|
||||
var ringLatLngs = [];
|
||||
for (var i = 0; i < ring.length; i++) {
|
||||
if (Array.isArray(ring[i]) && ring[i].length >= 2) {
|
||||
ringLatLngs.push([ring[i][0], ring[i][1]]);
|
||||
}
|
||||
}
|
||||
if (ringLatLngs.length >= 3) latlngs.push(ringLatLngs);
|
||||
}
|
||||
if (latlngs.length > 0 && latlngs[0].length >= 3) {
|
||||
var polygon = L.polygon(latlngs, { color: '#e67e22', weight: 2, fillOpacity: 0.4, fillColor: '#f39c12' });
|
||||
polygon.bindPopup('<b>🏞️ BIDANG TANAH</b><br><b>Status:</b> ' + item.status + '<br><b>Luas:</b> ' + parseFloat(item.luas).toFixed(2) + ' m²<hr><button class="btn-hapus" onclick="hapusData(\'tanah\', ' + item.id + ')">🗑️ Hapus Tanah</button>');
|
||||
polygon.addTo(tanahLayer);
|
||||
}
|
||||
} catch(e) { console.error("Error tanah:", item.id, e); }
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function(err) { console.error("Gagal load Tanah:", err); });
|
||||
}
|
||||
|
||||
// ==================== DRAW CONTROL ====================
|
||||
var drawControl = new L.Control.Draw({
|
||||
edit: { featureGroup: drawnItems, remove: false },
|
||||
draw: {
|
||||
polyline: {
|
||||
shapeOptions: { color: '#3498db', weight: 4 },
|
||||
metric: true,
|
||||
showLength: true
|
||||
},
|
||||
polygon: {
|
||||
shapeOptions: { color: '#e67e22', weight: 2 },
|
||||
metric: true,
|
||||
showArea: true
|
||||
},
|
||||
marker: {
|
||||
icon: defaultSpbuIcon
|
||||
},
|
||||
circle: false,
|
||||
rectangle: false,
|
||||
circlemarker: false
|
||||
}
|
||||
});
|
||||
map.addControl(drawControl);
|
||||
|
||||
// ==================== EVENT DRAW CREATED ====================
|
||||
map.on(L.Draw.Event.CREATED, function(e) {
|
||||
var layer = e.layer;
|
||||
var type = e.layerType;
|
||||
console.log("Event CREATED: " + type);
|
||||
|
||||
if (type === 'marker') {
|
||||
var latlng = layer.getLatLng();
|
||||
var form = '<div class="popup-form">' +
|
||||
'<h4>📌 Input SPBU Baru</h4>' +
|
||||
'<input type="text" id="nama_spbu" placeholder="Nama SPBU" required>' +
|
||||
'<input type="text" id="hp_spbu" placeholder="Nomor Telepon" required>' +
|
||||
'<select id="status_spbu"><option value="1">✅ Buka 24 Jam</option><option value="0">🌙 Tutup Malam</option></select>' +
|
||||
'<button onclick="simpanSPBU(' + latlng.lat + ', ' + latlng.lng + ')">💾 Simpan SPBU</button>' +
|
||||
'</div>';
|
||||
layer.bindPopup(form).openPopup();
|
||||
drawnItems.addLayer(layer);
|
||||
}
|
||||
else if (type === 'polyline') {
|
||||
var coords = layer.getLatLngs();
|
||||
|
||||
var distance = 0;
|
||||
for (var i = 0; i < coords.length - 1; i++) {
|
||||
distance += coords[i].distanceTo(coords[i + 1]);
|
||||
}
|
||||
|
||||
window.pendingJalan = { coords: coords, distance: distance };
|
||||
console.log("Jalan siap disimpan, panjang: " + distance.toFixed(2) + "m");
|
||||
|
||||
var form = '<div class="popup-form">' +
|
||||
'<h4>🛣️ Input Jalan Baru</h4>' +
|
||||
'<div class="form-group"><label>Status Jalan:</label>' +
|
||||
'<select id="status_jalan"><option value="Nasional">Jalan Nasional</option><option value="Provinsi">Jalan Provinsi</option><option value="Kota">Jalan Kota</option></select></div>' +
|
||||
'<p>📏 Panjang: ' + distance.toFixed(2) + ' meter</p>' +
|
||||
'<button onclick="window.simpanJalanBaru()">💾 Simpan Jalan</button>' +
|
||||
'</div>';
|
||||
layer.bindPopup(form).openPopup();
|
||||
drawnItems.addLayer(layer);
|
||||
}
|
||||
else if (type === 'polygon') {
|
||||
var latlngs = layer.getLatLngs()[0];
|
||||
var area = L.GeometryUtil.geodesicArea(latlngs);
|
||||
window.pendingTanah = { coords: latlngs, area: area };
|
||||
console.log("Tanah siap disimpan, luas: " + area.toFixed(2) + "m²");
|
||||
|
||||
var form = '<div class="popup-form">' +
|
||||
'<h4>🏞️ Input Bidang Tanah</h4>' +
|
||||
'<div class="form-group"><label>Status Tanah:</label>' +
|
||||
'<select id="status_tanah"><option value="SHM">SHM (Sertifikat Hak Milik)</option><option value="HGB">HGB (Hak Guna Bangunan)</option><option value="HGU">HGU (Hak Guna Usaha)</option></select></div>' +
|
||||
'<p>📐 Luas: ' + area.toFixed(2) + ' m²</p>' +
|
||||
'<button onclick="window.simpanTanahBaru()">💾 Simpan Tanah</button>' +
|
||||
'</div>';
|
||||
layer.bindPopup(form).openPopup();
|
||||
drawnItems.addLayer(layer);
|
||||
}
|
||||
});
|
||||
|
||||
// ==================== LOAD DATA SAAT HALAMAN DIBUKA ====================
|
||||
loadData();
|
||||
</script>
|
||||
<div class="note"><b>Catatan:</b> Deploy cukup satu resource aplikasi di Coolify. Tugas dapat diakses melalui subfolder <code>/Tugas1/</code>, <code>/Tugas2/</code>, <code>/Tugas3/</code>, dan <code>/Tugas4/</code>.</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
set_time_limit(300);
|
||||
|
||||
$host = getenv('DB_HOST') ?: 'localhost';
|
||||
$user = getenv('DB_USER') ?: 'root';
|
||||
$pass = getenv('DB_PASS') ?: (getenv('DB_PASSWORD') ?: '');
|
||||
$db = getenv('DB_NAME') ?: 'webgis';
|
||||
$port = (int)(getenv('DB_PORT') ?: 3306);
|
||||
|
||||
echo "<h2>Install Database Pertemuan 1-2-3-4</h2>";
|
||||
echo "<p>Target koneksi: <b>" . htmlspecialchars($host) . ":" . htmlspecialchars((string)$port) . "</b>, database: <b>" . htmlspecialchars($db) . "</b>, user: <b>" . htmlspecialchars($user) . "</b></p>";
|
||||
|
||||
$conn = new mysqli($host, $user, $pass, $db, $port);
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die("<p style='color:red'>Koneksi gagal: " . htmlspecialchars($conn->connect_error) . "</p>");
|
||||
}
|
||||
|
||||
$sqlFile = __DIR__ . '/database.sql';
|
||||
if (!file_exists($sqlFile)) {
|
||||
die("<p style='color:red'>File database.sql tidak ditemukan.</p>");
|
||||
}
|
||||
|
||||
$sql = file_get_contents($sqlFile);
|
||||
$sql = preg_replace('/CREATE\s+DATABASE\s+IF\s+NOT\s+EXISTS\s+`?[^`\s;]+`?.*?;/is', '', $sql);
|
||||
$sql = preg_replace('/CREATE\s+DATABASE\s+`?[^`\s;]+`?.*?;/is', '', $sql);
|
||||
$sql = preg_replace('/USE\s+`?[^`\s;]+`?\s*;/is', '', $sql);
|
||||
|
||||
if ($conn->multi_query($sql)) {
|
||||
do {
|
||||
if ($result = $conn->store_result()) {
|
||||
$result->free();
|
||||
}
|
||||
} while ($conn->more_results() && $conn->next_result());
|
||||
|
||||
if ($conn->errno) {
|
||||
echo "<p style='color:red'>Ada error saat import: " . htmlspecialchars($conn->error) . "</p>";
|
||||
} else {
|
||||
echo "<p style='color:green;font-weight:bold'>Database berhasil diimport.</p>";
|
||||
echo "<p>Setelah berhasil, hapus file <code>install_database.php</code> dari repo lalu redeploy.</p>";
|
||||
}
|
||||
} else {
|
||||
echo "<p style='color:red'>Import gagal: " . htmlspecialchars($conn->error) . "</p>";
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
?>
|
||||
+12
-8
@@ -1,15 +1,19 @@
|
||||
<?php
|
||||
$host = 'localhost';
|
||||
$user = 'root';
|
||||
$password = '';
|
||||
$database = 'webgis';
|
||||
$host = getenv('DB_HOST') ?: 'localhost';
|
||||
$user = getenv('DB_USER') ?: 'root';
|
||||
$password = getenv('DB_PASS') ?: (getenv('DB_PASSWORD') ?: '');
|
||||
$database = getenv('DB_NAME') ?: 'webgis';
|
||||
$port = (int)(getenv('DB_PORT') ?: 3306);
|
||||
|
||||
$conn = new mysqli($host, $user, $password, $database);
|
||||
$conn = new mysqli($host, $user, $password, $database, $port);
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die(json_encode(['status' => 'error', 'msg' => 'Koneksi database gagal: ' . $conn->connect_error]));
|
||||
http_response_code(500);
|
||||
die(json_encode([
|
||||
'status' => 'error',
|
||||
'msg' => 'Koneksi database gagal: ' . $conn->connect_error
|
||||
]));
|
||||
}
|
||||
|
||||
// Set charset ke UTF-8
|
||||
$conn->set_charset("utf8");
|
||||
$conn->set_charset('utf8mb4');
|
||||
?>
|
||||
Reference in New Issue
Block a user