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.MVC.Demos.Models.SampleData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Web.Mvc;
namespace DevExtreme.MVC.Demos.Controllers {
public class ChartsController : Controller {
public ActionResult LoadDataOnDemand() {
return View();
}
}
}
xxxxxxxxxx
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Cors;
using DevExtreme.MVC.Demos.Models;
using DevExtreme.MVC.Demos.Models.SampleData;
using System.Linq;
namespace DevExtreme.MVC.Demos.Controllers.ApiControllers {
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class TemperatureDataController : ApiController {
[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 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 SampleData.ServiceRepository.Instance.TemperatureItems.Where(t => t.Date >= startDate && t.Date <= endDate);
}
}
}
xxxxxxxxxx
using System.Collections.Generic;
using System.Web;
using System.Xml.Linq;
using System.Linq;
using System.Globalization;
using System;
using System.IO;
using DevExpress.Utils;
namespace DevExtreme.MVC.Demos.Models.SampleData {
public partial class SampleData {
public class ServiceRepository {
public static readonly ServiceRepository Instance = new ServiceRepository();
public readonly IEnumerable<TemperatureItem> TemperatureItems;
private ServiceRepository() {
CultureInfo ci = (CultureInfo)CultureInfo.CurrentCulture.Clone();
ci.NumberFormat.CurrencyDecimalSeparator = ".";
var xmlContent = File.ReadAllText(HttpContext.Current.Server.MapPath("~/Content/SampleData/TemperatureData.xml"));
XDocument tempDoc = SafeXml.CreateXDocument(xmlContent);
TemperatureItems = (from d in tempDoc.Root.Elements("dayItem")
select new TemperatureItem {
Date = DateTime.Parse(d.Element("date").Value, null, DateTimeStyles.RoundtripKind),
MinTemp = float.Parse(d.Element("minTemp").Value, NumberStyles.Any, ci),
MaxTemp = float.Parse(d.Element("maxTemp").Value, NumberStyles.Any, ci)
}).ToArray();
}
}
}
}
xxxxxxxxxx
using System;
using System.ComponentModel.DataAnnotations;
namespace DevExtreme.MVC.Demos.Models {
public class TemperatureItem {
[Key]
public DateTime Date { get; set; }
public float MinTemp { get; set; }
public float 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.
-