Files
TUGAS_SIG_JOHANESSATRIACHRI…/Projek Jalan/index.php
T

340 lines
12 KiB
PHP

<?php
// Data diambil dari API - tidak ada koneksi MySQL di frontend ini
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGIS Manajemen Data Jalan</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
body {
margin: 0;
font-family: Arial, sans-serif;
background: #f4f7fb;
color: #333;
}
header {
background: #1f2937;
color: #fff;
padding: 18px 24px;
text-align: center;
}
main {
max-width: 1160px;
margin: 24px auto;
padding: 0 16px 32px;
}
#map {
width: 100% !important;
height: 520px !important;
display: block !important;
position: relative !important;
visibility: visible !important;
border: 1px solid #cbd5e1;
border-radius: 12px;
box-shadow: 0 10px 24px rgba(15,23,42,.08);
}
.panel {
margin-top: 24px;
display: grid;
gap: 18px;
}
.card {
background: #fff;
border-radius: 14px;
padding: 20px;
box-shadow: 0 8px 20px rgba(15,23,42,.06);
}
.card h2 {
margin: 0 0 14px;
font-size: 1.2rem;
}
.form-group {
margin-bottom: 14px;
}
.form-group label {
display: block;
margin-bottom: 6px;
font-weight: 600;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 10px 12px;
border: 1px solid #cbd5e1;
border-radius: 10px;
font-size: 0.98rem;
background: #f8fafc;
}
.form-group input[readonly] {
background: #e2e8f0;
cursor: not-allowed;
}
.button-row {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
}
.btn {
display: inline-flex;
justify-content: center;
align-items: center;
padding: 12px 18px;
border: none;
border-radius: 10px;
font-size: 1rem;
cursor: pointer;
transition: background 0.2s ease;
}
.btn-primary {
background: #2563eb;
color: #fff;
}
.btn-primary:hover {
background: #1d4ed8;
}
.btn-secondary {
background: #64748b;
color: #fff;
}
.btn-secondary:hover {
background: #475569;
}
.alert {
padding: 14px 16px;
border-radius: 10px;
border: 1px solid transparent;
}
.alert-error {
background: #fee2e2;
border-color: #fca5a5;
color: #b91c1c;
}
.alert-success {
background: #dcfce7;
border-color: #a7f3d0;
color: #166534;
}
.note {
font-size: 0.95rem;
color: #475569;
}
.road-list {
display: grid;
gap: 12px;
}
.road-item {
border: 1px solid #e2e8f0;
padding: 14px 16px;
border-radius: 12px;
background: #f8fafc;
}
.road-item strong {
display: block;
margin-bottom: 6px;
font-size: 1rem;
}
.meta {
color: #475569;
font-size: 0.95rem;
line-height: 1.5;
}
</style>
</head>
<body>
<header>
<h1>🛣️ WebGIS Manajemen Data Jalan</h1>
<p>Tambah, simpan, dan tampilkan polyline jalan dengan LeafletJS (API Mode)</p>
</header>
<main>
<section class="card">
<h2>Petunjuk</h2>
<p class="note">Klik peta berurutan untuk membuat garis jalan sementara. Sistem akan menghitung panjang otomatis dan menyimpan koordinat JSON ke database.</p>
</section>
<section class="card">
<div id="map"></div>
</section>
<?php if (!empty($errors)): ?>
<section class="alert alert-error card">
<strong>Terjadi kesalahan:</strong>
<ul>
<?php foreach ($errors as $error): ?>
<li><?= htmlspecialchars($error) ?></li>
<?php endforeach; ?>
</ul>
</section>
<?php endif; ?>
<?php if ($success): ?>
<section class="alert alert-success card">
<?= htmlspecialchars($success) ?>
</section>
<?php endif; ?>
<section class="card">
<h2>Form Tambah Jalan</h2>
<form method="post" action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>">
<div class="form-group">
<label for="nama_jalan">Nama Jalan</label>
<input type="text" id="nama_jalan" name="nama_jalan" required value="<?= htmlspecialchars($input['nama_jalan']) ?>" placeholder="e.g. Jalan Ahmad Yani">
</div>
<div class="form-group">
<label for="status_jalan">Status Jalan</label>
<select id="status_jalan" name="status_jalan" required>
<option value="">Pilih status jalan</option>
<option value="nasional" <?= $input['status_jalan'] === 'nasional' ? 'selected' : '' ?>>nasional</option>
<option value="provinsi" <?= $input['status_jalan'] === 'provinsi' ? 'selected' : '' ?>>provinsi</option>
<option value="kabupaten" <?= $input['status_jalan'] === 'kabupaten' ? 'selected' : '' ?>>kabupaten</option>
</select>
</div>
<div class="form-group">
<label>Panjang Jalan (otomatis)</label>
<input type="text" id="panjang_tampil" readonly value="<?= $input['panjang_meter'] !== '' ? htmlspecialchars($input['panjang_meter']) . ' meter' : '0 meter' ?>">
<input type="hidden" name="panjang_meter" id="panjang_meter" value="<?= htmlspecialchars($input['panjang_meter']) ?>">
</div>
<div class="form-group">
<label>Koordinat JSON (otomatis)</label>
<textarea readonly rows="3" id="koordinat_tampil" style="resize: vertical; background: #e2e8f0;"><?= htmlspecialchars($input['koordinat_json']) ?></textarea>
<input type="hidden" name="koordinat_json" id="koordinat_json" value="<?= htmlspecialchars($input['koordinat_json']) ?>">
</div>
<div class="button-row">
<button type="button" class="btn btn-secondary" id="reset-button">Reset Garis</button>
<button type="submit" class="btn btn-primary">Simpan Data Jalan</button>
</div>
</form>
</section>
<section class="card">
<h2>Daftar Jalan Tersimpan</h2>
<div class="road-list">
<?php if (count($jalanList) === 0): ?>
<div class="road-item">Belum ada data jalan yang tersimpan.</div>
<?php else: ?>
<?php foreach ($jalanList as $jalan): ?>
<div class="road-item">
<strong><?= htmlspecialchars($jalan['nama_jalan']) ?></strong>
<div class="meta">Status: <?= htmlspecialchars($jalan['status_jalan']) ?> | Panjang: <?= htmlspecialchars($jalan['panjang_meter']) ?> meter</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</section>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const map = L.map('map').setView([-0.0263, 109.3425], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
const statusColors = {
nasional: '#DC3545',
provinsi: '#007BFF',
kabupaten: '#28A745'
};
const jalanData = <?= json_encode(array_map(function ($row) {
return [
'id' => $row['id'],
'nama_jalan' => $row['nama_jalan'],
'status_jalan' => $row['status_jalan'],
'panjang_meter' => $row['panjang_meter'],
'koordinat' => json_decode($row['koordinat_json'], true)
];
}, $jalanList), JSON_UNESCAPED_UNICODE) ?>;
jalanData.forEach(jalan => {
if (!Array.isArray(jalan.koordinat) || jalan.koordinat.length < 2) {
return;
}
const line = L.polyline(jalan.koordinat.map(([lat, lng]) => [lat, lng]), {
color: statusColors[jalan.status_jalan] || '#444',
weight: 6,
opacity: 0.8,
smoothFactor: 1
}).addTo(map);
line.bindPopup(`
<strong>${jalan.nama_jalan}</strong><br>
Status: ${jalan.status_jalan}<br>
Panjang: ${jalan.panjang_meter} meter
`);
});
let currentPoints = [];
let currentLine = null;
const panjangMeterInput = document.getElementById('panjang_meter');
const panjangTampil = document.getElementById('panjang_tampil');
const koordinatInput = document.getElementById('koordinat_json');
const koordinatTampil = document.getElementById('koordinat_tampil');
const resetButton = document.getElementById('reset-button');
map.on('click', function (event) {
currentPoints.push(event.latlng);
updateTemporaryPolyline();
updateFormFields();
});
resetButton.addEventListener('click', function () {
currentPoints = [];
if (currentLine) {
map.removeLayer(currentLine);
currentLine = null;
}
updateFormFields();
});
function updateTemporaryPolyline() {
if (currentLine) {
map.removeLayer(currentLine);
}
if (currentPoints.length >= 2) {
currentLine = L.polyline(currentPoints, {
color: '#0f172a',
weight: 5,
dashArray: '8, 8',
opacity: 0.85
}).addTo(map);
} else if (currentPoints.length === 1) {
currentLine = L.circleMarker(currentPoints[0], {
radius: 6,
fillColor: '#0f172a',
color: '#ffffff',
weight: 2,
fillOpacity: 1
}).addTo(map);
}
}
function updateFormFields() {
let totalDistance = 0;
for (let i = 1; i < currentPoints.length; i++) {
totalDistance += currentPoints[i - 1].distanceTo(currentPoints[i]);
}
const roundedDistance = Math.round(totalDistance);
panjangMeterInput.value = roundedDistance;
panjangTampil.value = `${roundedDistance} meter`;
const coordsArray = currentPoints.map(point => [point.lat, point.lng]);
koordinatInput.value = JSON.stringify(coordsArray);
koordinatTampil.value = koordinatInput.value;
}
updateFormFields();
window.addEventListener('load', function () {
map.invalidateSize();
});
</script>
</body>
</html>