@acorex/charts 19.15.0-next.22 → 19.15.0-next.25
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/bar-chart/lib/bar-chart.component.d.ts +32 -1
- package/chart-legend/index.d.ts +2 -0
- package/chart-legend/lib/chart-legend.component.d.ts +60 -0
- package/chart-legend/lib/chart-legend.type.d.ts +40 -0
- package/donut-chart/lib/donut-chart.component.d.ts +9 -5
- package/fesm2022/acorex-charts-bar-chart.mjs +229 -38
- package/fesm2022/acorex-charts-bar-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-chart-legend.mjs +109 -0
- package/fesm2022/acorex-charts-chart-legend.mjs.map +1 -0
- package/fesm2022/acorex-charts-chart-tooltip.mjs +4 -4
- package/fesm2022/acorex-charts-chart-tooltip.mjs.map +1 -1
- package/fesm2022/acorex-charts-donut-chart.mjs +179 -69
- package/fesm2022/acorex-charts-donut-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-gauge-chart.mjs +3 -3
- package/fesm2022/acorex-charts-hierarchy-chart.mjs +3 -3
- package/fesm2022/acorex-charts-line-chart.mjs +220 -104
- package/fesm2022/acorex-charts-line-chart.mjs.map +1 -1
- package/line-chart/lib/line-chart.component.d.ts +9 -4
- package/package.json +7 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NXComponent } from '@acorex/cdk/common';
|
|
2
2
|
import { AX_CHART_COLOR_PALETTE, getChartColor } from '@acorex/charts';
|
|
3
3
|
import { AXChartTooltipComponent } from '@acorex/charts/chart-tooltip';
|
|
4
|
+
import { AXPlatform } from '@acorex/core/platform';
|
|
4
5
|
import { CommonModule } from '@angular/common';
|
|
5
6
|
import * as i0 from '@angular/core';
|
|
6
7
|
import { InjectionToken, inject, input, output, viewChild, signal, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
|
|
@@ -75,6 +76,8 @@ class AXLineChartComponent extends NXComponent {
|
|
|
75
76
|
});
|
|
76
77
|
_initialized = signal(false);
|
|
77
78
|
_rendered = signal(false);
|
|
79
|
+
hiddenSeries = new Set();
|
|
80
|
+
_fullNormalizedData = [];
|
|
78
81
|
tooltipVisible = this._tooltipVisible.asReadonly();
|
|
79
82
|
tooltipPosition = this._tooltipPosition.asReadonly();
|
|
80
83
|
tooltipData = this._tooltipData.asReadonly();
|
|
@@ -82,6 +85,8 @@ class AXLineChartComponent extends NXComponent {
|
|
|
82
85
|
configToken = inject(AX_LINE_CHART_CONFIG);
|
|
83
86
|
// Inject the chart colors
|
|
84
87
|
chartColors = inject(AX_CHART_COLOR_PALETTE);
|
|
88
|
+
// Inject AXPlatform
|
|
89
|
+
platform = inject(AXPlatform);
|
|
85
90
|
effectiveOptions = computed(() => {
|
|
86
91
|
return {
|
|
87
92
|
...this.configToken,
|
|
@@ -92,7 +97,16 @@ class AXLineChartComponent extends NXComponent {
|
|
|
92
97
|
this.loadD3();
|
|
93
98
|
}
|
|
94
99
|
#effect = effect(() => {
|
|
95
|
-
this.data();
|
|
100
|
+
const rawData = this.data();
|
|
101
|
+
if (Array.isArray(rawData)) {
|
|
102
|
+
this._fullNormalizedData = rawData.map((s, i) => ({ ...s, originalIndex: i }));
|
|
103
|
+
}
|
|
104
|
+
else if (rawData && 'data' in rawData) {
|
|
105
|
+
this._fullNormalizedData = [{ ...rawData, originalIndex: 0 }];
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this._fullNormalizedData = [];
|
|
109
|
+
}
|
|
96
110
|
this.effectiveOptions();
|
|
97
111
|
if (this._rendered()) {
|
|
98
112
|
this.updateChart();
|
|
@@ -108,6 +122,68 @@ class AXLineChartComponent extends NXComponent {
|
|
|
108
122
|
ngOnDestroy() {
|
|
109
123
|
this.cleanupChart();
|
|
110
124
|
}
|
|
125
|
+
// AXChartLegendCompatible Implementation
|
|
126
|
+
getLegendItems() {
|
|
127
|
+
const totalSum = this._fullNormalizedData.reduce((sum, series) => {
|
|
128
|
+
return sum + series.data.reduce((sSum, p) => sSum + p.y, 0);
|
|
129
|
+
}, 0);
|
|
130
|
+
return this._fullNormalizedData.map((series) => {
|
|
131
|
+
const seriesSum = series.data.reduce((sum, p) => sum + p.y, 0);
|
|
132
|
+
const percentage = totalSum > 0 ? (seriesSum / totalSum) * 100 : 0;
|
|
133
|
+
return {
|
|
134
|
+
id: series.id || series.label || `series-${series.originalIndex}`,
|
|
135
|
+
name: series.label || `Series ${series.originalIndex + 1}`,
|
|
136
|
+
value: seriesSum,
|
|
137
|
+
color: series.lineColor || getChartColor(series.originalIndex, this.chartColors),
|
|
138
|
+
hidden: this.hiddenSeries.has(series.id || series.label || `series-${series.originalIndex}`),
|
|
139
|
+
percentage: parseFloat(percentage.toFixed(2)),
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
highlightSegment(id) {
|
|
144
|
+
if (!this.svg)
|
|
145
|
+
return;
|
|
146
|
+
const allSeriesGroups = this.svg.selectAll('g.ax-line-chart-series');
|
|
147
|
+
const allPointsGroups = this.svg.selectAll('g.ax-line-chart-points');
|
|
148
|
+
if (id === null) {
|
|
149
|
+
allSeriesGroups.classed('ax-chart-dimmed', false).style('opacity', 1);
|
|
150
|
+
allPointsGroups.classed('ax-chart-dimmed', false).style('opacity', 1);
|
|
151
|
+
allSeriesGroups
|
|
152
|
+
.selectAll('.ax-line-chart-line')
|
|
153
|
+
.attr('stroke-width', this.effectiveOptions().lineWidth ?? 2)
|
|
154
|
+
.classed('ax-chart-highlighted-path', false);
|
|
155
|
+
allPointsGroups
|
|
156
|
+
.selectAll('circle.ax-line-chart-point')
|
|
157
|
+
.attr('r', this.effectiveOptions().pointRadius ?? 4)
|
|
158
|
+
.classed('ax-chart-highlighted-point', false);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
allSeriesGroups.classed('ax-chart-dimmed', true).style('opacity', 0.3);
|
|
162
|
+
allPointsGroups.classed('ax-chart-dimmed', true).style('opacity', 0.3);
|
|
163
|
+
const targetSeriesGroup = this.svg.selectAll(`g.ax-line-chart-series[data-series-identifier="${id}"]`);
|
|
164
|
+
const targetPointsGroup = this.svg.selectAll(`g.ax-line-chart-points[data-series-identifier="${id}"]`);
|
|
165
|
+
targetSeriesGroup.classed('ax-chart-dimmed', false).style('opacity', 1);
|
|
166
|
+
targetPointsGroup.classed('ax-chart-dimmed', false).style('opacity', 1);
|
|
167
|
+
targetSeriesGroup
|
|
168
|
+
.selectAll('.ax-line-chart-line')
|
|
169
|
+
.attr('stroke-width', (this.effectiveOptions().lineWidth ?? 2) * 1.5)
|
|
170
|
+
.classed('ax-chart-highlighted-path', true);
|
|
171
|
+
targetPointsGroup
|
|
172
|
+
.selectAll('circle.ax-line-chart-point')
|
|
173
|
+
.attr('r', (this.effectiveOptions().pointRadius ?? 4) * 1.5)
|
|
174
|
+
.classed('ax-chart-highlighted-point', true);
|
|
175
|
+
}
|
|
176
|
+
toggleSegment(id) {
|
|
177
|
+
const seriesId = id;
|
|
178
|
+
if (this.hiddenSeries.has(seriesId)) {
|
|
179
|
+
this.hiddenSeries.delete(seriesId);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
this.hiddenSeries.add(seriesId);
|
|
183
|
+
}
|
|
184
|
+
this.updateChart();
|
|
185
|
+
return !this.hiddenSeries.has(seriesId);
|
|
186
|
+
}
|
|
111
187
|
async loadD3() {
|
|
112
188
|
try {
|
|
113
189
|
this.d3 = await import('d3');
|
|
@@ -124,24 +200,37 @@ class AXLineChartComponent extends NXComponent {
|
|
|
124
200
|
if (!this.d3 || !this.chartContainerEl()?.nativeElement)
|
|
125
201
|
return;
|
|
126
202
|
const containerElement = this.chartContainerEl().nativeElement;
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
normalizedData = chartData;
|
|
131
|
-
}
|
|
132
|
-
else if (chartData && 'data' in chartData) {
|
|
133
|
-
normalizedData = [chartData];
|
|
134
|
-
}
|
|
135
|
-
this.d3.select(containerElement).selectAll('svg').remove();
|
|
136
|
-
if (normalizedData.length === 0 || normalizedData.some((series) => !series.data || series.data.length === 0)) {
|
|
203
|
+
const allSeriesData = this._fullNormalizedData;
|
|
204
|
+
this.d3.select(containerElement).selectAll('*').remove();
|
|
205
|
+
if (allSeriesData.length === 0 || allSeriesData.every((series) => !series.data || series.data.length === 0)) {
|
|
137
206
|
this.showNoDataMessage(containerElement);
|
|
138
207
|
return;
|
|
139
208
|
}
|
|
209
|
+
const visibleDataForRendering = allSeriesData.filter((series) => !this.hiddenSeries.has(series.id || series.label || `series-${series.originalIndex}`));
|
|
210
|
+
if (visibleDataForRendering.length === 0) {
|
|
211
|
+
// All data is present, but all series are hidden by the legend
|
|
212
|
+
this.showAllSeriesHiddenMessage(containerElement);
|
|
213
|
+
// Still setup basic SVG and chart group for consistency if needed, or return
|
|
214
|
+
// For now, we will show the message and return, as scales/axes can't be drawn.
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// Scales should be based on potentially visible data to avoid errors with empty domains
|
|
218
|
+
// If all are hidden, scales might become an issue. Let's use all data for scales,
|
|
219
|
+
// and rendering will handle visibility.
|
|
220
|
+
const dataForScales = allSeriesData.flatMap((s) => s.data).length > 0 ? allSeriesData : [{ data: [{ x: 0, y: 0 }] }];
|
|
140
221
|
const chartOptions = this.effectiveOptions();
|
|
141
222
|
this.setupDimensions(containerElement, chartOptions);
|
|
142
|
-
|
|
223
|
+
// Use allSeriesData for domain calculation to keep scales consistent even if some series are hidden
|
|
224
|
+
// but filter out series with no data points for scale calculation.
|
|
225
|
+
const dataForScaleSetup = allSeriesData.filter((s) => s.data && s.data.length > 0);
|
|
226
|
+
if (dataForScaleSetup.length === 0) {
|
|
227
|
+
// If after filtering, there's no data with points (e.g. all series have empty data arrays)
|
|
228
|
+
this.showNoDataMessage(containerElement);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.setupScales(dataForScaleSetup);
|
|
143
232
|
this.createAxes(chartOptions);
|
|
144
|
-
this.renderLines(
|
|
233
|
+
this.renderLines(allSeriesData); // RenderLines will handle hiding based on hiddenSeries
|
|
145
234
|
}
|
|
146
235
|
updateChart() {
|
|
147
236
|
this.createChart();
|
|
@@ -213,15 +302,21 @@ class AXLineChartComponent extends NXComponent {
|
|
|
213
302
|
}
|
|
214
303
|
}
|
|
215
304
|
setupScales(data) {
|
|
305
|
+
// Expects already filtered data for scales
|
|
216
306
|
const chartOptions = this.effectiveOptions();
|
|
217
307
|
const padding = chartOptions.axisPadding ?? 0;
|
|
218
308
|
const paddingMultiplier = padding / 100;
|
|
219
|
-
|
|
309
|
+
// Ensure data is not empty for scale domain calculation
|
|
310
|
+
const allDataPoints = data.length > 0 ? data.flatMap((series) => series.data) : [{ x: 0, y: 0 }];
|
|
311
|
+
if (allDataPoints.length === 0) {
|
|
312
|
+
// Should ideally not happen if createChart filters correctly
|
|
313
|
+
allDataPoints.push({ x: 0, y: 0 }); // Default fallback to prevent crash with empty domain
|
|
314
|
+
}
|
|
220
315
|
const allNumericX = allDataPoints.every((d) => typeof d.x === 'number');
|
|
221
316
|
const allDates = !allNumericX && allDataPoints.every((d) => !isNaN(new Date(d.x).getTime()));
|
|
222
317
|
if (allNumericX) {
|
|
223
|
-
const xMin = this.d3.min(allDataPoints, (d) => d.x)
|
|
224
|
-
const xMax = this.d3.max(allDataPoints, (d) => d.x)
|
|
318
|
+
const xMin = this.d3.min(allDataPoints, (d) => d.x) ?? 0;
|
|
319
|
+
const xMax = this.d3.max(allDataPoints, (d) => d.x) ?? 0;
|
|
225
320
|
if (xMin === xMax) {
|
|
226
321
|
this.xScale = this.d3
|
|
227
322
|
.scaleLinear()
|
|
@@ -233,8 +328,8 @@ class AXLineChartComponent extends NXComponent {
|
|
|
233
328
|
}
|
|
234
329
|
}
|
|
235
330
|
else if (allDates) {
|
|
236
|
-
const xMin = this.d3.min(allDataPoints, (d) => new Date(d.x))
|
|
237
|
-
const xMax = this.d3.max(allDataPoints, (d) => new Date(d.x))
|
|
331
|
+
const xMin = this.d3.min(allDataPoints, (d) => new Date(d.x)) ?? new Date();
|
|
332
|
+
const xMax = this.d3.max(allDataPoints, (d) => new Date(d.x)) ?? new Date();
|
|
238
333
|
if (xMin.getTime() === xMax.getTime()) {
|
|
239
334
|
const oneDayMs = 86400000;
|
|
240
335
|
this.xScale = this.d3
|
|
@@ -255,8 +350,11 @@ class AXLineChartComponent extends NXComponent {
|
|
|
255
350
|
.paddingOuter(0);
|
|
256
351
|
}
|
|
257
352
|
const yAxisStartsAtZero = chartOptions.yAxisStartsAtZero !== false;
|
|
258
|
-
|
|
259
|
-
|
|
353
|
+
let yMin = this.d3.min(allDataPoints, (d) => d.y) ?? 0;
|
|
354
|
+
if (yAxisStartsAtZero) {
|
|
355
|
+
yMin = Math.min(0, yMin);
|
|
356
|
+
}
|
|
357
|
+
const yMax = this.d3.max(allDataPoints, (d) => d.y) ?? 0;
|
|
260
358
|
const yRange = yMax - yMin;
|
|
261
359
|
this.yScale = this.d3
|
|
262
360
|
.scaleLinear()
|
|
@@ -269,6 +367,7 @@ class AXLineChartComponent extends NXComponent {
|
|
|
269
367
|
const showYAxis = options.showYAxis !== false;
|
|
270
368
|
const showGrid = options.showGrid !== false;
|
|
271
369
|
const isBandScale = this.xScale.bandwidth !== undefined;
|
|
370
|
+
const isRtl = this.platform.isRtl();
|
|
272
371
|
const axesGroup = this.chart.append('g').attr('class', 'ax-line-chart-axes');
|
|
273
372
|
if (showXAxis) {
|
|
274
373
|
this.xAxis = axesGroup
|
|
@@ -283,13 +382,14 @@ class AXLineChartComponent extends NXComponent {
|
|
|
283
382
|
.attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.2)')
|
|
284
383
|
.attr('stroke-dasharray', '2,2')
|
|
285
384
|
.attr('stroke-opacity', '0.5');
|
|
385
|
+
const dynamicXAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.width / 45)));
|
|
286
386
|
this.xAxis.selectAll('text').attr('style', `
|
|
287
|
-
font-size:
|
|
387
|
+
font-size: ${dynamicXAxisTickFontSize}px;
|
|
288
388
|
font-weight: 400;
|
|
289
389
|
fill: rgba(var(--ax-comp-line-chart-labels-color), 0.7);
|
|
290
390
|
`);
|
|
291
391
|
if (options.xAxisLabel) {
|
|
292
|
-
const labelY = this.height + this.margin.bottom * 0.
|
|
392
|
+
const labelY = this.height + this.margin.bottom * 0.8;
|
|
293
393
|
axesGroup
|
|
294
394
|
.append('text')
|
|
295
395
|
.attr('class', 'ax-line-chart-axis-label ax-x-axis-label')
|
|
@@ -298,9 +398,8 @@ class AXLineChartComponent extends NXComponent {
|
|
|
298
398
|
.attr('x', this.width / 2)
|
|
299
399
|
.attr('y', labelY)
|
|
300
400
|
.attr('transform', 'translate(0, 5)')
|
|
301
|
-
.attr('font-family', 'var(--ax-font-family, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)')
|
|
302
401
|
.attr('style', `
|
|
303
|
-
font-size:
|
|
402
|
+
font-size: 14px;
|
|
304
403
|
font-weight: 500;
|
|
305
404
|
fill: rgb(var(--ax-comp-line-chart-text-color));
|
|
306
405
|
pointer-events: none;
|
|
@@ -320,14 +419,18 @@ class AXLineChartComponent extends NXComponent {
|
|
|
320
419
|
.attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.2)')
|
|
321
420
|
.attr('stroke-dasharray', '2,2')
|
|
322
421
|
.attr('stroke-opacity', '0.5');
|
|
323
|
-
|
|
324
|
-
|
|
422
|
+
const dynamicYAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.height / 30)));
|
|
423
|
+
const yTickTexts = this.yAxis.selectAll('text').attr('style', `
|
|
424
|
+
font-size: ${dynamicYAxisTickFontSize}px;
|
|
325
425
|
font-weight: 400;
|
|
326
426
|
fill: rgba(var(--ax-comp-line-chart-labels-color), 0.7);
|
|
327
427
|
`);
|
|
428
|
+
if (isRtl) {
|
|
429
|
+
yTickTexts.attr('text-anchor', 'start');
|
|
430
|
+
}
|
|
328
431
|
if (options.yAxisLabel) {
|
|
329
432
|
const labelX = -this.height / 2;
|
|
330
|
-
const labelY = -this.margin.left * 0.
|
|
433
|
+
const labelY = -this.margin.left * 0.8;
|
|
331
434
|
axesGroup
|
|
332
435
|
.append('text')
|
|
333
436
|
.attr('class', 'ax-line-chart-axis-label ax-y-axis-label')
|
|
@@ -336,9 +439,8 @@ class AXLineChartComponent extends NXComponent {
|
|
|
336
439
|
.attr('transform', 'rotate(-90) translate(-5, 0)')
|
|
337
440
|
.attr('x', labelX)
|
|
338
441
|
.attr('y', labelY)
|
|
339
|
-
.attr('font-family', 'var(--ax-font-family, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)')
|
|
340
442
|
.attr('style', `
|
|
341
|
-
font-size:
|
|
443
|
+
font-size: 14px;
|
|
342
444
|
font-weight: 500;
|
|
343
445
|
fill: rgb(var(--ax-comp-line-chart-text-color));
|
|
344
446
|
pointer-events: none;
|
|
@@ -388,7 +490,7 @@ class AXLineChartComponent extends NXComponent {
|
|
|
388
490
|
}
|
|
389
491
|
}
|
|
390
492
|
}
|
|
391
|
-
renderLines(
|
|
493
|
+
renderLines(allSeriesData) {
|
|
392
494
|
const isBandScale = this.xScale.bandwidth !== undefined;
|
|
393
495
|
const getX = (d) => {
|
|
394
496
|
if (isBandScale) {
|
|
@@ -413,34 +515,35 @@ class AXLineChartComponent extends NXComponent {
|
|
|
413
515
|
if (this.effectiveOptions().smoothLine !== false) {
|
|
414
516
|
areaGenerator.curve(this.d3.curveMonotoneX);
|
|
415
517
|
}
|
|
416
|
-
// Add class to chart container to disable pointer events during animation
|
|
417
518
|
this.svg.attr('class', 'ax-line-chart-animating');
|
|
418
519
|
const allSeriesGroup = this.chart
|
|
419
520
|
.append('g')
|
|
420
521
|
.attr('class', 'ax-line-chart-all-series')
|
|
421
|
-
.attr('pointer-events', 'none');
|
|
522
|
+
.attr('pointer-events', 'none');
|
|
422
523
|
const allPointsGroup = this.chart
|
|
423
524
|
.append('g')
|
|
424
525
|
.attr('class', 'ax-line-chart-all-points')
|
|
425
|
-
.attr('pointer-events', 'none');
|
|
526
|
+
.attr('pointer-events', 'none');
|
|
426
527
|
if (this.effectiveOptions().showCrosshair === true) {
|
|
427
|
-
|
|
428
|
-
.append('g')
|
|
429
|
-
.attr('class', 'ax-line-chart-crosshair')
|
|
430
|
-
.attr('pointer-events', 'none');
|
|
528
|
+
this.chart.append('g').attr('class', 'ax-line-chart-crosshair').attr('pointer-events', 'none');
|
|
431
529
|
}
|
|
432
|
-
// Get animation options
|
|
433
530
|
const animationDuration = this.effectiveOptions().animationDuration;
|
|
434
531
|
const animationEasing = this.getEasingFunction(this.effectiveOptions().animationEasing);
|
|
435
|
-
|
|
532
|
+
allSeriesData.forEach((series) => {
|
|
533
|
+
const seriesIdentifier = series.id || series.label || `series-${series.originalIndex}`;
|
|
534
|
+
if (this.hiddenSeries.has(seriesIdentifier)) {
|
|
535
|
+
this.chart.selectAll(`.ax-line-chart-series[data-series-identifier="${seriesIdentifier}"]`).remove();
|
|
536
|
+
this.chart.selectAll(`.ax-line-chart-points[data-series-identifier="${seriesIdentifier}"]`).remove();
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
436
539
|
if (!series.data || series.data.length === 0)
|
|
437
540
|
return;
|
|
438
541
|
const seriesGroup = allSeriesGroup
|
|
439
542
|
.append('g')
|
|
440
|
-
.attr('class', `ax-line-chart-series ax-line-chart-series-${
|
|
441
|
-
.attr('data-series',
|
|
442
|
-
.attr('pointer-events', 'none');
|
|
443
|
-
const lineColor = series.lineColor || getChartColor(
|
|
543
|
+
.attr('class', `ax-line-chart-series ax-line-chart-series-${series.originalIndex}`)
|
|
544
|
+
.attr('data-series-identifier', seriesIdentifier)
|
|
545
|
+
.attr('pointer-events', 'none');
|
|
546
|
+
const lineColor = series.lineColor || getChartColor(series.originalIndex, this.chartColors);
|
|
444
547
|
const fillColor = series.fillColor || lineColor;
|
|
445
548
|
const line = seriesGroup
|
|
446
549
|
.append('path')
|
|
@@ -453,8 +556,7 @@ class AXLineChartComponent extends NXComponent {
|
|
|
453
556
|
.attr('d', lineGenerator)
|
|
454
557
|
.attr('fill', 'none')
|
|
455
558
|
.attr('style', 'transition: stroke-width 0.3s ease;')
|
|
456
|
-
.attr('pointer-events', 'none');
|
|
457
|
-
// Setup hover listener
|
|
559
|
+
.attr('pointer-events', 'none');
|
|
458
560
|
line
|
|
459
561
|
.on('mouseenter', () => {
|
|
460
562
|
line
|
|
@@ -477,7 +579,6 @@ class AXLineChartComponent extends NXComponent {
|
|
|
477
579
|
.ease(animationEasing)
|
|
478
580
|
.attr('stroke-dashoffset', 0)
|
|
479
581
|
.on('end', function () {
|
|
480
|
-
// Enable pointer events after animation completes
|
|
481
582
|
line.attr('pointer-events', 'all');
|
|
482
583
|
});
|
|
483
584
|
if (this.effectiveOptions().fillArea) {
|
|
@@ -489,8 +590,7 @@ class AXLineChartComponent extends NXComponent {
|
|
|
489
590
|
.attr('opacity', 0)
|
|
490
591
|
.attr('d', areaGenerator)
|
|
491
592
|
.attr('style', 'transition: opacity 0.3s ease;')
|
|
492
|
-
.attr('pointer-events', 'none');
|
|
493
|
-
// Setup hover listener
|
|
593
|
+
.attr('pointer-events', 'none');
|
|
494
594
|
area
|
|
495
595
|
.on('mouseenter', () => {
|
|
496
596
|
area
|
|
@@ -510,17 +610,18 @@ class AXLineChartComponent extends NXComponent {
|
|
|
510
610
|
.ease(animationEasing)
|
|
511
611
|
.attr('opacity', (this.effectiveOptions().fillOpacity ?? 20) / 100)
|
|
512
612
|
.on('end', function () {
|
|
513
|
-
// Enable pointer events after animation completes
|
|
514
613
|
area.attr('pointer-events', 'all');
|
|
515
614
|
});
|
|
516
615
|
}
|
|
517
616
|
});
|
|
518
617
|
if (this.effectiveOptions().showPoints !== false) {
|
|
519
618
|
const pointMap = new Map();
|
|
520
|
-
|
|
521
|
-
|
|
619
|
+
allSeriesData.forEach((series) => {
|
|
620
|
+
const seriesIdentifier = series.id || series.label || `series-${series.originalIndex}`;
|
|
621
|
+
if (this.hiddenSeries.has(seriesIdentifier) || !series.data || series.data.length === 0) {
|
|
522
622
|
return;
|
|
523
|
-
|
|
623
|
+
}
|
|
624
|
+
const lineColor = series.lineColor || getChartColor(series.originalIndex, this.chartColors);
|
|
524
625
|
const maxPoints = 100;
|
|
525
626
|
const pointData = series.data.length > maxPoints ? this.getReducedDataPoints(series.data, maxPoints) : series.data;
|
|
526
627
|
pointData.forEach((point) => {
|
|
@@ -530,26 +631,24 @@ class AXLineChartComponent extends NXComponent {
|
|
|
530
631
|
if (!pointMap.has(key)) {
|
|
531
632
|
pointMap.set(key, []);
|
|
532
633
|
}
|
|
533
|
-
pointMap.get(key)?.push({
|
|
534
|
-
point,
|
|
535
|
-
series,
|
|
536
|
-
seriesIndex,
|
|
537
|
-
});
|
|
634
|
+
pointMap.get(key)?.push({ point, series, originalIndex: series.originalIndex });
|
|
538
635
|
});
|
|
539
636
|
});
|
|
540
|
-
// Create a counter to track animation completion
|
|
541
637
|
let animationCounter = 0;
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
638
|
+
const totalVisibleSeriesCount = allSeriesData.filter((s) => !this.hiddenSeries.has(s.id || s.label || `series-${s.originalIndex}`) && s.data && s.data.length > 0).length;
|
|
639
|
+
allSeriesData.forEach((series) => {
|
|
640
|
+
const seriesIdentifier = series.id || series.label || `series-${series.originalIndex}`;
|
|
641
|
+
if (this.hiddenSeries.has(seriesIdentifier) || !series.data || series.data.length === 0) {
|
|
545
642
|
return;
|
|
546
|
-
|
|
643
|
+
}
|
|
644
|
+
const lineColor = series.lineColor || getChartColor(series.originalIndex, this.chartColors);
|
|
547
645
|
const pointsGroup = allPointsGroup
|
|
548
646
|
.append('g')
|
|
549
|
-
.attr('class', `ax-line-chart-points ax-line-chart-points-${
|
|
550
|
-
.attr('
|
|
647
|
+
.attr('class', `ax-line-chart-points ax-line-chart-points-${series.originalIndex}`)
|
|
648
|
+
.attr('data-series-identifier', seriesIdentifier)
|
|
649
|
+
.attr('pointer-events', 'none');
|
|
551
650
|
pointsGroup
|
|
552
|
-
.on('mouseenter', () => this.handlePointGroupEnter(
|
|
651
|
+
.on('mouseenter', () => this.handlePointGroupEnter(series.originalIndex, lineColor))
|
|
553
652
|
.on('mouseleave', () => this.handlePointGroupLeave());
|
|
554
653
|
const maxPoints = 100;
|
|
555
654
|
const pointData = series.data.length > maxPoints ? this.getReducedDataPoints(series.data, maxPoints) : series.data;
|
|
@@ -568,7 +667,7 @@ class AXLineChartComponent extends NXComponent {
|
|
|
568
667
|
.attr('data-x', (d) => d.x)
|
|
569
668
|
.attr('data-y', (d) => d.y)
|
|
570
669
|
.style('cursor', 'pointer')
|
|
571
|
-
.attr('pointer-events', 'none')
|
|
670
|
+
.attr('pointer-events', 'none')
|
|
572
671
|
.on('mouseenter', (event, d) => {
|
|
573
672
|
const x = getX(d);
|
|
574
673
|
const y = this.yScale(d.y);
|
|
@@ -578,7 +677,7 @@ class AXLineChartComponent extends NXComponent {
|
|
|
578
677
|
this.handleOverlappingPointsHover(event, overlappingPoints);
|
|
579
678
|
}
|
|
580
679
|
else {
|
|
581
|
-
this.handlePointHover(event, d, series,
|
|
680
|
+
this.handlePointHover(event, d, series, series.originalIndex);
|
|
582
681
|
}
|
|
583
682
|
this.d3
|
|
584
683
|
.select(event.target)
|
|
@@ -614,17 +713,14 @@ class AXLineChartComponent extends NXComponent {
|
|
|
614
713
|
}
|
|
615
714
|
})
|
|
616
715
|
.transition()
|
|
617
|
-
.delay((d, i) => i * Math.min(50, animationDuration * 0.05) + animationDuration * 0.5)
|
|
618
|
-
.duration(animationDuration * 0.3)
|
|
716
|
+
.delay((d, i) => i * Math.min(50, (animationDuration || 0) * 0.05) + (animationDuration || 0) * 0.5)
|
|
717
|
+
.duration((animationDuration || 0) * 0.3)
|
|
619
718
|
.ease(animationEasing)
|
|
620
719
|
.attr('r', this.effectiveOptions().pointRadius ?? 4)
|
|
621
720
|
.on('end', (d, i, nodes) => {
|
|
622
|
-
// When the last point finishes animating
|
|
623
721
|
if (i === nodes.length - 1) {
|
|
624
722
|
animationCounter++;
|
|
625
|
-
|
|
626
|
-
if (animationCounter >= totalSeriesCount) {
|
|
627
|
-
// Enable pointer events for all elements after all animations have completed
|
|
723
|
+
if (animationCounter >= totalVisibleSeriesCount) {
|
|
628
724
|
this.enablePointerEventsAfterAnimation();
|
|
629
725
|
}
|
|
630
726
|
}
|
|
@@ -632,18 +728,14 @@ class AXLineChartComponent extends NXComponent {
|
|
|
632
728
|
});
|
|
633
729
|
}
|
|
634
730
|
else {
|
|
635
|
-
// If not showing points, wait for line animations to complete
|
|
636
731
|
setTimeout(() => {
|
|
637
|
-
// Enable pointer events for all elements after animation duration
|
|
638
732
|
this.enablePointerEventsAfterAnimation();
|
|
639
|
-
}, animationDuration + 100);
|
|
733
|
+
}, animationDuration || 0 + 100);
|
|
640
734
|
}
|
|
641
735
|
}
|
|
642
736
|
enablePointerEventsAfterAnimation() {
|
|
643
|
-
// Guard against null chart or svg
|
|
644
737
|
if (!this.chart || !this.svg)
|
|
645
738
|
return;
|
|
646
|
-
// Enable pointer events for all chart elements after animation completes
|
|
647
739
|
this.chart.selectAll('.ax-line-chart-all-series').attr('pointer-events', 'all');
|
|
648
740
|
this.chart.selectAll('.ax-line-chart-series').attr('pointer-events', 'all');
|
|
649
741
|
this.chart.selectAll('.ax-line-chart-line').attr('pointer-events', 'all');
|
|
@@ -651,12 +743,11 @@ class AXLineChartComponent extends NXComponent {
|
|
|
651
743
|
this.chart.selectAll('.ax-line-chart-all-points').attr('pointer-events', 'all');
|
|
652
744
|
this.chart.selectAll('.ax-line-chart-points').attr('pointer-events', 'all');
|
|
653
745
|
this.chart.selectAll('.ax-line-chart-point').attr('pointer-events', 'all');
|
|
654
|
-
// Remove the animating class from the SVG
|
|
655
746
|
this.svg.classed('ax-line-chart-animating', false);
|
|
656
747
|
}
|
|
657
|
-
handlePointGroupEnter(
|
|
748
|
+
handlePointGroupEnter(originalIndex, color) {
|
|
658
749
|
this.chart
|
|
659
|
-
.select(`.ax-line-chart-series-${
|
|
750
|
+
.select(`.ax-line-chart-series-${originalIndex} .ax-line-chart-line`)
|
|
660
751
|
.transition()
|
|
661
752
|
.duration(150)
|
|
662
753
|
.attr('stroke-width', (this.effectiveOptions().lineWidth ?? 2) * 1.5);
|
|
@@ -684,11 +775,11 @@ class AXLineChartComponent extends NXComponent {
|
|
|
684
775
|
}
|
|
685
776
|
return result;
|
|
686
777
|
}
|
|
687
|
-
handlePointHover(event, dataPoint, series,
|
|
778
|
+
handlePointHover(event, dataPoint, series, originalIndex) {
|
|
688
779
|
if (this.effectiveOptions().showTooltip !== false) {
|
|
689
|
-
const color = series.lineColor || getChartColor(
|
|
780
|
+
const color = series.lineColor || getChartColor(originalIndex, this.chartColors);
|
|
690
781
|
this._tooltipData.set({
|
|
691
|
-
title: dataPoint.tooltipLabel || series.tooltipLabel || series.label || `Series ${
|
|
782
|
+
title: dataPoint.tooltipLabel || series.tooltipLabel || series.label || `Series ${originalIndex + 1}`,
|
|
692
783
|
value: dataPoint.y.toString(),
|
|
693
784
|
seriesName: `x: ${dataPoint.x}`,
|
|
694
785
|
color: color,
|
|
@@ -755,16 +846,11 @@ class AXLineChartComponent extends NXComponent {
|
|
|
755
846
|
if (x + tooltipRect.width + 20 > container.width) {
|
|
756
847
|
x = x - tooltipRect.width - 15;
|
|
757
848
|
}
|
|
758
|
-
// if (y + tooltipRect.height / 2 > container.height) {
|
|
759
|
-
// y = container.height - tooltipRect.height / 2;
|
|
760
|
-
// } else if (y - tooltipRect.height / 2 < 0) {
|
|
761
|
-
// y = tooltipRect.height / 2;
|
|
762
|
-
// }
|
|
763
849
|
this._tooltipPosition.set({ x, y });
|
|
764
850
|
}
|
|
765
851
|
handlePointClick(event, dataPoint, series) {
|
|
766
852
|
this.pointClick.emit({
|
|
767
|
-
series: series,
|
|
853
|
+
series: series, // series still refers to the full series data with originalIndex
|
|
768
854
|
point: dataPoint,
|
|
769
855
|
event: {
|
|
770
856
|
nativeEvent: event,
|
|
@@ -773,7 +859,6 @@ class AXLineChartComponent extends NXComponent {
|
|
|
773
859
|
});
|
|
774
860
|
}
|
|
775
861
|
showNoDataMessage(containerElement) {
|
|
776
|
-
// Clear existing contents first
|
|
777
862
|
this.d3.select(containerElement).selectAll('*').remove();
|
|
778
863
|
const messageContainer = this.d3
|
|
779
864
|
.select(containerElement)
|
|
@@ -790,14 +875,12 @@ class AXLineChartComponent extends NXComponent {
|
|
|
790
875
|
.style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
|
|
791
876
|
.style('width', '80%')
|
|
792
877
|
.style('max-width', '300px');
|
|
793
|
-
// Add an icon
|
|
794
878
|
messageContainer
|
|
795
879
|
.append('div')
|
|
796
880
|
.attr('class', 'ax-line-chart-no-data-icon')
|
|
797
881
|
.style('opacity', '0.6')
|
|
798
882
|
.style('margin-bottom', '0.75rem')
|
|
799
883
|
.html('<i class="fa-light fa-chart-line fa-2x"></i>');
|
|
800
|
-
// Add text message
|
|
801
884
|
messageContainer
|
|
802
885
|
.append('div')
|
|
803
886
|
.attr('class', 'ax-line-chart-no-data-text')
|
|
@@ -805,7 +888,6 @@ class AXLineChartComponent extends NXComponent {
|
|
|
805
888
|
.style('font-weight', '600')
|
|
806
889
|
.style('margin-bottom', '0.5rem')
|
|
807
890
|
.text('No data available');
|
|
808
|
-
// Add help text
|
|
809
891
|
messageContainer
|
|
810
892
|
.append('div')
|
|
811
893
|
.attr('class', 'ax-line-chart-no-data-help')
|
|
@@ -813,6 +895,43 @@ class AXLineChartComponent extends NXComponent {
|
|
|
813
895
|
.style('opacity', '0.6')
|
|
814
896
|
.text('Please provide data to display the chart');
|
|
815
897
|
}
|
|
898
|
+
showAllSeriesHiddenMessage(containerElement) {
|
|
899
|
+
this.d3.select(containerElement).selectAll('*').remove(); // Clear existing chart elements
|
|
900
|
+
const messageContainer = this.d3
|
|
901
|
+
.select(containerElement)
|
|
902
|
+
.append('div')
|
|
903
|
+
.attr('class', 'ax-line-chart-all-hidden-message') // Different class
|
|
904
|
+
.style('position', 'absolute')
|
|
905
|
+
.style('left', '50%')
|
|
906
|
+
.style('top', '50%')
|
|
907
|
+
.style('transform', 'translate(-50%, -50%)')
|
|
908
|
+
.style('text-align', 'center')
|
|
909
|
+
.style('background-color', 'rgb(var(--ax-comp-line-chart-bg-color))')
|
|
910
|
+
.style('padding', '1.5rem')
|
|
911
|
+
.style('border-radius', '0.5rem')
|
|
912
|
+
.style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
|
|
913
|
+
.style('width', '80%')
|
|
914
|
+
.style('max-width', '350px'); // Slightly wider for longer text
|
|
915
|
+
messageContainer
|
|
916
|
+
.append('div')
|
|
917
|
+
.attr('class', 'ax-line-chart-all-hidden-icon')
|
|
918
|
+
.style('opacity', '0.6')
|
|
919
|
+
.style('margin-bottom', '0.75rem')
|
|
920
|
+
.html('<i class="fa-light fa-eye-slash fa-2x"></i>'); // Different icon
|
|
921
|
+
messageContainer
|
|
922
|
+
.append('div')
|
|
923
|
+
.attr('class', 'ax-line-chart-all-hidden-text')
|
|
924
|
+
.style('font-size', '1rem')
|
|
925
|
+
.style('font-weight', '600')
|
|
926
|
+
.style('margin-bottom', '0.5rem')
|
|
927
|
+
.text('All series are hidden');
|
|
928
|
+
messageContainer
|
|
929
|
+
.append('div')
|
|
930
|
+
.attr('class', 'ax-line-chart-all-hidden-help')
|
|
931
|
+
.style('font-size', '0.8rem')
|
|
932
|
+
.style('opacity', '0.6')
|
|
933
|
+
.text('Click legend items to show series in the chart.');
|
|
934
|
+
}
|
|
816
935
|
handleOverlappingPointsHover(event, overlappingPoints) {
|
|
817
936
|
if (this.effectiveOptions().showTooltip === false)
|
|
818
937
|
return;
|
|
@@ -821,10 +940,10 @@ class AXLineChartComponent extends NXComponent {
|
|
|
821
940
|
value: overlappingPoints[0].point.y.toString(),
|
|
822
941
|
seriesName: '',
|
|
823
942
|
color: '',
|
|
824
|
-
items: overlappingPoints.map(({ point, series,
|
|
825
|
-
const color = series.lineColor || getChartColor(
|
|
943
|
+
items: overlappingPoints.map(({ point, series, originalIndex }) => {
|
|
944
|
+
const color = series.lineColor || getChartColor(originalIndex, this.chartColors);
|
|
826
945
|
return {
|
|
827
|
-
label: series.label || `Series ${
|
|
946
|
+
label: series.label || `Series ${originalIndex + 1}`,
|
|
828
947
|
value: point.y.toString(),
|
|
829
948
|
color: color,
|
|
830
949
|
};
|
|
@@ -837,9 +956,6 @@ class AXLineChartComponent extends NXComponent {
|
|
|
837
956
|
this.showCrosshairLines(overlappingPoints[0].point);
|
|
838
957
|
}
|
|
839
958
|
}
|
|
840
|
-
/**
|
|
841
|
-
* Gets the appropriate D3 easing function based on the option string
|
|
842
|
-
*/
|
|
843
959
|
getEasingFunction(easing) {
|
|
844
960
|
switch (easing) {
|
|
845
961
|
case 'linear':
|
|
@@ -861,13 +977,13 @@ class AXLineChartComponent extends NXComponent {
|
|
|
861
977
|
case 'cubic-in-out':
|
|
862
978
|
return this.d3.easeCubicInOut;
|
|
863
979
|
default:
|
|
864
|
-
return this.d3.easeCubicOut;
|
|
980
|
+
return this.d3.easeCubicOut;
|
|
865
981
|
}
|
|
866
982
|
}
|
|
867
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
868
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.
|
|
983
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AXLineChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
984
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.14", type: AXLineChartComponent, isStandalone: true, selector: "ax-line-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pointClick: "pointClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-line-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"false\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-line-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-line-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-axis-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-bg-color: var(--ax-sys-color-lightest-surface);--ax-comp-line-chart-text-color: var(--ax-sys-color-on-lightest-surface)}ax-line-chart .ax-line-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-comp-line-chart-text-color));background-color:rgb(var(--ax-comp-line-chart-bg-color))}ax-line-chart .ax-line-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-line-chart .ax-line-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);background-color:rgb(var(--ax-comp-line-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-help{font-size:.8rem;opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
869
985
|
}
|
|
870
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
986
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AXLineChartComponent, decorators: [{
|
|
871
987
|
type: Component,
|
|
872
988
|
args: [{ selector: 'ax-line-chart', standalone: true, encapsulation: ViewEncapsulation.None, imports: [CommonModule, AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-line-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"false\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-line-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-line-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-axis-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-bg-color: var(--ax-sys-color-lightest-surface);--ax-comp-line-chart-text-color: var(--ax-sys-color-on-lightest-surface)}ax-line-chart .ax-line-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-comp-line-chart-text-color));background-color:rgb(var(--ax-comp-line-chart-bg-color))}ax-line-chart .ax-line-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-line-chart .ax-line-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);background-color:rgb(var(--ax-comp-line-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-help{font-size:.8rem;opacity:.6}\n"] }]
|
|
873
989
|
}] });
|