@opendata-ai/openchart-vanilla 6.7.1 → 6.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.
package/dist/index.js CHANGED
@@ -12,6 +12,10 @@ function getSVGDimensions(svg) {
12
12
  }
13
13
  return { width: 600, height: 400 };
14
14
  }
15
+ function ensureSVGDimensions(svgString, width, height) {
16
+ if (/^<svg[^>]*\swidth\s*=/.test(svgString)) return svgString;
17
+ return svgString.replace(/^(<svg)/, `$1 width="${width}" height="${height}"`);
18
+ }
15
19
  function collectUsedFonts(svgElement) {
16
20
  const fonts = /* @__PURE__ */ new Map();
17
21
  const textElements = svgElement.querySelectorAll("text");
@@ -135,8 +139,8 @@ async function exportPNG(svgElement, options) {
135
139
  if (shouldEmbed) {
136
140
  await embedFonts(svgElement);
137
141
  }
138
- const svgString = exportSVG(svgElement);
139
142
  const { width, height } = getSVGDimensions(svgElement);
143
+ const svgString = ensureSVGDimensions(exportSVG(svgElement), width, height);
140
144
  const canvas = document.createElement("canvas");
141
145
  canvas.width = width * dpi;
142
146
  canvas.height = height * dpi;
@@ -150,7 +154,7 @@ async function exportPNG(svgElement, options) {
150
154
  const url = URL.createObjectURL(blob);
151
155
  return new Promise((resolve, reject) => {
152
156
  img.onload = () => {
153
- ctx.drawImage(img, 0, 0);
157
+ ctx.drawImage(img, 0, 0, width, height);
154
158
  URL.revokeObjectURL(url);
155
159
  canvas.toBlob((result) => {
156
160
  if (result) {
@@ -174,8 +178,8 @@ async function exportJPG(svgElement, options) {
174
178
  if (shouldEmbed) {
175
179
  await embedFonts(svgElement);
176
180
  }
177
- const svgString = exportSVG(svgElement);
178
181
  const { width, height } = getSVGDimensions(svgElement);
182
+ const svgString = ensureSVGDimensions(exportSVG(svgElement), width, height);
179
183
  const canvas = document.createElement("canvas");
180
184
  canvas.width = width * dpi;
181
185
  canvas.height = height * dpi;
@@ -191,7 +195,7 @@ async function exportJPG(svgElement, options) {
191
195
  const url = URL.createObjectURL(blob);
192
196
  return new Promise((resolve, reject) => {
193
197
  img.onload = () => {
194
- ctx.drawImage(img, 0, 0);
198
+ ctx.drawImage(img, 0, 0, width, height);
195
199
  URL.revokeObjectURL(url);
196
200
  canvas.toBlob(
197
201
  (result) => {
@@ -3356,6 +3360,12 @@ function applyTextStyle(el, style) {
3356
3360
  }
3357
3361
  function wrapText(text, fontSize, fontWeight, maxWidth) {
3358
3362
  if (maxWidth <= 0) return [text];
3363
+ const segments = text.split("\n");
3364
+ if (segments.length > 1) {
3365
+ return segments.flatMap(
3366
+ (segment) => segment.length === 0 ? [""] : wrapText(segment, fontSize, fontWeight, maxWidth)
3367
+ );
3368
+ }
3359
3369
  const AVG_CHAR_WIDTH = 0.55;
3360
3370
  const WEIGHT_FACTORS = {
3361
3371
  100: 0.9,
@@ -6654,11 +6664,14 @@ function buildNodePositionMap(nodes) {
6654
6664
  }
6655
6665
  return map;
6656
6666
  }
6667
+ function sanitizeId(s) {
6668
+ return s.replace(/[^a-zA-Z0-9_-]/g, "_");
6669
+ }
6657
6670
  function renderGradientDefs(defs, links, nodePositions) {
6658
6671
  for (let i = 0; i < links.length; i++) {
6659
6672
  const link = links[i];
6660
6673
  if (link.sourceColor === link.targetColor) continue;
6661
- const gradId = `oc-sg-${link.sourceId}-${link.targetId}-${i}`;
6674
+ const gradId = `oc-sg-${sanitizeId(link.sourceId)}-${sanitizeId(link.targetId)}-${i}`;
6662
6675
  const gradient = createSVGElement2("linearGradient");
6663
6676
  gradient.setAttribute("id", gradId);
6664
6677
  gradient.setAttribute("gradientUnits", "userSpaceOnUse");
@@ -6684,7 +6697,7 @@ function renderLinks(parent, links, _nodePositions, animation) {
6684
6697
  const link = links[i];
6685
6698
  const linkG = createSVGElement2("g");
6686
6699
  linkG.setAttribute("class", "oc-sankey-link");
6687
- linkG.setAttribute("data-mark-id", `link-${link.sourceId}-${link.targetId}`);
6700
+ linkG.setAttribute("data-mark-id", `link-${link.sourceId}-${link.targetId}-${i}`);
6688
6701
  linkG.setAttribute("data-source", link.sourceId);
6689
6702
  linkG.setAttribute("data-target", link.targetId);
6690
6703
  if (link.aria?.label) {
@@ -6696,7 +6709,7 @@ function renderLinks(parent, links, _nodePositions, animation) {
6696
6709
  path.setAttribute("stroke", "none");
6697
6710
  path.setAttribute("fill-opacity", String(link.fillOpacity));
6698
6711
  if (link.sourceColor !== link.targetColor) {
6699
- const gradId = `oc-sg-${link.sourceId}-${link.targetId}-${i}`;
6712
+ const gradId = `oc-sg-${sanitizeId(link.sourceId)}-${sanitizeId(link.targetId)}-${i}`;
6700
6713
  path.setAttribute("fill", `url(#${gradId})`);
6701
6714
  } else {
6702
6715
  path.setAttribute("fill", link.sourceColor);
@@ -6811,6 +6824,7 @@ function resolveDarkMode3(mode) {
6811
6824
  }
6812
6825
  var HIGHLIGHT_OPACITY = 0.7;
6813
6826
  var DIM_OPACITY = 0.15;
6827
+ var NODE_DIM_OPACITY = 0.2;
6814
6828
  function createSankey(container, spec, options) {
6815
6829
  let currentSpec = spec;
6816
6830
  let currentLayout;
@@ -6945,6 +6959,7 @@ function createSankey(container, spec, options) {
6945
6959
  return link?.data ?? {};
6946
6960
  }
6947
6961
  function highlightConnectedLinks(svg, nodeId, _layout) {
6962
+ const connectedNodeIds = /* @__PURE__ */ new Set([nodeId]);
6948
6963
  const linkElements = svg.querySelectorAll(".oc-sankey-link");
6949
6964
  for (const el of linkElements) {
6950
6965
  const source = el.getAttribute("data-source");
@@ -6953,6 +6968,17 @@ function createSankey(container, spec, options) {
6953
6968
  if (!path) continue;
6954
6969
  const isConnected = source === nodeId || target === nodeId;
6955
6970
  path.setAttribute("fill-opacity", String(isConnected ? HIGHLIGHT_OPACITY : DIM_OPACITY));
6971
+ if (isConnected) {
6972
+ if (source) connectedNodeIds.add(source);
6973
+ if (target) connectedNodeIds.add(target);
6974
+ }
6975
+ }
6976
+ const nodeElements = svg.querySelectorAll(".oc-sankey-node");
6977
+ for (const el of nodeElements) {
6978
+ const nid = el.getAttribute("data-node-id");
6979
+ if (!nid) continue;
6980
+ const isConnected = connectedNodeIds.has(nid);
6981
+ el.style.opacity = isConnected ? "1" : String(NODE_DIM_OPACITY);
6956
6982
  }
6957
6983
  }
6958
6984
  function resetLinkOpacity(svg, layout) {
@@ -6963,7 +6989,11 @@ function createSankey(container, spec, options) {
6963
6989
  const source = el.getAttribute("data-source");
6964
6990
  const target = el.getAttribute("data-target");
6965
6991
  const link = layout.links.find((l) => l.sourceId === source && l.targetId === target);
6966
- path.setAttribute("fill-opacity", String(link?.fillOpacity ?? 0.35));
6992
+ path.setAttribute("fill-opacity", String(link?.fillOpacity ?? 0.5));
6993
+ }
6994
+ const nodeElements = svg.querySelectorAll(".oc-sankey-node");
6995
+ for (const el of nodeElements) {
6996
+ el.style.opacity = "1";
6967
6997
  }
6968
6998
  }
6969
6999
  function render() {