Ekaropolus 42334746bb
Some checks reported errors
continuous-integration/drone/push Build was killed
Pre Operations Section
2025-05-19 20:54:15 -06:00

125 lines
4.1 KiB
HTML

{% extends "pxy_dashboard/partials/base.html" %}
{% block content %}
<div class="container mt-4">
{% include "pxy_dashboard/partials/dashboard/kpi_row.html" %}
<div class="row g-3 mb-3">
<div class="col-auto">
<label for="subdivisionSelect" class="form-label">Subdivision:</label>
<select id="subdivisionSelect" class="form-select">
{% for subdiv in subdivisions %}
<option value="{{ subdiv }}">{{ subdiv }}</option>
{% endfor %}
</select>
</div>
<div class="col-auto">
<label for="routeSelect" class="form-label">Vehicle / Route:</label>
<select id="routeSelect" class="form-select"></select>
</div>
</div>
<div id="dispatch-map" style="height: 600px; width: 100%;"></div>
</div>
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 1) parse your two JSON-blobs
const geojsonData = JSON.parse('{{ geojson_by_subdivision|escapejs }}');
const routesBySubdivision = JSON.parse('{{ routes_by_subdivision|escapejs }}');
// 2) set up map
const map = L.map('dispatch-map');
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
// 3) icons as before
const iconOptions = {
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
shadowSize: [41, 41]
};
const icons = {
start: L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png', ...iconOptions }),
end: L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png', ...iconOptions }),
job: L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-orange.png', ...iconOptions }),
other: L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-grey.png', ...iconOptions })
};
let currentLayer = null;
const subdivSel = document.getElementById('subdivisionSelect');
const routeSel = document.getElementById('routeSelect');
// populate the “route” dropdown given a subdivision
function populateRoutes(subdiv) {
routeSel.innerHTML = '';
const list = routesBySubdivision[subdiv] || [];
list.forEach(rid => {
const o = document.createElement('option');
o.value = rid;
o.text = rid;
routeSel.append(o);
});
}
// render only the selected subdivision+route
function render(subdiv, routeId) {
if (currentLayer) map.removeLayer(currentLayer);
map.invalidateSize();
// filter to only those features matching this route
const allFC = geojsonData[subdiv] || { features: [] };
const filtered = {
type: 'FeatureCollection',
features: allFC.features.filter(f => f.properties.route_id === routeId)
};
currentLayer = L.geoJSON(filtered, {
pointToLayer: (f, latlng) => {
const type = f.properties.step_type || 'other';
return L.marker(latlng, { icon: icons[type] }).bindPopup(f.properties.popup);
},
style: feat => feat.geometry.type === 'LineString'
? { weight: 3, opacity: 0.7 }
: {}
}).addTo(map);
const b = currentLayer.getBounds();
if (b.isValid()) {
map.fitBounds(b, { padding: [20, 20] });
}
}
// wire up select events
subdivSel.addEventListener('change', () => {
const s = subdivSel.value;
populateRoutes(s);
const firstRoute = routeSel.options[0]?.value;
if (firstRoute) render(s, firstRoute);
});
routeSel.addEventListener('change', () => {
render(subdivSel.value, routeSel.value);
});
// initial load
const firstSub = subdivSel.options[0]?.value;
if (firstSub) {
subdivSel.value = firstSub;
populateRoutes(firstSub);
const firstRoute = routeSel.options[0]?.value;
if (firstRoute) render(firstSub, firstRoute);
}
});
</script>
{% endblock %}