@opendata-ai/openchart-vanilla 7.7.0 → 7.8.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.
@@ -1670,11 +1670,351 @@ function renderFacetedPanels(svg, layout, panels, defs) {
1670
1670
  }
1671
1671
  }
1672
1672
 
1673
+ // src/tilemap-renderer.ts
1674
+ import { textAscent as textAscent4 } from "@opendata-ai/openchart-core";
1675
+ var SVG_NS3 = "http://www.w3.org/2000/svg";
1676
+ var XLINK_NS2 = "http://www.w3.org/1999/xlink";
1677
+ var BRAND_URL2 = "https://tryopendata.ai";
1678
+ var EASE_VAR_MAP2 = {
1679
+ smooth: "var(--oc-ease-smooth)",
1680
+ snappy: "var(--oc-ease-snappy)"
1681
+ };
1682
+ function createSVGElement2(tag) {
1683
+ return document.createElementNS(SVG_NS3, tag);
1684
+ }
1685
+ function setAttrs2(el, attrs) {
1686
+ for (const [key, value] of Object.entries(attrs)) {
1687
+ el.setAttribute(key, String(value));
1688
+ }
1689
+ }
1690
+ function renderChrome2(parent, layout) {
1691
+ const g = createSVGElement2("g");
1692
+ g.setAttribute("class", "oc-chrome");
1693
+ const { chrome } = layout;
1694
+ const bottomOffset = layout.area.y + layout.area.height;
1695
+ if (chrome.title) {
1696
+ const text = createSVGElement2("text");
1697
+ setAttrs2(text, {
1698
+ x: chrome.title.x,
1699
+ y: chrome.title.y + textAscent4(chrome.title.style.fontSize)
1700
+ });
1701
+ text.setAttribute("class", "oc-title");
1702
+ text.setAttribute("font-family", chrome.title.style.fontFamily);
1703
+ text.setAttribute("font-size", String(chrome.title.style.fontSize));
1704
+ text.setAttribute("font-weight", String(chrome.title.style.fontWeight));
1705
+ text.style.setProperty("fill", chrome.title.style.fill);
1706
+ text.textContent = chrome.title.text;
1707
+ g.appendChild(text);
1708
+ }
1709
+ if (chrome.subtitle) {
1710
+ const text = createSVGElement2("text");
1711
+ setAttrs2(text, {
1712
+ x: chrome.subtitle.x,
1713
+ y: chrome.subtitle.y + textAscent4(chrome.subtitle.style.fontSize)
1714
+ });
1715
+ text.setAttribute("class", "oc-subtitle");
1716
+ text.setAttribute("font-family", chrome.subtitle.style.fontFamily);
1717
+ text.setAttribute("font-size", String(chrome.subtitle.style.fontSize));
1718
+ text.setAttribute("font-weight", String(chrome.subtitle.style.fontWeight));
1719
+ text.style.setProperty(
1720
+ "fill",
1721
+ chrome.subtitle.style.fill
1722
+ );
1723
+ text.textContent = chrome.subtitle.text;
1724
+ g.appendChild(text);
1725
+ }
1726
+ if (chrome.source) {
1727
+ const text = createSVGElement2("text");
1728
+ setAttrs2(text, {
1729
+ x: chrome.source.x,
1730
+ y: bottomOffset + chrome.source.y + textAscent4(chrome.source.style.fontSize)
1731
+ });
1732
+ text.setAttribute("class", "oc-source");
1733
+ text.setAttribute("font-family", chrome.source.style.fontFamily);
1734
+ text.setAttribute("font-size", String(chrome.source.style.fontSize));
1735
+ text.setAttribute("font-weight", String(chrome.source.style.fontWeight));
1736
+ text.style.setProperty(
1737
+ "fill",
1738
+ chrome.source.style.fill
1739
+ );
1740
+ text.textContent = chrome.source.text;
1741
+ g.appendChild(text);
1742
+ }
1743
+ if (chrome.byline) {
1744
+ const text = createSVGElement2("text");
1745
+ setAttrs2(text, {
1746
+ x: chrome.byline.x,
1747
+ y: bottomOffset + chrome.byline.y + textAscent4(chrome.byline.style.fontSize)
1748
+ });
1749
+ text.setAttribute("class", "oc-byline");
1750
+ text.setAttribute("font-family", chrome.byline.style.fontFamily);
1751
+ text.setAttribute("font-size", String(chrome.byline.style.fontSize));
1752
+ text.setAttribute("font-weight", String(chrome.byline.style.fontWeight));
1753
+ text.style.setProperty(
1754
+ "fill",
1755
+ chrome.byline.style.fill
1756
+ );
1757
+ text.textContent = chrome.byline.text;
1758
+ g.appendChild(text);
1759
+ }
1760
+ if (chrome.footer) {
1761
+ const text = createSVGElement2("text");
1762
+ setAttrs2(text, {
1763
+ x: chrome.footer.x,
1764
+ y: bottomOffset + chrome.footer.y + textAscent4(chrome.footer.style.fontSize)
1765
+ });
1766
+ text.setAttribute("class", "oc-footer");
1767
+ text.setAttribute("font-family", chrome.footer.style.fontFamily);
1768
+ text.setAttribute("font-size", String(chrome.footer.style.fontSize));
1769
+ text.setAttribute("font-weight", String(chrome.footer.style.fontWeight));
1770
+ text.style.setProperty(
1771
+ "fill",
1772
+ chrome.footer.style.fill
1773
+ );
1774
+ text.textContent = chrome.footer.text;
1775
+ g.appendChild(text);
1776
+ }
1777
+ parent.appendChild(g);
1778
+ }
1779
+ function renderWatermark(parent, layout) {
1780
+ if (layout.width < 480) return;
1781
+ const { width, height } = layout;
1782
+ const { theme } = layout;
1783
+ const padding = theme.spacing.padding;
1784
+ const rightEdge = width - padding;
1785
+ const bottomEdge = height - padding;
1786
+ const fill = theme.colors.axis;
1787
+ const a = createSVGElement2("a");
1788
+ a.setAttribute("href", BRAND_URL2);
1789
+ a.setAttributeNS(XLINK_NS2, "xlink:href", BRAND_URL2);
1790
+ a.setAttribute("target", "_blank");
1791
+ a.setAttribute("rel", "noopener");
1792
+ a.setAttribute("class", "oc-chrome-ref");
1793
+ const text = createSVGElement2("text");
1794
+ setAttrs2(text, {
1795
+ x: rightEdge,
1796
+ y: bottomEdge,
1797
+ "dominant-baseline": "alphabetic",
1798
+ "text-anchor": "end",
1799
+ "font-family": theme.fonts.family,
1800
+ "font-size": 12,
1801
+ "fill-opacity": 0.55
1802
+ });
1803
+ text.style.setProperty("fill", fill);
1804
+ const trySpan = createSVGElement2("tspan");
1805
+ setAttrs2(trySpan, { "font-weight": 500 });
1806
+ trySpan.textContent = "try";
1807
+ const openDataSpan = createSVGElement2("tspan");
1808
+ setAttrs2(openDataSpan, { "font-weight": 600, "font-size": 16 });
1809
+ openDataSpan.textContent = "OpenData";
1810
+ const aiSpan = createSVGElement2("tspan");
1811
+ setAttrs2(aiSpan, { "font-weight": 500 });
1812
+ aiSpan.textContent = ".ai";
1813
+ text.appendChild(trySpan);
1814
+ text.appendChild(openDataSpan);
1815
+ text.appendChild(aiSpan);
1816
+ a.appendChild(text);
1817
+ parent.appendChild(a);
1818
+ }
1819
+ function renderTiles(parent, tiles, animation) {
1820
+ const g = createSVGElement2("g");
1821
+ g.setAttribute("class", "oc-tilemap-tiles");
1822
+ g.setAttribute("role", "list");
1823
+ const tileDelays = [];
1824
+ if (animation?.enabled) {
1825
+ const baseStagger = 800 / Math.max(tiles.length, 1);
1826
+ let seed = 17;
1827
+ for (let i = 0; i < tiles.length; i++) {
1828
+ const idx = tiles[i].animationIndex ?? i;
1829
+ seed = seed * 1103515245 + 12345 & 2147483647;
1830
+ const jitter = (seed % 1e3 / 1e3 - 0.5) * 0.8;
1831
+ tileDelays.push(Math.max(0, Math.round(idx * baseStagger * (1 + jitter))));
1832
+ }
1833
+ }
1834
+ for (let i = 0; i < tiles.length; i++) {
1835
+ const tile = tiles[i];
1836
+ const tileGroup = createSVGElement2("g");
1837
+ tileGroup.setAttribute("class", "oc-tilemap-tile");
1838
+ tileGroup.setAttribute("data-state", tile.stateCode);
1839
+ tileGroup.setAttribute("role", "listitem");
1840
+ if (tile.aria?.label) {
1841
+ tileGroup.setAttribute("aria-label", tile.aria.label);
1842
+ }
1843
+ if (animation?.enabled) {
1844
+ const idx = tile.animationIndex ?? i;
1845
+ tileGroup.setAttribute("data-animation-index", String(idx));
1846
+ tileGroup.style.setProperty(
1847
+ "--oc-mark-index",
1848
+ String(idx)
1849
+ );
1850
+ tileGroup.style.setProperty(
1851
+ "--oc-tile-delay",
1852
+ `${tileDelays[i]}ms`
1853
+ );
1854
+ }
1855
+ const rect = createSVGElement2("rect");
1856
+ setAttrs2(rect, {
1857
+ x: tile.x,
1858
+ y: tile.y,
1859
+ width: tile.size,
1860
+ height: tile.size,
1861
+ rx: tile.cornerRadius,
1862
+ fill: tile.fill,
1863
+ "fill-opacity": tile.fillOpacity ?? 1,
1864
+ stroke: tile.stroke,
1865
+ "stroke-width": tile.strokeWidth
1866
+ });
1867
+ tileGroup.appendChild(rect);
1868
+ const codeLabel = createSVGElement2("text");
1869
+ setAttrs2(codeLabel, {
1870
+ x: tile.label.x,
1871
+ y: tile.label.y,
1872
+ "text-anchor": "middle",
1873
+ "dominant-baseline": "central",
1874
+ "font-family": tile.label.style.fontFamily,
1875
+ "font-size": tile.label.style.fontSize,
1876
+ "font-weight": tile.label.style.fontWeight
1877
+ });
1878
+ codeLabel.style.setProperty(
1879
+ "fill",
1880
+ tile.label.style.fill
1881
+ );
1882
+ codeLabel.textContent = tile.label.text;
1883
+ tileGroup.appendChild(codeLabel);
1884
+ if (tile.valueLabel.visible && tile.valueLabel.text) {
1885
+ const valueLabel = createSVGElement2("text");
1886
+ setAttrs2(valueLabel, {
1887
+ x: tile.valueLabel.x,
1888
+ y: tile.valueLabel.y,
1889
+ "text-anchor": "middle",
1890
+ "dominant-baseline": "central",
1891
+ "font-family": tile.valueLabel.style.fontFamily,
1892
+ "font-size": tile.valueLabel.style.fontSize,
1893
+ "font-weight": tile.valueLabel.style.fontWeight
1894
+ });
1895
+ valueLabel.style.setProperty(
1896
+ "fill",
1897
+ tile.valueLabel.style.fill
1898
+ );
1899
+ valueLabel.textContent = tile.valueLabel.text;
1900
+ tileGroup.appendChild(valueLabel);
1901
+ }
1902
+ g.appendChild(tileGroup);
1903
+ }
1904
+ parent.appendChild(g);
1905
+ }
1906
+ function renderGradientLegend(parent, layout) {
1907
+ if (!layout.gradientLegend) return;
1908
+ const { gradientLegend } = layout;
1909
+ const g = createSVGElement2("g");
1910
+ g.setAttribute("class", "oc-tilemap-legend");
1911
+ const defs = parent.querySelector("defs") || createSVGElement2("defs");
1912
+ const exists = parent.querySelector("defs");
1913
+ if (!exists) {
1914
+ parent.insertBefore(defs, parent.firstChild);
1915
+ }
1916
+ const gradientId = nextSvgId("oc-tilemap-legend-gradient");
1917
+ const grad = createSVGElement2("linearGradient");
1918
+ grad.id = gradientId;
1919
+ grad.setAttribute("x1", "0%");
1920
+ grad.setAttribute("y1", "0%");
1921
+ grad.setAttribute("x2", "100%");
1922
+ grad.setAttribute("y2", "0%");
1923
+ for (const stop of gradientLegend.colorStops) {
1924
+ const s = createSVGElement2("stop");
1925
+ const attrs = {
1926
+ offset: `${stop.offset * 100}%`,
1927
+ "stop-color": stop.color
1928
+ };
1929
+ if (stop.opacity !== void 0) {
1930
+ attrs["stop-opacity"] = stop.opacity;
1931
+ }
1932
+ setAttrs2(s, attrs);
1933
+ grad.appendChild(s);
1934
+ }
1935
+ defs.appendChild(grad);
1936
+ const barHeight = gradientLegend.bounds.height;
1937
+ const bar = createSVGElement2("rect");
1938
+ setAttrs2(bar, {
1939
+ x: gradientLegend.bounds.x,
1940
+ y: gradientLegend.bounds.y,
1941
+ width: gradientLegend.bounds.width,
1942
+ height: barHeight,
1943
+ rx: barHeight / 2,
1944
+ fill: `url(#${gradientId})`
1945
+ });
1946
+ g.appendChild(bar);
1947
+ const minText = createSVGElement2("text");
1948
+ setAttrs2(minText, {
1949
+ x: gradientLegend.bounds.x,
1950
+ y: gradientLegend.bounds.y + gradientLegend.bounds.height + 14,
1951
+ "text-anchor": "start",
1952
+ "font-family": gradientLegend.labelStyle.fontFamily,
1953
+ "font-size": gradientLegend.labelStyle.fontSize,
1954
+ "font-weight": gradientLegend.labelStyle.fontWeight
1955
+ });
1956
+ minText.style.setProperty(
1957
+ "fill",
1958
+ gradientLegend.labelStyle.fill
1959
+ );
1960
+ minText.textContent = gradientLegend.minLabel;
1961
+ g.appendChild(minText);
1962
+ const maxText = createSVGElement2("text");
1963
+ setAttrs2(maxText, {
1964
+ x: gradientLegend.bounds.x + gradientLegend.bounds.width,
1965
+ y: gradientLegend.bounds.y + gradientLegend.bounds.height + 14,
1966
+ "text-anchor": "end",
1967
+ "font-family": gradientLegend.labelStyle.fontFamily,
1968
+ "font-size": gradientLegend.labelStyle.fontSize,
1969
+ "font-weight": gradientLegend.labelStyle.fontWeight
1970
+ });
1971
+ maxText.style.setProperty(
1972
+ "fill",
1973
+ gradientLegend.labelStyle.fill
1974
+ );
1975
+ maxText.textContent = gradientLegend.maxLabel;
1976
+ g.appendChild(maxText);
1977
+ parent.appendChild(g);
1978
+ }
1979
+ function renderTileMapSVG(layout, opts) {
1980
+ const { width, height, tiles, a11y, watermark, animation } = layout;
1981
+ const animate = opts?.animate && animation?.enabled;
1982
+ const svg = createSVGElement2("svg");
1983
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
1984
+ svg.setAttribute("role", "img");
1985
+ if (a11y.altText) {
1986
+ svg.setAttribute("aria-label", a11y.altText);
1987
+ }
1988
+ const classes = animate ? "oc-tilemap oc-animate" : "oc-tilemap";
1989
+ svg.setAttribute("class", classes);
1990
+ if (animate && animation) {
1991
+ const stagger = Math.max(5, Math.round(800 / Math.max(tiles.length, 1)));
1992
+ svg.style.setProperty("--oc-animation-duration", `${animation.duration}ms`);
1993
+ svg.style.setProperty("--oc-animation-stagger", `${stagger}ms`);
1994
+ svg.style.setProperty("--oc-annotation-delay", `${animation.annotationDelay}ms`);
1995
+ const easeVar = EASE_VAR_MAP2[animation.ease] || EASE_VAR_MAP2.smooth;
1996
+ svg.style.setProperty("--oc-animation-ease", easeVar);
1997
+ }
1998
+ const defs = createSVGElement2("defs");
1999
+ svg.appendChild(defs);
2000
+ renderChrome2(svg, layout);
2001
+ renderTiles(svg, tiles, animate ? animation : void 0);
2002
+ if (layout.categoricalLegend) {
2003
+ renderLegend(svg, layout.categoricalLegend);
2004
+ } else {
2005
+ renderGradientLegend(svg, layout);
2006
+ }
2007
+ if (watermark) {
2008
+ renderWatermark(svg, layout);
2009
+ }
2010
+ return svg;
2011
+ }
2012
+
1673
2013
  export {
1674
2014
  resetSvgIdCounter,
1675
2015
  SVG_NS,
1676
- renderLegend,
1677
2016
  registerMarkRenderer,
1678
- renderChartSVG
2017
+ renderChartSVG,
2018
+ renderTileMapSVG
1679
2019
  };
1680
- //# sourceMappingURL=chunk-PSMDJEXK.js.map
2020
+ //# sourceMappingURL=chunk-KYRQV6KR.js.map