From 7c3dd9820e59ad532ca0de129ccea6e1e5edcbaa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:08:06 +0000 Subject: [PATCH 1/3] Initial plan From df9560ed7148c9e2baf54058b3caee9a7d909dd5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:12:22 +0000 Subject: [PATCH 2/3] fix: restore module map bootstrap Co-authored-by: SolutionsAsService <152567394+SolutionsAsService@users.noreply.github.com> --- index.html | 6 -- js/app.js | 233 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 151 insertions(+), 88 deletions(-) diff --git a/index.html b/index.html index 690da02..9cab254 100644 --- a/index.html +++ b/index.html @@ -281,12 +281,6 @@

- - - - - - diff --git a/js/app.js b/js/app.js index 7667065..ec0f8e3 100644 --- a/js/app.js +++ b/js/app.js @@ -65,7 +65,9 @@ let mapState = { simulation: null, width: 0, - height: 0 + height: 0, + isInitializing: false, + hasInitialized: false }; @@ -73,11 +75,48 @@ let mapState = { // START APPLICATION // ============================================================ -document.addEventListener("DOMContentLoaded", () => { +if (document.readyState === "loading") { - initializeMap(); + document.addEventListener( + "DOMContentLoaded", + startApplication, + { once: true } + ); + +} + +else { + + startApplication(); + +} + +function startApplication() { + + if ( + mapState.isInitializing || + mapState.hasInitialized + ) { + + console.warn( + "Map initialization skipped because it already ran." + ); + + return; + + } -}); + + mapState.isInitializing = true; + + initializeMap() + .finally(() => { + + mapState.isInitializing = false; + + }); + +} // ============================================================ @@ -268,6 +307,8 @@ async function initializeMap() { "Internet Infrastructure Map Ready" ); + mapState.hasInitialized = true; + } catch (error) { @@ -580,7 +621,6 @@ function renderLinks() { // NODES // ============================================================ -```js function renderNodes() { mapState.nodeElements = @@ -614,17 +654,12 @@ function renderNodes() { .attr( "fill", - d => - colorForType( - d.type || - d.layer || - "physical" - ) + resolveNodeColor ) .attr( "stroke", - COLORS.effects.selection + getNodeStrokeColor() ) .attr( @@ -652,7 +687,7 @@ function renderNodes() { .attr( "stroke", - COLORS.state.selected + getNodeHoverStrokeColor() ) .attr( @@ -672,7 +707,7 @@ function renderNodes() { .attr( "stroke", - COLORS.effects.selection + getNodeStrokeColor() ) .attr( @@ -699,93 +734,128 @@ function renderNodes() { } +// ============================================================ +// NODE SIZE +// ============================================================ +function getNodeRadius(node) { - // -------------------------------------------------------- - // HOVER - // -------------------------------------------------------- + const importance = + Number(node.importance) || 5; - mapState.nodeElements - .on( - "mouseenter", - function () { + /* + * Keep node sizes controlled. + * + * Importance 1-10 becomes approximately + * 10px-28px. + */ - d3.select(this) + return Math.max( + 9, + Math.min( + 28, + 8 + importance * 2 + ) + ); - .attr( - "stroke", - "#ffffff" - ) +} - .attr( - "stroke-width", - 3 - ); +function resolveNodeColor(node) { - } - ) + const importedColor = + colorForType( + node?.type || + node?.layer || + "physical" + ); - .on( - "mouseleave", - function () { + if (importedColor) { - d3.select(this) + return importedColor; - .attr( - "stroke", - "#000000" - ) + } - .attr( - "stroke-width", - 2 - ); - } - ) + return ( + resolveColorToken(node?.type) || + resolveColorToken(node?.layer) || + resolveColorToken("default") || + "#60A5FA" + ); +} - .on( - "click", - function (event, node) { +function getNodeStrokeColor() { - showDetails( - event, - node - ); + return ( + resolveColorToken("selection") || + resolveColorToken("white") || + "#FFFFFF" + ); - } - ); +} + +function getNodeHoverStrokeColor() { + + return ( + resolveColorToken("selected") || + getNodeStrokeColor() + ); } +function getLabelColor() { -// ============================================================ -// NODE SIZE -// ============================================================ + return ( + resolveColorToken("text") || + resolveColorToken("white") || + "#E6EDF3" + ); -function getNodeRadius(node) { +} - const importance = - Number(node.importance) || 5; +function resolveColorToken(token) { + if (!token || typeof token !== "string") { - /* - * Keep node sizes controlled. - * - * Importance 1-10 becomes approximately - * 10px-28px. - */ + return null; + + } + + + if (typeof COLORS[token] === "string") { + + return COLORS[token]; + + } - return Math.max( - 9, - Math.min( - 28, - 8 + importance * 2 - ) - ); + + const normalized = + token + .toLowerCase() + .replace(/[\s_-]+/g, ""); + + + for (const [key, value] of Object.entries(COLORS)) { + + if ( + typeof value === "string" && + key + .toLowerCase() + .replace(/[\s_-]+/g, "") === + normalized + ) { + + return value; + + } + + } + + + return null; } @@ -824,7 +894,7 @@ function renderLabels() { .attr( "fill", - "COLORS.text" + getLabelColor() ) .attr( @@ -1325,7 +1395,7 @@ function setupLayerFilters() { // GLOBAL FILTER FUNCTION // ============================================================ -window.filterLayer = function (layer) { +function filterLayer(layer) { if (!mapState.nodeElements) { @@ -1443,7 +1513,7 @@ window.filterLayer = function (layer) { } ); -}; +} // ============================================================ @@ -1745,7 +1815,7 @@ function escapeHTML(value) { // RESET VIEW // ============================================================ -window.resetView = function () { +function resetView() { if ( !mapState.svg || @@ -1768,7 +1838,7 @@ window.resetView = function () { d3.zoomIdentity ); -}; +} // ============================================================ @@ -1784,10 +1854,10 @@ function setupGlobalFunctions() { */ window.resetView = - window.resetView; + resetView; window.filterLayer = - window.filterLayer; + filterLayer; } @@ -1931,4 +2001,3 @@ function handleMapError(error) { `; } - From 33603e2a81577f9ff5f747a5c5c6400eba17cfc8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:13:46 +0000 Subject: [PATCH 3/3] perf: cache normalized color lookup Co-authored-by: SolutionsAsService <152567394+SolutionsAsService@users.noreply.github.com> --- js/app.js | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/js/app.js b/js/app.js index ec0f8e3..e8e08f4 100644 --- a/js/app.js +++ b/js/app.js @@ -70,6 +70,9 @@ let mapState = { hasInitialized: false }; +const normalizedColorLookup = + buildNormalizedColorLookup(); + // ============================================================ // START APPLICATION @@ -837,25 +840,39 @@ function resolveColorToken(token) { .toLowerCase() .replace(/[\s_-]+/g, ""); + return normalizedColorLookup.get( + normalized + ) || null; - for (const [key, value] of Object.entries(COLORS)) { +} - if ( - typeof value === "string" && - key - .toLowerCase() - .replace(/[\s_-]+/g, "") === - normalized - ) { +function buildNormalizedColorLookup() { - return value; + const lookup = new Map(); - } - } + Object.entries(COLORS).forEach( + ([key, value]) => { + + if (typeof value !== "string") { + + return; + + } + + + lookup.set( + key + .toLowerCase() + .replace(/[\s_-]+/g, ""), + value + ); + + } + ); - return null; + return lookup; }