From df86efbd0880f0e078414ae949d4e851df6bbdfc Mon Sep 17 00:00:00 2001 From: "akash.sonune" Date: Wed, 19 Aug 2026 13:13:55 +0530 Subject: [PATCH] feat(charts/gauge): support for value arc start point --- api-goldens/charts-ng/gauge/index.api.md | 1 + api-goldens/charts-ng/index.api.md | 1 + .../gauge/si-chart-gauge.component.spec.ts | 32 ++++++++++ .../gauge/si-chart-gauge.component.ts | 62 +++++++++++++++++-- src/app/examples/si-charts/gauge/chart.html | 2 + .../examples/si-charts/gauge/gauge-basic.ts | 5 +- 6 files changed, 97 insertions(+), 6 deletions(-) diff --git a/api-goldens/charts-ng/gauge/index.api.md b/api-goldens/charts-ng/gauge/index.api.md index 1182567655..b9feda911e 100644 --- a/api-goldens/charts-ng/gauge/index.api.md +++ b/api-goldens/charts-ng/gauge/index.api.md @@ -53,6 +53,7 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha readonly unit: _angular_core.InputSignal; readonly unitsOnSplit: _angular_core.InputSignal; readonly value: _angular_core.InputSignal; + readonly valueArcStart: _angular_core.InputSignal; readonly valueFormatter: _angular_core.InputSignal<((val: number) => string) | undefined>; } diff --git a/api-goldens/charts-ng/index.api.md b/api-goldens/charts-ng/index.api.md index 68479215af..56753a7e6b 100644 --- a/api-goldens/charts-ng/index.api.md +++ b/api-goldens/charts-ng/index.api.md @@ -516,6 +516,7 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha readonly unit: i0.InputSignal; readonly unitsOnSplit: i0.InputSignal; readonly value: i0.InputSignal; + readonly valueArcStart: i0.InputSignal; readonly valueFormatter: i0.InputSignal<((val: number) => string) | undefined>; } diff --git a/projects/charts-ng/gauge/si-chart-gauge.component.spec.ts b/projects/charts-ng/gauge/si-chart-gauge.component.spec.ts index 0dc0626840..02049ca316 100644 --- a/projects/charts-ng/gauge/si-chart-gauge.component.spec.ts +++ b/projects/charts-ng/gauge/si-chart-gauge.component.spec.ts @@ -14,6 +14,7 @@ import { SiChartGaugeComponent } from './si-chart-gauge.component'; [minValue]="minValue" [maxValue]="maxValue" [value]="value" + [valueArcStart]="valueArcStart" [title]="title" [subTitle]="subTitle" />` @@ -23,6 +24,7 @@ class TestHostComponent { minValue!: number; maxValue!: number; value!: number; + valueArcStart?: number; title?: string; subTitle?: string; } @@ -77,4 +79,34 @@ describe('SiChartGaugeComponent', () => { component.chartGaugeComponent().setValue(5); expect(getOption(component.chartGaugeComponent()).series[2].data[0].value).toEqual(5); }); + + it('should start the value arc at a custom value without changing the gauge range', () => { + const fixture = TestBed.createComponent(TestHostComponent); + const component = fixture.componentInstance; + component.minValue = 0; + component.maxValue = 200; + component.valueArcStart = 45; + component.value = 90; + fixture.detectChanges(); + + const options = getOption(component.chartGaugeComponent()); + expect(options.series[0]).toMatchObject({ min: 0, max: 200, startAngle: 180 }); + expect(options.series[2]).toMatchObject({ + min: 45, + max: 200, + startAngle: 139.5, + endAngle: 0, + data: [{ value: 90 }] + }); + }); + + it('should start the value arc at the minimum value by default', () => { + const { component } = createChartWithTestData(); + expect(getOption(component.chartGaugeComponent()).series[2]).toMatchObject({ + min: 0, + max: 50, + startAngle: 180, + data: [{ value: 2 }] + }); + }); }); diff --git a/projects/charts-ng/gauge/si-chart-gauge.component.ts b/projects/charts-ng/gauge/si-chart-gauge.component.ts index 916880717f..f2c47b093c 100644 --- a/projects/charts-ng/gauge/si-chart-gauge.component.ts +++ b/projects/charts-ng/gauge/si-chart-gauge.component.ts @@ -46,6 +46,11 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha * @defaultValue 0 */ readonly value = input(0); + /** The value at which the main value arc starts. + * Values outside the gauge range are clamped to `minValue` or `maxValue`. + * When not set, the value arc starts at `minValue`. + */ + readonly valueArcStart = input(); /** The number of intervals displayed on the gauge axis. */ readonly splitSteps = input(); /** Whether the number of gauge-axis intervals adapts to the component size. @@ -160,7 +165,10 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha } (this.actualOptions.series![0] as any).axisLine.show = hasIndicator; - this.setAxisLineColor(newColors, (this.actualOptions.series![2] as any).axisLine); + this.setAxisLineColor( + this.getValueArcColors(newColors), + (this.actualOptions.series![2] as any).axisLine + ); this.refreshSeries(); } @@ -169,6 +177,44 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha axisLine.lineStyle.color = colors; } + private getValueArcColors(colors: [number, string][]): [number, string][] { + const minValue = this.minValue(); + const maxValue = this.maxValue(); + const valueArcStart = this.valueArcStart(); + if ( + valueArcStart === undefined || + valueArcStart <= minValue || + valueArcStart >= maxValue || + maxValue <= minValue + ) { + return colors; + } + + const startRatio = (valueArcStart - minValue) / (maxValue - minValue); + return colors + .filter(([threshold]) => threshold > startRatio) + .map(([threshold, color]) => [(threshold - startRatio) / (1 - startRatio), color]); + } + + private getValueArcOptions(): { min: number; startAngle: number; showProgress: boolean } { + const minValue = this.minValue(); + const maxValue = this.maxValue(); + const valueArcStart = this.valueArcStart(); + if (valueArcStart === undefined || valueArcStart <= minValue || maxValue <= minValue) { + return { min: minValue, startAngle: 180, showProgress: true }; + } + if (valueArcStart >= maxValue) { + return { min: minValue, startAngle: 180, showProgress: false }; + } + + const startRatio = (valueArcStart - minValue) / (maxValue - minValue); + return { + min: valueArcStart, + startAngle: 180 * (1 - startRatio), + showProgress: true + }; + } + private getResponsiveConfig(): { outerRadius: number; center: (string | number)[]; @@ -240,6 +286,7 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha protected override applyOptions(): void { const resp = this.getResponsiveConfig(); const hasIndicator = !!this.segments().length; + const valueArcOptions = this.getValueArcOptions(); const splitNumber = this.responsiveSplitSteps() && resp.splits ? resp.splits : this.splitSteps(); @@ -310,13 +357,13 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha type: 'gauge', silent: false, radius: resp.outerRadius, - startAngle: 180, + startAngle: valueArcOptions.startAngle, endAngle: 0, - min: this.minValue(), + min: valueArcOptions.min, max: this.maxValue(), splitNumber, progress: { - show: true, + show: valueArcOptions.showProgress, itemStyle: { color: 'auto' }, width: resp.progressWidth }, @@ -391,15 +438,20 @@ export class SiChartGaugeComponent extends SiChartBaseComponent implements OnCha if (this.chart && (changes.palette || changes.colors || changes.segments)) { this.updateColors(); } + const updateValueArcColors = + this.chart && (changes.minValue || changes.maxValue || changes.valueArcStart); changes.forceAll = new SimpleChange(false, true, false); super.ngOnChanges(changes); + if (updateValueArcColors) { + this.updateColors(); + } } protected override applyDataZoom(): void {} protected override afterChartResize(): void { this.applyOptions(); - this.refreshSeries(); + this.updateColors(); } /** diff --git a/src/app/examples/si-charts/gauge/chart.html b/src/app/examples/si-charts/gauge/chart.html index 77e5604d83..31589ff945 100644 --- a/src/app/examples/si-charts/gauge/chart.html +++ b/src/app/examples/si-charts/gauge/chart.html @@ -8,6 +8,8 @@ [unit]="chartData.unit" [minValue]="chartData.minValue" [maxValue]="chartData.maxValue" + [value]="chartData.value" + [valueArcStart]="chartData.valueArcStart" [splitSteps]="chartData.splitSteps" [colors]="chartData.colors" [segments]="chartData.segments" diff --git a/src/app/examples/si-charts/gauge/gauge-basic.ts b/src/app/examples/si-charts/gauge/gauge-basic.ts index 3a7d6aa7be..a64aa41c55 100644 --- a/src/app/examples/si-charts/gauge/gauge-basic.ts +++ b/src/app/examples/si-charts/gauge/gauge-basic.ts @@ -19,6 +19,8 @@ export class SampleComponent implements OnDestroy { unit: ' km/h', minValue: 0, maxValue: 180, + value: 90, + valueArcStart: 45, splitSteps: 12, colors: ['#28bf66', '#f3cb55', '#d92b48', '#9544ed'], segments: [0.2, 0.5, 0.7, 1], @@ -43,7 +45,8 @@ export class SampleComponent implements OnDestroy { startLive(): void { this.chartData.liveUpdate = true; this.liveSubscription = interval(1000).subscribe(() => { - this.chart().setValue(Math.random() * this.chart().maxValue()); + this.chartData.value = Math.random() * this.chart().maxValue(); + this.chart().setValue(this.chartData.value); }); } }