Initial WebGIS portal project
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const DEFAULT_SOURCE = 'assets/data/Kecamatan.json';
|
||||
const DEFAULT_ANCHOR = {
|
||||
lat: -0.06054796552220232,
|
||||
lng: 109.34490231930592
|
||||
};
|
||||
const DEFAULT_GEO_BOUNDS = {
|
||||
south: -0.0981948,
|
||||
west: 109.2741676,
|
||||
north: 0.0381168,
|
||||
east: 109.3853475
|
||||
};
|
||||
const DEFAULT_CALIBRATION = {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
offsetLat: 0,
|
||||
offsetLng: 0
|
||||
};
|
||||
|
||||
function walkCoordinates(coordinates, callback) {
|
||||
if (!Array.isArray(coordinates)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (coordinates.length >= 2 && typeof coordinates[0] === 'number' && typeof coordinates[1] === 'number') {
|
||||
callback(coordinates[0], coordinates[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
coordinates.forEach((child) => walkCoordinates(child, callback));
|
||||
}
|
||||
|
||||
function getCoordinateBounds(data) {
|
||||
const bounds = {
|
||||
minX: Infinity,
|
||||
minY: Infinity,
|
||||
maxX: -Infinity,
|
||||
maxY: -Infinity
|
||||
};
|
||||
|
||||
function addGeometry(geometry) {
|
||||
if (!geometry) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (geometry.type === 'GeometryCollection') {
|
||||
(geometry.geometries || []).forEach(addGeometry);
|
||||
return;
|
||||
}
|
||||
|
||||
walkCoordinates(geometry.coordinates, (x, y) => {
|
||||
bounds.minX = Math.min(bounds.minX, x);
|
||||
bounds.minY = Math.min(bounds.minY, y);
|
||||
bounds.maxX = Math.max(bounds.maxX, x);
|
||||
bounds.maxY = Math.max(bounds.maxY, y);
|
||||
});
|
||||
}
|
||||
|
||||
if (data.type === 'FeatureCollection') {
|
||||
(data.features || []).forEach((feature) => addGeometry(feature.geometry));
|
||||
} else if (data.type === 'Feature') {
|
||||
addGeometry(data.geometry);
|
||||
} else {
|
||||
addGeometry(data);
|
||||
}
|
||||
|
||||
if (!Number.isFinite(bounds.minX) || !Number.isFinite(bounds.minY)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
function createBoundingBoxTransform(sourceBounds, targetBounds, calibration) {
|
||||
const sourceWidth = sourceBounds.maxX - sourceBounds.minX;
|
||||
const sourceHeight = sourceBounds.maxY - sourceBounds.minY;
|
||||
const targetCenterLng = (targetBounds.west + targetBounds.east) / 2 + calibration.offsetLng;
|
||||
const targetCenterLat = (targetBounds.south + targetBounds.north) / 2 + calibration.offsetLat;
|
||||
const targetWidth = (targetBounds.east - targetBounds.west) * calibration.scaleX;
|
||||
const targetHeight = (targetBounds.north - targetBounds.south) * calibration.scaleY;
|
||||
|
||||
return function coordsToLatLng(coordinates) {
|
||||
const xRatio = ((coordinates[0] - sourceBounds.minX) / sourceWidth) - 0.5;
|
||||
const yRatio = ((coordinates[1] - sourceBounds.minY) / sourceHeight) - 0.5;
|
||||
const lng = targetCenterLng + (xRatio * targetWidth);
|
||||
const lat = targetCenterLat + (yRatio * targetHeight);
|
||||
return L.latLng(lat, lng);
|
||||
};
|
||||
}
|
||||
|
||||
window.addKecamatanLayer = async function addKecamatanLayer(map, options) {
|
||||
const settings = Object.assign({
|
||||
source: DEFAULT_SOURCE,
|
||||
anchor: DEFAULT_ANCHOR,
|
||||
targetBounds: DEFAULT_GEO_BOUNDS,
|
||||
calibration: DEFAULT_CALIBRATION,
|
||||
fitBounds: false
|
||||
}, options || {});
|
||||
|
||||
if (!map || typeof L === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!map.getPane('kecamatanPane')) {
|
||||
map.createPane('kecamatanPane');
|
||||
map.getPane('kecamatanPane').style.zIndex = 350;
|
||||
}
|
||||
|
||||
const response = await fetch(settings.source, {
|
||||
headers: { 'Accept': 'application/json' }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Gagal memuat data batas kecamatan.');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const coordinateBounds = getCoordinateBounds(data);
|
||||
|
||||
if (!coordinateBounds) {
|
||||
throw new Error('Data batas kecamatan tidak memiliki koordinat valid.');
|
||||
}
|
||||
|
||||
const layer = L.geoJSON(data, {
|
||||
coordsToLatLng: createBoundingBoxTransform(coordinateBounds, settings.targetBounds, settings.calibration),
|
||||
pane: 'kecamatanPane',
|
||||
style: {
|
||||
color: '#0f766e',
|
||||
weight: 2,
|
||||
opacity: 0.9,
|
||||
fillColor: '#14b8a6',
|
||||
fillOpacity: 0.08,
|
||||
dashArray: '6 4'
|
||||
},
|
||||
onEachFeature: function (feature, featureLayer) {
|
||||
const name = feature && feature.properties && (
|
||||
feature.properties.nama ||
|
||||
feature.properties.NAMA ||
|
||||
feature.properties.KECAMATAN ||
|
||||
feature.properties.kecamatan
|
||||
);
|
||||
|
||||
featureLayer.bindPopup(name ? `Kecamatan: ${name}` : 'Batas Kecamatan');
|
||||
}
|
||||
}).addTo(map);
|
||||
|
||||
if (settings.fitBounds && layer.getBounds().isValid()) {
|
||||
map.fitBounds(layer.getBounds().pad(0.12), { maxZoom: 15 });
|
||||
}
|
||||
|
||||
return layer;
|
||||
};
|
||||
}());
|
||||
Reference in New Issue
Block a user