284 lines
7.8 KiB
HTML
284 lines
7.8 KiB
HTML
{{template "base.html" .}}
|
|
|
|
{{define "title"}}Dash{{end}}
|
|
{{define "extraheader"}}
|
|
<script src='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js'></script>
|
|
<link href='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css' rel='stylesheet' />
|
|
<script src="/static/js/address-display.js"></script>
|
|
<script src="/static/js/address-suggestion.js"></script>
|
|
<script src="/static/js/geocode.js"></script>
|
|
<script src="/static/js/location.js"></script>
|
|
<script src="/static/js/map.js"></script>
|
|
<script>
|
|
const MAPBOX_ACCESS_TOKEN = '{{.MapboxToken}}';
|
|
function setDistrictColors(map) {
|
|
const features = map.querySourceFeatures('tegola-mosquito', {sourceLayer: 'district'});
|
|
//console.log("features", features);
|
|
const regionIds = [...new Set(features.map(f => f.properties.regionid))];
|
|
map.setPaintProperty('districts', 'fill-opacity', 0.4);
|
|
if (regionIds.length > 0) {
|
|
// Generate color mapping
|
|
const colorScale = {};
|
|
regionIds.forEach((id, index) => {
|
|
// Generate a color (this is a simple example - consider using a proper color library)
|
|
colorScale[id] = `hsl(${index * (360 / regionIds.length)}, 70%, 50%)`;
|
|
});
|
|
const matchExpression = ['match', ['get', 'regionid']];
|
|
regionIds.forEach(id => {
|
|
matchExpression.push(id, colorScale[id]);
|
|
});
|
|
matchExpression.push('#cccccc'); // Default color
|
|
//console.log("using district coloring", matchExpression);
|
|
map.setPaintProperty('districts', 'fill-color', matchExpression);
|
|
} else {
|
|
map.setPaintProperty('districts', 'fill-color', 'rgb(250, 100, 100)');
|
|
//console.log("using fallback district coloring");
|
|
}
|
|
}
|
|
|
|
async function fetchDistrict(lng, lat) {
|
|
try {
|
|
const url = `/api/district?lat=${lat}&lng=${lng}`
|
|
const response = await fetch(url);
|
|
var agencyEl = document.querySelector("#district-agency");
|
|
var managerEl = document.querySelector("#district-manager");
|
|
var phoneEl = document.querySelector("#district-phone");
|
|
var websiteEl = document.querySelector("#district-website");
|
|
if (response.status == 404) {
|
|
agencyEl.innerHTML = "no matching district";
|
|
managerEl.innerHTML = "-";
|
|
phoneEl.innerHTML = "-";
|
|
websiteEl.innerHTML = "-";
|
|
return
|
|
}
|
|
const data = await response.json();
|
|
console.log("district", data);
|
|
agencyEl.innerHTML = data.agency;
|
|
managerEl.innerHTML = data.manager;
|
|
phoneEl.innerHTML = data.phone;
|
|
websiteEl.innerHTML = data.website;
|
|
} catch (error) {
|
|
console.error('Error fetching geocoding suggestions:', error);
|
|
}
|
|
}
|
|
|
|
function onLoad() {
|
|
console.log("Setting up the map...");
|
|
mapboxgl.accessToken = MAPBOX_ACCESS_TOKEN;
|
|
const map = new mapboxgl.Map({
|
|
container: 'map', // container ID
|
|
style: 'mapbox://styles/mapbox/standard', // style URL
|
|
//style: 'mapbox://styles/eliribble/cmke4af8i004401suh3cahegw',
|
|
center: [-119.3, 36.327], // starting position [lng, lat]
|
|
//center: [7.01, 50.74],
|
|
zoom: 9 // starting zoom
|
|
});
|
|
map.on("load", function() {
|
|
console.log("Map post-load...");
|
|
map.addSource('tegola-mosquito', {
|
|
'type': 'vector',
|
|
'tiles': [
|
|
'https://dev-tegola.nidus.cloud/maps/mosquito/{z}/{x}/{y}'
|
|
]
|
|
});
|
|
map.addLayer({
|
|
'id': 'districts',
|
|
'source': 'tegola-mosquito', // ID of the tile source created above
|
|
'source-layer': 'district',
|
|
'type': 'fill',
|
|
});
|
|
map.addInteraction("nidus-click-interaction", {
|
|
type: 'click',
|
|
target: { layerId: 'mosquito' },
|
|
handler: (e) => {
|
|
const coordinates = e.feature.geometry.coordinates.slice();
|
|
const properties = e.feature.properties;
|
|
console.log("Coordinates", coordinates[0]);
|
|
console.log("Properties", properties);
|
|
/*new mapboxgl.Popup()
|
|
.setLngLat(coordinates[0][0])
|
|
.setHTML("Cell: " + properties.cell)
|
|
.addTo(map);*/
|
|
//window.location.href = '/cell/' + properties.cell;
|
|
}
|
|
});
|
|
map.addInteraction('nidus-mouseenter-interaction', {
|
|
type: 'mouseenter',
|
|
target: { layerId: 'nidus' },
|
|
handler: () => {
|
|
map.getCanvas().style.cursor = 'pointer';
|
|
}
|
|
});
|
|
map.addInteraction('nidus-mouseleave-interaction', {
|
|
type: 'mouseleave',
|
|
target: { layerId: 'nidus' },
|
|
handler: () => {
|
|
map.getCanvas().style.cursor = '';
|
|
}
|
|
});
|
|
map.on('sourcedata', (e) => {
|
|
if (e.sourceId == 'tegola-mosquito' && e.isSourceLoaded) {
|
|
setDistrictColors(map)
|
|
}
|
|
});
|
|
console.log("Map post-load done.");
|
|
});
|
|
|
|
map.addControl(new mapboxgl.NavigationControl());
|
|
console.log("Map init done.");
|
|
|
|
/*const address = document.getElementById('address');
|
|
const suggestionsContainer = document.getElementById('suggestions');
|
|
addressSuggestionEnable(address, suggestionsContainer);*/
|
|
const addressDisplay = document.querySelector("address-display");
|
|
const addressInput = document.querySelector("address-input");
|
|
addressInput.addEventListener("address-selected", (event) => {
|
|
const l = event.detail.location;
|
|
// Center map on selected address
|
|
|
|
map.jumpTo({
|
|
center: l.geometry.coordinates,
|
|
zoom: 14,
|
|
});
|
|
|
|
// Add marker for selected address
|
|
const marker = new mapboxgl.Marker({
|
|
color: "#FF0000",
|
|
draggable: false
|
|
}).setLngLat(l.geometry.coordinates).addTo(map);
|
|
|
|
addressDisplay.show(l);
|
|
fetchDistrict(l.geometry.coordinates[0], l.geometry.coordinates[1]);
|
|
});
|
|
}
|
|
document.addEventListener("DOMContentLoaded", onLoad);
|
|
</script>
|
|
<style>
|
|
body {
|
|
background-color: #f8f9fa;
|
|
}
|
|
.detail-label {
|
|
font-size: 0.8rem;
|
|
text-transform: uppercase;
|
|
color: #6c757d;
|
|
margin-bottom: 2px;
|
|
font-weight: 600;
|
|
}
|
|
.dashboard-container {
|
|
padding: 20px 0;
|
|
}
|
|
.stats-card {
|
|
border-radius: 10px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
|
transition: transform 0.2s;
|
|
height: 100%;
|
|
}
|
|
.stats-card:hover {
|
|
transform: translateY(-5px);
|
|
}
|
|
.map-container {
|
|
background-color: #e9ecef;
|
|
border-radius: 10px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
|
height: 500px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-top: 20px;
|
|
}
|
|
#map {
|
|
height: 500px;
|
|
width:100%;
|
|
margin-bottom: 10px;
|
|
}
|
|
#map img {
|
|
max-width: none;
|
|
min-width: 0px;
|
|
height: auto;
|
|
}
|
|
.section-title {
|
|
margin: 30px 0 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
.last-refreshed {
|
|
color: #6c757d;
|
|
}
|
|
.logo-placeholder {
|
|
width: 100px;
|
|
height: 40px;
|
|
background-color: #e9ecef;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 4px;
|
|
}
|
|
.metric-icon {
|
|
font-size: 2rem;
|
|
margin-bottom: 10px;
|
|
display: inline-block;
|
|
width: 50px;
|
|
height: 50px;
|
|
line-height: 50px;
|
|
text-align: center;
|
|
border-radius: 50%;
|
|
}
|
|
.metric-value {
|
|
font-size: 2rem;
|
|
font-weight: bold;
|
|
}
|
|
.syncing {
|
|
color: #28a745;
|
|
animation: fa-spin 2s linear infinite;
|
|
}
|
|
</style>
|
|
{{end}}
|
|
{{define "content"}}
|
|
<div class="container my-4">
|
|
<div class="card-body p-0">
|
|
<div class="mb-3 position-relative">
|
|
<address-input
|
|
placeholder="Start typing an address (min 3 characters)"
|
|
api-key="{{ .MapboxToken }}">
|
|
</address-input>
|
|
</div>
|
|
<div class="mt-3">
|
|
</div>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="map-container" id="map-container">
|
|
<div id="map"></div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-6">
|
|
<div class="card-body p-0">
|
|
<address-display></address-display>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="district-display" class="mt-4 ">
|
|
<h5 class="mb-3">District Details</h5>
|
|
<div class="location-card p-3 mb-3">
|
|
<div class="district-detail">
|
|
<div class="detail-label">Agency</div>
|
|
<div class="detail-value" id="district-agency">-</div>
|
|
</div>
|
|
<div class="district-detail">
|
|
<div class="detail-label">Manager</div>
|
|
<div class="agency detail-value" id="district-manager">-</div>
|
|
</div>
|
|
<div class="district-detail">
|
|
<div class="detail-label">Phone</div>
|
|
<div class="agency detail-value" id="district-phone">-</div>
|
|
</div>
|
|
<div class="district-detail">
|
|
<div class="detail-label">Website</div>
|
|
<div class="agency detail-value" id="district-website">-</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|