Apply a Gradient to an Area Chart
Environment
| Product | Progress® Kendo UI® for Angular Charts |
Description
How can I apply a vertical gradient to an Angular Chart area series, with blue near the line and a transparent fill near the chart baseline?
This KB also answers the following questions:
- How do I apply a gradient to an Area Chart in Kendo UI for Angular?
- How can I apply different gradients to multiple Area Chart series?
- How do I use an SVG linear gradient as an Angular Chart area series color?
Solution
Render the Chart as SVG and handle its render event. Add a linearGradient definition to the rendered SVG, then replace each target area path fill with a reference to its gradient.
The following example renders multiple Area Chart series with distinct vertical gradients.
To configure the gradients, complete the following steps:
-
Handle the
renderAsevent and bind each area series. Hide markers so their fill does not match the selector that identifies the area paths.html<kendo-chart #chart renderAs="svg" (render)="applyAreaGradient()"> <kendo-chart-series> @for (series of areaSeries; track series.gradientId) { <kendo-chart-series-item type="area" [data]="series.data" [name]="series.name" [color]="series.color" [line]="{ color: series.color, width: 2 }" [markers]="{ visible: false }" > </kendo-chart-series-item> } </kendo-chart-series> </kendo-chart> -
Inside the component class, import
ElementRefandViewChild, reference the Chart host, and define a distinctcolorand gradient ID for each area series. Use one object for each series that needs a gradient.tsimport { ElementRef, ViewChild } from '@angular/core'; interface AreaSeries { color: string; data: number[]; gradientId: string; name: string; } export class AppComponent { @ViewChild('chart', { read: ElementRef }) private chartElement!: ElementRef<HTMLElement>; public readonly areaSeries: AreaSeries[] = [ { name: 'Online', data: [123, 276, 310], color: '#3171f4', gradientId: 'online-area-gradient' }, { name: 'Retail', data: [80, 150, 200], color: '#e5536d', gradientId: 'retail-area-gradient' } ]; } -
Add each gradient definition once, then replace only area paths whose original fill matches the series color.
tspublic applyAreaGradient(): void { const svg = this.chartElement.nativeElement.querySelector<SVGSVGElement>('svg'); if (!svg) { return; } this.areaSeries.forEach((series) => { this.ensureGradient(svg, series); svg.querySelectorAll<SVGPathElement>(`path[fill="${series.color}"]`).forEach((path) => { path.setAttribute('fill', `url(#${series.gradientId})`); }); }); } private ensureGradient(svg: SVGSVGElement, series: AreaSeries): void { if (svg.querySelector(`#${series.gradientId}`)) { return; } const definitions = svg.querySelector('defs') ?? svg.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'defs'); const gradient = svg.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'linearGradient'); gradient.setAttribute('id', series.gradientId); gradient.setAttribute('x1', '0%'); gradient.setAttribute('y1', '0%'); gradient.setAttribute('x2', '0%'); gradient.setAttribute('y2', '100%'); this.addGradientStop(gradient, series.color, '0%', '0.5'); this.addGradientStop(gradient, series.color, '55%', '0.16'); this.addGradientStop(gradient, series.color, '100%', '0'); definitions.appendChild(gradient); if (!definitions.parentNode) { svg.insertBefore(definitions, svg.firstChild); } } private addGradientStop(gradient: SVGLinearGradientElement, color: string, offset: string, opacity: string): void { const stop = gradient.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'stop'); stop.setAttribute('offset', offset); stop.setAttribute('stop-color', color); stop.setAttribute('stop-opacity', opacity); gradient.appendChild(stop); }