Your search did not match any results.
Charts

SignalR Service

Documentation

This example demonstrates real-time data update in a financial chart bound to a SignalR server. Note that data used in this demo is for demonstration purposes only.

@(Html.DevExtreme().Chart() .ID("chart") .Title("Stock Price") .Series(s => { s.Add() .Type(SeriesType.Candlestick) .ArgumentField("date") .Pane("Price") .Aggregation(a => a.Enabled(true) .Calculate((@<text> function(e) { var prices = e.data.map(function(i) { return i.price; }); if(prices.length) { return { date: e.intervalStart, open: prices[0], high: Math.max.apply(null, prices), low: Math.min.apply(null, prices), close: prices[prices.length - 1] }; } } </text>)) .Method(ChartSeriesAggregationMethod.Custom)); s.Add() .Type(SeriesType.Bar) .ArgumentField("date") .ValueField("volume") .Color("red") .Pane("Volume") .Name("Volume") .Aggregation(a => a.Enabled(true) .Method(ChartSeriesAggregationMethod.Sum)); }) .CustomizePoint((@<text> function(arg) { if(arg.seriesName === "Volume") { var ohlc = $("#chart").dxChart("getAllSeries")[0].getPointsByArg(arg.argument)[0].data; if(ohlc.close >= ohlc.open) { return { color: "#1db2f5" }; } } } </text>)) .Panes(p => { p.Add().Name("Price"); p.Add().Name("Volume").Height(80); }) .ArgumentAxis(a => a.ArgumentType(ChartDataType.DateTime) .MinVisualRangeLength(l => l.Minutes(10)) .VisualRange(v => v.Length(VizTimeInterval.Hour)) ) .Legend(l => l.Visible(false)) .ValueAxis(v => v.Add().PlaceholderSize(50)) .Margin(m => m.Right(30)) .ScrollBar(s => s.Visible(true)) .LoadingIndicator(l => l.Enabled(true)) .ZoomAndPan(z => z.ArgumentAxis(ChartZoomAndPanMode.Both)) .Tooltip(t => t.Enabled(true) .Shared(true) .ArgumentFormat("shortDateShortTime") .ContentTemplate(@<text> <% var volume = points.filter(point => point.seriesName === 'Volume')[0]; %> <% var prices = points.filter(point => point.seriesName !== 'Volume')[0]; %> <div class='tooltip-template'> <div><%- argumentText %></div> <div> <span>Open: </span> <%- Globalize.formatCurrency(prices.openValue, "USD") %> </div> <div> <span>High: </span> <%- Globalize.formatCurrency(prices.highValue, "USD") %> </div> <div> <span>Low: </span> <%- Globalize.formatCurrency(prices.lowValue, "USD") %> </div> <div> <span>Close: </span> <%- Globalize.formatCurrency(prices.closeValue, "USD") %> </div> <div> <span>Volume: </span> <%- Globalize.formatNumber(volume.value, { maximumFractionDigits: 0 }) %> </div> </div> </text>) ) .Crosshair(c => c.Enabled(true).HorizontalLine(hl => hl.Visible(false))) ) <script src="~/signalr/signalr-client.js"></script> <script> var connection = new signalR.HubConnectionBuilder() .withUrl("@Url.Content("~/stockTickDataHub")") .configureLogging(signalR.LogLevel.Information) .build(); $(function () { connection.start() .then(function () { var store = new DevExpress.data.CustomStore({ load: function () { return connection.invoke("getAllData"); }, key: "date" }); $("#chart").dxChart({ dataSource: store }); connection.on("updateStockPrice", function (data) { store.push([{ type: "insert", key: data.date, data: data }]); }); }); }); </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 SignalRService() { return View(); } } }
using System.Collections.Generic; using DevExtreme.NETCore.Demos.Models.SignalRTickData; using Microsoft.AspNetCore.SignalR; namespace DevExtreme.NETCore.Demos.Hubs { public class StockTickDataHub : Hub { private readonly TickDataService _service; public StockTickDataHub(TickDataService service) { _service = service; } public IEnumerable<TickItem> GetAllData() { return _service.GetAllData(); } } }
using DevExtreme.NETCore.Demos.Hubs; using Microsoft.AspNetCore.SignalR; using System; using System.Collections.Generic; using System.Threading; namespace DevExtreme.NETCore.Demos.Models.SignalRTickData { public class TickDataService { private IHubContext<StockTickDataHub> hubContext { get; set; } private readonly object updateStockPricesLock = new object(); private TickItem[] tickData; private int lastTickIndex; private Timer timer; public TickDataService(IHubContext<StockTickDataHub> hubCtx) { hubContext = hubCtx; tickData = GenerateTestData(); lastTickIndex = tickData.Length - 1; timer = new Timer(Update, null, 1000, 1000); } public IEnumerable<TickItem> GetAllData() { var data = new List<TickItem>(); lock(updateStockPricesLock) { for(var i = lastTickIndex; data.Count < 10000; i--) { data.Add(tickData[i]); if(i == 0) { i = tickData.Length - 1; } } } return data; } private void Update(object state) { lock(updateStockPricesLock) { lastTickIndex = (lastTickIndex + 1) % tickData.Length; var tick = tickData[lastTickIndex]; tick.Date = DateTime.Now; BroadcastStockPrice(tick); } } private void BroadcastStockPrice(TickItem item) { hubContext.Clients.All.SendAsync("updateStockPrice", item); } private TickItem[] GenerateTestData() { var lastPrice = 140m; var random = new Random(); var slowRandomValue = random.NextDouble(); var data = new TickItem[60 * 60 * 20]; var curTime = DateTime.Now; for(var i = 0; i < data.Length / 2; i++) { lastPrice = Math.Round(lastPrice * (decimal)(1 + 0.002 * (-1 + 2 * random.NextDouble())), 2); if(i % 50 == 0) { slowRandomValue = random.NextDouble(); if(slowRandomValue > 0.3 && slowRandomValue <= 0.5) slowRandomValue -= 0.2; if(slowRandomValue > 0.5 && slowRandomValue <= 0.7) slowRandomValue += 0.2; } var volume = (int)(100 + 1900 * random.NextDouble() * slowRandomValue); data[data.Length - 1 - i] = new TickItem(lastPrice, volume, curTime.AddSeconds(-1 * i)); data[i] = new TickItem(lastPrice, volume, curTime.AddSeconds(-1 * (data.Length - 1 - i))); } return data; } } }
using System; namespace DevExtreme.NETCore.Demos.Models.SignalRTickData { public class TickItem { public DateTime Date { get; set; } public decimal Price { get; set; } public int Volume { get; set; } public TickItem(decimal price, int volume, DateTime date) { Date = date; Price = price; Volume = volume; } } }
#chart { height: 440px; } .tooltip-template span { font-weight: 500; }