@opendata-ai/openchart-vanilla 6.15.1 → 6.17.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendata-ai/openchart-vanilla",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.17.0",
|
|
4
4
|
"description": "Vanilla JS renderer for openchart: SVG charts, HTML tables, force-directed graphs",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Riley Hilliard",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@floating-ui/dom": "^1.7.6",
|
|
53
|
-
"@opendata-ai/openchart-core": "6.
|
|
54
|
-
"@opendata-ai/openchart-engine": "6.
|
|
53
|
+
"@opendata-ai/openchart-core": "6.17.0",
|
|
54
|
+
"@opendata-ai/openchart-engine": "6.17.0",
|
|
55
55
|
"d3-force": "^3.0.0",
|
|
56
56
|
"d3-quadtree": "^3.0.1"
|
|
57
57
|
},
|
|
@@ -114,7 +114,13 @@ describe('chart event handlers', () => {
|
|
|
114
114
|
describe('onLegendToggle', () => {
|
|
115
115
|
it('fires when a legend entry is clicked', () => {
|
|
116
116
|
const onLegendToggle = vi.fn();
|
|
117
|
-
const chart = createChart(
|
|
117
|
+
const chart = createChart(
|
|
118
|
+
container,
|
|
119
|
+
{ ...lineSpec, legend: { show: true } },
|
|
120
|
+
{
|
|
121
|
+
onLegendToggle,
|
|
122
|
+
},
|
|
123
|
+
);
|
|
118
124
|
|
|
119
125
|
const legendEntry = container.querySelector('[data-legend-index]');
|
|
120
126
|
expect(legendEntry).not.toBeNull();
|
|
@@ -565,8 +565,11 @@ describe('gridline rendering', () => {
|
|
|
565
565
|
// ---------------------------------------------------------------------------
|
|
566
566
|
|
|
567
567
|
describe('legend rendering', () => {
|
|
568
|
+
/** Legend is auto-suppressed for line charts with endpoint labels; force it on for these tests. */
|
|
569
|
+
const lineSpecWithLegend = { ...lineSpec, legend: { show: true } };
|
|
570
|
+
|
|
568
571
|
it('multi-series chart renders legend entries', () => {
|
|
569
|
-
const { svg } = renderSpec(
|
|
572
|
+
const { svg } = renderSpec(lineSpecWithLegend);
|
|
570
573
|
const legend = svg.querySelector('.oc-legend');
|
|
571
574
|
expect(legend).not.toBeNull();
|
|
572
575
|
const entries = legend!.querySelectorAll('.oc-legend-entry');
|
|
@@ -575,7 +578,7 @@ describe('legend rendering', () => {
|
|
|
575
578
|
});
|
|
576
579
|
|
|
577
580
|
it('legend entries have labels with series names', () => {
|
|
578
|
-
const { svg } = renderSpec(
|
|
581
|
+
const { svg } = renderSpec(lineSpecWithLegend);
|
|
579
582
|
const entries = svg.querySelectorAll('.oc-legend-entry');
|
|
580
583
|
const labels: string[] = [];
|
|
581
584
|
for (const entry of entries) {
|
|
@@ -587,7 +590,7 @@ describe('legend rendering', () => {
|
|
|
587
590
|
});
|
|
588
591
|
|
|
589
592
|
it('legend entries have data-legend-label attribute', () => {
|
|
590
|
-
const { svg } = renderSpec(
|
|
593
|
+
const { svg } = renderSpec(lineSpecWithLegend);
|
|
591
594
|
const entries = svg.querySelectorAll('.oc-legend-entry');
|
|
592
595
|
for (const entry of entries) {
|
|
593
596
|
expect(entry.getAttribute('data-legend-label')).not.toBeNull();
|
|
@@ -595,7 +598,7 @@ describe('legend rendering', () => {
|
|
|
595
598
|
});
|
|
596
599
|
|
|
597
600
|
it('legend has ARIA attributes for accessibility', () => {
|
|
598
|
-
const { svg } = renderSpec(
|
|
601
|
+
const { svg } = renderSpec(lineSpecWithLegend);
|
|
599
602
|
const legend = svg.querySelector('.oc-legend');
|
|
600
603
|
expect(legend!.getAttribute('role')).toBe('list');
|
|
601
604
|
expect(legend!.getAttribute('aria-label')).toBe('Chart legend');
|
package/src/gradient-utils.ts
CHANGED
|
@@ -89,25 +89,31 @@ function appendStop(
|
|
|
89
89
|
parent.appendChild(stopEl);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Global counter for gradient IDs. Ensures uniqueness across all charts
|
|
94
|
+
* on the same page, since SVG url(#id) resolves globally in the document.
|
|
95
|
+
*/
|
|
96
|
+
let globalGradientCounter = 0;
|
|
97
|
+
|
|
92
98
|
/**
|
|
93
99
|
* Scan all marks for GradientDef fill values, create SVG gradient elements
|
|
94
100
|
* in the provided <defs> node, and return a map from gradient key to element ID.
|
|
95
101
|
*
|
|
96
|
-
* Identical gradients (by key) share a single SVG element.
|
|
102
|
+
* Identical gradients (by key) share a single SVG element within one chart.
|
|
103
|
+
* IDs are globally unique across charts to avoid SVG url(#id) collisions.
|
|
97
104
|
*/
|
|
98
105
|
export function buildGradientDefs(
|
|
99
106
|
marks: Array<{ fill?: unknown }>,
|
|
100
107
|
defs: SVGElement,
|
|
101
108
|
): Map<string, string> {
|
|
102
109
|
const map = new Map<string, string>();
|
|
103
|
-
let counter = 0;
|
|
104
110
|
|
|
105
111
|
for (const mark of marks) {
|
|
106
112
|
const fill = mark.fill;
|
|
107
113
|
if (fill && isGradientDef(fill)) {
|
|
108
114
|
const key = gradientKey(fill);
|
|
109
115
|
if (!map.has(key)) {
|
|
110
|
-
const id = `oc-grad-${
|
|
116
|
+
const id = `oc-grad-${globalGradientCounter++}`;
|
|
111
117
|
const el = createGradientElement(fill, id);
|
|
112
118
|
defs.appendChild(el);
|
|
113
119
|
map.set(key, id);
|