DevExtreme v24.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

Pie with Custom Fill Styles

This demo uses custom patterns and gradients for PieChart slices.

Backend API
<dx-pie-chart id="pie" [dataSource]="data" [customizePoint]="customizePoint"> <dxi-series argumentField="type" valueField="value"> <dxo-label [visible]="true" [customizeText]="customizeText"> <dxo-connector [visible]="true"></dxo-connector> </dxo-label> </dxi-series> <dxo-export [enabled]="true"></dxo-export> </dx-pie-chart>
import { NgModule, Component, enableProdMode } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { DxPieChartModule } from 'devextreme-angular'; import { registerGradient, registerPattern } from 'devextreme/common/charts'; import { Data, Service } from './app.service'; if (!/localhost/.test(document.location.host)) { enableProdMode(); } @Component({ selector: 'demo-app', templateUrl: `app/app.component.html`, styleUrls: [`app/app.component.css`], providers: [Service], }) export class AppComponent { data: Data[]; imagePatternSize = 12; shapePatternSize = 6; constructor(service: Service) { this.data = service.getData(); } customizePoint = (point) => { const color = point.series.getPointsByArg(point.argument)[0].getColor(); let fillId; switch (point.argument) { case 'Stripes': fillId = this.getStrokePattern(color); break; case 'Grid': fillId = this.getSquarePattern(color); break; case 'Linear Gradient': fillId = this.getLinearGradient(color); break; case 'Radial Gradient': fillId = this.getRadialGradient(color); break; case 'Image': fillId = this.getPatternImage(color); break; default: break; } return { color: { fillId } }; }; customizeText = (info) => info.argument; private hexToRgb = (hex: string, opacity = 1) => { const hexColorParts = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return `rgba(${parseInt(hexColorParts[1], 16)}, ${parseInt(hexColorParts[2], 16)}, ${parseInt(hexColorParts[3], 16)}, ${opacity})`; }; private getGradient = (type: string, color1: string, color2: string) => registerGradient(type, { colors: [{ offset: '20%', color: color1, }, { offset: '90%', color: color2, }], }); private getLinearGradient = (color: string) => this.getGradient('linear', color, this.hexToRgb(color, 0.5)); private getRadialGradient = (color: string) => this.getGradient('radial', this.hexToRgb(color, 0.5), color); private getPatternImage = (color: string) => registerPattern({ width: this.imagePatternSize, height: this.imagePatternSize, template: (container) => { const rect = this.createRect(this.imagePatternSize, color, '', 0); const image = document.createElementNS('http://www.w3.org/2000/svg', 'image'); image.setAttribute('x', '0'); image.setAttribute('y', '0'); image.setAttribute('width', this.imagePatternSize.toString()); image.setAttribute('height', this.imagePatternSize.toString()); image.setAttribute('href', '../../../../images/Charts/PieWithCustomStyles/diamond.svg'); image.setAttribute('opacity', '0.6'); container.appendChild(rect); container.appendChild(image); }, }); private getStrokePattern = (color: string) => registerPattern({ width: this.shapePatternSize, height: this.shapePatternSize, template: (container) => { const halfSize = this.shapePatternSize / 2; const oneAndAHalfSize = this.shapePatternSize * 1.5; const d = `M ${halfSize} ${-halfSize} L ${-halfSize} ${halfSize} M 0 ${ this.shapePatternSize } L ${ this.shapePatternSize } 0 M ${oneAndAHalfSize} ${halfSize} L ${halfSize} ${oneAndAHalfSize}`; const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('stroke', color); path.setAttribute('stroke-width', '2'); path.setAttribute('d', d); container.appendChild(path); }, }); private getSquarePattern = (color: string) => registerPattern({ width: this.shapePatternSize, height: this.shapePatternSize, template: (container) => { const rect = this.createRect(this.shapePatternSize, '', color, 2); container.appendChild(rect); }, }); private createRect = (size: number, fill: string, stroke: string, strokeWidth: number) => { const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', '0'); rect.setAttribute('y', '0'); rect.setAttribute('width', size.toString()); rect.setAttribute('height', size.toString()); rect.setAttribute('fill', fill); rect.setAttribute('stroke', stroke); rect.setAttribute('stroke-width', strokeWidth.toString()); return rect; }; } @NgModule({ imports: [ BrowserModule, DxPieChartModule, ], declarations: [AppComponent], bootstrap: [AppComponent], }) export class AppModule { } platformBrowserDynamic().bootstrapModule(AppModule);
#pie { height: 440px; }
import { Injectable } from '@angular/core'; export class Data { type: string; value: number; } const data: Data[] = [{ type: 'Stripes', value: 1, }, { type: 'Grid', value: 1, }, { type: 'Linear Gradient', value: 1, }, { type: 'Radial Gradient', value: 1, }, { type: 'Image', value: 1, }]; @Injectable() export class Service { getData(): Data[] { return data; } }
// In real applications, you should not transpile code in the browser. // You can see how to create your own application with Angular and DevExtreme here: // https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/ const componentNames = [ 'accordion', 'action-sheet', 'autocomplete', 'bar-gauge', 'box', 'bullet', 'button-group', 'button', 'calendar', 'chart', 'check-box', 'circular-gauge', 'color-box', 'context-menu', 'data-grid', 'date-box', 'date-range-box', 'defer-rendering', 'diagram', 'draggable', 'drawer', 'drop-down-box', 'drop-down-button', 'file-manager', 'file-uploader', 'filter-builder', 'form', 'funnel', 'gallery', 'gantt', 'html-editor', 'linear-gauge', 'list', 'load-indicator', 'load-panel', 'lookup', 'map', 'menu', 'multi-view', 'nested', 'number-box', 'pie-chart', 'pivot-grid-field-chooser', 'pivot-grid', 'polar-chart', 'popover', 'popup', 'progress-bar', 'radio-group', 'range-selector', 'range-slider', 'recurrence-editor', 'resizable', 'responsive-box', 'sankey', 'scheduler', 'scroll-view', 'select-box', 'slider', 'sortable', 'sparkline', 'speed-dial-action', 'splitter', 'switch', 'tab-panel', 'tabs', 'tag-box', 'text-area', 'text-box', 'tile-view', 'toast', 'toolbar', 'tooltip', 'tree-list', 'tree-map', 'tree-view', 'validation-group', 'validation-summary', 'validator', 'vector-map', ]; window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, }, meta: { 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, '@angular/platform-browser-dynamic': { 'esModule': true, }, '@angular/platform-browser': { 'esModule': true, }, '@angular/core': { 'esModule': true, }, '@angular/common': { 'esModule': true, }, '@angular/common/http': { 'esModule': true, }, '@angular/compiler': { 'esModule': true, }, '@angular/animations': { 'esModule': true, }, '@angular/forms': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', 'bundles:': '../../../../bundles/', }, map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', /* @angular */ '@angular/compiler': 'bundles:@angular/compiler.umd.js', '@angular/platform-browser-dynamic': 'bundles:@angular/platform-browser-dynamic.umd.js', '@angular/core': 'bundles:@angular/core.umd.js', '@angular/core/primitives/signals': 'bundles:@angular/core.primitives.signals.umd.js', '@angular/common': 'bundles:@angular/common.umd.js', '@angular/common/http': 'bundles:@angular/common-http.umd.js', '@angular/platform-browser': 'bundles:@angular/platform-browser.umd.js', '@angular/platform-browser/animations': 'bundles:@angular/platform-browser.umd.js', '@angular/forms': 'bundles:@angular/forms.umd.js', /* devextreme */ 'devextreme': 'npm:devextreme@24.1.4/cjs', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', 'devextreme/bundles/dx.all': 'npm:devextreme@24.1.4/bundles/dx.all.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.10', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56', /* devextreme-angular umd maps */ 'devextreme-angular': 'bundles:devextreme-angular/devextreme-angular.umd.js', 'devextreme-angular/core': 'bundles:devextreme-angular/devextreme-angular-core.umd.js', ...componentNames.reduce((acc, name) => { acc[`devextreme-angular/ui/${name}`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}.umd.js`; return acc; }, {}), 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'tslib': 'npm:tslib@2.6.1/tslib.js', 'rxjs': 'npm:rxjs@7.5.3/dist/bundles/rxjs.umd.js', 'rxjs/operators': 'npm:rxjs@7.5.3/dist/cjs/operators/index.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'app': { main: './app.component.ts', defaultExtension: 'ts', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, 'rxjs': { defaultExtension: 'js', }, 'rxjs/operators': { defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.13/inferno/package.json', 'npm:rxjs@7.5.3/package.json', 'npm:rxjs@7.5.3/operators/package.json', 'npm:devexpress-diagram@2.2.10/package.json', 'npm:devexpress-gantt@4.1.56/package.json', ], }; System.config(window.config); // System.import('@angular/compiler').catch(console.error.bind(console));
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.4/css/dx.light.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/zone.js@0.13.0/dist/zone.js"></script> <script src="https://unpkg.com/reflect-metadata@0.1.13/Reflect.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script src="config.js"></script> <script> System.import("app").catch(console.error.bind(console)); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <demo-app>Loading...</demo-app> </div> </body> </html>

Gradient

Call the registerGradient() method to obtain a gradient ID. Specify method arguments as follows:

  • type
    This method supports two gradient types: 'linear' and 'radial'.

  • options
    An object for gradient options.

    • colors
      An array of gradient colors. Each color is an object that includes color and offset fields. The offset field specifies the starting point for each color.

    • rotationAngle (linear gradients only)
      You can use this option to rotate linear gradients.

Pattern

To obtain a pattern ID, call the registerPattern() method. Specify method arguments as follows:

  • options
    An object with pattern options.

    • height
      Template height.

    • width
      Template width.

    • template
      A repeating SVG-based template that creates the required pattern.

Fill the PieChart

To fill all slices with the same pattern or gradient, assign a pattern ID to series.color.fillId. If you want to customize each slice individually, implement the customizePoint function (review this demo for more information).

Custom patterns and gradients are not limited to the PieChart. The following DevExtreme components support the use of patterns/gradients: