Your search did not match any results.

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
@(Html.DevExtreme().Chart() .ID("chart") .Title("Temperature in Toronto (2017)") .DataSource(d => d.Array()) .DataSourceOptions(c => c .Sort("date") .Paginate(false) ) .ZoomAndPan(z => z.ArgumentAxis(ChartZoomAndPanMode.Pan)) .ScrollBar(s => s.Visible(true)) .ArgumentAxis(a => a .ArgumentType(ChartDataType.DateTime) .WholeRange(w => w .StartValue(new DateTime(2017, 1, 1)) .EndValue(new DateTime(2017, 12, 31)) ) .VisualRange(v => v .StartValue(new DateTime(2017, 4, 1)) .Length(l => l.Weeks(2)) ) .VisualRangeUpdateMode(VisualRangeUpdateMode.Keep) ) .ValueAxis(v => v.Add() .Name("temperature") .AllowDecimals(false) .Title(t => t .Text("Temperature, °C") .Font(f => f.Color("#ff950c")) ) .Label(l => l.Font(f => f.Color("#ff950c"))) ) .Series(s => s.Add() .Color("#ff950c") .Type(SeriesType.RangeArea) .ArgumentField("date") .RangeValue1Field("minTemp") .RangeValue2Field("maxTemp") .Name("Temperature range") ) .OnOptionChanged(@<text> function(e){ if(e.fullName === "argumentAxis.visualRange") { onVisualRangeChanged(e.value, e.component); } } </text>) .Animation(a => a.Enabled(false)) .LoadingIndicator(l => l .BackgroundColor("none") .Font(f => f.Size(14)) ) .Legend(l => l.Visible(false)) ) <script> var HALFDAY = 43200000; var packetsLock = 0; function onVisualRangeChanged(visualRange, component) { var items = component.getDataSource().items(); if (!items.length || items[0].date - visualRange.startValue >= HALFDAY || visualRange.endValue - items[items.length - 1].date >= HALFDAY) { uploadDataByVisualRange(visualRange, component); } } function uploadDataByVisualRange(visualRange, component) { var dataSource = component.getDataSource(); var storage = dataSource.items(); var ajaxArgs = { startVisible: getDateString(visualRange.startValue), endVisible: getDateString(visualRange.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++; component.showLoadingIndicator(); getDataFrame(ajaxArgs) .then(function(dataFrame) { packetsLock--; var componentStorage = dataSource.store(); dataFrame.forEach(function(item) { componentStorage.insert(item); }); dataSource.reload(); var range = component.getArgumentAxis().visualRange(); onVisualRangeChanged(range, component); }, function(reason) { packetsLock--; dataSource.reload(); }); } } function getDataFrame(args) { var deferred = $.Deferred(); $.ajax({ url: "@Url.Content("~/api/TemperatureData")", dataType: "json", data: args, success: function (result) { deferred.resolve(result.map(function(i) { return { date: new Date(i.Date), minTemp: i.MinTemp, maxTemp: i.MaxTemp }; })); }, error: function () { deferred.reject("Data Loading Error"); }, timeout: 2000 }); return deferred.promise(); } function getDateString(dateTime) { return dateTime ? dateTime.toLocaleDateString("en-US") : ""; } </script>
using DevExtreme.AspNet.Data; using DevExtreme.AspNet.Mvc; using DevExtreme.NETCore.Demos.Models; using DevExtreme.NETCore.Demos.Models.SampleData; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace DevExtreme.NETCore.Demos.Controllers { public class ChartsController : Controller { public ActionResult LoadDataOnDemand() { return View(); } } }
using DevExtreme.NETCore.Demos.Models; using DevExtreme.NETCore.Demos.Models.SampleData; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; namespace DevExtreme.NETCore.Demos.Controllers.ApiControllers { [Route("api/[controller]")] public class TemperatureDataController : Controller { [HttpGet] public IEnumerable<TemperatureItem> Get(string startVisible = "01/01/2017", string endVisible = "12/31/2017", string startBound = "01/01/2017", string endBound = "12/31/2017") { var totalList = SampleData.GetTemperatureRepository(); var startVisibleDate = DateTime.Parse(startVisible); var endVisibleDate = DateTime.Parse(endVisible); var startBoundDate = string.IsNullOrEmpty(startBound) ? DateTime.MaxValue : DateTime.Parse(startBound); var endBoundDate = string.IsNullOrEmpty(endBound) ? DateTime.MinValue : DateTime.Parse(endBound); var startDate = startBoundDate > startVisibleDate ? startVisibleDate.AddDays(-7) : endBoundDate.AddDays(1); var endDate = endBoundDate < endVisibleDate ? endVisibleDate.AddDays(7) : startBoundDate.AddDays(-1); return totalList.Where(t => t.Date >= startDate && t.Date <= endDate); } } }
using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Xml.Linq; using DevExpress.Utils; namespace DevExtreme.NETCore.Demos.Models.SampleData { public static partial class SampleData { public static string RootPath; static readonly object _temperatureItemsLock = new object(); static IEnumerable<TemperatureItem> _temperatureItems; public static IEnumerable<TemperatureItem> GetTemperatureRepository() { lock(_temperatureItemsLock) { if(_temperatureItems == null) { var xmlContent = File.ReadAllText(Path.Combine(RootPath, "SampleData/TemperatureData.xml")); var xml = SafeXml.CreateXDocument(xmlContent); _temperatureItems = xml.Root.Elements("dayItem") .Select(d => new TemperatureItem { Date = DateTime.Parse(d.Element("date").Value, null, DateTimeStyles.RoundtripKind), MinTemp = double.Parse(d.Element("minTemp").Value, CultureInfo.InvariantCulture), MaxTemp = double.Parse(d.Element("maxTemp").Value, CultureInfo.InvariantCulture) }) .ToArray(); } return _temperatureItems; } } } }
using System; using System.ComponentModel.DataAnnotations; namespace DevExtreme.NETCore.Demos.Models { public class TemperatureItem { [Key] public DateTime Date { get; set; } public double MinTemp { get; set; } public double MaxTemp { get; set; } } }
#chart { height: 440px; }

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.