From 328d8c9e4528826fce975212aabc4135267e2a7c Mon Sep 17 00:00:00 2001 From: Tim Dykes Date: Fri, 13 Feb 2026 12:42:22 +1100 Subject: [PATCH 1/9] 4 colour theory on unit polygon fill (#308) --- src/pages/tasking/mapLayers/geoservices.js | 15 +- src/pages/tasking/utils/unitColorMap.js | 237 +++++++++++++++++++++ 2 files changed, 240 insertions(+), 12 deletions(-) create mode 100644 src/pages/tasking/utils/unitColorMap.js diff --git a/src/pages/tasking/mapLayers/geoservices.js b/src/pages/tasking/mapLayers/geoservices.js index 67dfce1e..cea5e80b 100644 --- a/src/pages/tasking/mapLayers/geoservices.js +++ b/src/pages/tasking/mapLayers/geoservices.js @@ -1,4 +1,5 @@ import BeaconClient from "../../../shared/BeaconClient"; +import { unitColorMap } from "../utils/unitColorMap"; import L from "leaflet"; @@ -152,7 +153,7 @@ export function registerSESUnitsZonesHybridGridLayer(vm, map) { drawFn: (layerGroup, data) => { if (!data) return; - const LABEL_ZOOM_THRESHOLD = 10; // tweak to taste + const LABEL_ZOOM_THRESHOLD = 9; // tweak to taste const vectorGrid = L.vectorGrid.protobuf( `https://map.lighthouse-extension.com/sesunits/tiles/{z}/{x}/{y}.pbf`, // Replace with actual path @@ -266,16 +267,7 @@ function zoneFillColor(code) { function colorByUnitCode(code) { if (!code) return '#999'; - - let hash = 0; - for (let i = 0; i < code.length; i++) { - hash = (hash << 5) - hash + code.charCodeAt(i); - hash |= 0; - } - - // Spread around 360° hue wheel - const hue = Math.abs(hash) % 360; - return `hsl(${hue}, 70%, 50%)`; + return unitColorMap[code] || '#999'; } @@ -311,7 +303,6 @@ export function registerSESUnitLocationsLayer(vm) { marker.on('popupopen', async () => { try { const details = await vm.fetchHQDetails(feature.properties.HQNAME); - console.log("Fetched HQ details for popup:", details); const popupContent = `
${name} diff --git a/src/pages/tasking/utils/unitColorMap.js b/src/pages/tasking/utils/unitColorMap.js new file mode 100644 index 00000000..7cc5d5d2 --- /dev/null +++ b/src/pages/tasking/utils/unitColorMap.js @@ -0,0 +1,237 @@ +// Auto-generated by unitColors.js – 2026-02-13T01:14:22.306Z +// Maps SES UNITCODE → hex colour (4-colour theorem) +export const unitColorMap = { + "WGT": "#4363d8", + "WWY": "#e6194b", + "CCX": "#f58231", + "WAL": "#3cb44b", + "WBN": "#e6194b", + "YNG": "#4363d8", + "NRN": "#f58231", + "WGA": "#e6194b", + "LPS": "#3cb44b", + "OOM": "#e6194b", + "WRN": "#3cb44b", + "BDN": "#4363d8", + "LSY": "#3cb44b", + "BRW": "#3cb44b", + "MOL": "#e6194b", + "GUN": "#f58231", + "NAA": "#3cb44b", + "ARM": "#e6194b", + "COP": "#3cb44b", + "CLB": "#e6194b", + "HIL": "#f58231", + "CWT": "#3cb44b", + "CON": "#f58231", + "CLR": "#e6194b", + "WHT": "#e6194b", + "NME": "#4363d8", + "GLS": "#f58231", + "KPS": "#4363d8", + "TAR": "#e6194b", + "BIN": "#e6194b", + "WRI": "#3cb44b", + "IVL": "#f58231", + "BNG": "#f58231", + "COB": "#4363d8", + "MGE": "#3cb44b", + "MRE": "#f58231", + "MWA": "#f58231", + "DUN": "#e6194b", + "URL": "#f58231", + "BAY": "#e6194b", + "NOW": "#f58231", + "TMT": "#3cb44b", + "FBS": "#4363d8", + "BWR": "#f58231", + "OAG": "#f58231", + "NYN": "#e6194b", + "CBL": "#e6194b", + "GIL": "#f58231", + "WHP": "#f58231", + "STO": "#e6194b", + "CAS": "#f58231", + "DEP": "#4363d8", + "IVH": "#e6194b", + "GUY": "#3cb44b", + "BAB": "#4363d8", + "GBN": "#4363d8", + "LAW": "#f58231", + "ULM": "#3cb44b", + "MCL": "#4363d8", + "MSV": "#e6194b", + "CCN": "#f58231", + "HAY": "#4363d8", + "GND": "#4363d8", + "DQN": "#3cb44b", + "URN": "#4363d8", + "GLG": "#3cb44b", + "TMW": "#e6194b", + "CAW": "#4363d8", + "EUG": "#f58231", + "SYD": "#3cb44b", + "BKE": "#3cb44b", + "DBO": "#3cb44b", + "PIL": "#f58231", + "NUN": "#4363d8", + "KYG": "#e6194b", + "TAB": "#4363d8", + "ASH": "#e6194b", + "TEN": "#f58231", + "TGA": "#4363d8", + "MEN": "#3cb44b", + "WTN": "#4363d8", + "PTS": "#3cb44b", + "MBH": "#4363d8", + "ASL": "#e6194b", + "CFS": "#3cb44b", + "BEL": "#f58231", + "DOR": "#4363d8", + "HDN": "#3cb44b", + "YAS": "#f58231", + "SHE": "#4363d8", + "BRD": "#3cb44b", + "CLM": "#4363d8", + "CTA": "#e6194b", + "BAR": "#e6194b", + "JER": "#f58231", + "JUN": "#3cb44b", + "TEM": "#f58231", + "PKE": "#3cb44b", + "TDL": "#e6194b", + "EUA": "#3cb44b", + "BOM": "#3cb44b", + "CFL": "#4363d8", + "SNO": "#4363d8", + "BLY": "#e6194b", + "MAR": "#4363d8", + "BUR": "#4363d8", + "WLC": "#f58231", + "WIL": "#f58231", + "MUN": "#3cb44b", + "LRG": "#3cb44b", + "GGY": "#e6194b", + "WWA": "#e6194b", + "WGM": "#4363d8", + "NAB": "#3cb44b", + "CHV": "#3cb44b", + "NAM": "#3cb44b", + "MNL": "#3cb44b", + "BAL": "#4363d8", + "MUL": "#e6194b", + "GLN": "#e6194b", + "BEG": "#4363d8", + "ULD": "#4363d8", + "WNT": "#4363d8", + "BIG": "#e6194b", + "GAH": "#e6194b", + "MOU": "#4363d8", + "BHQ": "#f58231", + "WDL": "#e6194b", + "GRF": "#4363d8", + "TOC": "#e6194b", + "CWA": "#3cb44b", + "HBK": "#4363d8", + "GRI": "#4363d8", + "LCG": "#4363d8", + "MUR": "#4363d8", + "TRK": "#3cb44b", + "GFL": "#f58231", + "PKH": "#f58231", + "TUM": "#f58231", + "YUR": "#e6194b", + "GDA": "#4363d8", + "KMA": "#3cb44b", + "KOG": "#4363d8", + "CAR": "#f58231", + "CBI": "#f58231", + "FPP": "#4363d8", + "MDI": "#f58231", + "BWT": "#f58231", + "CKI": "#4363d8", + "YET": "#4363d8", + "URB": "#3cb44b", + "BGI": "#3cb44b", + "BGA": "#e6194b", + "BOG": "#f58231", + "TSP": "#e6194b", + "BRI": "#e6194b", + "BMB": "#e6194b", + "TWC": "#3cb44b", + "PAC": "#3cb44b", + "TIB": "#4363d8", + "STN": "#3cb44b", + "BSH": "#e6194b", + "URG": "#e6194b", + "RWK": "#4363d8", + "SWN": "#4363d8", + "LTN": "#3cb44b", + "PTM": "#e6194b", + "KHN": "#e6194b", + "COR": "#4363d8", + "QBN": "#e6194b", + "WVW": "#e6194b", + "NSY": "#e6194b", + "GLD": "#e6194b", + "ABD": "#3cb44b", + "TOM": "#4363d8", + "HAR": "#4363d8", + "EDN": "#e6194b", + "TWH": "#e6194b", + "DPT": "#3cb44b", + "SGB": "#3cb44b", + "YAM": "#3cb44b", + "MOA": "#3cb44b", + "ABX": "#e6194b", + "SWE": "#3cb44b", + "HHL": "#e6194b", + "MOS": "#3cb44b", + "MAN": "#3cb44b", + "LHI": "#e6194b", + "SCN": "#e6194b", + "BTH": "#4363d8", + "CRK": "#3cb44b", + "CBY": "#3cb44b", + "DNG": "#4363d8", + "HVL": "#f58231", + "SUD": "#3cb44b", + "WPW": "#4363d8", + "RYL": "#4363d8", + "MBK": "#4363d8", + "RYD": "#4363d8", + "WOL": "#e6194b", + "WCB": "#f58231", + "CAN": "#3cb44b", + "STR": "#e6194b", + "OBR": "#f58231", + "WYG": "#e6194b", + "SOF": "#f58231", + "COO": "#3cb44b", + "LMQ": "#e6194b", + "MAI": "#e6194b", + "NTL": "#f58231", + "DEN": "#e6194b", + "KRG": "#3cb44b", + "FFD": "#f58231", + "HAW": "#f58231", + "PEN": "#3cb44b", + "BTN": "#e6194b", + "BKK": "#4363d8", + "LVP": "#e6194b", + "AUB": "#3cb44b", + "HOL": "#4363d8", + "BLU": "#e6194b", + "GOS": "#3cb44b", + "LGW": "#3cb44b", + "PRT": "#e6194b", + "CES": "#4363d8", + "SIN": "#3cb44b", + "HBY": "#e6194b", + "HLS": "#4363d8", + "WDY": "#4363d8", + "PAR": "#f58231", + "CAM": "#3cb44b", + "CTN": "#f58231", + "MDT": "#4363d8" +}; From 572cc41fc3cc21f79257429983409b5bf9c271f7 Mon Sep 17 00:00:00 2001 From: Tim Dykes Date: Fri, 13 Feb 2026 12:42:54 +1100 Subject: [PATCH 2/9] added a word to a notification (#307) --- src/pages/tasking/components/alerts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/tasking/components/alerts.js b/src/pages/tasking/components/alerts.js index 737bce70..3fcd424e 100644 --- a/src/pages/tasking/components/alerts.js +++ b/src/pages/tasking/components/alerts.js @@ -246,7 +246,7 @@ function buildDefaultRules(vm) { { id: 'unacked-notifications', level: 'danger', - title: 'Unacknowledged notifications', + title: 'Unacknowledged ICEMS notifications', active: unackedNotifications.length > 0, items: unackedNotifications.slice(0, 10).map(asItem), count: unackedNotifications.length, From 109b95d5ad580d25ffeb3feb330218f4dc1f81fe Mon Sep 17 00:00:00 2001 From: Tim Dykes Date: Fri, 13 Feb 2026 12:43:08 +1100 Subject: [PATCH 3/9] added map layer for power boundaries (#306) --- src/pages/tasking/main.js | 2 + src/pages/tasking/mapLayers/power.js | 95 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/pages/tasking/mapLayers/power.js diff --git a/src/pages/tasking/main.js b/src/pages/tasking/main.js index 5238810e..36eb33f5 100644 --- a/src/pages/tasking/main.js +++ b/src/pages/tasking/main.js @@ -56,6 +56,7 @@ import { registerSESUnitLocationsLayer } from "./mapLayers/geoservices.js"; import { registerTransportIncidentsLayer } from "./mapLayers/transport.js"; import { renderFRAOSLayer } from "./mapLayers/frao.js"; import { registerHazardWatchWarningsLayer } from "./mapLayers/hazardwatch.js" +import { registerPowerBoundariesGridLayer } from "./mapLayers/power.js"; import { fetchHqDetailsSummary } from './utils/hqSummary.js'; @@ -2143,6 +2144,7 @@ function VM() { registerHazardWatchWarningsLayer(self, apiHost); registerSESUnitLocationsLayer(self); renderFRAOSLayer(self, map, getToken, apiHost, params); + registerPowerBoundariesGridLayer(self, map); // --- Layers Drawer (under zoom) const LayersDrawer = L.Control.extend({ diff --git a/src/pages/tasking/mapLayers/power.js b/src/pages/tasking/mapLayers/power.js new file mode 100644 index 00000000..0ea1522e --- /dev/null +++ b/src/pages/tasking/mapLayers/power.js @@ -0,0 +1,95 @@ +import L from "leaflet"; + +export function registerPowerBoundariesGridLayer(vm, _map) { + vm.mapVM.registerPollingLayer("powerBoundaries", { + label: "Electrical Distribution Boundaries", + menuGroup: "Public Utilities", + refreshMs: 0, // No auto-refresh, only redraw on filter change + visibleByDefault: localStorage.getItem(`ov.powerBoundaries`) || false, + fetchFn: async () => { + return {}; + }, + drawFn: (layerGroup, data) => { + + if (!data) return; + + const vectorGrid = L.vectorGrid.protobuf( + `https://map.lighthouse-extension.com/power/tiles/{z}/{x}/{y}.pbf`, + { + pane: 'pane-lowest', + vectorTileLayerStyles: { + 'ausgrid_boundary': (_props) => { + return { + weight: 1.2, + color: '#333', + opacity: 1, + fill: true, + fillColor: '#ff7800', + fillOpacity: 0.3 + }; + }, + 'endeavour_boundary': (_props) => { + return { + weight: 1.2, + color: '#333', + opacity: 1, + fill: true, + fillColor: '#26229cff', + fillOpacity: 0.3 + }; + }, + 'essential_boundary': (_props) => { + return { + weight: 1.2, + color: '#333', + opacity: 1, + fill: true, + fillColor: '#74ac7aff', + fillOpacity: 0.3 + }; + }, + 'evo_boundary': (_props) => { + return { + weight: 1.2, + color: '#333', + opacity: 1, + fill: true, + fillColor: '#812e2eff', + fillOpacity: 0.3 + }; + }, + }, + interactive: true + }); + + + layerGroup.addLayer(vectorGrid); + + const powerLabelLayer = L.geoJSON(null, { + pointToLayer: (feature, latlng) => { + const name = feature.properties.name; + return L.marker(latlng, { + interactive: false, + pane: 'pane-middle-plus', + icon: L.divIcon({ + className: 'unit-label', + html: name, + iconSize: [0, 0] + }) + }); + } + }); + + + // Load unit labels + fetch('https://map.lighthouse-extension.com/power/power_labels.geojson') + .then(r => r.json()) + .then(data => { + powerLabelLayer.addData(data); + layerGroup.addLayer(powerLabelLayer) + }); + + + }, + }); +} \ No newline at end of file From bd3e968aae4ce1025e0f9e0d37682c2de7cfd776 Mon Sep 17 00:00:00 2001 From: Tim Dykes Date: Sat, 14 Feb 2026 09:42:50 +1100 Subject: [PATCH 4/9] google maps js-api-loader removal (#310) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit leaflet-geosearch optionally depends on @googlemaps/js-api-loader which dynamically injects