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 - Load Data On Demand

In this demo, the range area Chart loads data as you pan it. Once the component loads a data block, this data stays in memory to reduce requests to the server.

www.kaggle.com
Backend API
<template> <DxChart id="chart" ref="chart" :data-source="chartDataSource" title="Temperature in Toronto (2017)" > <DxZoomAndPan argument-axis="pan"/> <DxScrollBar :visible="true"/> <DxArgumentAxis v-model:visual-range="currentVisualRange" :whole-range="bounds" argument-type="datetime" visual-range-update-mode="keep" /> <DxValueAxis :allow-decimals="false" name="temperature" > <DxTitle text="Temperature, &deg;C"> <DxFont color="#ff950c"/> </DxTitle> <DxLabel> <DxFont color="#ff950c"/> </DxLabel> </DxValueAxis> <DxSeries color="#ff950c" type="rangearea" argument-field="date" range-value1-field="minTemp" range-value2-field="maxTemp" name="Temperature range" /> <DxAnimation :enabled="false"/> <DxLoadingIndicator background-color="none"> <DxFont :size="14"/> </DxLoadingIndicator> <DxLegend :visible="false"/> </DxChart> </template> <script setup lang="ts"> import { computed, ref } from 'vue'; import DxChart, { DxZoomAndPan, DxScrollBar, DxArgumentAxis, DxSeries, DxValueAxis, DxTitle, DxLabel, DxFont, DxAnimation, DxLoadingIndicator, DxLegend, } from 'devextreme-vue/chart'; import DataSource from 'devextreme/data/data_source'; import 'whatwg-fetch'; const HALFDAY = 43200000; const chart = ref(); const visualRange = ref({ startValue: new Date(2017, 3, 1), endValue: new Date(2017, 3, 15), }); const chartDataSource = ref(new DataSource({ store: [], sort: 'date', paginate: false, })); const bounds = ref({ startValue: new Date(2017, 0, 1), endValue: new Date(2017, 11, 31), }); let packetsLock = 0; const currentVisualRange = computed({ get() { return visualRange.value; }, set(newRange) { const stateStart = visualRange.value.startValue; const currentStart = newRange.startValue; if (stateStart.valueOf() !== currentStart.valueOf()) { visualRange.value = newRange; } onVisualRangeChanged(); }, }); function onVisualRangeChanged() { const component = chart.value.instance; const items = component.getDataSource().items(); if (!items.length || items[0].date - visualRange.value.startValue >= HALFDAY || visualRange.value.endValue - items[items.length - 1].date >= HALFDAY) { uploadDataByVisualRange(visualRange.value, component); } } function uploadDataByVisualRange({ startValue, endValue }, component) { const dataSource = component.getDataSource(); const storage = dataSource.items(); const ajaxArgs = { startVisible: getDateString(startValue), endVisible: getDateString(endValue), startBound: getDateString(storage.length ? storage[0].date : null), endBound: getDateString(storage.length ? storage[storage.length - 1].date : null), }; if (ajaxArgs.startVisible !== ajaxArgs.startBound && ajaxArgs.endVisible !== ajaxArgs.endBound && !packetsLock) { packetsLock += 1; component.showLoadingIndicator(); getDataFrame(ajaxArgs) .then((dataFrame) => { packetsLock -= 1; const componentStorage = dataSource.store(); dataFrame .map((i) => ({ date: new Date(i.Date), minTemp: i.MinTemp, maxTemp: i.MaxTemp, })) .forEach((item) => componentStorage.insert(item)); dataSource.reload(); onVisualRangeChanged(); }) .catch(() => { packetsLock -= 1; dataSource.reload(); }); } } function getDataFrame(args) { let params = '?'; params += `startVisible=${args.startVisible} &endVisible=${args.endVisible} &startBound=${args.startBound} &endBound=${args.endBound}`; return fetch(`https://js.devexpress.com/Demos/WidgetsGallery/data/temperatureData${params}`) .then((response) => response.json()); } function getDateString(dateTime) { return dateTime ? dateTime.toLocaleDateString('en-US') : ''; } </script> <style> #chart { height: 440px; } </style>
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', 'whatwg-fetch': 'npm:whatwg-fetch@2.0.4/fetch.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);
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>

To implement this functionality, do the following:

  1. Configure a data source.

  2. Configure the Chart to support on-demand data loading.

  3. Implement functions that load the data.

    • In this demo, Chart displays daily information. If a user pan the Chart left or right more than half a day, additional data starts to load. The onVisualRangeChanged initiates this procedure.

    • The uploadDataByVisualRange function analyzes the starting and ending points of the visual range and the bounds of already loaded data. If necessary, it calls the getDataFrame function to obtain new data points. Finally, it reloads the DataSource and saves the current visual range.

    • The getDataFrame Ajax request gets the new data frame from the server.