@acorex/charts 0.0.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.
@@ -0,0 +1,995 @@
1
+ import { NXComponent } from '@acorex/cdk/common';
2
+ import { AX_CHART_COLOR_PALETTE, getChartColor } from '@acorex/charts';
3
+ import { AXChartTooltipComponent } from '@acorex/charts/chart-tooltip';
4
+ import { AXPlatform } from '@acorex/core/platform';
5
+ import * as i0 from '@angular/core';
6
+ import { InjectionToken, inject, input, output, viewChild, signal, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
7
+ import { AX_GLOBAL_CONFIG } from '@acorex/core/config';
8
+ import { set } from 'lodash-es';
9
+
10
+ const AXLineChartDefaultConfig = {
11
+ margins: {
12
+ top: 20,
13
+ right: 25,
14
+ bottom: 40,
15
+ left: 50,
16
+ },
17
+ showXAxis: true,
18
+ showYAxis: true,
19
+ showGrid: true,
20
+ showVerticalGrid: false,
21
+ yAxisStartsAtZero: true,
22
+ axisPadding: 5,
23
+ showTooltip: true,
24
+ lineWidth: 2,
25
+ showPoints: true,
26
+ pointRadius: 4,
27
+ smoothLine: false,
28
+ fillArea: false,
29
+ fillOpacity: 20,
30
+ showCrosshair: false,
31
+ animationDuration: 1000,
32
+ animationEasing: 'cubic-out',
33
+ };
34
+ const AX_LINE_CHART_CONFIG = new InjectionToken('AX_LINE_CHART_CONFIG', {
35
+ providedIn: 'root',
36
+ factory: () => {
37
+ const global = inject(AX_GLOBAL_CONFIG);
38
+ set(global, 'chart.lineChart', AXLineChartDefaultConfig);
39
+ return AXLineChartDefaultConfig;
40
+ },
41
+ });
42
+ function lineChartConfig(config = {}) {
43
+ const result = {
44
+ ...AXLineChartDefaultConfig,
45
+ ...config,
46
+ };
47
+ return result;
48
+ }
49
+
50
+ /**
51
+ * Line Chart Component for rendering data as lines with interactive hover effects and animations
52
+ */
53
+ class AXLineChartComponent extends NXComponent {
54
+ data = input([]);
55
+ options = input({});
56
+ pointClick = output();
57
+ chartContainerEl = viewChild.required('chartContainer');
58
+ d3;
59
+ svg;
60
+ chart;
61
+ xScale;
62
+ yScale;
63
+ xAxis;
64
+ yAxis;
65
+ width;
66
+ height;
67
+ margin = { top: 20, right: 25, bottom: 40, left: 50 };
68
+ _tooltipVisible = signal(false);
69
+ _tooltipPosition = signal({ x: 0, y: 0 });
70
+ _tooltipData = signal({
71
+ title: '',
72
+ value: '0',
73
+ percentage: '0%',
74
+ color: '',
75
+ });
76
+ _initialized = signal(false);
77
+ _rendered = signal(false);
78
+ hiddenSeries = new Set();
79
+ _fullNormalizedData = [];
80
+ tooltipVisible = this._tooltipVisible.asReadonly();
81
+ tooltipPosition = this._tooltipPosition.asReadonly();
82
+ tooltipData = this._tooltipData.asReadonly();
83
+ // Inject configuration
84
+ configToken = inject(AX_LINE_CHART_CONFIG);
85
+ // Inject the chart colors
86
+ chartColors = inject(AX_CHART_COLOR_PALETTE);
87
+ // Inject AXPlatform
88
+ platform = inject(AXPlatform);
89
+ effectiveOptions = computed(() => {
90
+ return {
91
+ ...this.configToken,
92
+ ...this.options(),
93
+ };
94
+ });
95
+ ngOnInit() {
96
+ this.loadD3();
97
+ }
98
+ #effect = effect(() => {
99
+ const rawData = this.data();
100
+ if (Array.isArray(rawData)) {
101
+ this._fullNormalizedData = rawData.map((s, i) => ({ ...s, originalIndex: i }));
102
+ }
103
+ else if (rawData && 'data' in rawData) {
104
+ this._fullNormalizedData = [{ ...rawData, originalIndex: 0 }];
105
+ }
106
+ else {
107
+ this._fullNormalizedData = [];
108
+ }
109
+ this.effectiveOptions();
110
+ if (this._rendered()) {
111
+ this.updateChart();
112
+ }
113
+ });
114
+ ngAfterViewInit() {
115
+ this._initialized.set(true);
116
+ if (this.d3 && this.chartContainerEl()) {
117
+ this.createChart();
118
+ this._rendered.set(true);
119
+ }
120
+ }
121
+ ngOnDestroy() {
122
+ this.cleanupChart();
123
+ }
124
+ // AXChartLegendCompatible Implementation
125
+ getLegendItems() {
126
+ const totalSum = this._fullNormalizedData.reduce((sum, series) => {
127
+ return sum + series.data.reduce((sSum, p) => sSum + p.y, 0);
128
+ }, 0);
129
+ return this._fullNormalizedData.map((series) => {
130
+ const seriesSum = series.data.reduce((sum, p) => sum + p.y, 0);
131
+ const percentage = totalSum > 0 ? (seriesSum / totalSum) * 100 : 0;
132
+ return {
133
+ id: series.id || series.label || `series-${series.originalIndex}`,
134
+ name: series.label || `Series ${series.originalIndex + 1}`,
135
+ value: seriesSum,
136
+ color: series.lineColor || getChartColor(series.originalIndex, this.chartColors),
137
+ hidden: this.hiddenSeries.has(series.id || series.label || `series-${series.originalIndex}`),
138
+ percentage: parseFloat(percentage.toFixed(2)),
139
+ };
140
+ });
141
+ }
142
+ highlightSegment(id) {
143
+ if (!this.svg)
144
+ return;
145
+ const allSeriesGroups = this.svg.selectAll('g.ax-line-chart-series');
146
+ const allPointsGroups = this.svg.selectAll('g.ax-line-chart-points');
147
+ if (id === null) {
148
+ allSeriesGroups.classed('ax-chart-dimmed', false).style('opacity', 1);
149
+ allPointsGroups.classed('ax-chart-dimmed', false).style('opacity', 1);
150
+ allSeriesGroups
151
+ .selectAll('.ax-line-chart-line')
152
+ .attr('stroke-width', this.effectiveOptions().lineWidth ?? 2)
153
+ .classed('ax-chart-highlighted-path', false);
154
+ allPointsGroups
155
+ .selectAll('circle.ax-line-chart-point')
156
+ .attr('r', this.effectiveOptions().pointRadius ?? 4)
157
+ .classed('ax-chart-highlighted-point', false);
158
+ return;
159
+ }
160
+ allSeriesGroups.classed('ax-chart-dimmed', true).style('opacity', 0.3);
161
+ allPointsGroups.classed('ax-chart-dimmed', true).style('opacity', 0.3);
162
+ const targetSeriesGroup = this.svg.selectAll(`g.ax-line-chart-series[data-series-identifier="${id}"]`);
163
+ const targetPointsGroup = this.svg.selectAll(`g.ax-line-chart-points[data-series-identifier="${id}"]`);
164
+ targetSeriesGroup.classed('ax-chart-dimmed', false).style('opacity', 1);
165
+ targetPointsGroup.classed('ax-chart-dimmed', false).style('opacity', 1);
166
+ targetSeriesGroup
167
+ .selectAll('.ax-line-chart-line')
168
+ .attr('stroke-width', (this.effectiveOptions().lineWidth ?? 2) * 1.5)
169
+ .classed('ax-chart-highlighted-path', true);
170
+ targetPointsGroup
171
+ .selectAll('circle.ax-line-chart-point')
172
+ .attr('r', (this.effectiveOptions().pointRadius ?? 4) * 1.5)
173
+ .classed('ax-chart-highlighted-point', true);
174
+ }
175
+ toggleSegment(id) {
176
+ const seriesId = id;
177
+ if (this.hiddenSeries.has(seriesId)) {
178
+ this.hiddenSeries.delete(seriesId);
179
+ }
180
+ else {
181
+ this.hiddenSeries.add(seriesId);
182
+ }
183
+ this.updateChart();
184
+ return !this.hiddenSeries.has(seriesId);
185
+ }
186
+ async loadD3() {
187
+ try {
188
+ this.d3 = await import('d3');
189
+ if (this._initialized() && this.chartContainerEl()) {
190
+ this.createChart();
191
+ this._rendered.set(true);
192
+ }
193
+ }
194
+ catch (error) {
195
+ console.error('Failed to load D3.js:', error);
196
+ }
197
+ }
198
+ createChart() {
199
+ if (!this.d3 || !this.chartContainerEl()?.nativeElement)
200
+ return;
201
+ const containerElement = this.chartContainerEl().nativeElement;
202
+ const allSeriesData = this._fullNormalizedData;
203
+ this.d3.select(containerElement).selectAll('*').remove();
204
+ if (allSeriesData.length === 0 || allSeriesData.every((series) => !series.data || series.data.length === 0)) {
205
+ this.showNoDataMessage(containerElement);
206
+ return;
207
+ }
208
+ const visibleDataForRendering = allSeriesData.filter((series) => !this.hiddenSeries.has(series.id || series.label || `series-${series.originalIndex}`));
209
+ if (visibleDataForRendering.length === 0) {
210
+ // All data is present, but all series are hidden by the legend
211
+ this.showAllSeriesHiddenMessage(containerElement);
212
+ // Still setup basic SVG and chart group for consistency if needed, or return
213
+ // For now, we will show the message and return, as scales/axes can't be drawn.
214
+ return;
215
+ }
216
+ // Scales should be based on potentially visible data to avoid errors with empty domains
217
+ // If all are hidden, scales might become an issue. Let's use all data for scales,
218
+ // and rendering will handle visibility.
219
+ const dataForScales = allSeriesData.flatMap((s) => s.data).length > 0 ? allSeriesData : [{ data: [{ x: 0, y: 0 }] }];
220
+ const chartOptions = this.effectiveOptions();
221
+ this.setupDimensions(containerElement, chartOptions);
222
+ // Use allSeriesData for domain calculation to keep scales consistent even if some series are hidden
223
+ // but filter out series with no data points for scale calculation.
224
+ const dataForScaleSetup = allSeriesData.filter((s) => s.data && s.data.length > 0);
225
+ if (dataForScaleSetup.length === 0) {
226
+ // If after filtering, there's no data with points (e.g. all series have empty data arrays)
227
+ this.showNoDataMessage(containerElement);
228
+ return;
229
+ }
230
+ this.setupScales(dataForScaleSetup);
231
+ this.createAxes(chartOptions);
232
+ this.renderLines(allSeriesData); // RenderLines will handle hiding based on hiddenSeries
233
+ }
234
+ updateChart() {
235
+ this.createChart();
236
+ }
237
+ cleanupChart() {
238
+ if (this.svg) {
239
+ this.d3?.select(this.chartContainerEl()?.nativeElement).selectAll('svg').remove();
240
+ this.svg = null;
241
+ this.chart = null;
242
+ }
243
+ this._tooltipVisible.set(false);
244
+ }
245
+ setupDimensions(containerElement, options) {
246
+ this.calculateMargins(options);
247
+ const containerWidth = containerElement.clientWidth;
248
+ const containerHeight = containerElement.clientHeight;
249
+ const minDim = Math.min(200, containerWidth, containerHeight);
250
+ if (options.width && options.height) {
251
+ this.width = options.width - this.margin.left - this.margin.right;
252
+ this.height = options.height - this.margin.top - this.margin.bottom;
253
+ }
254
+ else {
255
+ this.width = Math.max(containerWidth, minDim) - this.margin.left - this.margin.right;
256
+ this.height = Math.max(containerHeight, minDim) - this.margin.top - this.margin.bottom;
257
+ }
258
+ this.width = Math.max(this.width, 100);
259
+ this.height = Math.max(this.height, 100);
260
+ const totalWidth = this.width + this.margin.left + this.margin.right;
261
+ const totalHeight = this.height + this.margin.top + this.margin.bottom;
262
+ const svg = this.d3
263
+ .select(containerElement)
264
+ .append('svg')
265
+ .attr('width', '100%')
266
+ .attr('height', '100%')
267
+ .attr('viewBox', `0 0 ${totalWidth} ${totalHeight}`)
268
+ .attr('preserveAspectRatio', 'xMidYMid meet')
269
+ .attr('style', `
270
+ width: 100%;
271
+ height: 100%;
272
+ max-width: 100%;
273
+ max-height: 100%;
274
+ overflow: visible;
275
+ `);
276
+ this.svg = svg;
277
+ this.chart = this.svg.append('g').attr('transform', `translate(${this.margin.left},${this.margin.top})`);
278
+ }
279
+ calculateMargins(options) {
280
+ this.margin = {
281
+ top: options.margins?.top ?? 20,
282
+ right: options.margins?.right ?? 25,
283
+ bottom: options.margins?.bottom ?? 40,
284
+ left: options.margins?.left ?? 50,
285
+ };
286
+ if (options.xAxisLabel) {
287
+ const xLabelLength = options.xAxisLabel.length;
288
+ const extraBottomMargin = Math.min(20, Math.max(10, xLabelLength * 0.8));
289
+ this.margin.bottom = Math.max(this.margin.bottom, 40 + extraBottomMargin);
290
+ }
291
+ if (options.yAxisLabel) {
292
+ const yLabelLength = options.yAxisLabel.length;
293
+ const extraLeftMargin = Math.min(20, Math.max(10, yLabelLength * 0.8));
294
+ this.margin.left = Math.max(this.margin.left, 50 + extraLeftMargin);
295
+ }
296
+ if (options.showXAxis !== false) {
297
+ this.margin.bottom = Math.max(this.margin.bottom, 45);
298
+ }
299
+ if (options.showYAxis !== false) {
300
+ this.margin.left = Math.max(this.margin.left, 55);
301
+ }
302
+ }
303
+ setupScales(data) {
304
+ // Expects already filtered data for scales
305
+ const chartOptions = this.effectiveOptions();
306
+ const padding = chartOptions.axisPadding ?? 0;
307
+ const paddingMultiplier = padding / 100;
308
+ // Ensure data is not empty for scale domain calculation
309
+ const allDataPoints = data.length > 0 ? data.flatMap((series) => series.data) : [{ x: 0, y: 0 }];
310
+ if (allDataPoints.length === 0) {
311
+ // Should ideally not happen if createChart filters correctly
312
+ allDataPoints.push({ x: 0, y: 0 }); // Default fallback to prevent crash with empty domain
313
+ }
314
+ const allNumericX = allDataPoints.every((d) => typeof d.x === 'number');
315
+ const allDates = !allNumericX && allDataPoints.every((d) => !isNaN(new Date(d.x).getTime()));
316
+ if (allNumericX) {
317
+ const xMin = this.d3.min(allDataPoints, (d) => d.x) ?? 0;
318
+ const xMax = this.d3.max(allDataPoints, (d) => d.x) ?? 0;
319
+ if (xMin === xMax) {
320
+ this.xScale = this.d3
321
+ .scaleLinear()
322
+ .domain([xMin - 1, xMax + 1])
323
+ .range([0, this.width]);
324
+ }
325
+ else {
326
+ this.xScale = this.d3.scaleLinear().domain([xMin, xMax]).range([0, this.width]);
327
+ }
328
+ }
329
+ else if (allDates) {
330
+ const xMin = this.d3.min(allDataPoints, (d) => new Date(d.x)) ?? new Date();
331
+ const xMax = this.d3.max(allDataPoints, (d) => new Date(d.x)) ?? new Date();
332
+ if (xMin.getTime() === xMax.getTime()) {
333
+ const oneDayMs = 86400000;
334
+ this.xScale = this.d3
335
+ .scaleTime()
336
+ .domain([new Date(xMin.getTime() - oneDayMs), new Date(xMax.getTime() + oneDayMs)])
337
+ .range([0, this.width]);
338
+ }
339
+ else {
340
+ this.xScale = this.d3.scaleTime().domain([xMin, xMax]).range([0, this.width]);
341
+ }
342
+ }
343
+ else {
344
+ this.xScale = this.d3
345
+ .scaleBand()
346
+ .domain(allDataPoints.map((d) => String(d.x)))
347
+ .range([0, this.width])
348
+ .paddingInner(0.2)
349
+ .paddingOuter(0);
350
+ }
351
+ const yAxisStartsAtZero = chartOptions.yAxisStartsAtZero !== false;
352
+ let yMin = this.d3.min(allDataPoints, (d) => d.y) ?? 0;
353
+ if (yAxisStartsAtZero) {
354
+ yMin = Math.min(0, yMin);
355
+ }
356
+ const yMax = this.d3.max(allDataPoints, (d) => d.y) ?? 0;
357
+ const yRange = yMax - yMin;
358
+ this.yScale = this.d3
359
+ .scaleLinear()
360
+ .domain([yMin, yMax + yRange * paddingMultiplier])
361
+ .nice()
362
+ .range([this.height, 0]);
363
+ }
364
+ createAxes(options) {
365
+ const showXAxis = options.showXAxis !== false;
366
+ const showYAxis = options.showYAxis !== false;
367
+ const showGrid = options.showGrid !== false;
368
+ const isBandScale = this.xScale.bandwidth !== undefined;
369
+ const isRtl = this.platform.isRtl();
370
+ const axesGroup = this.chart.append('g').attr('class', 'ax-line-chart-axes');
371
+ if (showXAxis) {
372
+ this.xAxis = axesGroup
373
+ .append('g')
374
+ .attr('class', 'ax-line-chart-axis-x')
375
+ .attr('transform', `translate(0,${this.height})`)
376
+ .call(this.d3.axisBottom(this.xScale).tickSize(5).tickPadding(8));
377
+ // Style the x-axis path and lines
378
+ this.xAxis.selectAll('path').attr('stroke', 'rgba(var(--ax-comp-line-chart-axis-color), 0.2)');
379
+ this.xAxis
380
+ .selectAll('line')
381
+ .attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.2)')
382
+ .attr('stroke-dasharray', '2,2')
383
+ .attr('stroke-opacity', '0.5');
384
+ const dynamicXAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.width / 45)));
385
+ this.xAxis.selectAll('text').attr('style', `
386
+ font-size: ${dynamicXAxisTickFontSize}px;
387
+ font-weight: 400;
388
+ fill: rgba(var(--ax-comp-line-chart-labels-color), 0.7);
389
+ `);
390
+ if (options.xAxisLabel) {
391
+ const labelY = this.height + this.margin.bottom * 0.8;
392
+ axesGroup
393
+ .append('text')
394
+ .attr('class', 'ax-line-chart-axis-label ax-x-axis-label')
395
+ .attr('text-anchor', 'middle')
396
+ .attr('dominant-baseline', 'middle')
397
+ .attr('x', this.width / 2)
398
+ .attr('y', labelY)
399
+ .attr('transform', 'translate(0, 5)')
400
+ .attr('style', `
401
+ font-size: 14px;
402
+ font-weight: 500;
403
+ fill: rgb(var(--ax-comp-line-chart-text-color));
404
+ pointer-events: none;
405
+ `)
406
+ .text(options.xAxisLabel);
407
+ }
408
+ }
409
+ if (showYAxis) {
410
+ this.yAxis = axesGroup
411
+ .append('g')
412
+ .attr('class', 'ax-line-chart-axis-y')
413
+ .call(this.d3.axisLeft(this.yScale).tickSize(5).tickPadding(8));
414
+ // Style the y-axis path and lines
415
+ this.yAxis.selectAll('path').attr('stroke', 'rgba(var(--ax-comp-line-chart-axis-color), 0.2)');
416
+ this.yAxis
417
+ .selectAll('line')
418
+ .attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.2)')
419
+ .attr('stroke-dasharray', '2,2')
420
+ .attr('stroke-opacity', '0.5');
421
+ const dynamicYAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.height / 30)));
422
+ const yTickTexts = this.yAxis.selectAll('text').attr('style', `
423
+ font-size: ${dynamicYAxisTickFontSize}px;
424
+ font-weight: 400;
425
+ fill: rgba(var(--ax-comp-line-chart-labels-color), 0.7);
426
+ `);
427
+ if (isRtl) {
428
+ yTickTexts.attr('text-anchor', 'start');
429
+ }
430
+ if (options.yAxisLabel) {
431
+ const labelX = -this.height / 2;
432
+ const labelY = -this.margin.left * 0.8;
433
+ axesGroup
434
+ .append('text')
435
+ .attr('class', 'ax-line-chart-axis-label ax-y-axis-label')
436
+ .attr('text-anchor', 'middle')
437
+ .attr('dominant-baseline', 'middle')
438
+ .attr('transform', 'rotate(-90) translate(-5, 0)')
439
+ .attr('x', labelX)
440
+ .attr('y', labelY)
441
+ .attr('style', `
442
+ font-size: 14px;
443
+ font-weight: 500;
444
+ fill: rgb(var(--ax-comp-line-chart-text-color));
445
+ pointer-events: none;
446
+ `)
447
+ .text(options.yAxisLabel);
448
+ }
449
+ }
450
+ if (showGrid) {
451
+ const gridGroup = this.chart
452
+ .append('g')
453
+ .attr('class', 'ax-line-chart-grid-container')
454
+ .attr('pointer-events', 'none');
455
+ const yGrid = gridGroup
456
+ .append('g')
457
+ .attr('class', 'ax-line-chart-grid')
458
+ .call(this.d3
459
+ .axisLeft(this.yScale)
460
+ .tickSize(-this.width)
461
+ .tickFormat(() => '')
462
+ .tickValues(this.yScale.ticks()));
463
+ // Style the grid path and lines
464
+ yGrid.selectAll('path').attr('stroke-width', '0');
465
+ yGrid
466
+ .selectAll('.tick')
467
+ .selectAll('line')
468
+ .attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.2)')
469
+ .attr('stroke-dasharray', '2,2')
470
+ .attr('stroke-opacity', '0.5');
471
+ if (options.showVerticalGrid) {
472
+ const xGrid = gridGroup
473
+ .append('g')
474
+ .attr('class', 'ax-line-chart-grid-vertical')
475
+ .attr('transform', `translate(0,${this.height})`)
476
+ .call(this.d3
477
+ .axisBottom(this.xScale)
478
+ .tickSize(-this.height)
479
+ .tickFormat(() => '')
480
+ .tickValues(isBandScale ? undefined : this.xScale.ticks()));
481
+ // Style the vertical grid path and lines
482
+ xGrid.selectAll('path').attr('stroke-width', '0');
483
+ xGrid
484
+ .selectAll('.tick')
485
+ .selectAll('line')
486
+ .attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.15)')
487
+ .attr('stroke-dasharray', '2,2')
488
+ .attr('stroke-opacity', '0.5');
489
+ }
490
+ }
491
+ }
492
+ renderLines(allSeriesData) {
493
+ const isBandScale = this.xScale.bandwidth !== undefined;
494
+ const getX = (d) => {
495
+ if (isBandScale) {
496
+ return this.xScale(String(d.x)) + this.xScale.bandwidth() / 2;
497
+ }
498
+ else {
499
+ return this.xScale(typeof d.x === 'number' ? d.x : new Date(d.x));
500
+ }
501
+ };
502
+ const lineGenerator = this.d3
503
+ .line()
504
+ .x(getX)
505
+ .y((d) => this.yScale(d.y));
506
+ if (this.effectiveOptions().smoothLine !== false) {
507
+ lineGenerator.curve(this.d3.curveMonotoneX);
508
+ }
509
+ const areaGenerator = this.d3
510
+ .area()
511
+ .x(getX)
512
+ .y0(this.height)
513
+ .y1((d) => this.yScale(d.y));
514
+ if (this.effectiveOptions().smoothLine !== false) {
515
+ areaGenerator.curve(this.d3.curveMonotoneX);
516
+ }
517
+ this.svg.attr('class', 'ax-line-chart-animating');
518
+ const allSeriesGroup = this.chart
519
+ .append('g')
520
+ .attr('class', 'ax-line-chart-all-series')
521
+ .attr('pointer-events', 'none');
522
+ const allPointsGroup = this.chart
523
+ .append('g')
524
+ .attr('class', 'ax-line-chart-all-points')
525
+ .attr('pointer-events', 'none');
526
+ if (this.effectiveOptions().showCrosshair === true) {
527
+ this.chart.append('g').attr('class', 'ax-line-chart-crosshair').attr('pointer-events', 'none');
528
+ }
529
+ const animationDuration = this.effectiveOptions().animationDuration;
530
+ const animationEasing = this.getEasingFunction(this.effectiveOptions().animationEasing);
531
+ allSeriesData.forEach((series) => {
532
+ const seriesIdentifier = series.id || series.label || `series-${series.originalIndex}`;
533
+ if (this.hiddenSeries.has(seriesIdentifier)) {
534
+ this.chart.selectAll(`.ax-line-chart-series[data-series-identifier="${seriesIdentifier}"]`).remove();
535
+ this.chart.selectAll(`.ax-line-chart-points[data-series-identifier="${seriesIdentifier}"]`).remove();
536
+ return;
537
+ }
538
+ if (!series.data || series.data.length === 0)
539
+ return;
540
+ const seriesGroup = allSeriesGroup
541
+ .append('g')
542
+ .attr('class', `ax-line-chart-series ax-line-chart-series-${series.originalIndex}`)
543
+ .attr('data-series-identifier', seriesIdentifier)
544
+ .attr('pointer-events', 'none');
545
+ const lineColor = series.lineColor || getChartColor(series.originalIndex, this.chartColors);
546
+ const fillColor = series.fillColor || lineColor;
547
+ const line = seriesGroup
548
+ .append('path')
549
+ .datum(series.data)
550
+ .attr('class', 'ax-line-chart-line')
551
+ .attr('stroke', lineColor)
552
+ .attr('stroke-width', this.effectiveOptions().lineWidth ?? 2)
553
+ .attr('stroke-linejoin', 'round')
554
+ .attr('stroke-linecap', 'round')
555
+ .attr('d', lineGenerator)
556
+ .attr('fill', 'none')
557
+ .attr('style', 'transition: stroke-width 0.3s ease;')
558
+ .attr('pointer-events', 'none');
559
+ line
560
+ .on('mouseenter', () => {
561
+ line
562
+ .transition()
563
+ .duration(150)
564
+ .attr('stroke-width', (this.effectiveOptions().lineWidth ?? 2) * 1.5);
565
+ })
566
+ .on('mouseleave', () => {
567
+ line
568
+ .transition()
569
+ .duration(150)
570
+ .attr('stroke-width', this.effectiveOptions().lineWidth ?? 2);
571
+ });
572
+ const totalLength = line.node().getTotalLength();
573
+ line
574
+ .attr('stroke-dasharray', totalLength + ' ' + totalLength)
575
+ .attr('stroke-dashoffset', totalLength)
576
+ .transition()
577
+ .duration(animationDuration)
578
+ .ease(animationEasing)
579
+ .attr('stroke-dashoffset', 0)
580
+ .on('end', function () {
581
+ line.attr('pointer-events', 'all');
582
+ });
583
+ if (this.effectiveOptions().fillArea) {
584
+ const area = seriesGroup
585
+ .append('path')
586
+ .datum(series.data)
587
+ .attr('class', 'ax-line-chart-area')
588
+ .attr('fill', fillColor)
589
+ .attr('opacity', 0)
590
+ .attr('d', areaGenerator)
591
+ .attr('style', 'transition: opacity 0.3s ease;')
592
+ .attr('pointer-events', 'none');
593
+ area
594
+ .on('mouseenter', () => {
595
+ area
596
+ .transition()
597
+ .duration(150)
598
+ .attr('opacity', ((this.effectiveOptions().fillOpacity ?? 20) / 100) * 1.5);
599
+ })
600
+ .on('mouseleave', () => {
601
+ area
602
+ .transition()
603
+ .duration(150)
604
+ .attr('opacity', (this.effectiveOptions().fillOpacity ?? 20) / 100);
605
+ });
606
+ area
607
+ .transition()
608
+ .duration(animationDuration)
609
+ .ease(animationEasing)
610
+ .attr('opacity', (this.effectiveOptions().fillOpacity ?? 20) / 100)
611
+ .on('end', function () {
612
+ area.attr('pointer-events', 'all');
613
+ });
614
+ }
615
+ });
616
+ if (this.effectiveOptions().showPoints !== false) {
617
+ const pointMap = new Map();
618
+ allSeriesData.forEach((series) => {
619
+ const seriesIdentifier = series.id || series.label || `series-${series.originalIndex}`;
620
+ if (this.hiddenSeries.has(seriesIdentifier) || !series.data || series.data.length === 0) {
621
+ return;
622
+ }
623
+ const lineColor = series.lineColor || getChartColor(series.originalIndex, this.chartColors);
624
+ const maxPoints = 100;
625
+ const pointData = series.data.length > maxPoints ? this.getReducedDataPoints(series.data, maxPoints) : series.data;
626
+ pointData.forEach((point) => {
627
+ const x = getX(point);
628
+ const y = this.yScale(point.y);
629
+ const key = `${Math.round(x * 10) / 10},${Math.round(y * 10) / 10}`;
630
+ if (!pointMap.has(key)) {
631
+ pointMap.set(key, []);
632
+ }
633
+ pointMap.get(key)?.push({ point, series, originalIndex: series.originalIndex });
634
+ });
635
+ });
636
+ let animationCounter = 0;
637
+ const totalVisibleSeriesCount = allSeriesData.filter((s) => !this.hiddenSeries.has(s.id || s.label || `series-${s.originalIndex}`) && s.data && s.data.length > 0).length;
638
+ allSeriesData.forEach((series) => {
639
+ const seriesIdentifier = series.id || series.label || `series-${series.originalIndex}`;
640
+ if (this.hiddenSeries.has(seriesIdentifier) || !series.data || series.data.length === 0) {
641
+ return;
642
+ }
643
+ const lineColor = series.lineColor || getChartColor(series.originalIndex, this.chartColors);
644
+ const pointsGroup = allPointsGroup
645
+ .append('g')
646
+ .attr('class', `ax-line-chart-points ax-line-chart-points-${series.originalIndex}`)
647
+ .attr('data-series-identifier', seriesIdentifier)
648
+ .attr('pointer-events', 'none');
649
+ pointsGroup
650
+ .on('mouseenter', () => this.handlePointGroupEnter(series.originalIndex, lineColor))
651
+ .on('mouseleave', () => this.handlePointGroupLeave());
652
+ const maxPoints = 100;
653
+ const pointData = series.data.length > maxPoints ? this.getReducedDataPoints(series.data, maxPoints) : series.data;
654
+ pointsGroup
655
+ .selectAll('circle')
656
+ .data(pointData)
657
+ .enter()
658
+ .append('circle')
659
+ .attr('class', 'ax-line-chart-point')
660
+ .attr('cx', getX)
661
+ .attr('cy', (d) => this.yScale(d.y))
662
+ .attr('r', 0)
663
+ .attr('fill', lineColor)
664
+ .attr('stroke', '#fff')
665
+ .attr('stroke-width', 1)
666
+ .attr('data-x', (d) => d.x)
667
+ .attr('data-y', (d) => d.y)
668
+ .style('cursor', 'pointer')
669
+ .attr('pointer-events', 'none')
670
+ .on('mouseenter', (event, d) => {
671
+ const x = getX(d);
672
+ const y = this.yScale(d.y);
673
+ const key = `${Math.round(x * 10) / 10},${Math.round(y * 10) / 10}`;
674
+ const overlappingPoints = pointMap.get(key) || [];
675
+ if (overlappingPoints.length > 1) {
676
+ this.handleOverlappingPointsHover(event, overlappingPoints);
677
+ }
678
+ else {
679
+ this.handlePointHover(event, d, series, series.originalIndex);
680
+ }
681
+ this.d3
682
+ .select(event.target)
683
+ .transition()
684
+ .duration(150)
685
+ .attr('r', (this.effectiveOptions().pointRadius ?? 4) * 1.5)
686
+ .attr('stroke-width', 2)
687
+ .attr('stroke', `rgb(var(--ax-comp-line-chart-bg-color))`);
688
+ })
689
+ .on('mousemove', (event) => this.updateTooltipPosition(event))
690
+ .on('mouseleave', (event) => {
691
+ this._tooltipVisible.set(false);
692
+ this.d3
693
+ .select(event.target)
694
+ .transition()
695
+ .duration(150)
696
+ .attr('r', this.effectiveOptions().pointRadius ?? 4)
697
+ .attr('stroke-width', 1)
698
+ .attr('stroke', '#fff');
699
+ })
700
+ .on('click', (event, d) => {
701
+ const x = getX(d);
702
+ const y = this.yScale(d.y);
703
+ const key = `${Math.round(x * 10) / 10},${Math.round(y * 10) / 10}`;
704
+ const overlappingPoints = pointMap.get(key) || [];
705
+ if (overlappingPoints.length > 1) {
706
+ overlappingPoints.forEach(({ point, series }) => {
707
+ this.handlePointClick(event, point, series);
708
+ });
709
+ }
710
+ else {
711
+ this.handlePointClick(event, d, series);
712
+ }
713
+ })
714
+ .transition()
715
+ .delay((d, i) => i * Math.min(50, (animationDuration || 0) * 0.05) + (animationDuration || 0) * 0.5)
716
+ .duration((animationDuration || 0) * 0.3)
717
+ .ease(animationEasing)
718
+ .attr('r', this.effectiveOptions().pointRadius ?? 4)
719
+ .on('end', (d, i, nodes) => {
720
+ if (i === nodes.length - 1) {
721
+ animationCounter++;
722
+ if (animationCounter >= totalVisibleSeriesCount) {
723
+ this.enablePointerEventsAfterAnimation();
724
+ }
725
+ }
726
+ });
727
+ });
728
+ }
729
+ else {
730
+ setTimeout(() => {
731
+ this.enablePointerEventsAfterAnimation();
732
+ }, animationDuration || 0 + 100);
733
+ }
734
+ }
735
+ enablePointerEventsAfterAnimation() {
736
+ if (!this.chart || !this.svg)
737
+ return;
738
+ this.chart.selectAll('.ax-line-chart-all-series').attr('pointer-events', 'all');
739
+ this.chart.selectAll('.ax-line-chart-series').attr('pointer-events', 'all');
740
+ this.chart.selectAll('.ax-line-chart-line').attr('pointer-events', 'all');
741
+ this.chart.selectAll('.ax-line-chart-area').attr('pointer-events', 'all');
742
+ this.chart.selectAll('.ax-line-chart-all-points').attr('pointer-events', 'all');
743
+ this.chart.selectAll('.ax-line-chart-points').attr('pointer-events', 'all');
744
+ this.chart.selectAll('.ax-line-chart-point').attr('pointer-events', 'all');
745
+ this.svg.classed('ax-line-chart-animating', false);
746
+ }
747
+ handlePointGroupEnter(originalIndex, color) {
748
+ this.chart
749
+ .select(`.ax-line-chart-series-${originalIndex} .ax-line-chart-line`)
750
+ .transition()
751
+ .duration(150)
752
+ .attr('stroke-width', (this.effectiveOptions().lineWidth ?? 2) * 1.5);
753
+ }
754
+ handlePointGroupLeave() {
755
+ this.chart
756
+ .selectAll('.ax-line-chart-line')
757
+ .transition()
758
+ .duration(150)
759
+ .attr('stroke-width', this.effectiveOptions().lineWidth ?? 2);
760
+ if (this.effectiveOptions().showCrosshair === true) {
761
+ this.chart.select('.ax-line-chart-crosshair').selectAll('*').remove();
762
+ }
763
+ }
764
+ getReducedDataPoints(data, maxPoints) {
765
+ if (data.length <= maxPoints)
766
+ return data;
767
+ const result = [];
768
+ const step = Math.ceil(data.length / maxPoints);
769
+ for (let i = 0; i < data.length; i += step) {
770
+ result.push(data[i]);
771
+ }
772
+ if (result[result.length - 1] !== data[data.length - 1]) {
773
+ result.push(data[data.length - 1]);
774
+ }
775
+ return result;
776
+ }
777
+ handlePointHover(event, dataPoint, series, originalIndex) {
778
+ if (this.effectiveOptions().showTooltip !== false) {
779
+ const color = series.lineColor || getChartColor(originalIndex, this.chartColors);
780
+ this._tooltipData.set({
781
+ title: dataPoint.tooltipLabel || series.tooltipLabel || series.label || `Series ${originalIndex + 1}`,
782
+ value: dataPoint.y.toString(),
783
+ seriesName: `x: ${dataPoint.x}`,
784
+ color: color,
785
+ });
786
+ this._tooltipVisible.set(true);
787
+ this.updateTooltipPosition(event);
788
+ if (this.effectiveOptions().showCrosshair === true) {
789
+ this.showCrosshairLines(dataPoint);
790
+ }
791
+ }
792
+ }
793
+ showCrosshairLines(dataPoint) {
794
+ const isBandScale = this.xScale.bandwidth !== undefined;
795
+ let x;
796
+ if (isBandScale) {
797
+ x = this.xScale(String(dataPoint.x)) + this.xScale.bandwidth() / 2;
798
+ }
799
+ else {
800
+ x = this.xScale(typeof dataPoint.x === 'number' ? dataPoint.x : new Date(dataPoint.x));
801
+ }
802
+ const y = this.yScale(dataPoint.y);
803
+ let crosshairGroup = this.chart.select('.ax-line-chart-crosshair');
804
+ if (crosshairGroup.empty()) {
805
+ crosshairGroup = this.chart.append('g').attr('class', 'ax-line-chart-crosshair').attr('pointer-events', 'none');
806
+ }
807
+ crosshairGroup.selectAll('*').remove();
808
+ crosshairGroup
809
+ .append('line')
810
+ .attr('class', 'ax-line-chart-crosshair-vertical')
811
+ .attr('x1', x)
812
+ .attr('y1', 0)
813
+ .attr('x2', x)
814
+ .attr('y2', this.height)
815
+ .attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.5)')
816
+ .attr('stroke-width', 1)
817
+ .attr('stroke-dasharray', '3,3')
818
+ .attr('opacity', 0.7)
819
+ .attr('pointer-events', 'none');
820
+ crosshairGroup
821
+ .append('line')
822
+ .attr('class', 'ax-line-chart-crosshair-horizontal')
823
+ .attr('x1', 0)
824
+ .attr('y1', y)
825
+ .attr('x2', this.width)
826
+ .attr('y2', y)
827
+ .attr('stroke', 'rgba(var(--ax-comp-line-chart-grid-lines-color), 0.5)')
828
+ .attr('stroke-width', 1)
829
+ .attr('stroke-dasharray', '3,3')
830
+ .attr('opacity', 0.7)
831
+ .attr('pointer-events', 'none');
832
+ }
833
+ updateTooltipPosition(event) {
834
+ const container = this.chartContainerEl().nativeElement.getBoundingClientRect();
835
+ const tooltipEl = this.chartContainerEl().nativeElement.querySelector('.chart-tooltip');
836
+ if (!tooltipEl) {
837
+ const x = event.clientX - container.left;
838
+ const y = event.clientY - container.top;
839
+ this._tooltipPosition.set({ x, y });
840
+ return;
841
+ }
842
+ const tooltipRect = tooltipEl.getBoundingClientRect();
843
+ let x = event.clientX - container.left;
844
+ const y = event.clientY - container.top;
845
+ if (x + tooltipRect.width + 20 > container.width) {
846
+ x = x - tooltipRect.width - 15;
847
+ }
848
+ this._tooltipPosition.set({ x, y });
849
+ }
850
+ handlePointClick(event, dataPoint, series) {
851
+ this.pointClick.emit({
852
+ series: series, // series still refers to the full series data with originalIndex
853
+ point: dataPoint,
854
+ event: {
855
+ nativeEvent: event,
856
+ sender: this,
857
+ },
858
+ });
859
+ }
860
+ showNoDataMessage(containerElement) {
861
+ this.d3.select(containerElement).selectAll('*').remove();
862
+ const messageContainer = this.d3
863
+ .select(containerElement)
864
+ .append('div')
865
+ .attr('class', 'ax-line-chart-no-data-message')
866
+ .style('position', 'absolute')
867
+ .style('left', '50%')
868
+ .style('top', '50%')
869
+ .style('transform', 'translate(-50%, -50%)')
870
+ .style('text-align', 'center')
871
+ .style('background-color', 'rgb(var(--ax-comp-line-chart-bg-color))')
872
+ .style('padding', '1.5rem')
873
+ .style('border-radius', '0.5rem')
874
+ .style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
875
+ .style('width', '80%')
876
+ .style('max-width', '300px');
877
+ messageContainer
878
+ .append('div')
879
+ .attr('class', 'ax-line-chart-no-data-icon')
880
+ .style('opacity', '0.6')
881
+ .style('margin-bottom', '0.75rem')
882
+ .html('<i class="fa-light fa-chart-line fa-2x"></i>');
883
+ messageContainer
884
+ .append('div')
885
+ .attr('class', 'ax-line-chart-no-data-text')
886
+ .style('font-size', '1rem')
887
+ .style('font-weight', '600')
888
+ .style('margin-bottom', '0.5rem')
889
+ .text('No data available');
890
+ messageContainer
891
+ .append('div')
892
+ .attr('class', 'ax-line-chart-no-data-help')
893
+ .style('font-size', '0.8rem')
894
+ .style('opacity', '0.6')
895
+ .text('Please provide data to display the chart');
896
+ }
897
+ showAllSeriesHiddenMessage(containerElement) {
898
+ this.d3.select(containerElement).selectAll('*').remove(); // Clear existing chart elements
899
+ const messageContainer = this.d3
900
+ .select(containerElement)
901
+ .append('div')
902
+ .attr('class', 'ax-line-chart-all-hidden-message') // Different class
903
+ .style('position', 'absolute')
904
+ .style('left', '50%')
905
+ .style('top', '50%')
906
+ .style('transform', 'translate(-50%, -50%)')
907
+ .style('text-align', 'center')
908
+ .style('background-color', 'rgb(var(--ax-comp-line-chart-bg-color))')
909
+ .style('padding', '1.5rem')
910
+ .style('border-radius', '0.5rem')
911
+ .style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
912
+ .style('width', '80%')
913
+ .style('max-width', '350px'); // Slightly wider for longer text
914
+ messageContainer
915
+ .append('div')
916
+ .attr('class', 'ax-line-chart-all-hidden-icon')
917
+ .style('opacity', '0.6')
918
+ .style('margin-bottom', '0.75rem')
919
+ .html('<i class="fa-light fa-eye-slash fa-2x"></i>'); // Different icon
920
+ messageContainer
921
+ .append('div')
922
+ .attr('class', 'ax-line-chart-all-hidden-text')
923
+ .style('font-size', '1rem')
924
+ .style('font-weight', '600')
925
+ .style('margin-bottom', '0.5rem')
926
+ .text('All series are hidden');
927
+ messageContainer
928
+ .append('div')
929
+ .attr('class', 'ax-line-chart-all-hidden-help')
930
+ .style('font-size', '0.8rem')
931
+ .style('opacity', '0.6')
932
+ .text('Click legend items to show series in the chart.');
933
+ }
934
+ handleOverlappingPointsHover(event, overlappingPoints) {
935
+ if (this.effectiveOptions().showTooltip === false)
936
+ return;
937
+ const tooltipData = {
938
+ title: 'Multiple Series',
939
+ value: overlappingPoints[0].point.y.toString(),
940
+ seriesName: '',
941
+ color: '',
942
+ items: overlappingPoints.map(({ point, series, originalIndex }) => {
943
+ const color = series.lineColor || getChartColor(originalIndex, this.chartColors);
944
+ return {
945
+ label: series.label || `Series ${originalIndex + 1}`,
946
+ value: point.y.toString(),
947
+ color: color,
948
+ };
949
+ }),
950
+ };
951
+ this._tooltipData.set(tooltipData);
952
+ this._tooltipVisible.set(true);
953
+ this.updateTooltipPosition(event);
954
+ if (this.effectiveOptions().showCrosshair === true && overlappingPoints.length > 0) {
955
+ this.showCrosshairLines(overlappingPoints[0].point);
956
+ }
957
+ }
958
+ getEasingFunction(easing) {
959
+ switch (easing) {
960
+ case 'linear':
961
+ return this.d3.easeLinear;
962
+ case 'ease':
963
+ return this.d3.easePolyInOut;
964
+ case 'ease-in':
965
+ return this.d3.easePolyIn;
966
+ case 'ease-out':
967
+ return this.d3.easePolyOut;
968
+ case 'ease-in-out':
969
+ return this.d3.easePolyInOut;
970
+ case 'cubic':
971
+ return this.d3.easeCubic;
972
+ case 'cubic-in':
973
+ return this.d3.easeCubicIn;
974
+ case 'cubic-out':
975
+ return this.d3.easeCubicOut;
976
+ case 'cubic-in-out':
977
+ return this.d3.easeCubicInOut;
978
+ default:
979
+ return this.d3.easeCubicOut;
980
+ }
981
+ }
982
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXLineChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
983
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", 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: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
984
+ }
985
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXLineChartComponent, decorators: [{
986
+ type: Component,
987
+ args: [{ selector: 'ax-line-chart', standalone: true, encapsulation: ViewEncapsulation.None, imports: [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"] }]
988
+ }] });
989
+
990
+ /**
991
+ * Generated bundle index. Do not edit.
992
+ */
993
+
994
+ export { AXLineChartComponent, AXLineChartDefaultConfig, AX_LINE_CHART_CONFIG, lineChartConfig };
995
+ //# sourceMappingURL=acorex-charts-line-chart.mjs.map