@internetstiftelsen/charts 0.8.0 → 0.9.1
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/LICENSE +21 -0
- package/README.md +97 -8
- package/{area.d.ts → dist/area.d.ts} +1 -2
- package/{area.js → dist/area.js} +2 -19
- package/{bar.d.ts → dist/bar.d.ts} +3 -5
- package/{bar.js → dist/bar.js} +8 -33
- package/{base-chart.d.ts → dist/base-chart.d.ts} +75 -14
- package/{base-chart.js → dist/base-chart.js} +429 -122
- package/dist/chart-interface.d.ts +19 -0
- package/{donut-center-content.d.ts → dist/donut-center-content.d.ts} +1 -1
- package/dist/donut-chart.d.ts +51 -0
- package/dist/donut-chart.js +374 -0
- package/{gauge-chart.d.ts → dist/gauge-chart.d.ts} +19 -8
- package/{gauge-chart.js → dist/gauge-chart.js} +317 -106
- package/{grid.d.ts → dist/grid.d.ts} +1 -1
- package/{layout-manager.d.ts → dist/layout-manager.d.ts} +5 -5
- package/{legend.d.ts → dist/legend.d.ts} +3 -1
- package/{legend.js → dist/legend.js} +32 -0
- package/{line.d.ts → dist/line.d.ts} +1 -1
- package/{line.js → dist/line.js} +3 -25
- package/{pie-chart.d.ts → dist/pie-chart.d.ts} +10 -21
- package/{pie-chart.js → dist/pie-chart.js} +51 -172
- package/dist/radial-chart-base.d.ts +25 -0
- package/dist/radial-chart-base.js +79 -0
- package/dist/scale-utils.d.ts +3 -0
- package/dist/scale-utils.js +14 -0
- package/{theme.d.ts → dist/theme.d.ts} +2 -0
- package/{theme.js → dist/theme.js} +24 -29
- package/{title.d.ts → dist/title.d.ts} +1 -1
- package/{tooltip.d.ts → dist/tooltip.d.ts} +1 -1
- package/{tooltip.js → dist/tooltip.js} +239 -74
- package/{types.d.ts → dist/types.d.ts} +27 -10
- package/{utils.d.ts → dist/utils.d.ts} +7 -2
- package/{utils.js → dist/utils.js} +24 -5
- package/dist/word-cloud-chart.d.ts +32 -0
- package/dist/word-cloud-chart.js +201 -0
- package/{x-axis.d.ts → dist/x-axis.d.ts} +2 -1
- package/{x-axis.js → dist/x-axis.js} +18 -14
- package/{xy-chart.d.ts → dist/xy-chart.d.ts} +14 -9
- package/{xy-chart.js → dist/xy-chart.js} +107 -130
- package/{y-axis.d.ts → dist/y-axis.d.ts} +1 -1
- package/{y-axis.js → dist/y-axis.js} +4 -4
- package/package.json +39 -35
- package/chart-interface.d.ts +0 -13
- package/donut-chart.d.ts +0 -38
- package/donut-chart.js +0 -316
- /package/{chart-interface.js → dist/chart-interface.js} +0 -0
- /package/{donut-center-content.js → dist/donut-center-content.js} +0 -0
- /package/{export-image.d.ts → dist/export-image.d.ts} +0 -0
- /package/{export-image.js → dist/export-image.js} +0 -0
- /package/{export-pdf.d.ts → dist/export-pdf.d.ts} +0 -0
- /package/{export-pdf.js → dist/export-pdf.js} +0 -0
- /package/{export-tabular.d.ts → dist/export-tabular.d.ts} +0 -0
- /package/{export-tabular.js → dist/export-tabular.js} +0 -0
- /package/{export-xlsx.d.ts → dist/export-xlsx.d.ts} +0 -0
- /package/{export-xlsx.js → dist/export-xlsx.js} +0 -0
- /package/{grid.js → dist/grid.js} +0 -0
- /package/{grouped-data.d.ts → dist/grouped-data.d.ts} +0 -0
- /package/{grouped-data.js → dist/grouped-data.js} +0 -0
- /package/{grouped-tabular.d.ts → dist/grouped-tabular.d.ts} +0 -0
- /package/{grouped-tabular.js → dist/grouped-tabular.js} +0 -0
- /package/{layout-manager.js → dist/layout-manager.js} +0 -0
- /package/{title.js → dist/title.js} +0 -0
- /package/{types.js → dist/types.js} +0 -0
- /package/{validation.d.ts → dist/validation.d.ts} +0 -0
- /package/{validation.js → dist/validation.js} +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Internetstiftelsen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -6,9 +6,12 @@ A framework-agnostic, composable charting library built on D3.js with TypeScript
|
|
|
6
6
|
|
|
7
7
|
- **Framework Agnostic** - Works with vanilla JS, React, Vue, Svelte, or any framework
|
|
8
8
|
- **Composable Architecture** - Build charts by composing components
|
|
9
|
-
- **Multiple Chart Types** - XYChart (lines, areas, bars), DonutChart, PieChart, and GaugeChart
|
|
9
|
+
- **Multiple Chart Types** - XYChart (lines, areas, bars), WordCloudChart, DonutChart, PieChart, and GaugeChart
|
|
10
|
+
- **Radial Value Labels** - Pie and donut charts support optional on-chart labels with custom formatters
|
|
11
|
+
- **Optional Gauge Animation** - Animate gauge value transitions with `gauge.animate`
|
|
10
12
|
- **Stacking Control** - Bar stacking modes with optional reversed visual series order
|
|
11
13
|
- **Flexible Scales** - Band, linear, time, and logarithmic scales
|
|
14
|
+
- **Explicit or Responsive Sizing** - Set top-level `width`/`height` or let the container drive size
|
|
12
15
|
- **Auto Resize** - Built-in ResizeObserver handles responsive behavior
|
|
13
16
|
- **Responsive Policy** - Chart-level container-query overrides for theme and components
|
|
14
17
|
- **Type Safe** - Written in TypeScript with full type definitions
|
|
@@ -81,6 +84,79 @@ chart
|
|
|
81
84
|
chart.render('#chart-container');
|
|
82
85
|
```
|
|
83
86
|
|
|
87
|
+
Use top-level `width` and `height` for fixed-size charts, or omit them to size
|
|
88
|
+
from the render container.
|
|
89
|
+
|
|
90
|
+
Theme overrides are deep-partial, so nested overrides like
|
|
91
|
+
`theme.axis.fontSize` preserve the rest of the theme defaults.
|
|
92
|
+
|
|
93
|
+
Responsive overrides are declarative and merge all matching breakpoints in
|
|
94
|
+
declaration order:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const chart = new XYChart({
|
|
98
|
+
data,
|
|
99
|
+
responsive: {
|
|
100
|
+
breakpoints: {
|
|
101
|
+
sm: {
|
|
102
|
+
maxWidth: 640,
|
|
103
|
+
theme: {
|
|
104
|
+
axis: {
|
|
105
|
+
fontSize: 11,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
components: [
|
|
109
|
+
{
|
|
110
|
+
match: { type: 'xAxis' },
|
|
111
|
+
override: { display: false },
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
md: {
|
|
116
|
+
minWidth: 641,
|
|
117
|
+
maxWidth: 768,
|
|
118
|
+
theme: {
|
|
119
|
+
axis: {
|
|
120
|
+
fontSize: 12,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Word Cloud
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
import { WordCloudChart } from '@internetstiftelsen/charts/word-cloud-chart';
|
|
133
|
+
|
|
134
|
+
const data = [
|
|
135
|
+
{ word: 'internet', count: 96 },
|
|
136
|
+
{ word: 'social', count: 82 },
|
|
137
|
+
{ word: 'news', count: 75 },
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const chart = new WordCloudChart({
|
|
141
|
+
data,
|
|
142
|
+
wordCloud: {
|
|
143
|
+
minValue: 5,
|
|
144
|
+
minWordLength: 3,
|
|
145
|
+
minFontSize: 3,
|
|
146
|
+
maxFontSize: 20,
|
|
147
|
+
padding: 1,
|
|
148
|
+
spiral: 'archimedean',
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
chart.render('#word-cloud');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`minFontSize` and `maxFontSize` are percentages of the smaller plot-area
|
|
156
|
+
dimension and define the relative size range passed into `d3-cloud`. The chart
|
|
157
|
+
expects flat `{ word, count }` rows, aggregates duplicate words after trimming,
|
|
158
|
+
and maps theme typography and colors directly into the layout and rendered SVG.
|
|
159
|
+
|
|
84
160
|
## Export
|
|
85
161
|
|
|
86
162
|
`chart.export()` supports `svg`, `json`, `csv`, `xlsx`, `png`, `jpg`, and `pdf`.
|
|
@@ -104,12 +180,9 @@ It auto-detects grouped and normal (flat) table layouts.
|
|
|
104
180
|
import { toChartData } from '@internetstiftelsen/charts/utils';
|
|
105
181
|
import { XYChart } from '@internetstiftelsen/charts/xy-chart';
|
|
106
182
|
|
|
107
|
-
const data = toChartData(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
categoryKey: 'Category',
|
|
111
|
-
},
|
|
112
|
-
);
|
|
183
|
+
const data = toChartData('\t\tDaily\tWeekly\nAll users\tSegment A\t85%\t92%\n\tSegment B\t84%\t91%', {
|
|
184
|
+
categoryKey: 'Category',
|
|
185
|
+
});
|
|
113
186
|
|
|
114
187
|
const chart = new XYChart({ data });
|
|
115
188
|
chart.render('#chart-container');
|
|
@@ -118,16 +191,32 @@ chart.render('#chart-container');
|
|
|
118
191
|
The parser supports JSON-escaped string payloads and grouped carry-forward row
|
|
119
192
|
structure (blank first column on continuation rows).
|
|
120
193
|
|
|
194
|
+
Supported input shapes:
|
|
195
|
+
|
|
196
|
+
- Plain tab-delimited strings
|
|
197
|
+
- JSON-escaped string payloads
|
|
198
|
+
|
|
199
|
+
Auto-detection behavior:
|
|
200
|
+
|
|
201
|
+
- Grouped rows when a carry-forward group structure is present
|
|
202
|
+
- Flat rows when no grouped continuation rows are detected
|
|
203
|
+
|
|
204
|
+
Grouped parsing rules:
|
|
205
|
+
|
|
206
|
+
- Header row starts with two structural columns (`group`, `category`) before metrics
|
|
207
|
+
- Continuation rows leave the first column blank to inherit the previous group
|
|
208
|
+
- Blank separator rows are ignored
|
|
209
|
+
|
|
121
210
|
## Documentation
|
|
122
211
|
|
|
123
212
|
- [Getting Started](./docs/getting-started.md) - Installation, Vanilla JS, React integration
|
|
124
213
|
- [XYChart](./docs/xy-chart.md) - Line, area, and bar charts API
|
|
214
|
+
- [WordCloudChart](./docs/word-cloud-chart.md) - Word frequency visualization API
|
|
125
215
|
- [DonutChart](./docs/donut-chart.md) - Donut/pie charts API
|
|
126
216
|
- [PieChart](./docs/pie-chart.md) - Pie chart API
|
|
127
217
|
- [GaugeChart](./docs/gauge-chart.md) - Gauge chart API
|
|
128
218
|
- [Components](./docs/components.md) - Axes, Grid, Tooltip, Legend, Title
|
|
129
219
|
- [Theming](./docs/theming.md) - Colors, fonts, and styling
|
|
130
|
-
- [Advanced](./docs/advanced.md) - Scales, TypeScript, architecture, performance
|
|
131
220
|
|
|
132
221
|
## Browser Support
|
|
133
222
|
|
|
@@ -18,8 +18,7 @@ export declare class Area implements ChartComponent<AreaConfigBase> {
|
|
|
18
18
|
readonly exportHooks?: ExportHooks<AreaConfigBase>;
|
|
19
19
|
constructor(config: AreaConfig);
|
|
20
20
|
getExportConfig(): AreaConfigBase;
|
|
21
|
-
createExportComponent(override?: Partial<AreaConfigBase>): ChartComponent
|
|
22
|
-
private getScaledPosition;
|
|
21
|
+
createExportComponent(override?: Partial<AreaConfigBase>): ChartComponent<AreaConfigBase>;
|
|
23
22
|
private getStackValues;
|
|
24
23
|
render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType: ScaleType | undefined, theme: ChartTheme, stackingContext?: AreaStackingContext, valueLabelLayer?: Selection<SVGGElement, undefined, null, undefined>): void;
|
|
25
24
|
private renderValueLabels;
|
package/{area.js → dist/area.js}
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { area, curveBasis, curveCardinal, curveLinear, curveMonotoneX, curveNatural, curveStep, line, } from 'd3';
|
|
2
2
|
import { mergeDeep, sanitizeForCSS } from './utils.js';
|
|
3
|
+
import { getScalePosition } from './scale-utils.js';
|
|
3
4
|
const AREA_CURVE_FACTORIES = {
|
|
4
5
|
linear: curveLinear,
|
|
5
6
|
monotone: curveMonotoneX,
|
|
@@ -132,24 +133,6 @@ export class Area {
|
|
|
132
133
|
exportHooks: this.exportHooks,
|
|
133
134
|
});
|
|
134
135
|
}
|
|
135
|
-
getScaledPosition(data, key, scale, scaleType) {
|
|
136
|
-
const value = data[key];
|
|
137
|
-
let scaledValue;
|
|
138
|
-
switch (scaleType) {
|
|
139
|
-
case 'band':
|
|
140
|
-
scaledValue = String(value);
|
|
141
|
-
break;
|
|
142
|
-
case 'time':
|
|
143
|
-
scaledValue =
|
|
144
|
-
value instanceof Date ? value : new Date(String(value));
|
|
145
|
-
break;
|
|
146
|
-
case 'linear':
|
|
147
|
-
case 'log':
|
|
148
|
-
scaledValue = typeof value === 'number' ? value : Number(value);
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
return scale(scaledValue) || 0;
|
|
152
|
-
}
|
|
153
136
|
getStackValues(dataPoint, xKey, parseValue, stackingContext) {
|
|
154
137
|
const value = parseValue(dataPoint[this.dataKey]);
|
|
155
138
|
if (!stackingContext || stackingContext.mode === 'none') {
|
|
@@ -176,7 +159,7 @@ export class Area {
|
|
|
176
159
|
}
|
|
177
160
|
render(plotGroup, data, xKey, x, y, parseValue, xScaleType = 'band', theme, stackingContext, valueLabelLayer) {
|
|
178
161
|
const getXPosition = (d) => {
|
|
179
|
-
const scaled =
|
|
162
|
+
const scaled = getScalePosition(x, d.data[xKey], xScaleType);
|
|
180
163
|
return scaled + (x.bandwidth ? x.bandwidth() / 2 : 0);
|
|
181
164
|
};
|
|
182
165
|
const hasValidValue = (d) => {
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import type { Selection } from 'd3';
|
|
2
|
-
import type { BarConfig, BarStackingContext, BarValueLabelConfig, ChartTheme, D3Scale, DataItem,
|
|
2
|
+
import type { BarConfig, BarStackingContext, BarValueLabelConfig, ChartTheme, D3Scale, DataItem, ScaleType, ExportHooks, BarConfigBase } from './types.js';
|
|
3
3
|
import type { ChartComponent } from './chart-interface.js';
|
|
4
4
|
export declare class Bar implements ChartComponent<BarConfigBase> {
|
|
5
5
|
readonly type: "bar";
|
|
6
6
|
readonly dataKey: string;
|
|
7
7
|
readonly fill: string;
|
|
8
8
|
readonly colorAdapter?: (data: DataItem, index: number) => string;
|
|
9
|
-
readonly orientation: Orientation;
|
|
10
9
|
readonly maxBarSize?: number;
|
|
11
10
|
readonly valueLabel?: BarValueLabelConfig;
|
|
12
11
|
readonly exportHooks?: ExportHooks<BarConfigBase>;
|
|
13
12
|
constructor(config: BarConfig);
|
|
14
13
|
getExportConfig(): BarConfigBase;
|
|
15
|
-
createExportComponent(override?: Partial<BarConfigBase>): ChartComponent
|
|
16
|
-
|
|
17
|
-
render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType?: ScaleType, theme?: ChartTheme, stackingContext?: BarStackingContext): void;
|
|
14
|
+
createExportComponent(override?: Partial<BarConfigBase>): ChartComponent<BarConfigBase>;
|
|
15
|
+
render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType?: ScaleType, theme?: ChartTheme, stackingContext?: BarStackingContext, orientation?: 'vertical' | 'horizontal'): void;
|
|
18
16
|
private renderVertical;
|
|
19
17
|
private renderHorizontal;
|
|
20
18
|
private renderVerticalValueLabels;
|
package/{bar.js → dist/bar.js}
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getContrastTextColor, sanitizeForCSS, mergeDeep } from './utils.js';
|
|
2
|
+
import { getScalePosition } from './scale-utils.js';
|
|
2
3
|
const LABEL_INSET_DEFAULT = 4;
|
|
3
4
|
const LABEL_INSET_STACKED = 6;
|
|
4
5
|
const LABEL_MIN_PADDING_DEFAULT = 8;
|
|
@@ -39,12 +40,6 @@ export class Bar {
|
|
|
39
40
|
writable: true,
|
|
40
41
|
value: void 0
|
|
41
42
|
});
|
|
42
|
-
Object.defineProperty(this, "orientation", {
|
|
43
|
-
enumerable: true,
|
|
44
|
-
configurable: true,
|
|
45
|
-
writable: true,
|
|
46
|
-
value: void 0
|
|
47
|
-
});
|
|
48
43
|
Object.defineProperty(this, "maxBarSize", {
|
|
49
44
|
enumerable: true,
|
|
50
45
|
configurable: true,
|
|
@@ -66,7 +61,6 @@ export class Bar {
|
|
|
66
61
|
this.dataKey = config.dataKey;
|
|
67
62
|
this.fill = config.fill || '#8884d8';
|
|
68
63
|
this.colorAdapter = config.colorAdapter;
|
|
69
|
-
this.orientation = config.orientation || 'vertical';
|
|
70
64
|
this.maxBarSize = config.maxBarSize;
|
|
71
65
|
this.valueLabel = config.valueLabel;
|
|
72
66
|
this.exportHooks = config.exportHooks;
|
|
@@ -76,7 +70,6 @@ export class Bar {
|
|
|
76
70
|
dataKey: this.dataKey,
|
|
77
71
|
fill: this.fill,
|
|
78
72
|
colorAdapter: this.colorAdapter,
|
|
79
|
-
orientation: this.orientation,
|
|
80
73
|
maxBarSize: this.maxBarSize,
|
|
81
74
|
valueLabel: this.valueLabel,
|
|
82
75
|
};
|
|
@@ -88,26 +81,8 @@ export class Bar {
|
|
|
88
81
|
exportHooks: this.exportHooks,
|
|
89
82
|
});
|
|
90
83
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
let scaledValue;
|
|
94
|
-
switch (scaleType) {
|
|
95
|
-
case 'band':
|
|
96
|
-
scaledValue = String(value);
|
|
97
|
-
break;
|
|
98
|
-
case 'time':
|
|
99
|
-
scaledValue =
|
|
100
|
-
value instanceof Date ? value : new Date(String(value));
|
|
101
|
-
break;
|
|
102
|
-
case 'linear':
|
|
103
|
-
case 'log':
|
|
104
|
-
scaledValue = typeof value === 'number' ? value : Number(value);
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
return scale(scaledValue) || 0;
|
|
108
|
-
}
|
|
109
|
-
render(plotGroup, data, xKey, x, y, parseValue, xScaleType = 'band', theme, stackingContext) {
|
|
110
|
-
if (this.orientation === 'vertical') {
|
|
84
|
+
render(plotGroup, data, xKey, x, y, parseValue, xScaleType = 'band', theme, stackingContext, orientation = 'vertical') {
|
|
85
|
+
if (orientation === 'vertical') {
|
|
111
86
|
this.renderVertical(plotGroup, data, xKey, x, y, parseValue, xScaleType, stackingContext);
|
|
112
87
|
}
|
|
113
88
|
else {
|
|
@@ -115,7 +90,7 @@ export class Bar {
|
|
|
115
90
|
}
|
|
116
91
|
// Render value labels if enabled
|
|
117
92
|
if (this.valueLabel?.show && theme) {
|
|
118
|
-
if (
|
|
93
|
+
if (orientation === 'vertical') {
|
|
119
94
|
this.renderVerticalValueLabels(plotGroup, data, xKey, x, y, parseValue, xScaleType, theme, stackingContext);
|
|
120
95
|
}
|
|
121
96
|
else {
|
|
@@ -178,7 +153,7 @@ export class Bar {
|
|
|
178
153
|
.attr('class', `bar-${sanitizedKey}`)
|
|
179
154
|
.attr('data-index', (_, i) => i)
|
|
180
155
|
.attr('x', (d) => {
|
|
181
|
-
const xPos =
|
|
156
|
+
const xPos = getScalePosition(x, d[xKey], xScaleType);
|
|
182
157
|
return xScaleType === 'band'
|
|
183
158
|
? xPos + barOffset
|
|
184
159
|
: xPos - barWidth / 2;
|
|
@@ -301,7 +276,7 @@ export class Bar {
|
|
|
301
276
|
}
|
|
302
277
|
})
|
|
303
278
|
.attr('y', (d) => {
|
|
304
|
-
const yPos =
|
|
279
|
+
const yPos = getScalePosition(y, d[xKey], yScaleType);
|
|
305
280
|
return yScaleType === 'band'
|
|
306
281
|
? yPos + barOffset
|
|
307
282
|
: yPos - barHeight / 2;
|
|
@@ -388,7 +363,7 @@ export class Bar {
|
|
|
388
363
|
const categoryKey = String(d[xKey]);
|
|
389
364
|
const value = parseValue(d[this.dataKey]);
|
|
390
365
|
const valueText = String(value);
|
|
391
|
-
const xPos =
|
|
366
|
+
const xPos = getScalePosition(x, d[xKey], xScaleType);
|
|
392
367
|
const barColor = this.colorAdapter
|
|
393
368
|
? this.colorAdapter(d, i)
|
|
394
369
|
: this.fill;
|
|
@@ -572,7 +547,7 @@ export class Bar {
|
|
|
572
547
|
const categoryKey = String(d[xKey]);
|
|
573
548
|
const value = parseValue(d[this.dataKey]);
|
|
574
549
|
const valueText = String(value);
|
|
575
|
-
const yPos =
|
|
550
|
+
const yPos = getScalePosition(y, d[xKey], yScaleType);
|
|
576
551
|
const barColor = this.colorAdapter
|
|
577
552
|
? this.colorAdapter(d, i)
|
|
578
553
|
: this.fill;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Selection } from 'd3';
|
|
2
|
-
import type { ChartData, DataItem, ChartTheme, AxisScaleConfig, ExportFormat, ExportOptions, D3Scale, ExportHookContext, ExportRenderContext, LegendItem, LegendSeries, ResponsiveConfig, ResponsiveRenderContext, DeepPartial } from './types.js';
|
|
3
|
-
import type {
|
|
2
|
+
import type { ChartData, DataItem, ChartTheme, ResolvedChartTheme, AxisScaleConfig, ExportFormat, ExportOptions, D3Scale, ExportHookContext, ExportRenderContext, LegendItem, LegendSeries, ResponsiveConfig, ResponsiveRenderContext, DeepPartial } from './types.js';
|
|
3
|
+
import type { ChartComponentBase, LayoutAwareComponentBase } from './chart-interface.js';
|
|
4
4
|
import type { XAxis } from './x-axis.js';
|
|
5
5
|
import type { YAxis } from './y-axis.js';
|
|
6
6
|
import type { Grid } from './grid.js';
|
|
@@ -12,15 +12,46 @@ type VisualExportFormat = 'svg' | 'png' | 'jpg' | 'pdf';
|
|
|
12
12
|
type RenderDimensions = {
|
|
13
13
|
width: number;
|
|
14
14
|
height: number;
|
|
15
|
+
svgWidthAttr: number | string;
|
|
15
16
|
svgHeightAttr: number | string;
|
|
16
17
|
};
|
|
17
18
|
type ResponsiveOverrides = {
|
|
18
19
|
theme?: DeepPartial<ChartTheme>;
|
|
19
|
-
components: Map<
|
|
20
|
+
components: Map<ChartComponentBase, Record<string, unknown>>;
|
|
21
|
+
};
|
|
22
|
+
type BaseLayoutComponentsOptions = {
|
|
23
|
+
title?: boolean;
|
|
24
|
+
xAxis?: boolean;
|
|
25
|
+
yAxis?: boolean;
|
|
26
|
+
inlineLegend?: boolean;
|
|
27
|
+
};
|
|
28
|
+
type BaseExportComponentsOptions = {
|
|
29
|
+
title?: boolean;
|
|
30
|
+
grid?: boolean;
|
|
31
|
+
xAxis?: boolean;
|
|
32
|
+
yAxis?: boolean;
|
|
33
|
+
tooltip?: boolean;
|
|
34
|
+
legend?: boolean;
|
|
35
|
+
};
|
|
36
|
+
export type BaseLayoutContext = {
|
|
37
|
+
svg: Selection<SVGSVGElement, undefined, null, undefined>;
|
|
38
|
+
svgNode: SVGSVGElement;
|
|
39
|
+
};
|
|
40
|
+
export type BaseRenderContext = BaseLayoutContext & {
|
|
41
|
+
plotGroup: Selection<SVGGElement, undefined, null, undefined>;
|
|
42
|
+
plotArea: PlotAreaBounds;
|
|
43
|
+
};
|
|
44
|
+
type ComponentSlot<TComponent extends ChartComponentBase = ChartComponentBase> = {
|
|
45
|
+
type: TComponent['type'];
|
|
46
|
+
get: () => TComponent | null;
|
|
47
|
+
set: (component: TComponent | null) => void;
|
|
48
|
+
onRegister?: (component: TComponent) => void;
|
|
20
49
|
};
|
|
21
50
|
export type BaseChartConfig = {
|
|
22
51
|
data: ChartData;
|
|
23
|
-
|
|
52
|
+
width?: number;
|
|
53
|
+
height?: number;
|
|
54
|
+
theme?: DeepPartial<ChartTheme>;
|
|
24
55
|
scales?: AxisScaleConfig;
|
|
25
56
|
responsive?: ResponsiveConfig;
|
|
26
57
|
};
|
|
@@ -30,6 +61,8 @@ export type BaseChartConfig = {
|
|
|
30
61
|
export declare abstract class BaseChart {
|
|
31
62
|
protected data: DataItem[];
|
|
32
63
|
protected sourceData: ChartData;
|
|
64
|
+
protected readonly configuredWidth?: number;
|
|
65
|
+
protected readonly configuredHeight?: number;
|
|
33
66
|
protected readonly theme: ChartTheme;
|
|
34
67
|
protected readonly scaleConfig: AxisScaleConfig;
|
|
35
68
|
protected readonly responsiveConfig?: ResponsiveConfig;
|
|
@@ -49,12 +82,15 @@ export declare abstract class BaseChart {
|
|
|
49
82
|
protected resizeObserver: ResizeObserver | null;
|
|
50
83
|
protected layoutManager: LayoutManager;
|
|
51
84
|
protected plotArea: PlotAreaBounds | null;
|
|
85
|
+
private readyPromise;
|
|
52
86
|
private disconnectedLegendContainer;
|
|
87
|
+
private renderThemeOverride;
|
|
88
|
+
private renderSizeOverride;
|
|
53
89
|
protected constructor(config: BaseChartConfig);
|
|
54
90
|
/**
|
|
55
91
|
* Adds a component (axis, grid, tooltip, etc.) to the chart
|
|
56
92
|
*/
|
|
57
|
-
|
|
93
|
+
addChild(component: ChartComponentBase): this;
|
|
58
94
|
/**
|
|
59
95
|
* Renders the chart to the specified target element
|
|
60
96
|
*/
|
|
@@ -65,27 +101,45 @@ export declare abstract class BaseChart {
|
|
|
65
101
|
*/
|
|
66
102
|
private performRender;
|
|
67
103
|
protected resolveRenderDimensions(containerRect: DOMRect): RenderDimensions;
|
|
104
|
+
private resolveAccessibleLabel;
|
|
105
|
+
private syncAccessibleLabelFromSvg;
|
|
68
106
|
protected resolveResponsiveContext(context: {
|
|
69
107
|
width: number;
|
|
70
108
|
height: number;
|
|
71
109
|
}): ResponsiveRenderContext;
|
|
72
|
-
private
|
|
110
|
+
private resolveActiveBreakpoints;
|
|
73
111
|
private resolveRenderTheme;
|
|
74
|
-
private
|
|
112
|
+
private applyRenderTheme;
|
|
113
|
+
protected get renderTheme(): ChartTheme;
|
|
114
|
+
protected get resolvedRenderTheme(): ResolvedChartTheme;
|
|
75
115
|
/**
|
|
76
116
|
* Get layout-aware components in order
|
|
77
117
|
* Override in subclasses to provide chart-specific components
|
|
78
118
|
*/
|
|
79
|
-
protected getLayoutComponents():
|
|
80
|
-
protected
|
|
81
|
-
protected
|
|
119
|
+
protected getLayoutComponents(): LayoutAwareComponentBase[];
|
|
120
|
+
protected getBaseLayoutComponents(options: BaseLayoutComponentsOptions): LayoutAwareComponentBase[];
|
|
121
|
+
protected getExportComponents(): ChartComponentBase[];
|
|
122
|
+
protected getOverrideableComponents(): ChartComponentBase[];
|
|
123
|
+
protected getBaseExportComponents(options: BaseExportComponentsOptions): ChartComponentBase[];
|
|
124
|
+
protected registerBaseComponent(component: ChartComponentBase): boolean;
|
|
125
|
+
protected collectExportOverrides(context: ExportRenderContext): Map<ChartComponentBase, Record<string, unknown>>;
|
|
82
126
|
protected collectResponsiveOverrides(context: ResponsiveRenderContext): ResponsiveOverrides;
|
|
127
|
+
private collectResponsiveBreakpointOverrides;
|
|
128
|
+
private createResponsiveComponentSnapshots;
|
|
129
|
+
private applyResponsiveComponentOverrideEntries;
|
|
83
130
|
protected runExportHooks(context: ExportHookContext): void;
|
|
84
131
|
private mergeComponentOverrideMaps;
|
|
85
132
|
private createOverrideComponents;
|
|
86
|
-
protected applyComponentOverrides(overrides: Map<
|
|
133
|
+
protected applyComponentOverrides(overrides: Map<ChartComponentBase, ChartComponentBase>): () => void;
|
|
87
134
|
private renderExportChart;
|
|
88
|
-
protected
|
|
135
|
+
protected renderTitle(svg: Selection<SVGSVGElement, undefined, null, undefined>): void;
|
|
136
|
+
protected renderInlineLegend(svg: Selection<SVGSVGElement, undefined, null, undefined>): void;
|
|
137
|
+
protected measureInlineLegend(svgNode: SVGSVGElement): void;
|
|
138
|
+
protected filterVisibleItems<T>(items: T[], getDataKey: (item: T) => string): T[];
|
|
139
|
+
protected validateSourceData(_data: ChartData): void;
|
|
140
|
+
protected syncDerivedState(_previousData?: DataItem[]): void;
|
|
141
|
+
protected initializeDataState(): void;
|
|
142
|
+
protected prepareLayout(context: BaseLayoutContext): void;
|
|
89
143
|
/**
|
|
90
144
|
* Setup ResizeObserver for automatic resize handling
|
|
91
145
|
*/
|
|
@@ -93,8 +147,10 @@ export declare abstract class BaseChart {
|
|
|
93
147
|
/**
|
|
94
148
|
* Subclasses must implement this method to define their rendering logic
|
|
95
149
|
*/
|
|
96
|
-
protected abstract renderChart(): void;
|
|
150
|
+
protected abstract renderChart(context: BaseRenderContext): void;
|
|
97
151
|
protected abstract createExportChart(): BaseChart;
|
|
152
|
+
protected setReadyPromise(promise: Promise<void>): void;
|
|
153
|
+
whenReady(): Promise<void>;
|
|
98
154
|
protected getLegendSeries(): LegendSeries[];
|
|
99
155
|
getLegendItems(): LegendItem[];
|
|
100
156
|
isLegendSeriesVisible(dataKey: string): boolean;
|
|
@@ -114,6 +170,11 @@ export declare abstract class BaseChart {
|
|
|
114
170
|
private resolveDisconnectedLegendHost;
|
|
115
171
|
private cleanupDisconnectedLegendContainer;
|
|
116
172
|
protected parseValue(value: unknown): number;
|
|
173
|
+
protected rerender(): void;
|
|
174
|
+
protected tryRegisterComponent(component: ChartComponentBase, slots: readonly ComponentSlot[]): boolean;
|
|
175
|
+
protected applySlotOverrides(overrides: Map<ChartComponentBase, ChartComponentBase>, slots: readonly ComponentSlot[]): () => void;
|
|
176
|
+
protected applyArrayComponentOverrides<TComponent extends ChartComponentBase>(components: TComponent[], overrides: Map<ChartComponentBase, ChartComponentBase>, isComponent: (component: ChartComponentBase) => component is TComponent): () => void;
|
|
177
|
+
private getBaseComponentSlots;
|
|
117
178
|
/**
|
|
118
179
|
* Exports the chart in the specified format
|
|
119
180
|
* @param format - The export format
|
|
@@ -131,7 +192,7 @@ export declare abstract class BaseChart {
|
|
|
131
192
|
private exportXLSX;
|
|
132
193
|
private exportImage;
|
|
133
194
|
private exportPDF;
|
|
134
|
-
protected exportSVG(options?: ExportOptions, formatForHooks?: VisualExportFormat): string
|
|
195
|
+
protected exportSVG(options?: ExportOptions, formatForHooks?: VisualExportFormat): Promise<string>;
|
|
135
196
|
protected exportJSON(): string;
|
|
136
197
|
}
|
|
137
198
|
export {};
|