@acorex/charts 20.9.2 → 20.9.4
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/index.d.ts +1 -0
- package/donut-chart/index.d.ts +1 -0
- package/fesm2022/acorex-charts-bar-chart.mjs +40 -39
- package/fesm2022/acorex-charts-bar-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-chart-tooltip.mjs +17 -13
- package/fesm2022/acorex-charts-chart-tooltip.mjs.map +1 -1
- package/fesm2022/acorex-charts-donut-chart.mjs +16 -5
- package/fesm2022/acorex-charts-donut-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-funnel-chart.mjs +9 -1
- package/fesm2022/acorex-charts-funnel-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-gauge-chart.mjs +111 -8
- package/fesm2022/acorex-charts-gauge-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-heatmap-chart.mjs +9 -1
- package/fesm2022/acorex-charts-heatmap-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts.mjs +18 -26
- package/fesm2022/acorex-charts.mjs.map +1 -1
- package/funnel-chart/index.d.ts +1 -0
- package/gauge-chart/index.d.ts +24 -0
- package/heatmap-chart/index.d.ts +1 -0
- package/package.json +5 -5
|
@@ -10,6 +10,7 @@ const AXGaugeChartDefaultConfig = {
|
|
|
10
10
|
cornerRadius: 5,
|
|
11
11
|
showValue: true,
|
|
12
12
|
showTooltip: true,
|
|
13
|
+
showDataLabels: true,
|
|
13
14
|
animationDuration: 750,
|
|
14
15
|
animationEasing: 'cubic-out',
|
|
15
16
|
messages: {
|
|
@@ -83,6 +84,10 @@ class AXGaugeChartComponent extends AXChartComponent {
|
|
|
83
84
|
TICK_LABEL_CHAR_WIDTH_RATIO = 0.62;
|
|
84
85
|
TICK_LABEL_SIDE_PADDING = 6;
|
|
85
86
|
LABEL_TICK_CLEARANCE = 4;
|
|
87
|
+
MIN_SEGMENT_CHORD_FOR_LABEL = 28;
|
|
88
|
+
MIN_SEGMENT_RING_FOR_LABEL = 14;
|
|
89
|
+
MIN_SEGMENT_LABEL_FONT = 10;
|
|
90
|
+
MAX_SEGMENT_LABEL_FONT = 16;
|
|
86
91
|
instanceId = createChartInstanceId('ax-gauge');
|
|
87
92
|
get bgGradientId() {
|
|
88
93
|
return `${this.instanceId}-bg-gradient`;
|
|
@@ -324,23 +329,28 @@ class AXGaugeChartComponent extends AXChartComponent {
|
|
|
324
329
|
const angles = sortedThresholds.map((t) => this.scaleValueToColorAngle(t.value, minValue, maxValue));
|
|
325
330
|
// Start from the minimum value angle
|
|
326
331
|
let previousEndAngle = this.scaleValueToColorAngle(minValue, minValue, maxValue);
|
|
332
|
+
const labeledSegments = [];
|
|
327
333
|
sortedThresholds.forEach((threshold, i) => {
|
|
328
334
|
const endAngle = angles[i];
|
|
329
335
|
// Skip if end angle is not greater than start angle
|
|
330
336
|
if (endAngle <= previousEndAngle)
|
|
331
337
|
return;
|
|
338
|
+
const startAngle = previousEndAngle;
|
|
332
339
|
const arcPath = chartGroup
|
|
333
340
|
.append('path')
|
|
334
341
|
.attr('d', arc({
|
|
335
342
|
innerRadius,
|
|
336
343
|
outerRadius,
|
|
337
|
-
startAngle
|
|
344
|
+
startAngle,
|
|
338
345
|
endAngle,
|
|
339
346
|
}))
|
|
340
347
|
.attr('fill', threshold.color || `url(#${this.thresholdGradientId(i)})`)
|
|
341
348
|
.attr('class', 'gauge-arc threshold-arc')
|
|
342
349
|
.attr('data-value', threshold.value)
|
|
343
350
|
.style('cursor', 'pointer');
|
|
351
|
+
if (threshold.label) {
|
|
352
|
+
labeledSegments.push({ startAngle, endAngle, label: threshold.label });
|
|
353
|
+
}
|
|
344
354
|
// Add tooltip interaction
|
|
345
355
|
if (this.effectiveOptions().showTooltip) {
|
|
346
356
|
// Convert angles back to values for tooltip
|
|
@@ -394,6 +404,88 @@ class AXGaugeChartComponent extends AXChartComponent {
|
|
|
394
404
|
});
|
|
395
405
|
}
|
|
396
406
|
}
|
|
407
|
+
if (this.effectiveOptions().showDataLabels !== false && labeledSegments.length > 0) {
|
|
408
|
+
this.drawSegmentLabels(chartGroup, labeledSegments, innerRadius, outerRadius);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Draws threshold labels centered on each segment arc when space allows.
|
|
413
|
+
*/
|
|
414
|
+
drawSegmentLabels(chartGroup, segments, innerRadius, outerRadius) {
|
|
415
|
+
const labelArc = this.d3
|
|
416
|
+
.arc()
|
|
417
|
+
.innerRadius(innerRadius)
|
|
418
|
+
.outerRadius(outerRadius * 0.98);
|
|
419
|
+
const labelGroup = chartGroup.append('g').attr('class', 'gauge-segment-labels');
|
|
420
|
+
const ringWidth = outerRadius - innerRadius;
|
|
421
|
+
const labelRadius = innerRadius + ringWidth / 2;
|
|
422
|
+
const animationDuration = this.effectiveOptions().animationDuration ?? 750;
|
|
423
|
+
segments.forEach((segment) => {
|
|
424
|
+
const angle = segment.endAngle - segment.startAngle;
|
|
425
|
+
const chordLength = 2 * labelRadius * Math.sin(angle / 2);
|
|
426
|
+
const fontSize = this.calculateSegmentLabelFontSize(angle, ringWidth, chordLength);
|
|
427
|
+
if (fontSize <= 0)
|
|
428
|
+
return;
|
|
429
|
+
const availableWidth = chordLength * 0.8;
|
|
430
|
+
const text = this.getFittedSegmentLabel(segment.label, fontSize, availableWidth);
|
|
431
|
+
if (!text)
|
|
432
|
+
return;
|
|
433
|
+
const centroid = labelArc.centroid({
|
|
434
|
+
innerRadius,
|
|
435
|
+
outerRadius: outerRadius * 0.98,
|
|
436
|
+
startAngle: segment.startAngle,
|
|
437
|
+
endAngle: segment.endAngle,
|
|
438
|
+
});
|
|
439
|
+
labelGroup
|
|
440
|
+
.append('text')
|
|
441
|
+
.attr('class', 'gauge-segment-label')
|
|
442
|
+
.attr('transform', `translate(${centroid[0]}, ${centroid[1]})`)
|
|
443
|
+
.attr('text-anchor', 'middle')
|
|
444
|
+
.attr('dominant-baseline', 'middle')
|
|
445
|
+
.style('pointer-events', 'none')
|
|
446
|
+
.style('font-size', `${fontSize}px`)
|
|
447
|
+
.style('font-weight', '600')
|
|
448
|
+
.style('fill', 'rgb(var(--ax-comp-gauge-chart-data-labels-color))')
|
|
449
|
+
.style('opacity', 0)
|
|
450
|
+
.text(text)
|
|
451
|
+
.transition()
|
|
452
|
+
.duration(animationDuration)
|
|
453
|
+
.style('opacity', 1);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
calculateSegmentLabelFontSize(angle, ringWidth, chordLength) {
|
|
457
|
+
if (chordLength < this.MIN_SEGMENT_CHORD_FOR_LABEL || ringWidth < this.MIN_SEGMENT_RING_FOR_LABEL) {
|
|
458
|
+
return 0;
|
|
459
|
+
}
|
|
460
|
+
const ringBasedSize = ringWidth * 0.45;
|
|
461
|
+
const angleScale = Math.min(1, 0.7 + 0.3 * (angle / (this.HALF_CIRCLE_RADIANS / 3)));
|
|
462
|
+
const maxByChord = chordLength / (2 * 0.65);
|
|
463
|
+
const fontSize = Math.min(ringBasedSize * angleScale, maxByChord);
|
|
464
|
+
if (fontSize < this.MIN_SEGMENT_LABEL_FONT)
|
|
465
|
+
return 0;
|
|
466
|
+
return Math.round(Math.max(this.MIN_SEGMENT_LABEL_FONT, Math.min(fontSize, this.MAX_SEGMENT_LABEL_FONT)) * 2) / 2;
|
|
467
|
+
}
|
|
468
|
+
getFittedSegmentLabel(label, fontSize, availableWidth) {
|
|
469
|
+
if (!label)
|
|
470
|
+
return '';
|
|
471
|
+
if (this.doesSegmentLabelFit(label, fontSize, availableWidth))
|
|
472
|
+
return label;
|
|
473
|
+
return this.truncateSegmentLabel(label, fontSize, availableWidth);
|
|
474
|
+
}
|
|
475
|
+
doesSegmentLabelFit(text, fontSize, availableWidth) {
|
|
476
|
+
return text.length * fontSize * 0.65 <= availableWidth;
|
|
477
|
+
}
|
|
478
|
+
truncateSegmentLabel(text, fontSize, availableWidth) {
|
|
479
|
+
const charWidth = fontSize * (fontSize <= 10 ? 0.7 : 0.65);
|
|
480
|
+
const availableForText = availableWidth - fontSize * 0.7;
|
|
481
|
+
if (availableForText <= 0)
|
|
482
|
+
return '';
|
|
483
|
+
const maxChars = Math.floor(availableForText / charWidth);
|
|
484
|
+
if (maxChars <= 0)
|
|
485
|
+
return '';
|
|
486
|
+
if (text.length <= maxChars)
|
|
487
|
+
return text;
|
|
488
|
+
return `${text.substring(0, Math.max(1, maxChars))}…`;
|
|
397
489
|
}
|
|
398
490
|
/**
|
|
399
491
|
* Shows tooltip for a threshold arc
|
|
@@ -416,28 +508,39 @@ class AXGaugeChartComponent extends AXChartComponent {
|
|
|
416
508
|
const options = this.effectiveOptions();
|
|
417
509
|
if (!options.showTooltip)
|
|
418
510
|
return;
|
|
419
|
-
this.updateTooltipPosition(event);
|
|
420
511
|
this._tooltipData.set({
|
|
421
512
|
title: options.label || 'Range',
|
|
422
513
|
value: `${options.minValue.toLocaleString()} - ${options.maxValue.toLocaleString()}`,
|
|
423
514
|
color: 'rgb(var(--ax-comp-gauge-chart-track-color))',
|
|
424
515
|
});
|
|
425
516
|
this._tooltipVisible.set(true);
|
|
517
|
+
this.updateTooltipPosition(event);
|
|
426
518
|
}
|
|
427
519
|
updateTooltipPosition(event) {
|
|
428
520
|
this._pendingTooltipCoords = { x: event.clientX, y: event.clientY };
|
|
429
521
|
if (this._tooltipRafId != null)
|
|
430
522
|
return;
|
|
523
|
+
this.scheduleTooltipPosition(0);
|
|
524
|
+
}
|
|
525
|
+
scheduleTooltipPosition(attempt) {
|
|
431
526
|
this._tooltipRafId = requestAnimationFrame(() => {
|
|
432
|
-
this._tooltipRafId = null;
|
|
433
527
|
const coords = this._pendingTooltipCoords;
|
|
434
|
-
if (!coords)
|
|
528
|
+
if (!coords) {
|
|
529
|
+
this._tooltipRafId = null;
|
|
435
530
|
return;
|
|
531
|
+
}
|
|
436
532
|
const containerEl = this.chartContainerEl()?.nativeElement;
|
|
437
|
-
if (!containerEl)
|
|
533
|
+
if (!containerEl) {
|
|
534
|
+
this._tooltipRafId = null;
|
|
438
535
|
return;
|
|
439
|
-
|
|
536
|
+
}
|
|
440
537
|
const tooltipEl = containerEl.querySelector('.chart-tooltip');
|
|
538
|
+
if (!tooltipEl && this._tooltipVisible() && attempt < 3) {
|
|
539
|
+
this.scheduleTooltipPosition(attempt + 1);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
this._tooltipRafId = null;
|
|
543
|
+
const rect = containerEl.getBoundingClientRect();
|
|
441
544
|
const tooltipRect = tooltipEl?.getBoundingClientRect() ?? null;
|
|
442
545
|
const pos = computeTooltipPosition(rect, tooltipRect, coords.x + 10, coords.y - 10, this.TOOLTIP_GAP);
|
|
443
546
|
this._tooltipPosition.set(pos);
|
|
@@ -753,11 +856,11 @@ class AXGaugeChartComponent extends AXChartComponent {
|
|
|
753
856
|
return radians * this.DEGREES_PER_RADIAN;
|
|
754
857
|
}
|
|
755
858
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXGaugeChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
756
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.3", type: AXGaugeChartComponent, isStandalone: true, selector: "ax-gauge-chart", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-gauge-chart\" role=\"img\" #chartContainer>\n <ax-chart-tooltip [data]=\"tooltipData()\" [position]=\"tooltipPosition()\" [visible]=\"tooltipVisible()\"></ax-chart-tooltip>\n</div>\n", styles: [".ax-chart-empty{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box;padding:1rem;pointer-events:none}.ax-chart-empty__card{text-align:center;padding:1.5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-surface));width:80%;max-width:300px;box-sizing:border-box}.ax-chart-empty__icon{opacity:.6;margin-bottom:.75rem}.ax-chart-empty__title{font-size:1rem;font-weight:600;margin-bottom:.5rem}.ax-chart-empty__help{font-size:.8rem;opacity:.6}ax-gauge-chart{display:block;width:100%;height:100%;min-height:clamp(220px,38vw,360px);box-sizing:border-box;--ax-comp-gauge-chart-bg-color: 0, 0, 0, 0;--ax-comp-gauge-chart-text-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-gauge-chart-track-color: var(--ax-sys-color-dark-surface);--ax-comp-gauge-chart-needle-color: var(--ax-sys-color-primary-500)}ax-gauge-chart .ax-gauge-chart{position:relative;width:100%;height:100%;min-height:0;box-sizing:border-box;padding:clamp(.5rem,1.2vw,.875rem);overflow:hidden;color:rgb(var(--ax-comp-gauge-chart-text-color));background-color:rgba(var(--ax-comp-gauge-chart-bg-color));border-radius:.5rem}ax-gauge-chart .ax-gauge-chart svg{display:block;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden}ax-gauge-chart .ax-gauge-chart svg g:has(text){font-family:inherit}\n"], dependencies: [{ kind: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
859
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.3", type: AXGaugeChartComponent, isStandalone: true, selector: "ax-gauge-chart", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-gauge-chart\" role=\"img\" #chartContainer>\n <ax-chart-tooltip [data]=\"tooltipData()\" [position]=\"tooltipPosition()\" [visible]=\"tooltipVisible()\"></ax-chart-tooltip>\n</div>\n", styles: [".ax-chart-empty{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box;padding:1rem;pointer-events:none}.ax-chart-empty__card{text-align:center;padding:1.5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-surface));width:80%;max-width:300px;box-sizing:border-box}.ax-chart-empty__icon{opacity:.6;margin-bottom:.75rem}.ax-chart-empty__title{font-size:1rem;font-weight:600;margin-bottom:.5rem}.ax-chart-empty__help{font-size:.8rem;opacity:.6}ax-gauge-chart{display:block;width:100%;height:100%;min-height:clamp(220px,38vw,360px);box-sizing:border-box;--ax-comp-gauge-chart-bg-color: 0, 0, 0, 0;--ax-comp-gauge-chart-text-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-gauge-chart-data-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-gauge-chart-track-color: var(--ax-sys-color-dark-surface);--ax-comp-gauge-chart-needle-color: var(--ax-sys-color-primary-500)}ax-gauge-chart .ax-gauge-chart{position:relative;width:100%;height:100%;min-height:0;box-sizing:border-box;padding:clamp(.5rem,1.2vw,.875rem);overflow:hidden;color:rgb(var(--ax-comp-gauge-chart-text-color));background-color:rgba(var(--ax-comp-gauge-chart-bg-color));border-radius:.5rem}ax-gauge-chart .ax-gauge-chart svg{display:block;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden}ax-gauge-chart .ax-gauge-chart svg g:has(text){font-family:inherit}\n"], dependencies: [{ kind: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
757
860
|
}
|
|
758
861
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXGaugeChartComponent, decorators: [{
|
|
759
862
|
type: Component,
|
|
760
|
-
args: [{ selector: 'ax-gauge-chart', encapsulation: ViewEncapsulation.None, imports: [AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-gauge-chart\" role=\"img\" #chartContainer>\n <ax-chart-tooltip [data]=\"tooltipData()\" [position]=\"tooltipPosition()\" [visible]=\"tooltipVisible()\"></ax-chart-tooltip>\n</div>\n", styles: [".ax-chart-empty{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box;padding:1rem;pointer-events:none}.ax-chart-empty__card{text-align:center;padding:1.5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-surface));width:80%;max-width:300px;box-sizing:border-box}.ax-chart-empty__icon{opacity:.6;margin-bottom:.75rem}.ax-chart-empty__title{font-size:1rem;font-weight:600;margin-bottom:.5rem}.ax-chart-empty__help{font-size:.8rem;opacity:.6}ax-gauge-chart{display:block;width:100%;height:100%;min-height:clamp(220px,38vw,360px);box-sizing:border-box;--ax-comp-gauge-chart-bg-color: 0, 0, 0, 0;--ax-comp-gauge-chart-text-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-gauge-chart-track-color: var(--ax-sys-color-dark-surface);--ax-comp-gauge-chart-needle-color: var(--ax-sys-color-primary-500)}ax-gauge-chart .ax-gauge-chart{position:relative;width:100%;height:100%;min-height:0;box-sizing:border-box;padding:clamp(.5rem,1.2vw,.875rem);overflow:hidden;color:rgb(var(--ax-comp-gauge-chart-text-color));background-color:rgba(var(--ax-comp-gauge-chart-bg-color));border-radius:.5rem}ax-gauge-chart .ax-gauge-chart svg{display:block;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden}ax-gauge-chart .ax-gauge-chart svg g:has(text){font-family:inherit}\n"] }]
|
|
863
|
+
args: [{ selector: 'ax-gauge-chart', encapsulation: ViewEncapsulation.None, imports: [AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-gauge-chart\" role=\"img\" #chartContainer>\n <ax-chart-tooltip [data]=\"tooltipData()\" [position]=\"tooltipPosition()\" [visible]=\"tooltipVisible()\"></ax-chart-tooltip>\n</div>\n", styles: [".ax-chart-empty{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box;padding:1rem;pointer-events:none}.ax-chart-empty__card{text-align:center;padding:1.5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-surface));width:80%;max-width:300px;box-sizing:border-box}.ax-chart-empty__icon{opacity:.6;margin-bottom:.75rem}.ax-chart-empty__title{font-size:1rem;font-weight:600;margin-bottom:.5rem}.ax-chart-empty__help{font-size:.8rem;opacity:.6}ax-gauge-chart{display:block;width:100%;height:100%;min-height:clamp(220px,38vw,360px);box-sizing:border-box;--ax-comp-gauge-chart-bg-color: 0, 0, 0, 0;--ax-comp-gauge-chart-text-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-gauge-chart-data-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-gauge-chart-track-color: var(--ax-sys-color-dark-surface);--ax-comp-gauge-chart-needle-color: var(--ax-sys-color-primary-500)}ax-gauge-chart .ax-gauge-chart{position:relative;width:100%;height:100%;min-height:0;box-sizing:border-box;padding:clamp(.5rem,1.2vw,.875rem);overflow:hidden;color:rgb(var(--ax-comp-gauge-chart-text-color));background-color:rgba(var(--ax-comp-gauge-chart-bg-color));border-radius:.5rem}ax-gauge-chart .ax-gauge-chart svg{display:block;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden}ax-gauge-chart .ax-gauge-chart svg g:has(text){font-family:inherit}\n"] }]
|
|
761
864
|
}], ctorParameters: () => [] });
|
|
762
865
|
|
|
763
866
|
/**
|