@opendata-ai/openchart-vanilla 8.0.0-rc.3 → 8.0.0-rc.5

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.
@@ -552,6 +552,7 @@ function setupTableAnimationCleanup(wrapper) {
552
552
  }
553
553
 
554
554
  // src/map-camera.ts
555
+ var FOCUS_DIM_OPACITY = 0.25;
555
556
  function focusTargetForFeatures(layout, ids, padding = 16) {
556
557
  const idSet = new Set(ids.map(String));
557
558
  let minX = Infinity;
@@ -594,7 +595,6 @@ function applyMapCamera(svg, camera, layout) {
594
595
  const baseSW = Number(p.getAttribute("data-base-stroke-width") ?? 1);
595
596
  p.setAttribute("r", String(baseR / camera.k));
596
597
  p.setAttribute("stroke-width", String(baseSW / camera.k));
597
- p.setAttribute("vector-effect", "non-scaling-stroke");
598
598
  }
599
599
  } else {
600
600
  cameraGroup.removeAttribute("transform");
@@ -736,7 +736,7 @@ function renderBorders(parent, borders) {
736
736
  }
737
737
  parent.appendChild(g);
738
738
  }
739
- function renderFeatures(parent, features, animation, staggerBudget = 0) {
739
+ function renderFeatures(parent, features, animation, staggerBudget = 0, focusIds) {
740
740
  const g = createSVGElement2("g");
741
741
  g.setAttribute("class", "oc-map-features");
742
742
  g.setAttribute("role", "list");
@@ -779,12 +779,19 @@ function renderFeatures(parent, features, animation, staggerBudget = 0) {
779
779
  if (feature.aria?.label) {
780
780
  path.setAttribute("aria-label", feature.aria.label);
781
781
  }
782
+ const dimmed = focusIds ? !focusIds.has(String(feature.id)) : false;
783
+ const s = path.style;
784
+ if (dimmed) {
785
+ s.setProperty("opacity", String(FOCUS_DIM_OPACITY));
786
+ }
782
787
  if (!bulk && animation?.enter) {
783
788
  const idx = feature.animationIndex ?? i;
784
789
  path.setAttribute("data-animation-index", String(idx));
785
- const s = path.style;
786
790
  s.setProperty("--oc-mark-index", String(idx));
787
791
  s.setProperty("--oc-feature-fill", feature.fill);
792
+ if (dimmed) {
793
+ s.setProperty("--oc-feature-target-opacity", String(FOCUS_DIM_OPACITY));
794
+ }
788
795
  if (staggerBudget > 0 && maxIdx > 0) {
789
796
  s.setProperty("--oc-map-delay", `${shuffledDelays[i]}ms`);
790
797
  }
@@ -797,16 +804,15 @@ function renderPointMarks(parent, points, animation) {
797
804
  if (points.length === 0) return;
798
805
  const g = createSVGElement2("g");
799
806
  g.setAttribute("class", "oc-map-points");
800
- g.setAttribute("role", "list");
801
807
  for (const pt of points) {
802
808
  const circle = createSVGElement2("circle");
803
809
  circle.setAttribute("class", "oc-map-point");
804
- circle.setAttribute("role", "listitem");
805
810
  setAttrs2(circle, {
806
811
  cx: pt.cx,
807
812
  cy: pt.cy,
808
813
  r: pt.r,
809
814
  fill: pt.fill,
815
+ "fill-opacity": pt.fillOpacity,
810
816
  stroke: pt.stroke,
811
817
  "stroke-width": pt.strokeWidth
812
818
  });
@@ -817,10 +823,9 @@ function renderPointMarks(parent, points, animation) {
817
823
  circle.setAttribute("aria-label", pt.aria.label);
818
824
  }
819
825
  if (animation?.enter) {
820
- circle.style.setProperty(
821
- "--oc-mark-index",
822
- String(pt.animationIndex)
823
- );
826
+ const s = circle.style;
827
+ s.setProperty("--oc-mark-index", String(pt.animationIndex));
828
+ s.setProperty("transform-origin", `${pt.cx}px ${pt.cy}px`);
824
829
  }
825
830
  g.appendChild(circle);
826
831
  }
@@ -856,28 +861,64 @@ function renderMapSVG(layout, opts) {
856
861
  }
857
862
  const defs = createSVGElement2("defs");
858
863
  svg.appendChild(defs);
859
- renderChrome(svg, layout);
860
864
  const mapGroup = createSVGElement2("g");
861
865
  mapGroup.setAttribute("class", "oc-map-group");
862
866
  mapGroup.setAttribute("transform", `translate(${layout.area.x},${layout.area.y})`);
863
867
  const cameraGroup = createSVGElement2("g");
864
868
  cameraGroup.setAttribute("class", "oc-map-camera");
865
869
  cameraGroup.setAttribute("data-oc-map-camera", "");
866
- renderFeatures(cameraGroup, features, animate ? animation : void 0, mapStaggerBudget);
870
+ const focusIdSet = layout.focus ? new Set(layout.focus.ids.map(String)) : void 0;
871
+ renderFeatures(
872
+ cameraGroup,
873
+ features,
874
+ animate ? animation : void 0,
875
+ mapStaggerBudget,
876
+ focusIdSet
877
+ );
867
878
  renderBorders(cameraGroup, borders);
868
879
  renderPointMarks(cameraGroup, layout.pointMarks, animate ? animation : void 0);
869
880
  mapGroup.appendChild(cameraGroup);
870
881
  svg.appendChild(mapGroup);
882
+ renderChrome(svg, layout);
871
883
  if (layout.continuousLegend) {
872
884
  renderLegend(svg, layout.continuousLegend);
873
885
  } else if (layout.categoricalLegend) {
874
886
  renderLegend(svg, layout.categoricalLegend);
875
887
  }
876
- if (layout.pointCategoricalLegend) {
877
- renderLegend(svg, layout.pointCategoricalLegend);
878
- }
879
- if (layout.pointContinuousLegend) {
880
- renderLegend(svg, layout.pointContinuousLegend);
888
+ const ptLegend = layout.pointCategoricalLegend ?? layout.pointContinuousLegend;
889
+ if (ptLegend) {
890
+ const isDark = layout.theme.isDark;
891
+ const padX = 10;
892
+ const padY = 8;
893
+ const swatchSize = "swatchSize" in ptLegend ? ptLegend.swatchSize : 10;
894
+ const swatchGap = "swatchGap" in ptLegend ? ptLegend.swatchGap : 6;
895
+ const entryGap = "entryGap" in ptLegend ? ptLegend.entryGap : 16;
896
+ let contentWidth = ptLegend.bounds.width;
897
+ if ("entries" in ptLegend && ptLegend.entries) {
898
+ const cat = ptLegend;
899
+ if (cat && cat.entries.length > 0) {
900
+ const fontSize = ptLegend.labelStyle.fontSize;
901
+ let w = 0;
902
+ for (const entry of cat.entries) {
903
+ w += swatchSize + swatchGap + entry.label.length * fontSize * 0.6 + entryGap;
904
+ }
905
+ w -= entryGap;
906
+ contentWidth = Math.min(w, ptLegend.bounds.width);
907
+ }
908
+ }
909
+ const contentCenterY = ptLegend.bounds.y + swatchSize / 2;
910
+ const bgHeight = swatchSize + padY * 2;
911
+ const bg = createSVGElement2("rect");
912
+ setAttrs2(bg, {
913
+ x: ptLegend.bounds.x - padX,
914
+ y: contentCenterY - bgHeight / 2,
915
+ width: contentWidth + padX * 2,
916
+ height: bgHeight,
917
+ rx: 4,
918
+ fill: isDark ? "rgba(24,24,27,0.9)" : "rgba(255,255,255,0.9)"
919
+ });
920
+ svg.appendChild(bg);
921
+ renderLegend(svg, ptLegend);
881
922
  }
882
923
  if (watermark) {
883
924
  renderWatermark(svg, layout);
@@ -1456,6 +1497,12 @@ function scheduleFontReload(fontFamily, isAlive, onReady) {
1456
1497
  }
1457
1498
 
1458
1499
  // src/map-mount.ts
1500
+ function focusSignature(focus) {
1501
+ if (!focus) return null;
1502
+ const t = focus.target;
1503
+ const ids = focus.ids.map(String).sort().join(",");
1504
+ return `${ids}|${Math.round(t.x)},${Math.round(t.y)},${Math.round(t.width)},${Math.round(t.height)},${t.padding}`;
1505
+ }
1459
1506
  function prefersReducedMotion() {
1460
1507
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
1461
1508
  try {
@@ -1540,6 +1587,7 @@ function createMap(container, spec, options) {
1540
1587
  }
1541
1588
  if (feature) {
1542
1589
  options?.onMarkHover?.({
1590
+ kind: "feature",
1543
1591
  id: feature.id,
1544
1592
  name: feature.name,
1545
1593
  data: feature.data
@@ -1564,6 +1612,7 @@ function createMap(container, spec, options) {
1564
1612
  const handleClick = () => {
1565
1613
  if (feature) {
1566
1614
  options?.onMarkClick?.({
1615
+ kind: "feature",
1567
1616
  id: feature.id,
1568
1617
  name: feature.name,
1569
1618
  data: feature.data
@@ -1600,8 +1649,8 @@ function createMap(container, spec, options) {
1600
1649
  }
1601
1650
  if (pointMark) {
1602
1651
  options?.onMarkHover?.({
1652
+ kind: "point",
1603
1653
  id: pointKey,
1604
- name: pointKey,
1605
1654
  data: pointMark.data
1606
1655
  });
1607
1656
  }
@@ -1624,8 +1673,8 @@ function createMap(container, spec, options) {
1624
1673
  const handlePointClick = () => {
1625
1674
  if (pointMark) {
1626
1675
  options?.onMarkClick?.({
1676
+ kind: "point",
1627
1677
  id: pointKey,
1628
- name: pointKey,
1629
1678
  data: pointMark.data
1630
1679
  });
1631
1680
  }
@@ -1708,7 +1757,7 @@ function createMap(container, spec, options) {
1708
1757
  const fid = el.getAttribute("data-feature-id");
1709
1758
  el.style.setProperty(
1710
1759
  "opacity",
1711
- fid && focusSet.has(fid) ? "1" : "0.25"
1760
+ fid && focusSet.has(fid) ? "1" : String(FOCUS_DIM_OPACITY)
1712
1761
  );
1713
1762
  }
1714
1763
  }
@@ -1721,15 +1770,17 @@ function createMap(container, spec, options) {
1721
1770
  fillTransitionHandle.cancel();
1722
1771
  fillTransitionHandle = null;
1723
1772
  }
1724
- if (svgElement) {
1773
+ const oldSvg = svgElement;
1774
+ const newSvg = renderMapSVG(currentLayout, { animate });
1775
+ if (oldSvg) {
1725
1776
  if (cleanupTooltipEvents) {
1726
1777
  cleanupTooltipEvents();
1727
1778
  cleanupTooltipEvents = null;
1728
1779
  }
1729
- svgElement.remove();
1780
+ container.replaceChild(newSvg, oldSvg);
1781
+ } else {
1782
+ container.appendChild(newSvg);
1730
1783
  }
1731
- const newSvg = renderMapSVG(currentLayout, { animate });
1732
- container.appendChild(newSvg);
1733
1784
  svgElement = newSvg;
1734
1785
  cleanupTooltipEvents = wireTooltipAndInteraction(newSvg, currentLayout);
1735
1786
  if (options?.tooltip !== false) {
@@ -1778,7 +1829,7 @@ function createMap(container, spec, options) {
1778
1829
  const canAnimate = !animationCleanup && !prefersReducedMotion();
1779
1830
  const prevFills = canAnimate ? captureFeatureFills(svgElement) : null;
1780
1831
  const prevFocusIds = currentFocusIds ? currentFocusIds.map(String).sort().join(",") : null;
1781
- const prevFocusPadding = currentLayout.focus?.target.padding ?? null;
1832
+ const prevFocusSig = focusSignature(currentLayout.focus);
1782
1833
  currentLayout = compile();
1783
1834
  render();
1784
1835
  if (canAnimate && prevFills && prevFills.size > 0 && svgElement && currentLayout.animation?.update) {
@@ -1787,9 +1838,8 @@ function createMap(container, spec, options) {
1787
1838
  });
1788
1839
  }
1789
1840
  const nextFocus = currentLayout.focus;
1790
- const nextFocusIds = nextFocus ? nextFocus.ids.map(String).sort().join(",") : null;
1791
- const nextFocusPadding = nextFocus?.target.padding ?? null;
1792
- if (nextFocusIds !== prevFocusIds || nextFocusPadding !== prevFocusPadding) {
1841
+ const nextFocusSig = focusSignature(nextFocus);
1842
+ if (nextFocusSig !== prevFocusSig) {
1793
1843
  if (nextFocus) {
1794
1844
  currentFocusIds = [...nextFocus.ids];
1795
1845
  const cam = cameraForTarget(currentLayout, nextFocus.target);
@@ -6626,4 +6676,4 @@ export {
6626
6676
  createYouDrawIt,
6627
6677
  createChart
6628
6678
  };
6629
- //# sourceMappingURL=chunk-SBIGNRAH.js.map
6679
+ //# sourceMappingURL=chunk-XZZGLZDA.js.map