DevExtreme v26.1 is now available.

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

Your search did not match any results.

Angular Charts - Export Custom Markup

The DevExpress.viz.exportFromMarkup(markup, options) method allows you to export SVG content, including SVG-based DevExtreme components, to an image or document.

The markup parameter accepts valid SVG markup (see the prepareMarkup() function in the code). To get the markup of a component, call its svg() method. The options parameter accepts an object whose fields configure export properties. In this demo, we specify the width, height, format, and svgToCanvas fields. Refer to the method description for more information on these and other available fields.

Backend API
<div class="chart-environment"> <div id="custom-markup-container"> <svg version="1.1" width="820px" height="420px"> <path d="M 0 0 L 820 0 L 820 420 L 0 420 L 0 0" stroke="#999999" stroke-width="1" stroke-linecap="butt" fill="white" stroke-linejoin="miter" ></path> <path d="M 13 407 L 128 407 L 232 39 L 13 39" fill="#6D39C3"></path> <path d="M 46 381 L 161 381 L 265 13 L 46 13" opacity="0.5" fill="#6D39C3" ></path> <text transform="translate(30,89)" class="custom-markup-text custom-markup-text-title" > <tspan x="0" y="0">Export</tspan> <tspan x="0" y="38">Custom</tspan> <tspan x="0" y="76">Markup</tspan> </text> <text transform="translate(32,199)" class="custom-markup-text custom-markup-text-subtitle" > <tspan x="0" y="0">Export a chart with</tspan> <tspan x="0" y="19.2">custom elements</tspan> </text> </svg> </div> <dx-chart id="chart" [dataSource]="oilProductionData" palette="Violet"> <dxi-chart-series valueField="year2000" name="2000"></dxi-chart-series> <dxi-chart-series valueField="year2010" name="2010"></dxi-chart-series> <dxi-chart-series valueField="year2020" name="2020"></dxi-chart-series> <dxi-chart-series valueField="year2021" name="2021"></dxi-chart-series> <dxi-chart-series valueField="year2022" name="2022"></dxi-chart-series> <dxo-chart-common-series-settings argumentField="state" type="bar" [barPadding]="0.3" > </dxo-chart-common-series-settings> <dxo-chart-legend verticalAlignment="bottom" horizontalAlignment="center"> </dxo-chart-legend> <dxo-chart-title text="Oil Production"> <dxo-chart-subtitle text="(in millions tonnes)"></dxo-chart-subtitle> </dxo-chart-title> </dx-chart> </div> <div class="controls-pane"> <dx-button icon="export" text="Export" type="default" [width]="145" (onClick)="export()" > </dx-button> </div>
import { bootstrapApplication } from '@angular/platform-browser'; import { Component, ViewChild, enableProdMode, provideZoneChangeDetection } from '@angular/core'; import { DxChartModule, DxChartComponent, DxButtonModule } from 'devextreme-angular'; import { exportFromMarkup } from 'devextreme/viz/export'; import { Canvg } from 'canvg'; import { Service, OilProductionDataItem } from './app.service'; if (!/localhost/.test(document.location.host)) { enableProdMode(); } @Component({ selector: 'demo-app', providers: [Service], templateUrl: './app.component.html', styleUrls: ['./app.component.css'], imports: [ DxChartModule, DxButtonModule, ], }) export class AppComponent { @ViewChild(DxChartComponent, { static: false }) chart: DxChartComponent; oilProductionData: OilProductionDataItem[]; constructor(service: Service) { this.oilProductionData = service.getOilProductionData(); } export() { exportFromMarkup(this.prepareMarkup(), { width: 820, height: 420, margin: 0, format: 'png', svgToCanvas(svg, canvas) { return new Promise((resolve) => { const v = Canvg.fromString( canvas.getContext('2d'), new XMLSerializer().serializeToString(svg) ); resolve(v.render()); }); }, }); } prepareMarkup() { const sourceContainer = document.getElementById('custom-markup-container'); const sourceElements = sourceContainer.querySelectorAll('*'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); svg.setAttribute('version', '1.1'); svg.setAttribute('width', '820px'); svg.setAttribute('height', '420px'); const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement; const clonedElements = clonedContainer.querySelectorAll('*'); clonedElements.forEach((clonedEl, index) => { const sourceEl = sourceElements[index] as HTMLElement; if (!sourceEl) return; const computed = window.getComputedStyle(sourceEl); ['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => { const value = computed.getPropertyValue(prop)?.trim(); if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') { (clonedEl as SVGElement).setAttribute(prop, value); } }); }); svg.innerHTML = clonedContainer.innerHTML; const group = document.createElementNS('http://www.w3.org/2000/svg', 'g'); group.setAttribute('transform', 'translate(305,12)'); group.innerHTML = this.chart.instance.svg(); svg.appendChild(group); return svg; } } bootstrapApplication(AppComponent, { providers: [ provideZoneChangeDetection({ eventCoalescing: true, runCoalescing: true }), ], });
::ng-deep #chart { position: absolute; top: 12px; right: 35px; width: 480px; height: 347px; } ::ng-deep .chart-environment { width: 820px; position: relative; margin: 0 auto; } ::ng-deep .controls-pane { text-align: center; } ::ng-deep .custom-markup-text { fill: #fff; font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif; } ::ng-deep .custom-markup-text-title { font-size: 36px; font-weight: bold; } ::ng-deep .custom-markup-text-subtitle { font-size: 14px; opacity: 0.8; }
import { Injectable } from '@angular/core'; export class OilProductionDataItem { state: string; year2000: number; year2010: number; year2020: number; year2021: number; year2022: number; } const oilProductionData: OilProductionDataItem[] = [{ state: 'Saudi Arabia', year2000: 408, year2010: 407, year2020: 498, year2021: 515, year2022: 602, }, { state: 'USA', year2000: 288, year2010: 270, year2020: 713, year2021: 711, year2022: 762, }, { state: 'Mexico', year2000: 150, year2010: 146, year2020: 101, year2021: 97, year2022: 95, }]; @Injectable() export class Service { getOilProductionData(): OilProductionDataItem[] { return oilProductionData; } }
<!DOCTYPE html> <html 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/26.1.5/css/dx.light.css" /> </head> <body class="dx-viewport"> <div class="demo-container"> <demo-app>Loading...</demo-app> </div> <script src="https://cdn.jsdelivr.net/npm/zone.js@0.16.2/bundles/zone.umd.js"></script> <script src="./bundle.js" type="module"></script> </body> </html>