DevExtreme v24.1 is now available.

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

Your search did not match any results.

Vue Charts - Custom Label in the Center

To customize the doughnut's center, declare the SVG markup in the centerTemplate. This template accepts the PieChart instance. Use this instance to call PieChart methods. For example, call the getInnerRaduis() method to get the radius of the doughnut hole.

Backend API
<template> <div> <div class="long-title"><h3>Energy Production (GWh, 2016)</h3></div> <div class="pies-container"> <DxPieChart v-for="country in countries" id="pie-chart" :key="country" :data-source="getData(country)" :inner-radius="0.65" resolve-label-overlapping="shift" size-group="piesGroup" type="doughnut" center-template="centerTemplate" > <DxSeries argument-field="commodity" value-field="total" > <DxLabel :visible="true" :customize-text="customizeLabel" background-color="none" format="fixedPoint" > <DxConnector :visible="true"/> </DxLabel> </DxSeries> <DxLegend :visible="false"/> <template #centerTemplate="data"> <CenterTemplate :pie-chart="data.data"/> </template> </DxPieChart> </div> </div> </template> <script setup lang="ts"> import { DxPieChart, DxSeries, DxLegend, DxLabel, DxConnector, } from 'devextreme-vue/pie-chart'; import { data } from './data.ts'; import CenterTemplate from './CenterTemplate.vue'; const countries = Array.from(new Set(data.map(({ country }) => country))); const customizeLabel = ({ argumentText, valueText }) => `${argumentText}\n${valueText}`; const getData = (country) => data.filter((i) => i.country === country); </script> <style scoped> .pies-container { margin: auto; width: 800px; } .pies-container > div { width: 400px; float: left; margin-top: -50px; } .long-title h3 { font-weight: 200; font-size: 28px; text-align: center; margin-bottom: 20px; } </style>
<template> <svg> <circle :r="pieChart.getInnerRadius() - 6" cx="100" cy="100" fill="#eee" /> <image :href="getImagePath(country)" x="70" y="58" width="60" height="40" /> <text :style="{fontSize: 18, fill: '#494949'}" text-anchor="middle" x="100" y="120" > <tspan x="100">{{ country }}</tspan><tspan :style="{ fontWeight: 600 }" x="100" dy="20px" >{{ calculateTotal(pieChart) }}</tspan> </text> </svg> </template> <script setup lang="ts"> const props = withDefaults(defineProps<{ pieChart?: Record<string, any> }>(), { pieChart: () => ({}), }); const country = props.pieChart .getAllSeries()[0] .getVisiblePoints()[0] .data .country; const getImagePath = (countryName) => `../../../../images/flags/${countryName.replace(/\s/, '').toLowerCase()}.svg`; const calculateTotal = (pieChart) => formatNumber( pieChart .getAllSeries()[0] .getVisiblePoints() .reduce((s, p) => s + p.originalValue, 0), ); const formatNumber = new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, }).format; </script>
window.exports = window.exports || {}; window.config = { transpiler: 'plugin-babel', meta: { '*.vue': { loader: 'vue-loader', }, '*.ts': { loader: 'demo-ts-loader', }, '*.svg': { loader: 'svg-loader', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, }, paths: { 'root:': '../../../../', 'npm:': 'https://unpkg.com/', }, map: { 'vue': 'npm:vue@3.2.47/dist/vue.esm-browser.js', 'vue-loader': 'npm:dx-systemjs-vue-browser@1.1.1/index.js', 'demo-ts-loader': 'root:utils/demo-ts-loader.js', 'svg-loader': 'root:utils/svg-loader.js', 'mitt': 'npm:mitt/dist/mitt.umd.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', 'devextreme': 'npm:devextreme@24.1.6/cjs', 'devextreme-vue': 'npm:devextreme-vue@24.1.6/cjs', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.11/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', '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', 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme-vue': { main: 'index.js', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.13/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, }, }; System.config(window.config);
export const data = [ { country: 'France', commodity: 'Nuclear', total: 413278 }, { country: 'Germany', commodity: 'Nuclear', total: 76536 }, { country: 'France', commodity: 'Thermal', total: 47594 }, { country: 'Germany', commodity: 'Thermal', total: 375809 }, { country: 'France', commodity: 'Wind', total: 21033 }, { country: 'Germany', commodity: 'Wind', total: 58228 }, { country: 'France', commodity: 'Solar', total: 7274 }, { country: 'Germany', commodity: 'Solar', total: 37520 }, { country: 'France', commodity: 'Tidal, Wave', total: 618 }, ];
import { createApp } from 'vue'; import App from './App.vue'; createApp(App).mount('#app');
<!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/24.1.6/css/dx.light.css" /> <script src="https://unpkg.com/typescript@4.9.5/lib/typescript.js"></script> <script type="module"> import * as vueCompilerSFC from "https://unpkg.com/@vue/compiler-sfc@3.4.16/dist/compiler-sfc.esm-browser.js"; window.vueCompilerSFC = vueCompilerSFC; </script> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.ts"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"> </div> </div> </body> </html>