@fusedashlabs/widgets 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/components/chart-renderer/element/ui9000-chart-renderer.d.ts.map +1 -1
- package/dist/components/chart-renderer/element/ui9000-chart-renderer.js +7 -3
- package/dist/components/chart-renderer/element/ui9000-chart-renderer.js.map +1 -1
- package/dist/components/kpi-widget/lib/normalize.d.ts.map +1 -1
- package/dist/components/kpi-widget/lib/normalize.js +26 -7
- package/dist/components/kpi-widget/lib/normalize.js.map +1 -1
- package/dist/components/map-chart/element/ui9000-map-chart.d.ts +1 -0
- package/dist/components/map-chart/element/ui9000-map-chart.d.ts.map +1 -1
- package/dist/components/map-chart/element/ui9000-map-chart.js +12 -4
- package/dist/components/map-chart/element/ui9000-map-chart.js.map +1 -1
- package/dist/components/map-chart/lib/geojson.d.ts.map +1 -1
- package/dist/components/map-chart/lib/geojson.js +3 -1
- package/dist/components/map-chart/lib/geojson.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.4.3 — 2026-09-07
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- KPI widget unwraps signed data-link envelopes (`data.items` / `config.items`) instead of treating the persist wrapper as a single empty KPI.
|
|
10
|
+
|
|
11
|
+
## 0.4.2 — 2026-09-07
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Map chart: set host attrs before connecting the custom element, read `MAP_GEOJSON_BASE_URL` from `__RUNTIME_CONFIG__`, and do not cache failed GeoJSON fetches. Empty state distinguishes a failed boundaries download from a missing host URL.
|
|
16
|
+
|
|
5
17
|
## 0.4.1 — 2026-09-07
|
|
6
18
|
|
|
7
19
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui9000-chart-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/chart-renderer/element/ui9000-chart-renderer.ts"],"names":[],"mappings":"AAsBA,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAcxC;IAED,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,WAAW,CAAK;IAExB,iBAAiB,IAAI,IAAI;IAqBzB,wBAAwB,IAAI,IAAI;IAIhC,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,SAAS;YAgBH,UAAU;
|
|
1
|
+
{"version":3,"file":"ui9000-chart-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/chart-renderer/element/ui9000-chart-renderer.ts"],"names":[],"mappings":"AAsBA,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAcxC;IAED,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,WAAW,CAAK;IAExB,iBAAiB,IAAI,IAAI;IAqBzB,wBAAwB,IAAI,IAAI;IAIhC,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,SAAS;YAgBH,UAAU;CAqFzB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,uBAAuB,EAAE,mBAAmB,CAAC;KAC9C;CACF;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C"}
|
|
@@ -122,11 +122,11 @@ class Ui9000ChartRenderer extends HTMLElement {
|
|
|
122
122
|
const widget = parseJsonAttr(this.dataJson, null);
|
|
123
123
|
const title = this.getAttribute("show-header") === "false" ? "" : ((_a = this.getAttribute("chart-title")) == null ? void 0 : _a.trim()) || (widget && typeof widget === "object" ? (_b = widget.name) == null ? void 0 : _b.trim() : "") || "";
|
|
124
124
|
let el = this._host.firstElementChild;
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
const reuse = !!el && el.tagName.toLowerCase() === target.tag;
|
|
126
|
+
if (!reuse) {
|
|
127
127
|
el = document.createElement(target.tag);
|
|
128
|
-
this._host.appendChild(el);
|
|
129
128
|
}
|
|
129
|
+
if (!el) return;
|
|
130
130
|
el.setAttribute("data", this.dataJson);
|
|
131
131
|
el.setAttribute("scale", this.scale);
|
|
132
132
|
if (title) el.setAttribute("chart-title", title);
|
|
@@ -157,6 +157,10 @@ class Ui9000ChartRenderer extends HTMLElement {
|
|
|
157
157
|
el.style.display = "block";
|
|
158
158
|
el.style.width = "100%";
|
|
159
159
|
el.style.height = "100%";
|
|
160
|
+
if (!reuse) {
|
|
161
|
+
this._host.replaceChildren();
|
|
162
|
+
this._host.appendChild(el);
|
|
163
|
+
}
|
|
160
164
|
this._empty.hidden = true;
|
|
161
165
|
this._host.hidden = false;
|
|
162
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui9000-chart-renderer.js","sources":["../../../../src/components/chart-renderer/element/ui9000-chart-renderer.ts"],"sourcesContent":["import { loadChart } from '../../../lazy/index.js';\nimport type { WidgetScale } from '../../../types/index.js';\nimport { parseJsonAttr } from '../../../utils/chart-helpers.js';\nimport {\n resolveChartTarget,\n resolveWidgetChartType,\n type ChartTargetAttrs,\n} from '../lib/index.js';\nimport { chartRendererStyles } from './styles.js';\n\nfunction applyTargetAttrs(el: HTMLElement, attrs?: ChartTargetAttrs): void {\n if (!attrs) return;\n for (const [key, value] of Object.entries(attrs)) {\n if (typeof value === 'boolean') {\n if (value) el.setAttribute(key, '');\n else el.removeAttribute(key);\n } else {\n el.setAttribute(key, String(value));\n }\n }\n}\n\nexport class Ui9000ChartRenderer extends HTMLElement {\n static get observedAttributes(): string[] {\n return [\n 'data',\n 'chart-type',\n 'scale',\n 'show-grid',\n 'show-legend',\n 'show-tooltip',\n 'show-header',\n 'chart-title',\n 'mapbox-token',\n 'geojson-base-url',\n 'pmtiles-base-url',\n ];\n }\n\n private _host: HTMLDivElement | null = null;\n private _empty: HTMLDivElement | null = null;\n private _mountToken = 0;\n\n connectedCallback(): void {\n if (this._host) return;\n const root = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = chartRendererStyles.cssText;\n root.appendChild(style);\n\n this._host = document.createElement('div');\n this._host.className = 'host';\n this._host.part = 'chart';\n root.appendChild(this._host);\n\n this._empty = document.createElement('div');\n this._empty.className = 'empty';\n this._empty.part = 'empty';\n this._empty.hidden = true;\n root.appendChild(this._empty);\n\n void this.mountChart();\n }\n\n attributeChangedCallback(): void {\n if (this._host) void this.mountChart();\n }\n\n private get dataJson(): string {\n return this.getAttribute('data') ?? '{}';\n }\n\n private get chartTypeAttr(): string {\n return this.getAttribute('chart-type') ?? '';\n }\n\n private get scale(): WidgetScale {\n return (this.getAttribute('scale') as WidgetScale) || 'default';\n }\n\n private applyBoolProp(el: HTMLElement, attr: string, prop: string): void {\n if (!this.hasAttribute(attr)) return;\n const on = this.getAttribute(attr) !== 'false';\n (el as unknown as Record<string, unknown>)[prop] = on;\n }\n\n private copyHostAttr(el: HTMLElement, name: string): void {\n const value = this.getAttribute(name);\n if (value) el.setAttribute(name, value);\n else el.removeAttribute(name);\n }\n\n private boolAttr(name: string): boolean | undefined {\n if (!this.hasAttribute(name)) return undefined;\n return this.getAttribute(name) !== 'false';\n }\n\n private showEmpty(message: string, detail?: string): void {\n if (!this._empty || !this._host) return;\n this._host.replaceChildren();\n this._host.hidden = true;\n this._empty.hidden = false;\n this._empty.replaceChildren();\n const strong = document.createElement('strong');\n strong.textContent = message;\n this._empty.appendChild(strong);\n if (detail) {\n const p = document.createElement('span');\n p.textContent = detail;\n this._empty.appendChild(p);\n }\n }\n\n private async mountChart(): Promise<void> {\n if (!this._host || !this._empty) return;\n const token = ++this._mountToken;\n\n const chartType = resolveWidgetChartType(this.dataJson, this.chartTypeAttr);\n if (!chartType) {\n this.showEmpty('No chart type', 'Pass chart-type or a widget payload with chartType.');\n return;\n }\n\n const target = resolveChartTarget(chartType);\n if (!target) {\n this.showEmpty(\n 'Unsupported chart type',\n `\"${chartType}\" is not available in @ui9000/widgets yet.`,\n );\n return;\n }\n\n try {\n await loadChart(target.kind);\n } catch {\n if (token !== this._mountToken) return;\n this.showEmpty('Failed to load chart', target.kind);\n return;\n }\n\n if (token !== this._mountToken) return;\n\n const widget = parseJsonAttr<{ name?: string } | null>(this.dataJson, null);\n const title =\n this.getAttribute('show-header') === 'false'\n ? ''\n : this.getAttribute('chart-title')?.trim() ||\n (widget && typeof widget === 'object' ? widget.name?.trim() : '') ||\n '';\n\n let el = this._host.firstElementChild as HTMLElement | null;\n if (!el || el.tagName.toLowerCase() !== target.tag) {\n this._host.replaceChildren();\n el = document.createElement(target.tag);\n this._host.appendChild(el);\n }\n\n el.setAttribute('data', this.dataJson);\n el.setAttribute('scale', this.scale);\n if (title) el.setAttribute('chart-title', title);\n else el.removeAttribute('chart-title');\n\n const showGrid = this.boolAttr('show-grid');\n const showLegend = this.boolAttr('show-legend');\n const showTooltip = this.boolAttr('show-tooltip');\n if (showGrid !== undefined) {\n if (showGrid) el.setAttribute('show-grid', '');\n else el.setAttribute('show-grid', 'false');\n }\n if (showLegend !== undefined) {\n if (showLegend) el.setAttribute('show-legend', '');\n else el.setAttribute('show-legend', 'false');\n }\n if (showTooltip !== undefined) {\n if (showTooltip) el.setAttribute('show-tooltip', '');\n else el.setAttribute('show-tooltip', 'false');\n }\n this.applyBoolProp(el, 'show-header', 'showHeader');\n this.applyBoolProp(el, 'show-grid', 'showGrid');\n this.applyBoolProp(el, 'show-legend', 'showLegend');\n this.applyBoolProp(el, 'show-tooltip', 'showTooltip');\n\n applyTargetAttrs(el, target.attrs);\n this.copyHostAttr(el, 'mapbox-token');\n this.copyHostAttr(el, 'geojson-base-url');\n this.copyHostAttr(el, 'pmtiles-base-url');\n el.style.display = 'block';\n el.style.width = '100%';\n el.style.height = '100%';\n\n this._empty.hidden = true;\n this._host.hidden = false;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ui9000-chart-renderer': Ui9000ChartRenderer;\n }\n}\n\nexport function registerChartRenderer(): void {\n if (!customElements.get('ui9000-chart-renderer')) {\n customElements.define('ui9000-chart-renderer', Ui9000ChartRenderer);\n }\n}\n\nregisterChartRenderer();\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ui9000-chart-renderer.js","sources":["../../../../src/components/chart-renderer/element/ui9000-chart-renderer.ts"],"sourcesContent":["import { loadChart } from '../../../lazy/index.js';\nimport type { WidgetScale } from '../../../types/index.js';\nimport { parseJsonAttr } from '../../../utils/chart-helpers.js';\nimport {\n resolveChartTarget,\n resolveWidgetChartType,\n type ChartTargetAttrs,\n} from '../lib/index.js';\nimport { chartRendererStyles } from './styles.js';\n\nfunction applyTargetAttrs(el: HTMLElement, attrs?: ChartTargetAttrs): void {\n if (!attrs) return;\n for (const [key, value] of Object.entries(attrs)) {\n if (typeof value === 'boolean') {\n if (value) el.setAttribute(key, '');\n else el.removeAttribute(key);\n } else {\n el.setAttribute(key, String(value));\n }\n }\n}\n\nexport class Ui9000ChartRenderer extends HTMLElement {\n static get observedAttributes(): string[] {\n return [\n 'data',\n 'chart-type',\n 'scale',\n 'show-grid',\n 'show-legend',\n 'show-tooltip',\n 'show-header',\n 'chart-title',\n 'mapbox-token',\n 'geojson-base-url',\n 'pmtiles-base-url',\n ];\n }\n\n private _host: HTMLDivElement | null = null;\n private _empty: HTMLDivElement | null = null;\n private _mountToken = 0;\n\n connectedCallback(): void {\n if (this._host) return;\n const root = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = chartRendererStyles.cssText;\n root.appendChild(style);\n\n this._host = document.createElement('div');\n this._host.className = 'host';\n this._host.part = 'chart';\n root.appendChild(this._host);\n\n this._empty = document.createElement('div');\n this._empty.className = 'empty';\n this._empty.part = 'empty';\n this._empty.hidden = true;\n root.appendChild(this._empty);\n\n void this.mountChart();\n }\n\n attributeChangedCallback(): void {\n if (this._host) void this.mountChart();\n }\n\n private get dataJson(): string {\n return this.getAttribute('data') ?? '{}';\n }\n\n private get chartTypeAttr(): string {\n return this.getAttribute('chart-type') ?? '';\n }\n\n private get scale(): WidgetScale {\n return (this.getAttribute('scale') as WidgetScale) || 'default';\n }\n\n private applyBoolProp(el: HTMLElement, attr: string, prop: string): void {\n if (!this.hasAttribute(attr)) return;\n const on = this.getAttribute(attr) !== 'false';\n (el as unknown as Record<string, unknown>)[prop] = on;\n }\n\n private copyHostAttr(el: HTMLElement, name: string): void {\n const value = this.getAttribute(name);\n if (value) el.setAttribute(name, value);\n else el.removeAttribute(name);\n }\n\n private boolAttr(name: string): boolean | undefined {\n if (!this.hasAttribute(name)) return undefined;\n return this.getAttribute(name) !== 'false';\n }\n\n private showEmpty(message: string, detail?: string): void {\n if (!this._empty || !this._host) return;\n this._host.replaceChildren();\n this._host.hidden = true;\n this._empty.hidden = false;\n this._empty.replaceChildren();\n const strong = document.createElement('strong');\n strong.textContent = message;\n this._empty.appendChild(strong);\n if (detail) {\n const p = document.createElement('span');\n p.textContent = detail;\n this._empty.appendChild(p);\n }\n }\n\n private async mountChart(): Promise<void> {\n if (!this._host || !this._empty) return;\n const token = ++this._mountToken;\n\n const chartType = resolveWidgetChartType(this.dataJson, this.chartTypeAttr);\n if (!chartType) {\n this.showEmpty('No chart type', 'Pass chart-type or a widget payload with chartType.');\n return;\n }\n\n const target = resolveChartTarget(chartType);\n if (!target) {\n this.showEmpty(\n 'Unsupported chart type',\n `\"${chartType}\" is not available in @ui9000/widgets yet.`,\n );\n return;\n }\n\n try {\n await loadChart(target.kind);\n } catch {\n if (token !== this._mountToken) return;\n this.showEmpty('Failed to load chart', target.kind);\n return;\n }\n\n if (token !== this._mountToken) return;\n\n const widget = parseJsonAttr<{ name?: string } | null>(this.dataJson, null);\n const title =\n this.getAttribute('show-header') === 'false'\n ? ''\n : this.getAttribute('chart-title')?.trim() ||\n (widget && typeof widget === 'object' ? widget.name?.trim() : '') ||\n '';\n\n let el = this._host.firstElementChild as HTMLElement | null;\n const reuse = !!el && el.tagName.toLowerCase() === target.tag;\n if (!reuse) {\n el = document.createElement(target.tag);\n }\n if (!el) return;\n\n el.setAttribute('data', this.dataJson);\n el.setAttribute('scale', this.scale);\n if (title) el.setAttribute('chart-title', title);\n else el.removeAttribute('chart-title');\n\n const showGrid = this.boolAttr('show-grid');\n const showLegend = this.boolAttr('show-legend');\n const showTooltip = this.boolAttr('show-tooltip');\n if (showGrid !== undefined) {\n if (showGrid) el.setAttribute('show-grid', '');\n else el.setAttribute('show-grid', 'false');\n }\n if (showLegend !== undefined) {\n if (showLegend) el.setAttribute('show-legend', '');\n else el.setAttribute('show-legend', 'false');\n }\n if (showTooltip !== undefined) {\n if (showTooltip) el.setAttribute('show-tooltip', '');\n else el.setAttribute('show-tooltip', 'false');\n }\n this.applyBoolProp(el, 'show-header', 'showHeader');\n this.applyBoolProp(el, 'show-grid', 'showGrid');\n this.applyBoolProp(el, 'show-legend', 'showLegend');\n this.applyBoolProp(el, 'show-tooltip', 'showTooltip');\n\n applyTargetAttrs(el, target.attrs);\n this.copyHostAttr(el, 'mapbox-token');\n this.copyHostAttr(el, 'geojson-base-url');\n this.copyHostAttr(el, 'pmtiles-base-url');\n el.style.display = 'block';\n el.style.width = '100%';\n el.style.height = '100%';\n\n if (!reuse) {\n this._host.replaceChildren();\n this._host.appendChild(el);\n }\n\n this._empty.hidden = true;\n this._host.hidden = false;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ui9000-chart-renderer': Ui9000ChartRenderer;\n }\n}\n\nexport function registerChartRenderer(): void {\n if (!customElements.get('ui9000-chart-renderer')) {\n customElements.define('ui9000-chart-renderer', Ui9000ChartRenderer);\n }\n}\n\nregisterChartRenderer();\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAyC5E,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE5D;AAgFD,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAqBrE"}
|
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
import { isAdvancedKpiItem, extractCardsFromKpi } from "./extract.js";
|
|
2
2
|
const EMPTY = { layout: "empty", cards: [], supporting: [] };
|
|
3
3
|
function isRawKpiItem(input) {
|
|
4
|
-
|
|
4
|
+
if (input == null || typeof input !== "object" || Array.isArray(input)) return false;
|
|
5
|
+
const obj = input;
|
|
6
|
+
if (Array.isArray(obj.items) || Array.isArray(obj.kpis)) return false;
|
|
7
|
+
const nested = obj.data;
|
|
8
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
9
|
+
const inner = nested;
|
|
10
|
+
if (Array.isArray(inner.items) || Array.isArray(inner.kpis)) return false;
|
|
11
|
+
}
|
|
12
|
+
return "column" in obj || "type" in obj || Array.isArray(obj.data);
|
|
13
|
+
}
|
|
14
|
+
function asItemList(input) {
|
|
15
|
+
const obj = input;
|
|
16
|
+
if (Array.isArray(obj.items) && obj.items.every((row) => row && typeof row === "object")) {
|
|
17
|
+
return obj.items;
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(obj.kpis) && obj.kpis.every((row) => row && typeof row === "object")) {
|
|
20
|
+
return obj.kpis;
|
|
21
|
+
}
|
|
22
|
+
for (const candidate of [obj.data, obj.config]) {
|
|
23
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) continue;
|
|
24
|
+
const nested = asItemList(candidate);
|
|
25
|
+
if (nested) return nested;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
5
28
|
}
|
|
6
29
|
function isNormalizedModel(input) {
|
|
7
30
|
return Array.isArray(input.cards) && "layout" in input;
|
|
@@ -76,12 +99,8 @@ function normalizeKpiData(input) {
|
|
|
76
99
|
if (typeof input === "object") {
|
|
77
100
|
if (isNormalizedModel(input)) return input;
|
|
78
101
|
const topName = typeof input.name === "string" ? input.name : void 0;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
if (Array.isArray(input.kpis)) {
|
|
83
|
-
return buildFromItems(input.kpis, topName);
|
|
84
|
-
}
|
|
102
|
+
const items = asItemList(input);
|
|
103
|
+
if (items) return buildFromItems(items, topName);
|
|
85
104
|
if (isRawKpiItem(input)) {
|
|
86
105
|
return buildFromItems([input], topName);
|
|
87
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.js","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"sourcesContent":["import { extractCardsFromKpi, isAdvancedKpiItem } from './extract.js';\nimport type { KpiWidgetData, KpiWidgetModel, RawKpiItem } from './types.js';\n\nconst EMPTY: KpiWidgetModel = { layout: 'empty', cards: [], supporting: [] };\n\nfunction isRawKpiItem(input: unknown): input is RawKpiItem {\n
|
|
1
|
+
{"version":3,"file":"normalize.js","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"sourcesContent":["import { extractCardsFromKpi, isAdvancedKpiItem } from './extract.js';\nimport type { KpiWidgetData, KpiWidgetModel, RawKpiItem } from './types.js';\n\nconst EMPTY: KpiWidgetModel = { layout: 'empty', cards: [], supporting: [] };\n\nfunction isRawKpiItem(input: unknown): input is RawKpiItem {\n if (input == null || typeof input !== 'object' || Array.isArray(input)) return false;\n const obj = input as Record<string, unknown>;\n if (Array.isArray(obj.items) || Array.isArray(obj.kpis)) return false;\n const nested = obj.data;\n if (nested && typeof nested === 'object' && !Array.isArray(nested)) {\n const inner = nested as Record<string, unknown>;\n if (Array.isArray(inner.items) || Array.isArray(inner.kpis)) return false;\n }\n return 'column' in obj || 'type' in obj || Array.isArray(obj.data);\n}\n\nfunction asItemList(input: object): RawKpiItem[] | null {\n const obj = input as {\n items?: unknown;\n kpis?: unknown;\n data?: unknown;\n config?: unknown;\n };\n if (Array.isArray(obj.items) && obj.items.every((row) => row && typeof row === 'object')) {\n return obj.items as RawKpiItem[];\n }\n if (Array.isArray(obj.kpis) && obj.kpis.every((row) => row && typeof row === 'object')) {\n return obj.kpis as RawKpiItem[];\n }\n for (const candidate of [obj.data, obj.config]) {\n if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) continue;\n const nested = asItemList(candidate);\n if (nested) return nested;\n }\n return null;\n}\n\nfunction isNormalizedModel(input: object): input is KpiWidgetModel {\n return Array.isArray((input as KpiWidgetModel).cards) && 'layout' in input;\n}\n\n/** Client `extractGroupId` — groupName is `{label}-group-kpi-ids-{id}`. */\nexport function extractGroupId(value?: string | null): string {\n return value?.split('-group-kpi-ids-')?.[0] ?? '';\n}\n\nfunction sortItems(items: RawKpiItem[]): RawKpiItem[] {\n return [...items].sort((a, b) => {\n if (isAdvancedKpiItem(a) && !isAdvancedKpiItem(b)) return -1;\n if (!isAdvancedKpiItem(a) && isAdvancedKpiItem(b)) return 1;\n return 0;\n });\n}\n\nfunction footerFrom(items: RawKpiItem[]): Pick<\n KpiWidgetModel,\n 'target' | 'showTimestamp' | 'updatedAt'\n> {\n const first = items[0];\n return {\n target: first?.target,\n showTimestamp: first?.showTimestamp,\n updatedAt: first?.updatedAt,\n };\n}\n\nfunction sectionTitle(\n items: RawKpiItem[],\n advanced: boolean,\n topName?: string,\n): string | undefined {\n if (advanced) return undefined;\n if (items.length === 1) return items[0]?.name;\n const grouped = extractGroupId(items[0]?.groupName);\n if (grouped) return grouped;\n return topName?.trim() || undefined;\n}\n\nfunction buildFromItems(items: RawKpiItem[], topName?: string): KpiWidgetModel {\n if (!items.length) return EMPTY;\n const sorted = sortItems(items);\n const advancedIndex = sorted.findIndex(isAdvancedKpiItem);\n const advanced = advancedIndex >= 0;\n const footer = footerFrom(sorted);\n\n if (advanced) {\n const mainItem = sorted[advancedIndex]!;\n const mainCards = extractCardsFromKpi(mainItem);\n const main = mainCards[0];\n const supporting = sorted\n .filter((_, i) => i !== advancedIndex)\n .flatMap((item) => extractCardsFromKpi(item));\n const viz =\n mainItem.visualisation && typeof mainItem.visualisation === 'object'\n ? (mainItem.visualisation as Record<string, unknown>)\n : null;\n return {\n layout: 'advanced',\n title: sectionTitle(sorted, true, topName),\n cards: main ? [main, ...supporting] : supporting,\n main,\n supporting,\n visualisation: viz,\n ...footer,\n };\n }\n\n const cards = sorted.flatMap((item) => extractCardsFromKpi(item));\n const hideNames = sorted.length === 1 && cards.length >= 1;\n const titledCards = hideNames\n ? cards.map((card) => ({ ...card, hideName: true }))\n : cards;\n const layout: KpiWidgetModel['layout'] =\n titledCards.length === 0 ? 'empty' : titledCards.length === 1 ? 'single' : 'grid';\n\n return {\n layout,\n title: sectionTitle(sorted, false, topName),\n cards: titledCards,\n supporting: [],\n ...footer,\n };\n}\n\n/** Normalize chat / FuseDash KPI payloads into display cards. */\nexport function normalizeKpiData(input: KpiWidgetData): KpiWidgetModel {\n if (!input) return EMPTY;\n\n if (Array.isArray(input)) {\n if (!input.length) return EMPTY;\n return buildFromItems(input);\n }\n\n if (typeof input === 'object') {\n if (isNormalizedModel(input)) return input;\n const topName = typeof (input as { name?: unknown }).name === 'string'\n ? (input as { name: string }).name\n : undefined;\n const items = asItemList(input);\n if (items) return buildFromItems(items, topName);\n if (isRawKpiItem(input)) {\n return buildFromItems([input], topName);\n }\n }\n\n return EMPTY;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui9000-map-chart.d.ts","sourceRoot":"","sources":["../../../../src/components/map-chart/element/ui9000-map-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAIzD,OAAO,EAAoB,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"ui9000-map-chart.d.ts","sourceRoot":"","sources":["../../../../src/components/map-chart/element/ui9000-map-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAIzD,OAAO,EAAoB,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAsF7F,qBACa,cAAe,SAAQ,kBAAkB;IACpD,OAAgB,MAAM,4BAAsC;IAG5D,UAAU,UAAQ;IAGlB,WAAW,UAAQ;IAGnB,WAAW,SAAM;IAGjB,cAAc,SAAM;IAGpB,cAAc,SAAc;IAG5B,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,YAAY,CAAa;IAGjC,OAAO,CAAC,QAAQ,CAAuE;IAGvF,OAAO,CAAC,OAAO,CAAuB;IAGtC,OAAO,CAAC,QAAQ,CAAmC;IAGnD,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,WAAW,CAAQ;IAG3B,OAAO,CAAC,UAAU,CAA+B;IAEjD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,IAAI,CAAmC;IAC/C,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,WAAW,CAAC,CAIlB;IACF,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,QAAQ,CAAK;IAEZ,iBAAiB,IAAI,IAAI;IAYzB,oBAAoB,IAAI,IAAI;IAU5B,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAM/C,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,IAAI;YAKE,IAAI;IA0FlB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,iBAAiB;IA4HhB,MAAM;CA0BhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAIvC"}
|
|
@@ -115,7 +115,7 @@ let Ui9000MapChart = class extends Ui9000ChartElement {
|
|
|
115
115
|
super.disconnectedCallback();
|
|
116
116
|
}
|
|
117
117
|
updated(changed) {
|
|
118
|
-
if (changed.has("dataJson")) this._model = null;
|
|
118
|
+
if (changed.has("dataJson") || changed.has("geojsonBaseUrl")) this._model = null;
|
|
119
119
|
if (changed.has("showTooltip") && !this.showTooltip) this._tooltip = null;
|
|
120
120
|
if (this.shouldRedraw(changed)) this.scheduleDraw();
|
|
121
121
|
}
|
|
@@ -145,6 +145,11 @@ let Ui9000MapChart = class extends Ui9000ChartElement {
|
|
|
145
145
|
const env = __vite_import_meta_env__;
|
|
146
146
|
return ((env == null ? void 0 : env.STORYBOOK_MAPBOX_TOKEN) || (env == null ? void 0 : env.VITE_MAPBOX_TOKEN) || "").trim();
|
|
147
147
|
}
|
|
148
|
+
geojsonUrl() {
|
|
149
|
+
if (this.geojsonBaseUrl.trim()) return this.geojsonBaseUrl.trim();
|
|
150
|
+
const runtime = typeof window !== "undefined" ? window.__RUNTIME_CONFIG__ : void 0;
|
|
151
|
+
return ((runtime == null ? void 0 : runtime.MAP_GEOJSON_BASE_URL) || "").trim();
|
|
152
|
+
}
|
|
148
153
|
pmtilesUrl() {
|
|
149
154
|
if (this.pmtilesBaseUrl.trim()) return this.pmtilesBaseUrl.trim();
|
|
150
155
|
const runtime = typeof window !== "undefined" ? window.__RUNTIME_CONFIG__ : void 0;
|
|
@@ -173,13 +178,16 @@ let Ui9000MapChart = class extends Ui9000ChartElement {
|
|
|
173
178
|
return;
|
|
174
179
|
}
|
|
175
180
|
const needsGeo = model.layers.some((layer) => !layer.features.length);
|
|
176
|
-
|
|
181
|
+
const geoBase = this.geojsonUrl();
|
|
182
|
+
let geoFetchFailed = false;
|
|
183
|
+
if (needsGeo && geoBase) {
|
|
177
184
|
const types = [...new Set(model.layers.map((l) => l.mapType))];
|
|
178
185
|
const loaded = await Promise.all(
|
|
179
|
-
types.map(async (mapType) => [mapType, await fetchMapGeoJson(mapType,
|
|
186
|
+
types.map(async (mapType) => [mapType, await fetchMapGeoJson(mapType, geoBase)])
|
|
180
187
|
);
|
|
181
188
|
if (gen !== this._drawGen) return;
|
|
182
189
|
const byType = Object.fromEntries(loaded.filter((entry) => entry[1]));
|
|
190
|
+
geoFetchFailed = loaded.some((entry) => !entry[1]);
|
|
183
191
|
model = {
|
|
184
192
|
...model,
|
|
185
193
|
layers: model.layers.map(
|
|
@@ -199,7 +207,7 @@ let Ui9000MapChart = class extends Ui9000ChartElement {
|
|
|
199
207
|
}
|
|
200
208
|
const hasMarks = model.layers.some((layer) => layer.features.length > 0);
|
|
201
209
|
this._empty = !hasMarks;
|
|
202
|
-
this._emptyReason = hasMarks ? "No data" : model.layers.some((l) => l.matchTotal > 0 && l.matchHit === 0) ? "No locations matched the map boundaries" : "Map boundaries required";
|
|
210
|
+
this._emptyReason = hasMarks ? "No data" : model.layers.some((l) => l.matchTotal > 0 && l.matchHit === 0) ? "No locations matched the map boundaries" : geoFetchFailed ? "Could not load map boundaries" : "Map boundaries required";
|
|
203
211
|
this._layers = model.layers;
|
|
204
212
|
if (!hasMarks) {
|
|
205
213
|
stopMapChart(root);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui9000-map-chart.js","sources":["../../../../src/components/map-chart/element/ui9000-map-chart.ts"],"sourcesContent":["import { html, nothing, type PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport { CSS_VARS, readCssVar } from '../../../context/widget-context.js';\nimport { chartShellStyles, Ui9000ChartElement } from '../../../element/ui9000-chart-base.js';\nimport { parseJsonAttr } from '../../../utils/chart-helpers.js';\nimport { chartPropsChanged } from '../../../utils/lit-draw.js';\nimport { fetchMapGeoJson } from '../lib/geojson.js';\nimport { joinLayerFeatures } from '../lib/join.js';\nimport {\n DEFAULT_BUBBLES_RADIUS,\n defaultLayerSlider,\n formatAverage,\n formatFieldLabel,\n formatLegendBucket,\n legendLayerOrder,\n legendSpikeHeight,\n MUTED_LEGEND_FILL,\n rangeTrackOffset,\n sanitizeKey,\n slideThumb,\n sliderIndexFromPointer,\n thumbTrackPercent,\n type LayerSlider,\n formatMapValue,\n normalizeMapData,\n type MapChartInput,\n type MapHoverEntry,\n type MapLayerModel,\n type MapModel,\n} from '../lib/index.js';\nimport { renderMapChart, resizeMapChart, stopMapChart, type MapChartController } from '../render/draw.js';\nimport { mapChartStyles } from './styles.js';\n\nconst SPIKE_COLOR = '#939BA7';\n\nfunction renderLegendSpike(index: number, id: string) {\n const h = legendSpikeHeight(index);\n return html`\n <span class=\"legend-spike\">\n <svg width=\"25\" height=${h} viewBox=${`0 0 25 ${h}`} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <mask\n id=${`mask_${id}`}\n style=\"mask-type:alpha\"\n maskUnits=\"userSpaceOnUse\"\n x=\"6\"\n y=\"0\"\n width=\"13\"\n height=${h}\n >\n <path\n d=${`M18.1992 ${h - 0.75}L12.1992 0.25L6.19922 ${h - 0.75}Z`}\n fill=${`url(#linear_gradient_${id})`}\n />\n </mask>\n <g mask=${`url(#mask_${id})`}>\n <path d=${`M18.1992 ${h - 0.75}L12.1992 0.25L6.19922 ${h - 0.75}Z`} fill=${SPIKE_COLOR} />\n </g>\n <path\n d=${`M22.1992 ${h - 0.75}H19.0291C18.5479 ${h - 0.75} 18.135 ${h - 0.1} 18.0463 ${h - 0.5}L12.1992 0.25L6.35216 ${h - 0.5}C6.26348 ${h - 0.1} 5.85051 ${h - 0.75} 5.36929 ${h - 0.75}H2.19922`}\n stroke=${SPIKE_COLOR}\n fill=${SPIKE_COLOR}\n fill-opacity=\"0\"\n stroke-width=\"1\"\n />\n <defs>\n <linearGradient\n id=${`linear_gradient_${id}`}\n x1=\"12.1992\"\n y1=\"0.25\"\n x2=\"12.1992\"\n y2=${h}\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop stop-color=${SPIKE_COLOR} stop-opacity=\"0.7\" />\n <stop offset=\"1\" stop-color=${SPIKE_COLOR} stop-opacity=\"0.2\" />\n </linearGradient>\n </defs>\n </svg>\n </span>\n `;\n}\n\ntype RuntimeConfig = {\n MAPBOX_TOKEN?: string;\n MAPBOX_DARK_TOKEN?: string;\n MAP_PMTILES_BASE_URL?: string;\n};\n\n@customElement('ui9000-map-chart')\nexport class Ui9000MapChart extends Ui9000ChartElement {\n static override styles = [mapChartStyles, chartShellStyles];\n\n @property({ type: Boolean, attribute: 'show-legend' })\n showLegend = true;\n\n @property({ type: Boolean, attribute: 'show-tooltip' })\n showTooltip = true;\n\n @property({ type: String, attribute: 'mapbox-token' })\n mapboxToken = '';\n\n @property({ type: String, attribute: 'geojson-base-url' })\n geojsonBaseUrl = '';\n\n @property({ type: String, attribute: 'pmtiles-base-url' })\n pmtilesBaseUrl = '/pmtiles';\n\n @state()\n private _empty = false;\n\n @state()\n private _emptyReason = 'No data';\n\n @state()\n private _tooltip: { x: number; y: number; title: string; value: string } | null = null;\n\n @state()\n private _layers: MapLayerModel[] = [];\n\n @state()\n private _sliders: Record<string, LayerSlider> = {};\n\n @state()\n private _activeLayers: string[] = [];\n\n @state()\n private _legendOpen = true;\n\n @state()\n private _layerOpen: Record<string, boolean> = {};\n\n private _model: MapModel | null = null;\n private _ctl: MapChartController | null = null;\n private _legendKey = '';\n private _legendDrag?: {\n thumb: HTMLElement;\n move: (e: PointerEvent) => void;\n up: (e: PointerEvent) => void;\n };\n private _resizeObserver?: ResizeObserver;\n private _raf = 0;\n private _drawGen = 0;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._resizeObserver = new ResizeObserver(() => {\n cancelAnimationFrame(this._raf);\n this._raf = requestAnimationFrame(() => {\n const root = this.chartRoot();\n if (root && !resizeMapChart(root)) this.scheduleDraw();\n });\n });\n this._resizeObserver.observe(this);\n }\n\n override disconnectedCallback(): void {\n this._resizeObserver?.disconnect();\n cancelAnimationFrame(this._raf);\n this.stopLegendDrag();\n const root = this.chartRoot();\n if (root) stopMapChart(root);\n this._ctl = null;\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n if (changed.has('dataJson')) this._model = null;\n if (changed.has('showTooltip') && !this.showTooltip) this._tooltip = null;\n if (this.shouldRedraw(changed)) this.scheduleDraw();\n }\n\n private shouldRedraw(changed: PropertyValues): boolean {\n if (!chartPropsChanged(changed)) return false;\n for (const key of changed.keys()) {\n if (typeof key !== 'string' || key.startsWith('_')) continue;\n if (key === 'showLegend' || key === 'showTooltip') continue;\n return true;\n }\n return false;\n }\n\n private scheduleDraw(): void {\n cancelAnimationFrame(this._raf);\n this._raf = requestAnimationFrame(() => {\n void this.draw();\n });\n }\n\n private chartRoot(): HTMLElement | null {\n return (this.shadowRoot?.querySelector('.chart-root') as HTMLElement | null) ?? null;\n }\n\n private token(): string {\n if (this.mapboxToken.trim()) return this.mapboxToken.trim();\n const runtime =\n typeof window !== 'undefined'\n ? (window as Window & { __RUNTIME_CONFIG__?: RuntimeConfig }).__RUNTIME_CONFIG__\n : undefined;\n if (runtime?.MAPBOX_TOKEN) return runtime.MAPBOX_TOKEN;\n const env = (import.meta as { env?: Record<string, string | undefined> }).env;\n return (env?.STORYBOOK_MAPBOX_TOKEN || env?.VITE_MAPBOX_TOKEN || '').trim();\n }\n\n private pmtilesUrl(): string {\n if (this.pmtilesBaseUrl.trim()) return this.pmtilesBaseUrl.trim();\n const runtime =\n typeof window !== 'undefined'\n ? (window as Window & { __RUNTIME_CONFIG__?: RuntimeConfig }).__RUNTIME_CONFIG__\n : undefined;\n if (runtime?.MAP_PMTILES_BASE_URL) return runtime.MAP_PMTILES_BASE_URL;\n const env = (import.meta as { env?: Record<string, string | undefined> }).env;\n return (env?.STORYBOOK_MAP_PMTILES_BASE_URL || env?.VITE_MAP_PMTILES_BASE_URL || '/pmtiles').trim();\n }\n\n private mode(): 'light' | 'dark' {\n const value = readCssVar(this, CSS_VARS.mode, 'light');\n return value === 'dark' ? 'dark' : 'light';\n }\n\n private async draw(): Promise<void> {\n const root = this.chartRoot();\n if (!root) return;\n const gen = ++this._drawGen;\n\n const parsed = parseJsonAttr<MapChartInput>(this.dataJson, null);\n let model = this._model ?? normalizeMapData(parsed);\n this._model = model;\n\n if (!model.layers.length) {\n this._empty = true;\n this._emptyReason = 'No data';\n this._layers = [];\n stopMapChart(root);\n this._ctl = null;\n return;\n }\n\n const needsGeo = model.layers.some((layer) => !layer.features.length);\n if (needsGeo && this.geojsonBaseUrl) {\n const types = [...new Set(model.layers.map((l) => l.mapType))];\n const loaded = await Promise.all(\n types.map(async (mapType) => [mapType, await fetchMapGeoJson(mapType, this.geojsonBaseUrl)] as const),\n );\n if (gen !== this._drawGen) return;\n const byType = Object.fromEntries(loaded.filter((entry) => entry[1]));\n model = {\n ...model,\n layers: model.layers.map((layer) =>\n layer.features.length ? layer : joinLayerFeatures(layer, byType[layer.mapType] ?? undefined),\n ),\n };\n this._model = model;\n }\n\n const token = this.token();\n if (!token) {\n this._empty = true;\n this._emptyReason = 'Mapbox token required';\n this._layers = model.layers;\n stopMapChart(root);\n this._ctl = null;\n return;\n }\n\n const hasMarks = model.layers.some((layer) => layer.features.length > 0);\n this._empty = !hasMarks;\n this._emptyReason = hasMarks\n ? 'No data'\n : model.layers.some((l) => l.matchTotal > 0 && l.matchHit === 0)\n ? 'No locations matched the map boundaries'\n : 'Map boundaries required';\n this._layers = model.layers;\n if (!hasMarks) {\n stopMapChart(root);\n this._ctl = null;\n return;\n }\n this.syncLegendState(model.layers);\n\n const ctl = await renderMapChart(root, {\n model,\n token,\n mode: this.mode(),\n showTooltip: this.showTooltip,\n pmtilesBaseUrl: this.pmtilesUrl(),\n activeLayerIds: this._activeLayers,\n sliders: this._sliders,\n year: model.layers.find((layer) => layer.selectedYear)?.selectedYear,\n onHover: this.showTooltip\n ? (entry) => this.setTooltip(entry)\n : undefined,\n });\n if (gen !== this._drawGen) {\n ctl?.destroy();\n return;\n }\n this._ctl = ctl;\n if (!this._ctl) {\n this._empty = true;\n this._emptyReason = 'Mapbox GL failed to load';\n stopMapChart(root);\n }\n }\n\n private syncLegendState(layers: MapLayerModel[]): void {\n const ids = layers.map((layer) => layer.layerId);\n const key = ids.join('\\0');\n if (key !== this._legendKey) {\n this._legendKey = key;\n this._sliders = Object.fromEntries(\n layers.map((layer) => [layer.layerId, defaultLayerSlider(layer.colorRanges.length)]),\n );\n this._activeLayers = ids;\n this._layerOpen = {};\n return;\n }\n const sliders = { ...this._sliders };\n let slidersChanged = false;\n for (const layer of layers) {\n if (!sliders[layer.layerId]) {\n sliders[layer.layerId] = defaultLayerSlider(layer.colorRanges.length);\n slidersChanged = true;\n }\n }\n if (slidersChanged) this._sliders = sliders;\n }\n\n private pushLegend(): void {\n this._ctl?.applyLegend(this._activeLayers, this._sliders);\n }\n\n private toggleLayer(layerId: string): void {\n const on = this._activeLayers.includes(layerId);\n this._activeLayers = on\n ? this._activeLayers.filter((id) => id !== layerId)\n : [...this._activeLayers, layerId];\n this.pushLegend();\n }\n\n private toggleLayerOpen(layerId: string): void {\n this._layerOpen = { ...this._layerOpen, [layerId]: this._layerOpen[layerId] === false };\n }\n\n private setSlider(layerId: string, edge: 'leftSlider' | 'rightSlider', raw: number): void {\n const layer = this._layers.find((item) => item.layerId === layerId);\n const rangeCount = layer?.colorRanges.length ?? 1;\n const current = this._sliders[layerId] ?? defaultLayerSlider(rangeCount);\n const next = slideThumb(current, edge, raw, rangeCount);\n if (next.leftSlider === current.leftSlider && next.rightSlider === current.rightSlider) return;\n this._sliders = { ...this._sliders, [layerId]: next };\n this.pushLegend();\n }\n\n private startThumbDrag(layerId: string, edge: 'leftSlider' | 'rightSlider', e: PointerEvent): void {\n const thumb = e.currentTarget;\n if (!(thumb instanceof HTMLElement)) return;\n const track = thumb.parentElement;\n if (!track) return;\n e.preventDefault();\n e.stopPropagation();\n thumb.setPointerCapture(e.pointerId);\n this.stopLegendDrag();\n\n const move = (ev: PointerEvent) => {\n const layer = this._layers.find((item) => item.layerId === layerId);\n const max = layer?.colorRanges.length ?? 1;\n const index = sliderIndexFromPointer(ev.clientX, track.getBoundingClientRect(), max);\n this.setSlider(layerId, edge, index);\n };\n const up = (ev: PointerEvent) => {\n if (thumb.hasPointerCapture(ev.pointerId)) thumb.releasePointerCapture(ev.pointerId);\n this.stopLegendDrag();\n };\n thumb.addEventListener('pointermove', move);\n thumb.addEventListener('pointerup', up);\n thumb.addEventListener('pointercancel', up);\n this._legendDrag = { thumb, move, up };\n move(e);\n }\n\n private stopLegendDrag(): void {\n const drag = this._legendDrag;\n if (!drag) return;\n drag.thumb.removeEventListener('pointermove', drag.move);\n drag.thumb.removeEventListener('pointerup', drag.up);\n drag.thumb.removeEventListener('pointercancel', drag.up);\n this._legendDrag = undefined;\n }\n\n private setTooltip(entry: MapHoverEntry | null): void {\n if (!entry) {\n this._tooltip = null;\n return;\n }\n const root = this.chartRoot();\n const x = entry.point?.x ?? (root?.clientWidth ?? 0) / 2;\n const y = entry.point?.y ?? 48;\n this._tooltip = {\n x,\n y,\n title: entry.regionName,\n value: `${entry.valueKey}: ${formatMapValue(entry.value)}`,\n };\n }\n\n private matchNotice(): string | null {\n const total = this._layers.reduce((sum, l) => sum + l.matchTotal, 0);\n const hit = this._layers.reduce((sum, l) => sum + l.matchHit, 0);\n if (total > 0 && hit === 0) {\n return `0 of ${total} ${total === 1 ? 'location' : 'locations'} matched the map boundaries`;\n }\n return null;\n }\n\n private renderLegend() {\n if (!this.showLegend || this._empty) return nothing;\n const layers = legendLayerOrder(this._layers.filter((layer) => layer.features.length > 0));\n if (!layers.length) return nothing;\n\n return html`\n <div class=\"map-legend\" part=\"legend\">\n <div class=\"legend-panel-header\">\n <p class=\"legend-kicker\">Legend</p>\n <button\n type=\"button\"\n class=\"legend-chevron\"\n aria-expanded=${this._legendOpen}\n aria-label=${this._legendOpen ? 'Collapse legend' : 'Expand legend'}\n @click=${() => {\n this._legendOpen = !this._legendOpen;\n }}\n ></button>\n </div>\n ${this._legendOpen\n ? html`<div class=\"legend-layers\">\n ${layers.map((layer) => this.renderLegendLayer(layer))}\n </div>`\n : nothing}\n </div>\n `;\n }\n\n private renderLegendLayer(layer: MapLayerModel) {\n const active = this._activeLayers.includes(layer.layerId);\n const open = this._layerOpen[layer.layerId] !== false;\n const slider = this._sliders[layer.layerId] ?? defaultLayerSlider(layer.colorRanges.length);\n const ranges = layer.colorRanges;\n const isBubble = layer.visualisationType === 'bubbles';\n const isSpike = layer.visualisationType === 'spike';\n const isMarkers = layer.visualisationType === 'markers';\n const showRamp = ranges.length > 0;\n\n return html`\n <div class=\"legend-layer\">\n <div class=\"legend-layer-header\">\n <label class=\"legend-check\">\n <input\n type=\"checkbox\"\n .checked=${active}\n @change=${(e: Event) => {\n e.stopPropagation();\n this.toggleLayer(layer.layerId);\n }}\n />\n <span>${layer.layerName}</span>\n </label>\n <button\n type=\"button\"\n class=\"legend-chevron\"\n aria-expanded=${open}\n aria-label=${open ? `Collapse ${layer.layerName}` : `Expand ${layer.layerName}`}\n @click=${() => this.toggleLayerOpen(layer.layerId)}\n ></button>\n </div>\n ${open\n ? html`\n <div class=\"legend-details\">\n <p class=\"legend-stat\">\n <span class=\"legend-avg\">${formatAverage(layer.average)}</span>\n ${formatFieldLabel(layer.valueKey)}\n </p>\n ${showRamp\n ? html`\n <div class=\"legend-scale\" data-kind=${layer.visualisationType}>\n <div\n class=\"legend-colors\"\n ?data-qualitative=${isBubble || isSpike}\n >\n <div class=\"legend-range\">\n <div\n class=\"legend-range-track\"\n style=\"left:${rangeTrackOffset('left', slider.leftSlider, ranges.length)}\"\n >\n <button\n type=\"button\"\n class=\"legend-thumb\"\n aria-label=\"Lowest ${layer.layerName} range\"\n style=\"left:${thumbTrackPercent(slider.leftSlider, ranges.length)}\"\n @pointerdown=${(e: PointerEvent) =>\n this.startThumbDrag(layer.layerId, 'leftSlider', e)}\n ></button>\n </div>\n <div\n class=\"legend-range-track\"\n style=\"right:${rangeTrackOffset('right', slider.rightSlider, ranges.length)}\"\n >\n <button\n type=\"button\"\n class=\"legend-thumb\"\n aria-label=\"Highest ${layer.layerName} range\"\n style=\"left:${thumbTrackPercent(slider.rightSlider, ranges.length)}\"\n @pointerdown=${(e: PointerEvent) =>\n this.startThumbDrag(layer.layerId, 'rightSlider', e)}\n ></button>\n </div>\n </div>\n <div class=\"legend-buckets\">\n ${ranges.map((range, index) => {\n const inRange =\n slider.leftSlider <= index && index < slider.rightSlider;\n const fill =\n isBubble || isSpike\n ? MUTED_LEGEND_FILL\n : inRange\n ? range.color\n : MUTED_LEGEND_FILL;\n const bubble = isBubble ? (DEFAULT_BUBBLES_RADIUS[index] ?? 12) : 0;\n const inner = bubble - 15 > 0 ? bubble - 15 : 0;\n return html`<span\n class=\"legend-bucket\"\n ?data-bubble=${isBubble}\n ?data-inner=${inner > 0}\n ?data-qualitative=${isBubble || isSpike}\n style=\"background:${fill};--bubble-size:${bubble}px;--inner-size:${inner}px\"\n ></span>`;\n })}\n </div>\n ${isSpike\n ? html`<div class=\"legend-spikes\">\n ${ranges.map((_range, index) =>\n renderLegendSpike(\n index,\n `${sanitizeKey(layer.layerId)}_${index}`,\n ),\n )}\n </div>`\n : nothing}\n </div>\n ${isMarkers\n ? nothing\n : html`<div class=\"legend-values\">\n ${ranges.map(\n (range) =>\n html`<span class=\"legend-value\">${formatLegendBucket(range.start, 2)}</span>`,\n )}\n </div>`}\n </div>\n `\n : nothing}\n </div>\n `\n : nothing}\n </div>\n `;\n }\n\n override render() {\n const title = this.headerTitle();\n const notice = this.matchNotice();\n return html`\n <div class=\"widget-shell\" part=\"shell\">\n ${this.renderShellHeader(title)}\n <div class=\"widget-body\">\n <div class=\"chart-root\" part=\"chart\" ?hidden=${this._empty}></div>\n ${this._empty ? html`<div class=\"empty\" part=\"empty\">${this._emptyReason}</div>` : nothing}\n ${this.renderLegend()}\n ${notice && !this._empty ? html`<div class=\"match-notice\">${notice}</div>` : nothing}\n ${this._tooltip\n ? html`<div\n class=\"tooltip\"\n part=\"tooltip\"\n style=\"left:${this._tooltip.x}px;top:${this._tooltip.y}px\"\n >\n <div>${this._tooltip.title}</div>\n <div>${this._tooltip.value}</div>\n </div>`\n : nothing}\n ${this.renderShellLabelTooltip()}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ui9000-map-chart': Ui9000MapChart;\n }\n}\n\nexport function registerMapChart(): void {\n if (!customElements.get('ui9000-map-chart')) {\n customElements.define('ui9000-map-chart', Ui9000MapChart);\n }\n}\n\nregisterMapChart();\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ui9000-map-chart.js","sources":["../../../../src/components/map-chart/element/ui9000-map-chart.ts"],"sourcesContent":["import { html, nothing, type PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport { CSS_VARS, readCssVar } from '../../../context/widget-context.js';\nimport { chartShellStyles, Ui9000ChartElement } from '../../../element/ui9000-chart-base.js';\nimport { parseJsonAttr } from '../../../utils/chart-helpers.js';\nimport { chartPropsChanged } from '../../../utils/lit-draw.js';\nimport { fetchMapGeoJson } from '../lib/geojson.js';\nimport { joinLayerFeatures } from '../lib/join.js';\nimport {\n DEFAULT_BUBBLES_RADIUS,\n defaultLayerSlider,\n formatAverage,\n formatFieldLabel,\n formatLegendBucket,\n legendLayerOrder,\n legendSpikeHeight,\n MUTED_LEGEND_FILL,\n rangeTrackOffset,\n sanitizeKey,\n slideThumb,\n sliderIndexFromPointer,\n thumbTrackPercent,\n type LayerSlider,\n formatMapValue,\n normalizeMapData,\n type MapChartInput,\n type MapHoverEntry,\n type MapLayerModel,\n type MapModel,\n} from '../lib/index.js';\nimport { renderMapChart, resizeMapChart, stopMapChart, type MapChartController } from '../render/draw.js';\nimport { mapChartStyles } from './styles.js';\n\nconst SPIKE_COLOR = '#939BA7';\n\nfunction renderLegendSpike(index: number, id: string) {\n const h = legendSpikeHeight(index);\n return html`\n <span class=\"legend-spike\">\n <svg width=\"25\" height=${h} viewBox=${`0 0 25 ${h}`} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <mask\n id=${`mask_${id}`}\n style=\"mask-type:alpha\"\n maskUnits=\"userSpaceOnUse\"\n x=\"6\"\n y=\"0\"\n width=\"13\"\n height=${h}\n >\n <path\n d=${`M18.1992 ${h - 0.75}L12.1992 0.25L6.19922 ${h - 0.75}Z`}\n fill=${`url(#linear_gradient_${id})`}\n />\n </mask>\n <g mask=${`url(#mask_${id})`}>\n <path d=${`M18.1992 ${h - 0.75}L12.1992 0.25L6.19922 ${h - 0.75}Z`} fill=${SPIKE_COLOR} />\n </g>\n <path\n d=${`M22.1992 ${h - 0.75}H19.0291C18.5479 ${h - 0.75} 18.135 ${h - 0.1} 18.0463 ${h - 0.5}L12.1992 0.25L6.35216 ${h - 0.5}C6.26348 ${h - 0.1} 5.85051 ${h - 0.75} 5.36929 ${h - 0.75}H2.19922`}\n stroke=${SPIKE_COLOR}\n fill=${SPIKE_COLOR}\n fill-opacity=\"0\"\n stroke-width=\"1\"\n />\n <defs>\n <linearGradient\n id=${`linear_gradient_${id}`}\n x1=\"12.1992\"\n y1=\"0.25\"\n x2=\"12.1992\"\n y2=${h}\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop stop-color=${SPIKE_COLOR} stop-opacity=\"0.7\" />\n <stop offset=\"1\" stop-color=${SPIKE_COLOR} stop-opacity=\"0.2\" />\n </linearGradient>\n </defs>\n </svg>\n </span>\n `;\n}\n\ntype RuntimeConfig = {\n MAPBOX_TOKEN?: string;\n MAPBOX_DARK_TOKEN?: string;\n MAP_PMTILES_BASE_URL?: string;\n MAP_GEOJSON_BASE_URL?: string;\n};\n\n@customElement('ui9000-map-chart')\nexport class Ui9000MapChart extends Ui9000ChartElement {\n static override styles = [mapChartStyles, chartShellStyles];\n\n @property({ type: Boolean, attribute: 'show-legend' })\n showLegend = true;\n\n @property({ type: Boolean, attribute: 'show-tooltip' })\n showTooltip = true;\n\n @property({ type: String, attribute: 'mapbox-token' })\n mapboxToken = '';\n\n @property({ type: String, attribute: 'geojson-base-url' })\n geojsonBaseUrl = '';\n\n @property({ type: String, attribute: 'pmtiles-base-url' })\n pmtilesBaseUrl = '/pmtiles';\n\n @state()\n private _empty = false;\n\n @state()\n private _emptyReason = 'No data';\n\n @state()\n private _tooltip: { x: number; y: number; title: string; value: string } | null = null;\n\n @state()\n private _layers: MapLayerModel[] = [];\n\n @state()\n private _sliders: Record<string, LayerSlider> = {};\n\n @state()\n private _activeLayers: string[] = [];\n\n @state()\n private _legendOpen = true;\n\n @state()\n private _layerOpen: Record<string, boolean> = {};\n\n private _model: MapModel | null = null;\n private _ctl: MapChartController | null = null;\n private _legendKey = '';\n private _legendDrag?: {\n thumb: HTMLElement;\n move: (e: PointerEvent) => void;\n up: (e: PointerEvent) => void;\n };\n private _resizeObserver?: ResizeObserver;\n private _raf = 0;\n private _drawGen = 0;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._resizeObserver = new ResizeObserver(() => {\n cancelAnimationFrame(this._raf);\n this._raf = requestAnimationFrame(() => {\n const root = this.chartRoot();\n if (root && !resizeMapChart(root)) this.scheduleDraw();\n });\n });\n this._resizeObserver.observe(this);\n }\n\n override disconnectedCallback(): void {\n this._resizeObserver?.disconnect();\n cancelAnimationFrame(this._raf);\n this.stopLegendDrag();\n const root = this.chartRoot();\n if (root) stopMapChart(root);\n this._ctl = null;\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n if (changed.has('dataJson') || changed.has('geojsonBaseUrl')) this._model = null;\n if (changed.has('showTooltip') && !this.showTooltip) this._tooltip = null;\n if (this.shouldRedraw(changed)) this.scheduleDraw();\n }\n\n private shouldRedraw(changed: PropertyValues): boolean {\n if (!chartPropsChanged(changed)) return false;\n for (const key of changed.keys()) {\n if (typeof key !== 'string' || key.startsWith('_')) continue;\n if (key === 'showLegend' || key === 'showTooltip') continue;\n return true;\n }\n return false;\n }\n\n private scheduleDraw(): void {\n cancelAnimationFrame(this._raf);\n this._raf = requestAnimationFrame(() => {\n void this.draw();\n });\n }\n\n private chartRoot(): HTMLElement | null {\n return (this.shadowRoot?.querySelector('.chart-root') as HTMLElement | null) ?? null;\n }\n\n private token(): string {\n if (this.mapboxToken.trim()) return this.mapboxToken.trim();\n const runtime =\n typeof window !== 'undefined'\n ? (window as Window & { __RUNTIME_CONFIG__?: RuntimeConfig }).__RUNTIME_CONFIG__\n : undefined;\n if (runtime?.MAPBOX_TOKEN) return runtime.MAPBOX_TOKEN;\n const env = (import.meta as { env?: Record<string, string | undefined> }).env;\n return (env?.STORYBOOK_MAPBOX_TOKEN || env?.VITE_MAPBOX_TOKEN || '').trim();\n }\n\n private geojsonUrl(): string {\n if (this.geojsonBaseUrl.trim()) return this.geojsonBaseUrl.trim();\n const runtime =\n typeof window !== 'undefined'\n ? (window as Window & { __RUNTIME_CONFIG__?: RuntimeConfig }).__RUNTIME_CONFIG__\n : undefined;\n return (runtime?.MAP_GEOJSON_BASE_URL || '').trim();\n }\n\n private pmtilesUrl(): string {\n if (this.pmtilesBaseUrl.trim()) return this.pmtilesBaseUrl.trim();\n const runtime =\n typeof window !== 'undefined'\n ? (window as Window & { __RUNTIME_CONFIG__?: RuntimeConfig }).__RUNTIME_CONFIG__\n : undefined;\n if (runtime?.MAP_PMTILES_BASE_URL) return runtime.MAP_PMTILES_BASE_URL;\n const env = (import.meta as { env?: Record<string, string | undefined> }).env;\n return (env?.STORYBOOK_MAP_PMTILES_BASE_URL || env?.VITE_MAP_PMTILES_BASE_URL || '/pmtiles').trim();\n }\n\n private mode(): 'light' | 'dark' {\n const value = readCssVar(this, CSS_VARS.mode, 'light');\n return value === 'dark' ? 'dark' : 'light';\n }\n\n private async draw(): Promise<void> {\n const root = this.chartRoot();\n if (!root) return;\n const gen = ++this._drawGen;\n\n const parsed = parseJsonAttr<MapChartInput>(this.dataJson, null);\n let model = this._model ?? normalizeMapData(parsed);\n this._model = model;\n\n if (!model.layers.length) {\n this._empty = true;\n this._emptyReason = 'No data';\n this._layers = [];\n stopMapChart(root);\n this._ctl = null;\n return;\n }\n\n const needsGeo = model.layers.some((layer) => !layer.features.length);\n const geoBase = this.geojsonUrl();\n let geoFetchFailed = false;\n if (needsGeo && geoBase) {\n const types = [...new Set(model.layers.map((l) => l.mapType))];\n const loaded = await Promise.all(\n types.map(async (mapType) => [mapType, await fetchMapGeoJson(mapType, geoBase)] as const),\n );\n if (gen !== this._drawGen) return;\n const byType = Object.fromEntries(loaded.filter((entry) => entry[1]));\n geoFetchFailed = loaded.some((entry) => !entry[1]);\n model = {\n ...model,\n layers: model.layers.map((layer) =>\n layer.features.length ? layer : joinLayerFeatures(layer, byType[layer.mapType] ?? undefined),\n ),\n };\n this._model = model;\n }\n\n const token = this.token();\n if (!token) {\n this._empty = true;\n this._emptyReason = 'Mapbox token required';\n this._layers = model.layers;\n stopMapChart(root);\n this._ctl = null;\n return;\n }\n\n const hasMarks = model.layers.some((layer) => layer.features.length > 0);\n this._empty = !hasMarks;\n this._emptyReason = hasMarks\n ? 'No data'\n : model.layers.some((l) => l.matchTotal > 0 && l.matchHit === 0)\n ? 'No locations matched the map boundaries'\n : geoFetchFailed\n ? 'Could not load map boundaries'\n : 'Map boundaries required';\n this._layers = model.layers;\n if (!hasMarks) {\n stopMapChart(root);\n this._ctl = null;\n return;\n }\n this.syncLegendState(model.layers);\n\n const ctl = await renderMapChart(root, {\n model,\n token,\n mode: this.mode(),\n showTooltip: this.showTooltip,\n pmtilesBaseUrl: this.pmtilesUrl(),\n activeLayerIds: this._activeLayers,\n sliders: this._sliders,\n year: model.layers.find((layer) => layer.selectedYear)?.selectedYear,\n onHover: this.showTooltip\n ? (entry) => this.setTooltip(entry)\n : undefined,\n });\n if (gen !== this._drawGen) {\n ctl?.destroy();\n return;\n }\n this._ctl = ctl;\n if (!this._ctl) {\n this._empty = true;\n this._emptyReason = 'Mapbox GL failed to load';\n stopMapChart(root);\n }\n }\n\n private syncLegendState(layers: MapLayerModel[]): void {\n const ids = layers.map((layer) => layer.layerId);\n const key = ids.join('\\0');\n if (key !== this._legendKey) {\n this._legendKey = key;\n this._sliders = Object.fromEntries(\n layers.map((layer) => [layer.layerId, defaultLayerSlider(layer.colorRanges.length)]),\n );\n this._activeLayers = ids;\n this._layerOpen = {};\n return;\n }\n const sliders = { ...this._sliders };\n let slidersChanged = false;\n for (const layer of layers) {\n if (!sliders[layer.layerId]) {\n sliders[layer.layerId] = defaultLayerSlider(layer.colorRanges.length);\n slidersChanged = true;\n }\n }\n if (slidersChanged) this._sliders = sliders;\n }\n\n private pushLegend(): void {\n this._ctl?.applyLegend(this._activeLayers, this._sliders);\n }\n\n private toggleLayer(layerId: string): void {\n const on = this._activeLayers.includes(layerId);\n this._activeLayers = on\n ? this._activeLayers.filter((id) => id !== layerId)\n : [...this._activeLayers, layerId];\n this.pushLegend();\n }\n\n private toggleLayerOpen(layerId: string): void {\n this._layerOpen = { ...this._layerOpen, [layerId]: this._layerOpen[layerId] === false };\n }\n\n private setSlider(layerId: string, edge: 'leftSlider' | 'rightSlider', raw: number): void {\n const layer = this._layers.find((item) => item.layerId === layerId);\n const rangeCount = layer?.colorRanges.length ?? 1;\n const current = this._sliders[layerId] ?? defaultLayerSlider(rangeCount);\n const next = slideThumb(current, edge, raw, rangeCount);\n if (next.leftSlider === current.leftSlider && next.rightSlider === current.rightSlider) return;\n this._sliders = { ...this._sliders, [layerId]: next };\n this.pushLegend();\n }\n\n private startThumbDrag(layerId: string, edge: 'leftSlider' | 'rightSlider', e: PointerEvent): void {\n const thumb = e.currentTarget;\n if (!(thumb instanceof HTMLElement)) return;\n const track = thumb.parentElement;\n if (!track) return;\n e.preventDefault();\n e.stopPropagation();\n thumb.setPointerCapture(e.pointerId);\n this.stopLegendDrag();\n\n const move = (ev: PointerEvent) => {\n const layer = this._layers.find((item) => item.layerId === layerId);\n const max = layer?.colorRanges.length ?? 1;\n const index = sliderIndexFromPointer(ev.clientX, track.getBoundingClientRect(), max);\n this.setSlider(layerId, edge, index);\n };\n const up = (ev: PointerEvent) => {\n if (thumb.hasPointerCapture(ev.pointerId)) thumb.releasePointerCapture(ev.pointerId);\n this.stopLegendDrag();\n };\n thumb.addEventListener('pointermove', move);\n thumb.addEventListener('pointerup', up);\n thumb.addEventListener('pointercancel', up);\n this._legendDrag = { thumb, move, up };\n move(e);\n }\n\n private stopLegendDrag(): void {\n const drag = this._legendDrag;\n if (!drag) return;\n drag.thumb.removeEventListener('pointermove', drag.move);\n drag.thumb.removeEventListener('pointerup', drag.up);\n drag.thumb.removeEventListener('pointercancel', drag.up);\n this._legendDrag = undefined;\n }\n\n private setTooltip(entry: MapHoverEntry | null): void {\n if (!entry) {\n this._tooltip = null;\n return;\n }\n const root = this.chartRoot();\n const x = entry.point?.x ?? (root?.clientWidth ?? 0) / 2;\n const y = entry.point?.y ?? 48;\n this._tooltip = {\n x,\n y,\n title: entry.regionName,\n value: `${entry.valueKey}: ${formatMapValue(entry.value)}`,\n };\n }\n\n private matchNotice(): string | null {\n const total = this._layers.reduce((sum, l) => sum + l.matchTotal, 0);\n const hit = this._layers.reduce((sum, l) => sum + l.matchHit, 0);\n if (total > 0 && hit === 0) {\n return `0 of ${total} ${total === 1 ? 'location' : 'locations'} matched the map boundaries`;\n }\n return null;\n }\n\n private renderLegend() {\n if (!this.showLegend || this._empty) return nothing;\n const layers = legendLayerOrder(this._layers.filter((layer) => layer.features.length > 0));\n if (!layers.length) return nothing;\n\n return html`\n <div class=\"map-legend\" part=\"legend\">\n <div class=\"legend-panel-header\">\n <p class=\"legend-kicker\">Legend</p>\n <button\n type=\"button\"\n class=\"legend-chevron\"\n aria-expanded=${this._legendOpen}\n aria-label=${this._legendOpen ? 'Collapse legend' : 'Expand legend'}\n @click=${() => {\n this._legendOpen = !this._legendOpen;\n }}\n ></button>\n </div>\n ${this._legendOpen\n ? html`<div class=\"legend-layers\">\n ${layers.map((layer) => this.renderLegendLayer(layer))}\n </div>`\n : nothing}\n </div>\n `;\n }\n\n private renderLegendLayer(layer: MapLayerModel) {\n const active = this._activeLayers.includes(layer.layerId);\n const open = this._layerOpen[layer.layerId] !== false;\n const slider = this._sliders[layer.layerId] ?? defaultLayerSlider(layer.colorRanges.length);\n const ranges = layer.colorRanges;\n const isBubble = layer.visualisationType === 'bubbles';\n const isSpike = layer.visualisationType === 'spike';\n const isMarkers = layer.visualisationType === 'markers';\n const showRamp = ranges.length > 0;\n\n return html`\n <div class=\"legend-layer\">\n <div class=\"legend-layer-header\">\n <label class=\"legend-check\">\n <input\n type=\"checkbox\"\n .checked=${active}\n @change=${(e: Event) => {\n e.stopPropagation();\n this.toggleLayer(layer.layerId);\n }}\n />\n <span>${layer.layerName}</span>\n </label>\n <button\n type=\"button\"\n class=\"legend-chevron\"\n aria-expanded=${open}\n aria-label=${open ? `Collapse ${layer.layerName}` : `Expand ${layer.layerName}`}\n @click=${() => this.toggleLayerOpen(layer.layerId)}\n ></button>\n </div>\n ${open\n ? html`\n <div class=\"legend-details\">\n <p class=\"legend-stat\">\n <span class=\"legend-avg\">${formatAverage(layer.average)}</span>\n ${formatFieldLabel(layer.valueKey)}\n </p>\n ${showRamp\n ? html`\n <div class=\"legend-scale\" data-kind=${layer.visualisationType}>\n <div\n class=\"legend-colors\"\n ?data-qualitative=${isBubble || isSpike}\n >\n <div class=\"legend-range\">\n <div\n class=\"legend-range-track\"\n style=\"left:${rangeTrackOffset('left', slider.leftSlider, ranges.length)}\"\n >\n <button\n type=\"button\"\n class=\"legend-thumb\"\n aria-label=\"Lowest ${layer.layerName} range\"\n style=\"left:${thumbTrackPercent(slider.leftSlider, ranges.length)}\"\n @pointerdown=${(e: PointerEvent) =>\n this.startThumbDrag(layer.layerId, 'leftSlider', e)}\n ></button>\n </div>\n <div\n class=\"legend-range-track\"\n style=\"right:${rangeTrackOffset('right', slider.rightSlider, ranges.length)}\"\n >\n <button\n type=\"button\"\n class=\"legend-thumb\"\n aria-label=\"Highest ${layer.layerName} range\"\n style=\"left:${thumbTrackPercent(slider.rightSlider, ranges.length)}\"\n @pointerdown=${(e: PointerEvent) =>\n this.startThumbDrag(layer.layerId, 'rightSlider', e)}\n ></button>\n </div>\n </div>\n <div class=\"legend-buckets\">\n ${ranges.map((range, index) => {\n const inRange =\n slider.leftSlider <= index && index < slider.rightSlider;\n const fill =\n isBubble || isSpike\n ? MUTED_LEGEND_FILL\n : inRange\n ? range.color\n : MUTED_LEGEND_FILL;\n const bubble = isBubble ? (DEFAULT_BUBBLES_RADIUS[index] ?? 12) : 0;\n const inner = bubble - 15 > 0 ? bubble - 15 : 0;\n return html`<span\n class=\"legend-bucket\"\n ?data-bubble=${isBubble}\n ?data-inner=${inner > 0}\n ?data-qualitative=${isBubble || isSpike}\n style=\"background:${fill};--bubble-size:${bubble}px;--inner-size:${inner}px\"\n ></span>`;\n })}\n </div>\n ${isSpike\n ? html`<div class=\"legend-spikes\">\n ${ranges.map((_range, index) =>\n renderLegendSpike(\n index,\n `${sanitizeKey(layer.layerId)}_${index}`,\n ),\n )}\n </div>`\n : nothing}\n </div>\n ${isMarkers\n ? nothing\n : html`<div class=\"legend-values\">\n ${ranges.map(\n (range) =>\n html`<span class=\"legend-value\">${formatLegendBucket(range.start, 2)}</span>`,\n )}\n </div>`}\n </div>\n `\n : nothing}\n </div>\n `\n : nothing}\n </div>\n `;\n }\n\n override render() {\n const title = this.headerTitle();\n const notice = this.matchNotice();\n return html`\n <div class=\"widget-shell\" part=\"shell\">\n ${this.renderShellHeader(title)}\n <div class=\"widget-body\">\n <div class=\"chart-root\" part=\"chart\" ?hidden=${this._empty}></div>\n ${this._empty ? html`<div class=\"empty\" part=\"empty\">${this._emptyReason}</div>` : nothing}\n ${this.renderLegend()}\n ${notice && !this._empty ? html`<div class=\"match-notice\">${notice}</div>` : nothing}\n ${this._tooltip\n ? html`<div\n class=\"tooltip\"\n part=\"tooltip\"\n style=\"left:${this._tooltip.x}px;top:${this._tooltip.y}px\"\n >\n <div>${this._tooltip.title}</div>\n <div>${this._tooltip.value}</div>\n </div>`\n : nothing}\n ${this.renderShellLabelTooltip()}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ui9000-map-chart': Ui9000MapChart;\n }\n}\n\nexport function registerMapChart(): void {\n if (!customElements.get('ui9000-map-chart')) {\n customElements.define('ui9000-map-chart', Ui9000MapChart);\n }\n}\n\nregisterMapChart();\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geojson.d.ts","sourceRoot":"","sources":["../../../../src/components/map-chart/lib/geojson.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAI3D,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,wBAAwB,CAIrF;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"geojson.d.ts","sourceRoot":"","sources":["../../../../src/components/map-chart/lib/geojson.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAI3D,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,wBAAwB,CAIrF;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAqB1C;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD"}
|
|
@@ -21,7 +21,9 @@ async function fetchMapGeoJson(mapType, baseUrl) {
|
|
|
21
21
|
}
|
|
22
22
|
})();
|
|
23
23
|
cache.set(url, pending);
|
|
24
|
-
|
|
24
|
+
const result = await pending;
|
|
25
|
+
if (!result) cache.delete(url);
|
|
26
|
+
return result;
|
|
25
27
|
}
|
|
26
28
|
function geoJsonFileName(mapType) {
|
|
27
29
|
switch (mapType) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geojson.js","sources":["../../../../src/components/map-chart/lib/geojson.ts"],"sourcesContent":["import type { GeoJsonFeatureCollection } from './types.js';\n\nconst cache = new Map<string, Promise<GeoJsonFeatureCollection | null>>();\n\nexport function isFeatureCollection(value: unknown): value is GeoJsonFeatureCollection {\n if (!value || typeof value !== 'object') return false;\n const obj = value as { type?: string; features?: unknown };\n return obj.type === 'FeatureCollection' && Array.isArray(obj.features);\n}\n\nexport async function fetchMapGeoJson(\n mapType: string,\n baseUrl?: string,\n): Promise<GeoJsonFeatureCollection | null> {\n const trimmed = baseUrl?.trim();\n if (!trimmed || !mapType) return null;\n const url = `${trimmed.replace(/\\/$/, '')}/${geoJsonFileName(mapType)}`;\n const hit = cache.get(url);\n if (hit) return hit;\n\n const pending = (async () => {\n try {\n const res = await fetch(url);\n if (!res.ok) return null;\n const json: unknown = await res.json();\n return isFeatureCollection(json) ? json : null;\n } catch {\n return null;\n }\n })();\n cache.set(url, pending);\n
|
|
1
|
+
{"version":3,"file":"geojson.js","sources":["../../../../src/components/map-chart/lib/geojson.ts"],"sourcesContent":["import type { GeoJsonFeatureCollection } from './types.js';\n\nconst cache = new Map<string, Promise<GeoJsonFeatureCollection | null>>();\n\nexport function isFeatureCollection(value: unknown): value is GeoJsonFeatureCollection {\n if (!value || typeof value !== 'object') return false;\n const obj = value as { type?: string; features?: unknown };\n return obj.type === 'FeatureCollection' && Array.isArray(obj.features);\n}\n\nexport async function fetchMapGeoJson(\n mapType: string,\n baseUrl?: string,\n): Promise<GeoJsonFeatureCollection | null> {\n const trimmed = baseUrl?.trim();\n if (!trimmed || !mapType) return null;\n const url = `${trimmed.replace(/\\/$/, '')}/${geoJsonFileName(mapType)}`;\n const hit = cache.get(url);\n if (hit) return hit;\n\n const pending = (async () => {\n try {\n const res = await fetch(url);\n if (!res.ok) return null;\n const json: unknown = await res.json();\n return isFeatureCollection(json) ? json : null;\n } catch {\n return null;\n }\n })();\n cache.set(url, pending);\n const result = await pending;\n if (!result) cache.delete(url);\n return result;\n}\n\nexport function geoJsonFileName(mapType: string): string {\n switch (mapType) {\n case 'city':\n return 'city.json';\n case 'county':\n return 'county.json';\n case 'state':\n return 'state.json';\n case 'province':\n case 'region':\n return 'province.json';\n case 'country':\n default:\n return 'country.json';\n }\n}\n"],"names":[],"mappings":"AAEA,MAAM,4BAAY,IAAA;AAEX,SAAS,oBAAoB,OAAmD;AACrF,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,MAAM;AACZ,SAAO,IAAI,SAAS,uBAAuB,MAAM,QAAQ,IAAI,QAAQ;AACvE;AAEA,eAAsB,gBACpB,SACA,SAC0C;AAC1C,QAAM,UAAU,mCAAS;AACzB,MAAI,CAAC,WAAW,CAAC,QAAS,QAAO;AACjC,QAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,IAAI,gBAAgB,OAAO,CAAC;AACrE,QAAM,MAAM,MAAM,IAAI,GAAG;AACzB,MAAI,IAAK,QAAO;AAEhB,QAAM,WAAW,YAAY;AAC3B,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,UAAI,CAAC,IAAI,GAAI,QAAO;AACpB,YAAM,OAAgB,MAAM,IAAI,KAAA;AAChC,aAAO,oBAAoB,IAAI,IAAI,OAAO;AAAA,IAC5C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAA;AACA,QAAM,IAAI,KAAK,OAAO;AACtB,QAAM,SAAS,MAAM;AACrB,MAAI,CAAC,OAAQ,OAAM,OAAO,GAAG;AAC7B,SAAO;AACT;AAEO,SAAS,gBAAgB,SAAyB;AACvD,UAAQ,SAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EAAA;AAEb;"}
|