@opendata-ai/openchart-vanilla 6.25.4 → 6.27.0
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/dist/index.d.ts +54 -2
- package/dist/index.js +661 -29
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
- package/src/__tests__/compound-labels.test.ts +122 -0
- package/src/__tests__/crosshair.test.ts +121 -0
- package/src/__tests__/mount.test.ts +19 -0
- package/src/__tests__/tilemap.test.ts +158 -0
- package/src/graph-mount.ts +1 -1
- package/src/index.ts +3 -0
- package/src/mount.ts +45 -2
- package/src/renderers/axes.ts +81 -20
- package/src/renderers/legend.ts +6 -2
- package/src/sankey-renderer.ts +4 -2
- package/src/svg-renderer.ts +28 -1
- package/src/tilemap-mount.ts +394 -0
- package/src/tilemap-renderer.ts +425 -0
package/dist/index.js
CHANGED
|
@@ -2805,7 +2805,7 @@ function createGraph(container, spec, options) {
|
|
|
2805
2805
|
}
|
|
2806
2806
|
chromeEl = document.createElement("div");
|
|
2807
2807
|
chromeEl.className = "oc-graph-chrome";
|
|
2808
|
-
|
|
2808
|
+
renderChrome4();
|
|
2809
2809
|
wrapper.appendChild(chromeEl);
|
|
2810
2810
|
canvas = document.createElement("canvas");
|
|
2811
2811
|
canvas.className = "oc-graph-canvas";
|
|
@@ -2825,7 +2825,7 @@ function createGraph(container, spec, options) {
|
|
|
2825
2825
|
renderer = new GraphCanvasRenderer(canvas);
|
|
2826
2826
|
renderer.resize(width, canvasHeight);
|
|
2827
2827
|
}
|
|
2828
|
-
function
|
|
2828
|
+
function renderChrome4() {
|
|
2829
2829
|
if (!chromeEl) return;
|
|
2830
2830
|
let html = "";
|
|
2831
2831
|
if (compilation.chrome.title) {
|
|
@@ -2843,7 +2843,7 @@ function createGraph(container, spec, options) {
|
|
|
2843
2843
|
}
|
|
2844
2844
|
function renderLegend3() {
|
|
2845
2845
|
if (!legendEl) return;
|
|
2846
|
-
const entries = compilation.legend.entries;
|
|
2846
|
+
const entries = "entries" in compilation.legend ? compilation.legend.entries : [];
|
|
2847
2847
|
if (entries.length === 0) {
|
|
2848
2848
|
legendEl.style.display = "none";
|
|
2849
2849
|
return;
|
|
@@ -3139,7 +3139,7 @@ function createGraph(container, spec, options) {
|
|
|
3139
3139
|
compilation = compile();
|
|
3140
3140
|
adjacencyMap = buildAdjacencyMap(compilation.edges);
|
|
3141
3141
|
buildDataMaps();
|
|
3142
|
-
|
|
3142
|
+
renderChrome4();
|
|
3143
3143
|
renderLegend3();
|
|
3144
3144
|
initSimulation();
|
|
3145
3145
|
initInteraction();
|
|
@@ -3174,7 +3174,7 @@ function createGraph(container, spec, options) {
|
|
|
3174
3174
|
};
|
|
3175
3175
|
});
|
|
3176
3176
|
spatialIndex.rebuild(positionedNodes);
|
|
3177
|
-
|
|
3177
|
+
renderChrome4();
|
|
3178
3178
|
renderLegend3();
|
|
3179
3179
|
needsRender = true;
|
|
3180
3180
|
scheduleRender();
|
|
@@ -3637,6 +3637,18 @@ import {
|
|
|
3637
3637
|
getAxisTitleOffset,
|
|
3638
3638
|
TICK_LABEL_OFFSET
|
|
3639
3639
|
} from "@opendata-ai/openchart-core";
|
|
3640
|
+
function appendCompoundLabel(parent, primaryText, subtitle, fontWeight) {
|
|
3641
|
+
const primarySpan = createSVGElement("tspan");
|
|
3642
|
+
primarySpan.setAttribute("font-weight", String(fontWeight));
|
|
3643
|
+
primarySpan.textContent = primaryText;
|
|
3644
|
+
parent.appendChild(primarySpan);
|
|
3645
|
+
const subtitleSpan = createSVGElement("tspan");
|
|
3646
|
+
subtitleSpan.setAttribute("dx", "0.5em");
|
|
3647
|
+
subtitleSpan.textContent = subtitle;
|
|
3648
|
+
subtitleSpan.setAttribute("font-weight", "400");
|
|
3649
|
+
subtitleSpan.setAttribute("fill-opacity", "0.6");
|
|
3650
|
+
parent.appendChild(subtitleSpan);
|
|
3651
|
+
}
|
|
3640
3652
|
function renderAxis(parent, axis, orientation, layout) {
|
|
3641
3653
|
const g = createSVGElement("g");
|
|
3642
3654
|
const isRight = orientation === "y" && axis.orient === "right";
|
|
@@ -3693,27 +3705,62 @@ function renderAxis(parent, axis, orientation, layout) {
|
|
|
3693
3705
|
const availableWidth = area.x - TICK_LABEL_OFFSET;
|
|
3694
3706
|
const fontSize = axis.tickLabelStyle.fontSize;
|
|
3695
3707
|
const fontWeight = axis.tickLabelStyle.fontWeight;
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
const
|
|
3699
|
-
const
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
const
|
|
3704
|
-
const
|
|
3705
|
-
|
|
3706
|
-
|
|
3708
|
+
if (tick.subtitle) {
|
|
3709
|
+
const gapWidth = fontSize * 0.5;
|
|
3710
|
+
const subtitleWidth = estimateTextWidth2(tick.subtitle, fontSize, fontWeight);
|
|
3711
|
+
const primaryWidth = estimateTextWidth2(tick.label, fontSize, fontWeight);
|
|
3712
|
+
const totalWidth = primaryWidth + gapWidth + subtitleWidth;
|
|
3713
|
+
if (totalWidth > availableWidth && availableWidth > 20) {
|
|
3714
|
+
const ellipsis = "\u2026";
|
|
3715
|
+
const ellipsisWidth = estimateTextWidth2(ellipsis, fontSize, fontWeight);
|
|
3716
|
+
const budgetForPrimary = availableWidth - gapWidth - subtitleWidth - ellipsisWidth;
|
|
3717
|
+
let primaryText = tick.label;
|
|
3718
|
+
if (budgetForPrimary > 0) {
|
|
3719
|
+
let lo = 0;
|
|
3720
|
+
let hi = tick.label.length;
|
|
3721
|
+
while (lo < hi) {
|
|
3722
|
+
const mid = lo + hi + 1 >>> 1;
|
|
3723
|
+
const candidate = tick.label.slice(0, mid);
|
|
3724
|
+
if (estimateTextWidth2(candidate, fontSize, fontWeight) <= budgetForPrimary) {
|
|
3725
|
+
lo = mid;
|
|
3726
|
+
} else {
|
|
3727
|
+
hi = mid - 1;
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
primaryText = lo > 0 ? tick.label.slice(0, lo).trimEnd() + ellipsis : ellipsis;
|
|
3707
3731
|
} else {
|
|
3708
|
-
|
|
3732
|
+
primaryText = ellipsis;
|
|
3709
3733
|
}
|
|
3734
|
+
appendCompoundLabel(label, primaryText, tick.subtitle, fontWeight);
|
|
3735
|
+
const titleEl = createSVGElement("title");
|
|
3736
|
+
titleEl.textContent = `${tick.label} ${tick.subtitle}`;
|
|
3737
|
+
label.appendChild(titleEl);
|
|
3738
|
+
} else {
|
|
3739
|
+
appendCompoundLabel(label, tick.label, tick.subtitle, fontWeight);
|
|
3710
3740
|
}
|
|
3711
|
-
label.textContent = lo > 0 ? tick.label.slice(0, lo).trimEnd() + ellipsis : ellipsis;
|
|
3712
|
-
const titleEl = createSVGElement("title");
|
|
3713
|
-
titleEl.textContent = tick.label;
|
|
3714
|
-
label.appendChild(titleEl);
|
|
3715
3741
|
} else {
|
|
3716
|
-
|
|
3742
|
+
const fullWidth = estimateTextWidth2(tick.label, fontSize, fontWeight);
|
|
3743
|
+
if (fullWidth > availableWidth && availableWidth > 20) {
|
|
3744
|
+
const ellipsis = "\u2026";
|
|
3745
|
+
const ellipsisWidth = estimateTextWidth2(ellipsis, fontSize, fontWeight);
|
|
3746
|
+
let lo = 0;
|
|
3747
|
+
let hi = tick.label.length;
|
|
3748
|
+
while (lo < hi) {
|
|
3749
|
+
const mid = lo + hi + 1 >>> 1;
|
|
3750
|
+
const candidate = tick.label.slice(0, mid);
|
|
3751
|
+
if (estimateTextWidth2(candidate, fontSize, fontWeight) + ellipsisWidth <= availableWidth) {
|
|
3752
|
+
lo = mid;
|
|
3753
|
+
} else {
|
|
3754
|
+
hi = mid - 1;
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
label.textContent = lo > 0 ? tick.label.slice(0, lo).trimEnd() + ellipsis : ellipsis;
|
|
3758
|
+
const titleEl = createSVGElement("title");
|
|
3759
|
+
titleEl.textContent = tick.label;
|
|
3760
|
+
label.appendChild(titleEl);
|
|
3761
|
+
} else {
|
|
3762
|
+
label.textContent = tick.label;
|
|
3763
|
+
}
|
|
3717
3764
|
}
|
|
3718
3765
|
} else {
|
|
3719
3766
|
label.textContent = tick.label;
|
|
@@ -3930,8 +3977,11 @@ function renderChrome(parent, layout) {
|
|
|
3930
3977
|
|
|
3931
3978
|
// src/renderers/legend.ts
|
|
3932
3979
|
import { estimateTextWidth as estimateTextWidth3 } from "@opendata-ai/openchart-core";
|
|
3980
|
+
function isCategorical(legend) {
|
|
3981
|
+
return !legend.type || legend.type === "categorical";
|
|
3982
|
+
}
|
|
3933
3983
|
function renderLegend(parent, legend) {
|
|
3934
|
-
if (legend.entries.length === 0) return;
|
|
3984
|
+
if (!isCategorical(legend) || legend.entries.length === 0) return;
|
|
3935
3985
|
const g = createSVGElement("g");
|
|
3936
3986
|
g.setAttribute("class", "oc-legend");
|
|
3937
3987
|
g.setAttribute("role", "list");
|
|
@@ -4364,6 +4414,9 @@ function renderChartSVG(layout, container, opts) {
|
|
|
4364
4414
|
svg.style.height = `${height}px`;
|
|
4365
4415
|
svg.setAttribute("role", layout.a11y.role);
|
|
4366
4416
|
svg.setAttribute("aria-label", layout.a11y.altText);
|
|
4417
|
+
if (layout.display === "sparkline") {
|
|
4418
|
+
svg.setAttribute("data-display", "sparkline");
|
|
4419
|
+
}
|
|
4367
4420
|
const classes = opts?.animate ? "oc-chart oc-animate" : "oc-chart";
|
|
4368
4421
|
svg.setAttribute("class", classes);
|
|
4369
4422
|
if (animation?.enabled) {
|
|
@@ -4434,6 +4487,24 @@ function renderChartSVG(layout, container, opts) {
|
|
|
4434
4487
|
overlay.setAttribute("class", "oc-voronoi-overlay");
|
|
4435
4488
|
overlay.setAttribute("data-voronoi-overlay", "true");
|
|
4436
4489
|
clippedGroup.appendChild(overlay);
|
|
4490
|
+
if (opts?.crosshair) {
|
|
4491
|
+
const crosshairLine = createSVGElement("line");
|
|
4492
|
+
crosshairLine.setAttribute("data-crosshair", "true");
|
|
4493
|
+
crosshairLine.setAttribute("class", "oc-crosshair");
|
|
4494
|
+
setAttrs(crosshairLine, {
|
|
4495
|
+
x1: 0,
|
|
4496
|
+
y1: layout.area.y,
|
|
4497
|
+
x2: 0,
|
|
4498
|
+
y2: layout.area.y + layout.area.height,
|
|
4499
|
+
stroke: layout.theme.colors.gridline,
|
|
4500
|
+
"stroke-opacity": "0.5",
|
|
4501
|
+
"stroke-dasharray": "4,3",
|
|
4502
|
+
"stroke-width": "1",
|
|
4503
|
+
"pointer-events": "none"
|
|
4504
|
+
});
|
|
4505
|
+
crosshairLine.style.display = "none";
|
|
4506
|
+
clippedGroup.appendChild(crosshairLine);
|
|
4507
|
+
}
|
|
4437
4508
|
}
|
|
4438
4509
|
svg.appendChild(clippedGroup);
|
|
4439
4510
|
renderAnnotations(svg, layout);
|
|
@@ -4695,6 +4766,7 @@ function wireVoronoiTooltipEvents(svg, layout, tooltipManager) {
|
|
|
4695
4766
|
const voronoiPoints = collectVoronoiPoints(layout);
|
|
4696
4767
|
if (voronoiPoints.length === 0) return () => {
|
|
4697
4768
|
};
|
|
4769
|
+
const crosshair = svg.querySelector("[data-crosshair]");
|
|
4698
4770
|
const cleanups = [];
|
|
4699
4771
|
const handleMouseMove = (e) => {
|
|
4700
4772
|
const mouseEvent = e;
|
|
@@ -4707,11 +4779,17 @@ function wireVoronoiTooltipEvents(svg, layout, tooltipManager) {
|
|
|
4707
4779
|
const svgY = (mouseEvent.clientY - svgRect.top) * scaleY;
|
|
4708
4780
|
const nearest = findNearestPoint(voronoiPoints, svgX, svgY);
|
|
4709
4781
|
if (!nearest?.tooltip) return;
|
|
4782
|
+
if (crosshair) {
|
|
4783
|
+
crosshair.setAttribute("x1", String(nearest.x));
|
|
4784
|
+
crosshair.setAttribute("x2", String(nearest.x));
|
|
4785
|
+
crosshair.style.display = "";
|
|
4786
|
+
}
|
|
4710
4787
|
const containerX = mouseEvent.clientX - svgRect.left;
|
|
4711
4788
|
const containerY = mouseEvent.clientY - svgRect.top;
|
|
4712
4789
|
tooltipManager.show(nearest.tooltip, containerX, containerY);
|
|
4713
4790
|
};
|
|
4714
4791
|
const handleMouseLeave = () => {
|
|
4792
|
+
if (crosshair) crosshair.style.display = "none";
|
|
4715
4793
|
tooltipManager.hide();
|
|
4716
4794
|
};
|
|
4717
4795
|
const handleTouchStart = (e) => {
|
|
@@ -4727,6 +4805,11 @@ function wireVoronoiTooltipEvents(svg, layout, tooltipManager) {
|
|
|
4727
4805
|
const svgY = (touch.clientY - svgRect.top) * scaleY;
|
|
4728
4806
|
const nearest = findNearestPoint(voronoiPoints, svgX, svgY);
|
|
4729
4807
|
if (!nearest?.tooltip) return;
|
|
4808
|
+
if (crosshair) {
|
|
4809
|
+
crosshair.setAttribute("x1", String(nearest.x));
|
|
4810
|
+
crosshair.setAttribute("x2", String(nearest.x));
|
|
4811
|
+
crosshair.style.display = "";
|
|
4812
|
+
}
|
|
4730
4813
|
const containerX = touch.clientX - svgRect.left;
|
|
4731
4814
|
const containerY = touch.clientY - svgRect.top;
|
|
4732
4815
|
tooltipManager.show(nearest.tooltip, containerX, containerY);
|
|
@@ -5058,7 +5141,7 @@ function wireAnnotationDrag(svg, specAnnotations, onAnnotationEdit, onEdit, setD
|
|
|
5058
5141
|
};
|
|
5059
5142
|
}
|
|
5060
5143
|
function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
|
|
5061
|
-
const
|
|
5144
|
+
const SVG_NS5 = "http://www.w3.org/2000/svg";
|
|
5062
5145
|
const cleanups = [];
|
|
5063
5146
|
const annotationGroups = svg.querySelectorAll(".oc-annotation-text");
|
|
5064
5147
|
for (const el of annotationGroups) {
|
|
@@ -5097,7 +5180,7 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
|
|
|
5097
5180
|
const createdHandles = [];
|
|
5098
5181
|
for (const ep of endpoints) {
|
|
5099
5182
|
if (!Number.isFinite(ep.cx) || !Number.isFinite(ep.cy)) continue;
|
|
5100
|
-
const handleEl = document.createElementNS(
|
|
5183
|
+
const handleEl = document.createElementNS(SVG_NS5, "circle");
|
|
5101
5184
|
handleEl.setAttribute("class", "oc-connector-handle");
|
|
5102
5185
|
handleEl.setAttribute("data-endpoint", ep.name);
|
|
5103
5186
|
handleEl.setAttribute("cx", String(ep.cx));
|
|
@@ -5612,7 +5695,7 @@ function getEditableElements(spec, layout) {
|
|
|
5612
5695
|
for (const series of seriesLabels) {
|
|
5613
5696
|
refs.push(elementRef.seriesLabel(series));
|
|
5614
5697
|
}
|
|
5615
|
-
if (layout.legend.entries.length > 0) {
|
|
5698
|
+
if ("entries" in layout.legend && layout.legend.entries.length > 0) {
|
|
5616
5699
|
refs.push(elementRef.legend());
|
|
5617
5700
|
}
|
|
5618
5701
|
return refs;
|
|
@@ -5733,6 +5816,20 @@ function createChart(container, spec, options) {
|
|
|
5733
5816
|
}
|
|
5734
5817
|
function getContainerDimensions() {
|
|
5735
5818
|
const rect = container.getBoundingClientRect();
|
|
5819
|
+
const isSparkline = "display" in currentSpec && currentSpec.display === "sparkline";
|
|
5820
|
+
if (isSparkline) {
|
|
5821
|
+
let width = rect.width;
|
|
5822
|
+
let height = rect.height;
|
|
5823
|
+
if (!height && container.parentElement) {
|
|
5824
|
+
const parentRect = container.parentElement.getBoundingClientRect();
|
|
5825
|
+
height = parentRect.height;
|
|
5826
|
+
if (!width) width = parentRect.width;
|
|
5827
|
+
}
|
|
5828
|
+
return {
|
|
5829
|
+
width: Math.max(width || 200, 30),
|
|
5830
|
+
height: Math.max(height || 40, 20)
|
|
5831
|
+
};
|
|
5832
|
+
}
|
|
5736
5833
|
return {
|
|
5737
5834
|
width: Math.max(rect.width || 600, 100),
|
|
5738
5835
|
height: Math.max(rect.height || 400, 100)
|
|
@@ -5994,7 +6091,11 @@ function createChart(container, spec, options) {
|
|
|
5994
6091
|
}
|
|
5995
6092
|
currentLayout = compile();
|
|
5996
6093
|
const shouldAnimate = isFirstRender && !!currentLayout.animation?.enabled;
|
|
5997
|
-
|
|
6094
|
+
const crosshair = !!currentLayout.crosshair;
|
|
6095
|
+
svgElement = renderChartSVG(currentLayout, container, {
|
|
6096
|
+
animate: shouldAnimate,
|
|
6097
|
+
crosshair
|
|
6098
|
+
});
|
|
5998
6099
|
tooltipManager = createTooltipManager(container);
|
|
5999
6100
|
cleanupTooltipEvents = wireTooltipEvents(
|
|
6000
6101
|
svgElement,
|
|
@@ -6706,8 +6807,9 @@ function renderBrand2(parent, layout) {
|
|
|
6706
6807
|
a2.appendChild(text);
|
|
6707
6808
|
parent.appendChild(a2);
|
|
6708
6809
|
}
|
|
6709
|
-
function renderLegend2(parent,
|
|
6710
|
-
if (
|
|
6810
|
+
function renderLegend2(parent, legendLayout) {
|
|
6811
|
+
if (!("entries" in legendLayout) || legendLayout.entries.length === 0) return;
|
|
6812
|
+
const legend = legendLayout;
|
|
6711
6813
|
const g = createSVGElement2("g");
|
|
6712
6814
|
g.setAttribute("class", "oc-legend");
|
|
6713
6815
|
g.setAttribute("role", "list");
|
|
@@ -8125,6 +8227,535 @@ function createTable(container, spec, options) {
|
|
|
8125
8227
|
destroy
|
|
8126
8228
|
};
|
|
8127
8229
|
}
|
|
8230
|
+
|
|
8231
|
+
// src/tilemap-mount.ts
|
|
8232
|
+
import { compileTileMap } from "@opendata-ai/openchart-engine";
|
|
8233
|
+
|
|
8234
|
+
// src/tilemap-renderer.ts
|
|
8235
|
+
var SVG_NS4 = "http://www.w3.org/2000/svg";
|
|
8236
|
+
var XLINK_NS3 = "http://www.w3.org/1999/xlink";
|
|
8237
|
+
var BRAND_URL4 = "https://tryopendata.ai";
|
|
8238
|
+
var EASE_VAR_MAP4 = {
|
|
8239
|
+
smooth: "var(--oc-ease-smooth)",
|
|
8240
|
+
snappy: "var(--oc-ease-snappy)"
|
|
8241
|
+
};
|
|
8242
|
+
var gradientIdCounter = 0;
|
|
8243
|
+
function createSVGElement3(tag) {
|
|
8244
|
+
return document.createElementNS(SVG_NS4, tag);
|
|
8245
|
+
}
|
|
8246
|
+
function setAttrs3(el, attrs) {
|
|
8247
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
8248
|
+
el.setAttribute(key, String(value));
|
|
8249
|
+
}
|
|
8250
|
+
}
|
|
8251
|
+
function renderChrome3(parent, layout) {
|
|
8252
|
+
const g = createSVGElement3("g");
|
|
8253
|
+
g.setAttribute("class", "oc-chrome");
|
|
8254
|
+
const { chrome } = layout;
|
|
8255
|
+
const bottomOffset = layout.area.y + layout.area.height;
|
|
8256
|
+
if (chrome.title) {
|
|
8257
|
+
const text = createSVGElement3("text");
|
|
8258
|
+
setAttrs3(text, { x: chrome.title.x, y: chrome.title.y });
|
|
8259
|
+
text.setAttribute("class", "oc-title");
|
|
8260
|
+
text.setAttribute("font-family", chrome.title.style.fontFamily);
|
|
8261
|
+
text.setAttribute("font-size", String(chrome.title.style.fontSize));
|
|
8262
|
+
text.setAttribute("font-weight", String(chrome.title.style.fontWeight));
|
|
8263
|
+
text.style.setProperty("fill", chrome.title.style.fill);
|
|
8264
|
+
text.textContent = chrome.title.text;
|
|
8265
|
+
g.appendChild(text);
|
|
8266
|
+
}
|
|
8267
|
+
if (chrome.subtitle) {
|
|
8268
|
+
const text = createSVGElement3("text");
|
|
8269
|
+
setAttrs3(text, { x: chrome.subtitle.x, y: chrome.subtitle.y });
|
|
8270
|
+
text.setAttribute("class", "oc-subtitle");
|
|
8271
|
+
text.setAttribute("font-family", chrome.subtitle.style.fontFamily);
|
|
8272
|
+
text.setAttribute("font-size", String(chrome.subtitle.style.fontSize));
|
|
8273
|
+
text.setAttribute("font-weight", String(chrome.subtitle.style.fontWeight));
|
|
8274
|
+
text.style.setProperty(
|
|
8275
|
+
"fill",
|
|
8276
|
+
chrome.subtitle.style.fill
|
|
8277
|
+
);
|
|
8278
|
+
text.textContent = chrome.subtitle.text;
|
|
8279
|
+
g.appendChild(text);
|
|
8280
|
+
}
|
|
8281
|
+
if (chrome.source) {
|
|
8282
|
+
const text = createSVGElement3("text");
|
|
8283
|
+
setAttrs3(text, { x: chrome.source.x, y: bottomOffset + chrome.source.y });
|
|
8284
|
+
text.setAttribute("class", "oc-source");
|
|
8285
|
+
text.setAttribute("font-family", chrome.source.style.fontFamily);
|
|
8286
|
+
text.setAttribute("font-size", String(chrome.source.style.fontSize));
|
|
8287
|
+
text.setAttribute("font-weight", String(chrome.source.style.fontWeight));
|
|
8288
|
+
text.style.setProperty(
|
|
8289
|
+
"fill",
|
|
8290
|
+
chrome.source.style.fill
|
|
8291
|
+
);
|
|
8292
|
+
text.textContent = chrome.source.text;
|
|
8293
|
+
g.appendChild(text);
|
|
8294
|
+
}
|
|
8295
|
+
if (chrome.byline) {
|
|
8296
|
+
const text = createSVGElement3("text");
|
|
8297
|
+
setAttrs3(text, { x: chrome.byline.x, y: bottomOffset + chrome.byline.y });
|
|
8298
|
+
text.setAttribute("class", "oc-byline");
|
|
8299
|
+
text.setAttribute("font-family", chrome.byline.style.fontFamily);
|
|
8300
|
+
text.setAttribute("font-size", String(chrome.byline.style.fontSize));
|
|
8301
|
+
text.setAttribute("font-weight", String(chrome.byline.style.fontWeight));
|
|
8302
|
+
text.style.setProperty(
|
|
8303
|
+
"fill",
|
|
8304
|
+
chrome.byline.style.fill
|
|
8305
|
+
);
|
|
8306
|
+
text.textContent = chrome.byline.text;
|
|
8307
|
+
g.appendChild(text);
|
|
8308
|
+
}
|
|
8309
|
+
if (chrome.footer) {
|
|
8310
|
+
const text = createSVGElement3("text");
|
|
8311
|
+
setAttrs3(text, { x: chrome.footer.x, y: bottomOffset + chrome.footer.y });
|
|
8312
|
+
text.setAttribute("class", "oc-footer");
|
|
8313
|
+
text.setAttribute("font-family", chrome.footer.style.fontFamily);
|
|
8314
|
+
text.setAttribute("font-size", String(chrome.footer.style.fontSize));
|
|
8315
|
+
text.setAttribute("font-weight", String(chrome.footer.style.fontWeight));
|
|
8316
|
+
text.style.setProperty(
|
|
8317
|
+
"fill",
|
|
8318
|
+
chrome.footer.style.fill
|
|
8319
|
+
);
|
|
8320
|
+
text.textContent = chrome.footer.text;
|
|
8321
|
+
g.appendChild(text);
|
|
8322
|
+
}
|
|
8323
|
+
parent.appendChild(g);
|
|
8324
|
+
}
|
|
8325
|
+
function renderWatermark(parent, layout) {
|
|
8326
|
+
if (layout.width < 480) return;
|
|
8327
|
+
const { width, height } = layout;
|
|
8328
|
+
const { theme } = layout;
|
|
8329
|
+
const padding = theme.spacing.padding;
|
|
8330
|
+
const rightEdge = width - padding;
|
|
8331
|
+
const bottomEdge = height - padding;
|
|
8332
|
+
const fill = theme.colors.axis;
|
|
8333
|
+
const a2 = createSVGElement3("a");
|
|
8334
|
+
a2.setAttribute("href", BRAND_URL4);
|
|
8335
|
+
a2.setAttributeNS(XLINK_NS3, "xlink:href", BRAND_URL4);
|
|
8336
|
+
a2.setAttribute("target", "_blank");
|
|
8337
|
+
a2.setAttribute("rel", "noopener");
|
|
8338
|
+
a2.setAttribute("class", "oc-chrome-ref");
|
|
8339
|
+
const text = createSVGElement3("text");
|
|
8340
|
+
setAttrs3(text, {
|
|
8341
|
+
x: rightEdge,
|
|
8342
|
+
y: bottomEdge,
|
|
8343
|
+
"dominant-baseline": "alphabetic",
|
|
8344
|
+
"text-anchor": "end",
|
|
8345
|
+
"font-family": theme.fonts.family,
|
|
8346
|
+
"font-size": 12,
|
|
8347
|
+
"fill-opacity": 0.55
|
|
8348
|
+
});
|
|
8349
|
+
text.style.setProperty("fill", fill);
|
|
8350
|
+
const trySpan = createSVGElement3("tspan");
|
|
8351
|
+
setAttrs3(trySpan, { "font-weight": 500 });
|
|
8352
|
+
trySpan.textContent = "try";
|
|
8353
|
+
const openDataSpan = createSVGElement3("tspan");
|
|
8354
|
+
setAttrs3(openDataSpan, { "font-weight": 600, "font-size": 16 });
|
|
8355
|
+
openDataSpan.textContent = "OpenData";
|
|
8356
|
+
const aiSpan = createSVGElement3("tspan");
|
|
8357
|
+
setAttrs3(aiSpan, { "font-weight": 500 });
|
|
8358
|
+
aiSpan.textContent = ".ai";
|
|
8359
|
+
text.appendChild(trySpan);
|
|
8360
|
+
text.appendChild(openDataSpan);
|
|
8361
|
+
text.appendChild(aiSpan);
|
|
8362
|
+
a2.appendChild(text);
|
|
8363
|
+
parent.appendChild(a2);
|
|
8364
|
+
}
|
|
8365
|
+
function renderTiles(parent, tiles, animation) {
|
|
8366
|
+
const g = createSVGElement3("g");
|
|
8367
|
+
g.setAttribute("class", "oc-tilemap-tiles");
|
|
8368
|
+
g.setAttribute("role", "list");
|
|
8369
|
+
const tileDelays = [];
|
|
8370
|
+
if (animation?.enabled) {
|
|
8371
|
+
const baseStagger = 800 / Math.max(tiles.length, 1);
|
|
8372
|
+
let seed = 17;
|
|
8373
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
8374
|
+
const idx = tiles[i].animationIndex ?? i;
|
|
8375
|
+
seed = seed * 1103515245 + 12345 & 2147483647;
|
|
8376
|
+
const jitter = (seed % 1e3 / 1e3 - 0.5) * 0.8;
|
|
8377
|
+
tileDelays.push(Math.max(0, Math.round(idx * baseStagger * (1 + jitter))));
|
|
8378
|
+
}
|
|
8379
|
+
}
|
|
8380
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
8381
|
+
const tile = tiles[i];
|
|
8382
|
+
const tileGroup = createSVGElement3("g");
|
|
8383
|
+
tileGroup.setAttribute("class", "oc-tilemap-tile");
|
|
8384
|
+
tileGroup.setAttribute("data-state", tile.stateCode);
|
|
8385
|
+
tileGroup.setAttribute("role", "listitem");
|
|
8386
|
+
if (tile.aria?.label) {
|
|
8387
|
+
tileGroup.setAttribute("aria-label", tile.aria.label);
|
|
8388
|
+
}
|
|
8389
|
+
if (animation?.enabled) {
|
|
8390
|
+
const idx = tile.animationIndex ?? i;
|
|
8391
|
+
tileGroup.setAttribute("data-animation-index", String(idx));
|
|
8392
|
+
tileGroup.style.setProperty(
|
|
8393
|
+
"--oc-mark-index",
|
|
8394
|
+
String(idx)
|
|
8395
|
+
);
|
|
8396
|
+
tileGroup.style.setProperty(
|
|
8397
|
+
"--oc-tile-delay",
|
|
8398
|
+
`${tileDelays[i]}ms`
|
|
8399
|
+
);
|
|
8400
|
+
}
|
|
8401
|
+
const rect = createSVGElement3("rect");
|
|
8402
|
+
setAttrs3(rect, {
|
|
8403
|
+
x: tile.x,
|
|
8404
|
+
y: tile.y,
|
|
8405
|
+
width: tile.size,
|
|
8406
|
+
height: tile.size,
|
|
8407
|
+
rx: tile.cornerRadius,
|
|
8408
|
+
fill: tile.fill,
|
|
8409
|
+
stroke: tile.stroke,
|
|
8410
|
+
"stroke-width": tile.strokeWidth
|
|
8411
|
+
});
|
|
8412
|
+
tileGroup.appendChild(rect);
|
|
8413
|
+
const codeLabel = createSVGElement3("text");
|
|
8414
|
+
setAttrs3(codeLabel, {
|
|
8415
|
+
x: tile.label.x,
|
|
8416
|
+
y: tile.label.y,
|
|
8417
|
+
"text-anchor": "middle",
|
|
8418
|
+
"dominant-baseline": "central",
|
|
8419
|
+
"font-family": tile.label.style.fontFamily,
|
|
8420
|
+
"font-size": tile.label.style.fontSize,
|
|
8421
|
+
"font-weight": tile.label.style.fontWeight
|
|
8422
|
+
});
|
|
8423
|
+
codeLabel.style.setProperty(
|
|
8424
|
+
"fill",
|
|
8425
|
+
tile.label.style.fill
|
|
8426
|
+
);
|
|
8427
|
+
codeLabel.textContent = tile.label.text;
|
|
8428
|
+
tileGroup.appendChild(codeLabel);
|
|
8429
|
+
if (tile.valueLabel.visible && tile.valueLabel.text) {
|
|
8430
|
+
const valueLabel = createSVGElement3("text");
|
|
8431
|
+
setAttrs3(valueLabel, {
|
|
8432
|
+
x: tile.valueLabel.x,
|
|
8433
|
+
y: tile.valueLabel.y,
|
|
8434
|
+
"text-anchor": "middle",
|
|
8435
|
+
"dominant-baseline": "central",
|
|
8436
|
+
"font-family": tile.valueLabel.style.fontFamily,
|
|
8437
|
+
"font-size": tile.valueLabel.style.fontSize,
|
|
8438
|
+
"font-weight": tile.valueLabel.style.fontWeight
|
|
8439
|
+
});
|
|
8440
|
+
valueLabel.style.setProperty(
|
|
8441
|
+
"fill",
|
|
8442
|
+
tile.valueLabel.style.fill
|
|
8443
|
+
);
|
|
8444
|
+
valueLabel.textContent = tile.valueLabel.text;
|
|
8445
|
+
tileGroup.appendChild(valueLabel);
|
|
8446
|
+
}
|
|
8447
|
+
g.appendChild(tileGroup);
|
|
8448
|
+
}
|
|
8449
|
+
parent.appendChild(g);
|
|
8450
|
+
}
|
|
8451
|
+
function renderGradientLegend(parent, layout) {
|
|
8452
|
+
if (!layout.gradientLegend) return;
|
|
8453
|
+
const { gradientLegend } = layout;
|
|
8454
|
+
const g = createSVGElement3("g");
|
|
8455
|
+
g.setAttribute("class", "oc-tilemap-legend");
|
|
8456
|
+
const defs = parent.querySelector("defs") || createSVGElement3("defs");
|
|
8457
|
+
const exists = parent.querySelector("defs");
|
|
8458
|
+
if (!exists) {
|
|
8459
|
+
parent.insertBefore(defs, parent.firstChild);
|
|
8460
|
+
}
|
|
8461
|
+
const gradientId = `oc-tilemap-legend-gradient-${gradientIdCounter++}`;
|
|
8462
|
+
const grad = createSVGElement3("linearGradient");
|
|
8463
|
+
grad.id = gradientId;
|
|
8464
|
+
grad.setAttribute("x1", "0%");
|
|
8465
|
+
grad.setAttribute("y1", "0%");
|
|
8466
|
+
grad.setAttribute("x2", "100%");
|
|
8467
|
+
grad.setAttribute("y2", "0%");
|
|
8468
|
+
for (const stop of gradientLegend.colorStops) {
|
|
8469
|
+
const s = createSVGElement3("stop");
|
|
8470
|
+
setAttrs3(s, { offset: `${stop.offset * 100}%`, "stop-color": stop.color });
|
|
8471
|
+
grad.appendChild(s);
|
|
8472
|
+
}
|
|
8473
|
+
defs.appendChild(grad);
|
|
8474
|
+
const bar = createSVGElement3("rect");
|
|
8475
|
+
setAttrs3(bar, {
|
|
8476
|
+
x: gradientLegend.bounds.x,
|
|
8477
|
+
y: gradientLegend.bounds.y,
|
|
8478
|
+
width: gradientLegend.bounds.width,
|
|
8479
|
+
height: gradientLegend.bounds.height,
|
|
8480
|
+
rx: 3,
|
|
8481
|
+
fill: `url(#${gradientId})`
|
|
8482
|
+
});
|
|
8483
|
+
g.appendChild(bar);
|
|
8484
|
+
const minText = createSVGElement3("text");
|
|
8485
|
+
setAttrs3(minText, {
|
|
8486
|
+
x: gradientLegend.bounds.x,
|
|
8487
|
+
y: gradientLegend.bounds.y + gradientLegend.bounds.height + 14,
|
|
8488
|
+
"text-anchor": "start",
|
|
8489
|
+
"font-family": gradientLegend.labelStyle.fontFamily,
|
|
8490
|
+
"font-size": gradientLegend.labelStyle.fontSize,
|
|
8491
|
+
"font-weight": gradientLegend.labelStyle.fontWeight
|
|
8492
|
+
});
|
|
8493
|
+
minText.style.setProperty(
|
|
8494
|
+
"fill",
|
|
8495
|
+
gradientLegend.labelStyle.fill
|
|
8496
|
+
);
|
|
8497
|
+
minText.textContent = gradientLegend.minLabel;
|
|
8498
|
+
g.appendChild(minText);
|
|
8499
|
+
const maxText = createSVGElement3("text");
|
|
8500
|
+
setAttrs3(maxText, {
|
|
8501
|
+
x: gradientLegend.bounds.x + gradientLegend.bounds.width,
|
|
8502
|
+
y: gradientLegend.bounds.y + gradientLegend.bounds.height + 14,
|
|
8503
|
+
"text-anchor": "end",
|
|
8504
|
+
"font-family": gradientLegend.labelStyle.fontFamily,
|
|
8505
|
+
"font-size": gradientLegend.labelStyle.fontSize,
|
|
8506
|
+
"font-weight": gradientLegend.labelStyle.fontWeight
|
|
8507
|
+
});
|
|
8508
|
+
maxText.style.setProperty(
|
|
8509
|
+
"fill",
|
|
8510
|
+
gradientLegend.labelStyle.fill
|
|
8511
|
+
);
|
|
8512
|
+
maxText.textContent = gradientLegend.maxLabel;
|
|
8513
|
+
g.appendChild(maxText);
|
|
8514
|
+
parent.appendChild(g);
|
|
8515
|
+
}
|
|
8516
|
+
function renderTileMapSVG(layout, opts) {
|
|
8517
|
+
const { width, height, tiles, a11y, watermark, animation } = layout;
|
|
8518
|
+
const animate = opts?.animate && animation?.enabled;
|
|
8519
|
+
const svg = createSVGElement3("svg");
|
|
8520
|
+
svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
8521
|
+
svg.setAttribute("width", String(width));
|
|
8522
|
+
svg.setAttribute("height", String(height));
|
|
8523
|
+
svg.setAttribute("role", "img");
|
|
8524
|
+
if (a11y.altText) {
|
|
8525
|
+
svg.setAttribute("aria-label", a11y.altText);
|
|
8526
|
+
}
|
|
8527
|
+
const classes = animate ? "oc-tilemap oc-animate" : "oc-tilemap";
|
|
8528
|
+
svg.setAttribute("class", classes);
|
|
8529
|
+
if (animate && animation) {
|
|
8530
|
+
const stagger = Math.max(5, Math.round(800 / Math.max(tiles.length, 1)));
|
|
8531
|
+
svg.style.setProperty("--oc-animation-duration", `${animation.duration}ms`);
|
|
8532
|
+
svg.style.setProperty("--oc-animation-stagger", `${stagger}ms`);
|
|
8533
|
+
svg.style.setProperty("--oc-annotation-delay", `${animation.annotationDelay}ms`);
|
|
8534
|
+
const easeVar = EASE_VAR_MAP4[animation.ease] || EASE_VAR_MAP4.smooth;
|
|
8535
|
+
svg.style.setProperty("--oc-animation-ease", easeVar);
|
|
8536
|
+
}
|
|
8537
|
+
const defs = createSVGElement3("defs");
|
|
8538
|
+
svg.appendChild(defs);
|
|
8539
|
+
renderChrome3(svg, layout);
|
|
8540
|
+
renderTiles(svg, tiles, animate ? animation : void 0);
|
|
8541
|
+
renderGradientLegend(svg, layout);
|
|
8542
|
+
if (watermark) {
|
|
8543
|
+
renderWatermark(svg, layout);
|
|
8544
|
+
}
|
|
8545
|
+
return svg;
|
|
8546
|
+
}
|
|
8547
|
+
|
|
8548
|
+
// src/tilemap-mount.ts
|
|
8549
|
+
function resolveDarkMode5(mode) {
|
|
8550
|
+
if (mode === "force") return true;
|
|
8551
|
+
if (mode === "off" || mode === void 0) return false;
|
|
8552
|
+
if (typeof window !== "undefined" && window.matchMedia) {
|
|
8553
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
8554
|
+
}
|
|
8555
|
+
return false;
|
|
8556
|
+
}
|
|
8557
|
+
function createTileMap(container, spec, options) {
|
|
8558
|
+
let currentSpec = spec;
|
|
8559
|
+
let currentLayout;
|
|
8560
|
+
let destroyed = false;
|
|
8561
|
+
let svgElement = null;
|
|
8562
|
+
let tooltipManager = null;
|
|
8563
|
+
let cleanupTooltipEvents = null;
|
|
8564
|
+
let disconnectResize = null;
|
|
8565
|
+
let animationCleanup = null;
|
|
8566
|
+
let pendingResize = false;
|
|
8567
|
+
const measureText = createMeasureText();
|
|
8568
|
+
function getContainerDimensions() {
|
|
8569
|
+
const rect = container.getBoundingClientRect();
|
|
8570
|
+
return {
|
|
8571
|
+
width: Math.max(rect.width || 600, 100),
|
|
8572
|
+
height: Math.max(rect.height || 400, 100)
|
|
8573
|
+
};
|
|
8574
|
+
}
|
|
8575
|
+
function compile() {
|
|
8576
|
+
const { width, height } = getContainerDimensions();
|
|
8577
|
+
const darkMode = resolveDarkMode5(options?.darkMode);
|
|
8578
|
+
const compileOpts = {
|
|
8579
|
+
width,
|
|
8580
|
+
height,
|
|
8581
|
+
theme: options?.theme,
|
|
8582
|
+
darkMode,
|
|
8583
|
+
watermark: options?.watermark,
|
|
8584
|
+
measureText
|
|
8585
|
+
};
|
|
8586
|
+
return compileTileMap(currentSpec, compileOpts);
|
|
8587
|
+
}
|
|
8588
|
+
function wireTooltipAndInteraction(svg, layout) {
|
|
8589
|
+
const cleanups = [];
|
|
8590
|
+
const tileElements = svg.querySelectorAll(".oc-tilemap-tile");
|
|
8591
|
+
for (const el of tileElements) {
|
|
8592
|
+
const stateCode = el.getAttribute("data-state");
|
|
8593
|
+
if (!stateCode) continue;
|
|
8594
|
+
const content = layout.tooltipDescriptors.get(stateCode);
|
|
8595
|
+
const tile = layout.tiles.find((t) => t.stateCode === stateCode);
|
|
8596
|
+
const handleMouseEnter = (e) => {
|
|
8597
|
+
const mouseEvent = e;
|
|
8598
|
+
if (content && tooltipManager && options?.tooltip !== false) {
|
|
8599
|
+
const svgRect = svg.getBoundingClientRect();
|
|
8600
|
+
const x3 = mouseEvent.clientX - svgRect.left;
|
|
8601
|
+
const y3 = mouseEvent.clientY - svgRect.top;
|
|
8602
|
+
tooltipManager.show(content, x3, y3);
|
|
8603
|
+
}
|
|
8604
|
+
if (tile) {
|
|
8605
|
+
options?.onTileHover?.({
|
|
8606
|
+
stateCode: tile.stateCode,
|
|
8607
|
+
stateName: tile.data.stateName,
|
|
8608
|
+
value: tile.value,
|
|
8609
|
+
data: tile.data
|
|
8610
|
+
});
|
|
8611
|
+
}
|
|
8612
|
+
};
|
|
8613
|
+
const handleMouseMove = (e) => {
|
|
8614
|
+
if (content && tooltipManager && options?.tooltip !== false) {
|
|
8615
|
+
const mouseEvent = e;
|
|
8616
|
+
const svgRect = svg.getBoundingClientRect();
|
|
8617
|
+
const x3 = mouseEvent.clientX - svgRect.left;
|
|
8618
|
+
const y3 = mouseEvent.clientY - svgRect.top;
|
|
8619
|
+
tooltipManager.show(content, x3, y3);
|
|
8620
|
+
}
|
|
8621
|
+
};
|
|
8622
|
+
const handleMouseLeave = () => {
|
|
8623
|
+
tooltipManager?.hide();
|
|
8624
|
+
options?.onTileHover?.(null);
|
|
8625
|
+
};
|
|
8626
|
+
const handleClick = () => {
|
|
8627
|
+
if (tile) {
|
|
8628
|
+
options?.onTileClick?.({
|
|
8629
|
+
stateCode: tile.stateCode,
|
|
8630
|
+
stateName: tile.data.stateName,
|
|
8631
|
+
value: tile.value,
|
|
8632
|
+
data: tile.data
|
|
8633
|
+
});
|
|
8634
|
+
}
|
|
8635
|
+
};
|
|
8636
|
+
el.addEventListener("mouseenter", handleMouseEnter);
|
|
8637
|
+
el.addEventListener("mousemove", handleMouseMove);
|
|
8638
|
+
el.addEventListener("mouseleave", handleMouseLeave);
|
|
8639
|
+
el.addEventListener("click", handleClick);
|
|
8640
|
+
cleanups.push(() => {
|
|
8641
|
+
el.removeEventListener("mouseenter", handleMouseEnter);
|
|
8642
|
+
el.removeEventListener("mousemove", handleMouseMove);
|
|
8643
|
+
el.removeEventListener("mouseleave", handleMouseLeave);
|
|
8644
|
+
el.removeEventListener("click", handleClick);
|
|
8645
|
+
});
|
|
8646
|
+
}
|
|
8647
|
+
return () => {
|
|
8648
|
+
for (const cleanup of cleanups) {
|
|
8649
|
+
cleanup();
|
|
8650
|
+
}
|
|
8651
|
+
};
|
|
8652
|
+
}
|
|
8653
|
+
function render(animate = false) {
|
|
8654
|
+
if (animationCleanup) {
|
|
8655
|
+
animationCleanup();
|
|
8656
|
+
animationCleanup = null;
|
|
8657
|
+
}
|
|
8658
|
+
if (svgElement) {
|
|
8659
|
+
if (cleanupTooltipEvents) {
|
|
8660
|
+
cleanupTooltipEvents();
|
|
8661
|
+
cleanupTooltipEvents = null;
|
|
8662
|
+
}
|
|
8663
|
+
svgElement.remove();
|
|
8664
|
+
}
|
|
8665
|
+
const newSvg = renderTileMapSVG(currentLayout, { animate });
|
|
8666
|
+
container.appendChild(newSvg);
|
|
8667
|
+
svgElement = newSvg;
|
|
8668
|
+
cleanupTooltipEvents = wireTooltipAndInteraction(newSvg, currentLayout);
|
|
8669
|
+
if (options?.tooltip !== false) {
|
|
8670
|
+
if (!tooltipManager) {
|
|
8671
|
+
tooltipManager = createTooltipManager(container);
|
|
8672
|
+
}
|
|
8673
|
+
}
|
|
8674
|
+
if (currentLayout.animation?.enabled) {
|
|
8675
|
+
animationCleanup = setupAnimationCleanup(newSvg, () => {
|
|
8676
|
+
if (pendingResize && !destroyed) {
|
|
8677
|
+
pendingResize = false;
|
|
8678
|
+
resize();
|
|
8679
|
+
}
|
|
8680
|
+
});
|
|
8681
|
+
}
|
|
8682
|
+
}
|
|
8683
|
+
function update(newSpec) {
|
|
8684
|
+
currentSpec = newSpec;
|
|
8685
|
+
currentLayout = compile();
|
|
8686
|
+
render();
|
|
8687
|
+
}
|
|
8688
|
+
function resize() {
|
|
8689
|
+
if (destroyed) return;
|
|
8690
|
+
if (animationCleanup) {
|
|
8691
|
+
pendingResize = true;
|
|
8692
|
+
return;
|
|
8693
|
+
}
|
|
8694
|
+
currentLayout = compile();
|
|
8695
|
+
render();
|
|
8696
|
+
}
|
|
8697
|
+
function exportChart(format, options_) {
|
|
8698
|
+
if (!svgElement) return "";
|
|
8699
|
+
switch (format) {
|
|
8700
|
+
case "svg":
|
|
8701
|
+
return exportSVG(svgElement);
|
|
8702
|
+
case "svg-with-fonts":
|
|
8703
|
+
return exportSVGWithFonts(svgElement);
|
|
8704
|
+
case "png":
|
|
8705
|
+
return exportPNG(svgElement, options_);
|
|
8706
|
+
case "jpg":
|
|
8707
|
+
return exportJPG(svgElement, options_);
|
|
8708
|
+
default:
|
|
8709
|
+
return "";
|
|
8710
|
+
}
|
|
8711
|
+
}
|
|
8712
|
+
function destroy() {
|
|
8713
|
+
if (destroyed) return;
|
|
8714
|
+
destroyed = true;
|
|
8715
|
+
if (animationCleanup) {
|
|
8716
|
+
cancelAnimations(svgElement);
|
|
8717
|
+
animationCleanup();
|
|
8718
|
+
animationCleanup = null;
|
|
8719
|
+
}
|
|
8720
|
+
if (cleanupTooltipEvents) {
|
|
8721
|
+
cleanupTooltipEvents();
|
|
8722
|
+
cleanupTooltipEvents = null;
|
|
8723
|
+
}
|
|
8724
|
+
if (svgElement) {
|
|
8725
|
+
svgElement.remove();
|
|
8726
|
+
svgElement = null;
|
|
8727
|
+
}
|
|
8728
|
+
if (tooltipManager) {
|
|
8729
|
+
tooltipManager.destroy();
|
|
8730
|
+
tooltipManager = null;
|
|
8731
|
+
}
|
|
8732
|
+
if (disconnectResize) {
|
|
8733
|
+
disconnectResize();
|
|
8734
|
+
disconnectResize = null;
|
|
8735
|
+
}
|
|
8736
|
+
container.classList.remove("oc-tilemap-root", "oc-dark");
|
|
8737
|
+
}
|
|
8738
|
+
container.classList.add("oc-tilemap-root");
|
|
8739
|
+
if (resolveDarkMode5(options?.darkMode)) {
|
|
8740
|
+
container.classList.add("oc-dark");
|
|
8741
|
+
}
|
|
8742
|
+
currentLayout = compile();
|
|
8743
|
+
render(true);
|
|
8744
|
+
if (options?.responsive !== false) {
|
|
8745
|
+
disconnectResize = observeResize(container, () => {
|
|
8746
|
+
resize();
|
|
8747
|
+
});
|
|
8748
|
+
}
|
|
8749
|
+
return {
|
|
8750
|
+
update,
|
|
8751
|
+
resize,
|
|
8752
|
+
export: exportChart,
|
|
8753
|
+
destroy,
|
|
8754
|
+
get layout() {
|
|
8755
|
+
return currentLayout;
|
|
8756
|
+
}
|
|
8757
|
+
};
|
|
8758
|
+
}
|
|
8128
8759
|
export {
|
|
8129
8760
|
attachKeyboardNav,
|
|
8130
8761
|
createChart,
|
|
@@ -8133,6 +8764,7 @@ export {
|
|
|
8133
8764
|
createSimulationWorker,
|
|
8134
8765
|
createTable,
|
|
8135
8766
|
createTextEditOverlay,
|
|
8767
|
+
createTileMap,
|
|
8136
8768
|
createTooltipManager,
|
|
8137
8769
|
exportCSV,
|
|
8138
8770
|
exportJPG,
|