If you have technical questions, please create a support ticket in the DevExpress Support Center.
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>
xxxxxxxxxx
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
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 {
public class ChartsController : Controller {
public ActionResult LoadDataOnDemand() {
return View();
}
}
}
xxxxxxxxxx
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);
}
}
}
xxxxxxxxxx
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;
}
}
}
}
xxxxxxxxxx
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; }
}
}
xxxxxxxxxx
#chart {
height: 440px;
}
To implement this functionality, do the following:
-
Configure a data source.
-
Assign a DataSource with an empty store to the Chart dataSource property.
-
Set the sort property to
date
. -
Disable the paginate property to prevent data from partitioning.
-
-
Configure the Chart to support on-demand data loading.
-
Set the visualRangeUpdateMode property to
keep
. -
Specify a loadingIndicator.
-
Specify the initial visualRange.
-
Implement a function that respond to user pan operations and tracks visualRange changes. If a user changed the visual range, initiate a request for additional data.
-
-
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 thegetDataFrame
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.
-