Project UAS Sistem Informasi Geografis (SIG)
This commit is contained in:
@@ -0,0 +1,331 @@
|
||||
/* ============================================================
|
||||
draw_geometri.js - WebGIS Point, Polyline, Polygon
|
||||
============================================================ */
|
||||
|
||||
var map = L.map('map', { zoomControl: false }).setView([-0.0263, 109.3425], 13);
|
||||
L.control.zoom({ position: 'bottomright' }).addTo(map);
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© OpenStreetMap contributors',
|
||||
maxZoom: 19
|
||||
}).addTo(map);
|
||||
|
||||
var drawnItems = new L.FeatureGroup().addTo(map);
|
||||
var layerGroupPoint = L.featureGroup().addTo(map);
|
||||
var currentLayer = null;
|
||||
|
||||
var drawControl = new L.Control.Draw({
|
||||
position: 'topleft',
|
||||
edit: { featureGroup: drawnItems },
|
||||
draw: {
|
||||
marker: true,
|
||||
polyline: { shapeOptions: { color: '#a855f7', weight: 3 } },
|
||||
polygon: { shapeOptions: { color: '#10b981', weight: 2, fillOpacity: 0.35 } },
|
||||
rectangle: false,
|
||||
circle: false,
|
||||
circlemarker: false
|
||||
}
|
||||
});
|
||||
map.addControl(drawControl);
|
||||
|
||||
function getLineColor(status) {
|
||||
return status === 'Nasional' ? '#ef4444' : status === 'Provinsi' ? '#38bdf8' : '#a855f7';
|
||||
}
|
||||
|
||||
function getLength(latlngs) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < latlngs.length - 1; i++) {
|
||||
total += latlngs[i].distanceTo(latlngs[i + 1]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function fmtNum(n, dec = 2) {
|
||||
return parseFloat(n).toLocaleString('id-ID', { maximumFractionDigits: dec });
|
||||
}
|
||||
|
||||
function statusBadge(status, type) {
|
||||
if (type === 'line') {
|
||||
var c = status === 'Nasional' ? 'badge-red' : status === 'Provinsi' ? 'badge-blue' : 'badge-gray';
|
||||
return `<span class="ip-badge ${c}">${status}</span>`;
|
||||
}
|
||||
return `<span class="ip-badge ${status === 'SHM' ? 'badge-green' : 'badge-blue'}">${status}</span>`;
|
||||
}
|
||||
|
||||
function makePointIcon() {
|
||||
var c = '#3b82f6';
|
||||
return L.divIcon({
|
||||
html: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="38" viewBox="0 0 26 38"><path d="M13 0C5.8 0 0 5.8 0 13c0 9.75 13 25 13 25S26 22.75 26 13C26 5.8 20.2 0 13 0z" fill="${c}" stroke="rgba(255,255,255,.25)" stroke-width="1.5"/><circle cx="13" cy="13" r="5" fill="rgba(0,0,0,.4)"/><circle cx="13" cy="13" r="3" fill="white"/></svg>`,
|
||||
iconSize: [26, 38],
|
||||
iconAnchor: [13, 38],
|
||||
popupAnchor: [0, -40],
|
||||
className: ''
|
||||
});
|
||||
}
|
||||
|
||||
function buildInfoPopup(d, type) {
|
||||
var headerColors = {
|
||||
point: 'linear-gradient(135deg,#1d4ed8,#3b82f6)',
|
||||
line: 'linear-gradient(135deg,#7c3aed,#a855f7)',
|
||||
polygon: 'linear-gradient(135deg,#065f46,#10b981)'
|
||||
};
|
||||
var icons = { point: '📍', line: '▱', polygon: '▰' };
|
||||
var titles = {
|
||||
point: `Point - ${d.nama}`,
|
||||
line: `Jalan - ${d.nama}`,
|
||||
polygon: `Parsil - ${d.nama}`
|
||||
};
|
||||
|
||||
var rows = '';
|
||||
if (type === 'point') {
|
||||
rows = `<div class="ip-row"><span class="ip-label">Nama</span><span class="ip-val">${d.nama}</span></div>
|
||||
<div class="ip-row"><span class="ip-label">Kode Point</span><span class="ip-val">${d.no_spbu}</span></div>`;
|
||||
} else if (type === 'line') {
|
||||
rows = `<div class="ip-row"><span class="ip-label">Status</span><span class="ip-val">${statusBadge(d.status, 'line')}</span></div>
|
||||
<div class="ip-row"><span class="ip-label">Panjang</span><span class="ip-val">${fmtNum(d.panjang)} m</span></div>`;
|
||||
} else if (type === 'polygon') {
|
||||
rows = `<div class="ip-row"><span class="ip-label">Status</span><span class="ip-val">${statusBadge(d.status, 'polygon')}</span></div>
|
||||
<div class="ip-row"><span class="ip-label">Luas</span><span class="ip-val">${fmtNum(d.luas)} m²</span></div>`;
|
||||
}
|
||||
|
||||
return `<div class="ip">
|
||||
<div class="ip-head" style="background:${headerColors[type]}">${icons[type]} ${titles[type]}</div>
|
||||
<div class="ip-body">${rows}<button class="ip-del" onclick="hapusData(${d.id},'${type}')">Hapus</button></div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
fetch('../php/show_geometri.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
data.forEach(d => {
|
||||
if (d.type === 'point') {
|
||||
var pointLayer = L.marker([d.latitude, d.longitude], { icon: makePointIcon() });
|
||||
pointLayer._type = 'point';
|
||||
pointLayer._db_id = d.id;
|
||||
pointLayer.bindPopup(buildInfoPopup(d, 'point'), { maxWidth: 260 });
|
||||
layerGroupPoint.addLayer(pointLayer);
|
||||
}
|
||||
|
||||
if (d.type === 'line') {
|
||||
var lineCoords = JSON.parse(d.geom);
|
||||
var lineLayer = L.polyline(lineCoords, { color: getLineColor(d.status), weight: 4, opacity: 0.9 });
|
||||
lineLayer._type = 'line';
|
||||
lineLayer._db_id = d.id;
|
||||
lineLayer.bindPopup(buildInfoPopup(d, 'line'), { maxWidth: 260 });
|
||||
drawnItems.addLayer(lineLayer);
|
||||
}
|
||||
|
||||
if (d.type === 'polygon') {
|
||||
var polygonCoords = JSON.parse(d.geom);
|
||||
var polygonLayer = L.polygon(polygonCoords, {
|
||||
color: '#10b981',
|
||||
weight: 2,
|
||||
fillColor: '#10b981',
|
||||
fillOpacity: 0.3
|
||||
});
|
||||
polygonLayer._type = 'polygon';
|
||||
polygonLayer._db_id = d.id;
|
||||
polygonLayer.bindPopup(buildInfoPopup(d, 'polygon'), { maxWidth: 260 });
|
||||
drawnItems.addLayer(polygonLayer);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(err => console.error('Gagal load data:', err));
|
||||
|
||||
function hapusData(id, type) {
|
||||
if (!confirm('Yakin ingin menghapus?')) return;
|
||||
fetch(`../php/delete.php?id=${id}&type=${type}`)
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
if (r.message && r.message.toLowerCase().includes('berhasil')) location.reload();
|
||||
else alert('Gagal: ' + (r.error || r.message));
|
||||
});
|
||||
}
|
||||
|
||||
map.on(L.Draw.Event.CREATED, function(e) {
|
||||
var layer = e.layer;
|
||||
|
||||
if (e.layerType === 'marker') {
|
||||
drawnItems.addLayer(layer);
|
||||
handlePoint(layer);
|
||||
}
|
||||
if (e.layerType === 'polyline') {
|
||||
drawnItems.addLayer(layer);
|
||||
handleLine(layer);
|
||||
}
|
||||
if (e.layerType === 'polygon') {
|
||||
drawnItems.addLayer(layer);
|
||||
handlePolygon(layer);
|
||||
}
|
||||
});
|
||||
|
||||
function handlePoint(layer) {
|
||||
var ll = layer.getLatLng();
|
||||
layer.bindPopup(`<div class="pf">
|
||||
<div class="pf-head pf-head-point">📍 Tambah Point</div>
|
||||
<div class="pf-body">
|
||||
<label>Nama Point</label><input id="pNama" placeholder="contoh: Titik Survei A">
|
||||
<label>Kode Point</label><input id="pNo" placeholder="contoh: P-001">
|
||||
<div class="pf-info">📍 ${ll.lat.toFixed(6)}, ${ll.lng.toFixed(6)}</div>
|
||||
<button class="pf-btn" onclick="savePoint(${ll.lat},${ll.lng})">Simpan</button>
|
||||
</div>
|
||||
</div>`, { maxWidth: 280 }).openPopup();
|
||||
}
|
||||
|
||||
function savePoint(lat, lng) {
|
||||
var nama = document.getElementById('pNama').value.trim();
|
||||
var no = document.getElementById('pNo').value.trim();
|
||||
var status = '24 Jam';
|
||||
if (!nama || !no) {
|
||||
alert('Nama dan kode point wajib diisi!');
|
||||
return;
|
||||
}
|
||||
fetch('../php/insert.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ nama, no, status, lat, lng })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
if (r.message && r.message.includes('berhasil')) location.reload();
|
||||
else alert('Gagal: ' + (r.error || r.message));
|
||||
});
|
||||
}
|
||||
|
||||
function handleLine(layer) {
|
||||
currentLayer = layer;
|
||||
var latlngs = layer.getLatLngs();
|
||||
var panjang = getLength(latlngs);
|
||||
layer._temp = { latlngs, panjang };
|
||||
L.popup({ maxWidth: 280 }).setLatLng(layer.getBounds().getCenter()).setContent(`<div class="pf">
|
||||
<div class="pf-head pf-head-line">▱ Tambah Jalan</div>
|
||||
<div class="pf-body">
|
||||
<label>Nama Jalan</label><input id="lNama" placeholder="contoh: Jl. Ahmad Yani">
|
||||
<label>Klasifikasi</label><select id="lStatus"><option value="Nasional">Nasional</option><option value="Provinsi">Provinsi</option><option value="Kabupaten">Kabupaten</option></select>
|
||||
<div class="pf-info">${fmtNum(panjang)} m</div>
|
||||
<button class="pf-btn" onclick="saveLine()">Simpan</button>
|
||||
</div>
|
||||
</div>`).openOn(map);
|
||||
}
|
||||
|
||||
function saveLine() {
|
||||
var layer = currentLayer;
|
||||
if (!layer) {
|
||||
alert('Layer tidak ditemukan');
|
||||
return;
|
||||
}
|
||||
var nama = document.getElementById('lNama').value.trim();
|
||||
var status = document.getElementById('lStatus').value;
|
||||
if (!nama) {
|
||||
alert('Nama wajib diisi!');
|
||||
return;
|
||||
}
|
||||
fetch('../php/insert_line.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
nama,
|
||||
status,
|
||||
panjang: layer._temp.panjang,
|
||||
geom: JSON.stringify(layer._temp.latlngs)
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
if (r.id) {
|
||||
layer._db_id = r.id;
|
||||
layer._type = 'line';
|
||||
map.closePopup();
|
||||
alert('Berhasil!');
|
||||
} else {
|
||||
alert('Gagal: ' + (r.error || r.message));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handlePolygon(layer) {
|
||||
currentLayer = layer;
|
||||
var latlngs = layer.getLatLngs();
|
||||
var luas = L.GeometryUtil.geodesicArea(latlngs[0]);
|
||||
layer._temp = { latlngs, luas };
|
||||
L.popup({ maxWidth: 280 }).setLatLng(layer.getBounds().getCenter()).setContent(`<div class="pf">
|
||||
<div class="pf-head pf-head-polygon">▰ Tambah Parsil</div>
|
||||
<div class="pf-body">
|
||||
<label>Nama Area</label><input id="gNama" placeholder="contoh: Lahan A">
|
||||
<label>Status Kepemilikan</label><select id="gStatus"><option value="SHM">SHM</option><option value="HGB">HGB</option><option value="HGU">HGU</option><option value="HP">HP</option></select>
|
||||
<div class="pf-info">${fmtNum(luas)} m²</div>
|
||||
<button class="pf-btn" onclick="savePolygon()">Simpan</button>
|
||||
</div>
|
||||
</div>`).openOn(map);
|
||||
}
|
||||
|
||||
function savePolygon() {
|
||||
var layer = currentLayer;
|
||||
if (!layer) {
|
||||
alert('Layer tidak ditemukan');
|
||||
return;
|
||||
}
|
||||
var nama = document.getElementById('gNama').value.trim();
|
||||
var status = document.getElementById('gStatus').value;
|
||||
if (!nama) {
|
||||
alert('Nama wajib diisi!');
|
||||
return;
|
||||
}
|
||||
fetch('../php/insert_polygon.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
nama,
|
||||
status,
|
||||
luas: layer._temp.luas,
|
||||
geom: JSON.stringify(layer._temp.latlngs)
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
if (r.id) {
|
||||
layer._db_id = r.id;
|
||||
layer._type = 'polygon';
|
||||
map.closePopup();
|
||||
alert('Berhasil!');
|
||||
} else {
|
||||
alert('Gagal: ' + (r.error || r.message));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map.on('draw:edited', function(e) {
|
||||
e.layers.eachLayer(layer => {
|
||||
if (!layer._db_id) return;
|
||||
if (layer._type === 'line') {
|
||||
fetch('../php/update_line.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
id: layer._db_id,
|
||||
geom: JSON.stringify(layer.getLatLngs()),
|
||||
panjang: getLength(layer.getLatLngs())
|
||||
})
|
||||
});
|
||||
}
|
||||
if (layer._type === 'polygon') {
|
||||
fetch('../php/update_polygon.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
id: layer._db_id,
|
||||
geom: JSON.stringify(layer.getLatLngs()),
|
||||
luas: L.GeometryUtil.geodesicArea(layer.getLatLngs()[0])
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
map.on('draw:deleted', function(e) {
|
||||
e.layers.eachLayer(layer => {
|
||||
if (layer._db_id && layer._type) {
|
||||
fetch(`../php/delete.php?id=${layer._db_id}&type=${layer._type}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user