@opendata-ai/openchart-vanilla 6.23.0 → 6.24.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 +70 -39
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/svg-renderer.test.ts +5 -5
- package/src/measure-text.ts +37 -0
- package/src/mount.ts +1 -33
- package/src/renderers/axes.ts +33 -1
- package/src/renderers/svg-dom.ts +8 -8
- package/src/sankey-mount.ts +4 -0
- package/src/sankey-renderer.ts +16 -6
package/dist/index.js
CHANGED
|
@@ -3313,6 +3313,28 @@ function setupTableAnimationCleanup(wrapper) {
|
|
|
3313
3313
|
};
|
|
3314
3314
|
}
|
|
3315
3315
|
|
|
3316
|
+
// src/measure-text.ts
|
|
3317
|
+
function createMeasureText() {
|
|
3318
|
+
let canvas = null;
|
|
3319
|
+
let ctx = null;
|
|
3320
|
+
return (text, fontSize, fontWeight) => {
|
|
3321
|
+
if (!canvas) {
|
|
3322
|
+
canvas = document.createElement("canvas");
|
|
3323
|
+
ctx = canvas.getContext("2d");
|
|
3324
|
+
}
|
|
3325
|
+
if (!ctx) {
|
|
3326
|
+
return { width: text.length * fontSize * 0.6, height: fontSize * 1.2 };
|
|
3327
|
+
}
|
|
3328
|
+
const weight = fontWeight ?? 400;
|
|
3329
|
+
ctx.font = `${weight} ${fontSize}px Inter, sans-serif`;
|
|
3330
|
+
const metrics = ctx.measureText(text);
|
|
3331
|
+
return {
|
|
3332
|
+
width: metrics.width,
|
|
3333
|
+
height: fontSize * 1.2
|
|
3334
|
+
};
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
|
|
3316
3338
|
// src/svg-renderer.ts
|
|
3317
3339
|
import { clampStaggerDelay } from "@opendata-ai/openchart-engine";
|
|
3318
3340
|
|
|
@@ -3418,12 +3440,11 @@ function setAttrs(el, attrs) {
|
|
|
3418
3440
|
}
|
|
3419
3441
|
}
|
|
3420
3442
|
function applyTextStyle(el, style) {
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
el.style.setProperty("fill", style.fill);
|
|
3443
|
+
const inline = el.style;
|
|
3444
|
+
inline.setProperty("fill", style.fill);
|
|
3445
|
+
inline.setProperty("font-size", `${style.fontSize}px`);
|
|
3446
|
+
inline.setProperty("font-weight", String(style.fontWeight));
|
|
3447
|
+
inline.setProperty("font-family", style.fontFamily);
|
|
3427
3448
|
if (style.textAnchor) {
|
|
3428
3449
|
el.setAttribute("text-anchor", style.textAnchor);
|
|
3429
3450
|
}
|
|
@@ -3663,7 +3684,31 @@ function renderAxis(parent, axis, orientation, layout) {
|
|
|
3663
3684
|
"dominant-baseline": "central"
|
|
3664
3685
|
});
|
|
3665
3686
|
applyTextStyle(label, axis.tickLabelStyle);
|
|
3666
|
-
|
|
3687
|
+
const availableWidth = area.x - 6;
|
|
3688
|
+
const fontSize = axis.tickLabelStyle.fontSize;
|
|
3689
|
+
const fontWeight = axis.tickLabelStyle.fontWeight;
|
|
3690
|
+
const fullWidth = estimateTextWidth2(tick.label, fontSize, fontWeight);
|
|
3691
|
+
if (fullWidth > availableWidth && availableWidth > 20) {
|
|
3692
|
+
const ellipsis = "\u2026";
|
|
3693
|
+
const ellipsisWidth = estimateTextWidth2(ellipsis, fontSize, fontWeight);
|
|
3694
|
+
let lo = 0;
|
|
3695
|
+
let hi = tick.label.length;
|
|
3696
|
+
while (lo < hi) {
|
|
3697
|
+
const mid = lo + hi + 1 >>> 1;
|
|
3698
|
+
const candidate = tick.label.slice(0, mid);
|
|
3699
|
+
if (estimateTextWidth2(candidate, fontSize, fontWeight) + ellipsisWidth <= availableWidth) {
|
|
3700
|
+
lo = mid;
|
|
3701
|
+
} else {
|
|
3702
|
+
hi = mid - 1;
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
label.textContent = lo > 0 ? tick.label.slice(0, lo).trimEnd() + ellipsis : ellipsis;
|
|
3706
|
+
const titleEl = createSVGElement("title");
|
|
3707
|
+
titleEl.textContent = tick.label;
|
|
3708
|
+
label.appendChild(titleEl);
|
|
3709
|
+
} else {
|
|
3710
|
+
label.textContent = tick.label;
|
|
3711
|
+
}
|
|
3667
3712
|
g.appendChild(label);
|
|
3668
3713
|
}
|
|
3669
3714
|
}
|
|
@@ -4542,26 +4587,6 @@ function resolveDarkMode2(mode) {
|
|
|
4542
4587
|
}
|
|
4543
4588
|
return false;
|
|
4544
4589
|
}
|
|
4545
|
-
function createMeasureText() {
|
|
4546
|
-
let canvas = null;
|
|
4547
|
-
let ctx = null;
|
|
4548
|
-
return (text, fontSize, fontWeight) => {
|
|
4549
|
-
if (!canvas) {
|
|
4550
|
-
canvas = document.createElement("canvas");
|
|
4551
|
-
ctx = canvas.getContext("2d");
|
|
4552
|
-
}
|
|
4553
|
-
if (!ctx) {
|
|
4554
|
-
return { width: text.length * fontSize * 0.6, height: fontSize * 1.2 };
|
|
4555
|
-
}
|
|
4556
|
-
const weight = fontWeight ?? 400;
|
|
4557
|
-
ctx.font = `${weight} ${fontSize}px Inter, sans-serif`;
|
|
4558
|
-
const metrics = ctx.measureText(text);
|
|
4559
|
-
return {
|
|
4560
|
-
width: metrics.width,
|
|
4561
|
-
height: fontSize * 1.2
|
|
4562
|
-
};
|
|
4563
|
-
};
|
|
4564
|
-
}
|
|
4565
4590
|
function wireTooltipEvents(svg, tooltipDescriptors, tooltipManager) {
|
|
4566
4591
|
const markElements = svg.querySelectorAll("[data-mark-id]");
|
|
4567
4592
|
const cleanups = [];
|
|
@@ -6547,7 +6572,7 @@ function stampAnimationAttrs2(el, mark, fallbackIndex, animation) {
|
|
|
6547
6572
|
el.setAttribute("data-animation-index", String(idx));
|
|
6548
6573
|
el.style.setProperty("--oc-mark-index", String(idx));
|
|
6549
6574
|
}
|
|
6550
|
-
function renderChromeElement2(parent, element, className, chromeKey) {
|
|
6575
|
+
function renderChromeElement2(parent, element, className, chromeKey, measureText) {
|
|
6551
6576
|
const text = createSVGElement2("text");
|
|
6552
6577
|
setAttrs2(text, { x: element.x, y: element.y });
|
|
6553
6578
|
applyTextStyle2(text, element.style);
|
|
@@ -6557,7 +6582,8 @@ function renderChromeElement2(parent, element, className, chromeKey) {
|
|
|
6557
6582
|
element.text,
|
|
6558
6583
|
element.style.fontSize,
|
|
6559
6584
|
element.style.fontWeight,
|
|
6560
|
-
element.maxWidth
|
|
6585
|
+
element.maxWidth,
|
|
6586
|
+
measureText
|
|
6561
6587
|
);
|
|
6562
6588
|
if (lines.length === 1) {
|
|
6563
6589
|
text.textContent = element.text;
|
|
@@ -6575,12 +6601,12 @@ function renderChromeElement2(parent, element, className, chromeKey) {
|
|
|
6575
6601
|
function renderChrome2(parent, layout) {
|
|
6576
6602
|
const g = createSVGElement2("g");
|
|
6577
6603
|
g.setAttribute("class", "oc-chrome");
|
|
6578
|
-
const { chrome } = layout;
|
|
6604
|
+
const { chrome, measureText } = layout;
|
|
6579
6605
|
if (chrome.title) {
|
|
6580
|
-
renderChromeElement2(g, chrome.title, "oc-title", "title");
|
|
6606
|
+
renderChromeElement2(g, chrome.title, "oc-title", "title", measureText);
|
|
6581
6607
|
}
|
|
6582
6608
|
if (chrome.subtitle) {
|
|
6583
|
-
renderChromeElement2(g, chrome.subtitle, "oc-subtitle", "subtitle");
|
|
6609
|
+
renderChromeElement2(g, chrome.subtitle, "oc-subtitle", "subtitle", measureText);
|
|
6584
6610
|
}
|
|
6585
6611
|
const bottomOffset = layout.area.y + layout.area.height;
|
|
6586
6612
|
if (chrome.source) {
|
|
@@ -6588,7 +6614,8 @@ function renderChrome2(parent, layout) {
|
|
|
6588
6614
|
g,
|
|
6589
6615
|
{ ...chrome.source, y: bottomOffset + chrome.source.y },
|
|
6590
6616
|
"oc-source",
|
|
6591
|
-
"source"
|
|
6617
|
+
"source",
|
|
6618
|
+
measureText
|
|
6592
6619
|
);
|
|
6593
6620
|
}
|
|
6594
6621
|
if (chrome.byline) {
|
|
@@ -6596,7 +6623,8 @@ function renderChrome2(parent, layout) {
|
|
|
6596
6623
|
g,
|
|
6597
6624
|
{ ...chrome.byline, y: bottomOffset + chrome.byline.y },
|
|
6598
6625
|
"oc-byline",
|
|
6599
|
-
"byline"
|
|
6626
|
+
"byline",
|
|
6627
|
+
measureText
|
|
6600
6628
|
);
|
|
6601
6629
|
}
|
|
6602
6630
|
if (chrome.footer) {
|
|
@@ -6604,7 +6632,8 @@ function renderChrome2(parent, layout) {
|
|
|
6604
6632
|
g,
|
|
6605
6633
|
{ ...chrome.footer, y: bottomOffset + chrome.footer.y },
|
|
6606
6634
|
"oc-footer",
|
|
6607
|
-
"footer"
|
|
6635
|
+
"footer",
|
|
6636
|
+
measureText
|
|
6608
6637
|
);
|
|
6609
6638
|
}
|
|
6610
6639
|
parent.appendChild(g);
|
|
@@ -6824,7 +6853,7 @@ function renderNodes(parent, nodes, animation) {
|
|
|
6824
6853
|
}
|
|
6825
6854
|
parent.appendChild(g);
|
|
6826
6855
|
}
|
|
6827
|
-
function renderLabels(parent, nodes) {
|
|
6856
|
+
function renderLabels(parent, nodes, measureText) {
|
|
6828
6857
|
const g = createSVGElement2("g");
|
|
6829
6858
|
g.setAttribute("class", "oc-sankey-labels");
|
|
6830
6859
|
for (const node of nodes) {
|
|
@@ -6836,7 +6865,7 @@ function renderLabels(parent, nodes) {
|
|
|
6836
6865
|
if (label.maxWidth !== void 0 && label.maxWidth > 0) {
|
|
6837
6866
|
const fontSize = label.style.fontSize ?? 12;
|
|
6838
6867
|
const fontWeight = label.style.fontWeight ?? 400;
|
|
6839
|
-
const lines = wrapText2(label.text, fontSize, fontWeight, label.maxWidth);
|
|
6868
|
+
const lines = wrapText2(label.text, fontSize, fontWeight, label.maxWidth, measureText);
|
|
6840
6869
|
if (lines.length > 1) {
|
|
6841
6870
|
const lineHeight = fontSize * (label.style.lineHeight ?? 1.3);
|
|
6842
6871
|
const totalHeight = (lines.length - 1) * lineHeight;
|
|
@@ -6897,7 +6926,7 @@ function renderSankeySVG(layout, animation) {
|
|
|
6897
6926
|
svg.appendChild(defs);
|
|
6898
6927
|
renderLinks(svg, layout.links, nodePositions, animation);
|
|
6899
6928
|
renderNodes(svg, layout.nodes, animation);
|
|
6900
|
-
renderLabels(svg, layout.nodes);
|
|
6929
|
+
renderLabels(svg, layout.nodes, layout.measureText);
|
|
6901
6930
|
renderLegend2(svg, layout.legend);
|
|
6902
6931
|
renderChrome2(svg, layout);
|
|
6903
6932
|
if (layout.watermark) {
|
|
@@ -6929,6 +6958,7 @@ function createSankey(container, spec, options) {
|
|
|
6929
6958
|
let isFirstRender = true;
|
|
6930
6959
|
let animationCleanup = null;
|
|
6931
6960
|
let pendingResize = false;
|
|
6961
|
+
const measureText = createMeasureText();
|
|
6932
6962
|
function getContainerDimensions() {
|
|
6933
6963
|
const rect = container.getBoundingClientRect();
|
|
6934
6964
|
return {
|
|
@@ -6944,7 +6974,8 @@ function createSankey(container, spec, options) {
|
|
|
6944
6974
|
height,
|
|
6945
6975
|
theme: options?.theme,
|
|
6946
6976
|
darkMode,
|
|
6947
|
-
watermark: options?.watermark
|
|
6977
|
+
watermark: options?.watermark,
|
|
6978
|
+
measureText
|
|
6948
6979
|
};
|
|
6949
6980
|
return compileSankey(currentSpec, compileOpts);
|
|
6950
6981
|
}
|