ChartDirector 7.1 (.NET Edition)

Real-Time MultiChart (Web)




NOTE: This section describes Real-Time MultiChart for web applications only. For Windows applications, please refer to Real-Time MultiChart (Windows).

This example demonstrates a real-time multichart with track cursor.

The example is modified from the Real-Time Chart with Track Line (Web) example with the following changes:

Source Code Listing

[ASP.NET Web Forms - C# version] NetWebCharts\CSharpASP\realtimemultichart.aspx
(Click here on how to convert this code to code-behind style.)
<%@ Page Language="C#" Debug="true" %> <%@ Import Namespace="ChartDirector" %> <%@ Register TagPrefix="chart" Namespace="ChartDirector" Assembly="netchartdir" %> <script runat="server"> // // Draw a single chart // private XYChart drawXYChart(WebChartViewer viewer, DateTime[] timeStamps, double[] dataSeries, string name, int color, Axis xAxisScale, bool xAxisVisible) { // Only the last chart has an x-axis int xAxisHeight = 25; if (!xAxisVisible) { xAxisHeight = 0; } // Create an XYChart object of size 640 x 120 pixels (excluding x-axis height) XYChart c = new XYChart(640, 120 + xAxisHeight); // Set the plotarea at (55, 10) with width 85 pixels less than chart width, and height 20 pixels // less than chart height. Use a vertical gradient from light blue (f0f6ff) to sky blue (a0c0ff) // as background. Set border to transparent and grid lines to white (ffffff). c.setPlotArea(55, 10, c.getWidth() - 85, c.getHeight() - 20 - xAxisHeight, c.linearGradientColor(0, 10, 0, c.getHeight() - 20 - xAxisHeight, 0xf0f6ff, 0xa0c0ff), -1, Chart.Transparent, 0xffffff, 0xffffff); // As the data can lie outside the plotarea in a zoomed chart, we need enable clipping. c.setClipping(); // Add a legend box at (55, 5) using horizontal layout. Use 8pts Arial Bold as font. Set the // background and border color to Transparent and use line style legend key. LegendBox b = c.addLegend(55, 5, false, "Arial Bold", 10); b.setBackground(Chart.Transparent); b.setLineStyleKey(); // Set the x and y axis stems to transparent and the label font to 10pt Arial c.xAxis().setColors(Chart.Transparent); c.yAxis().setColors(Chart.Transparent); c.xAxis().setLabelStyle("Arial", 10); c.yAxis().setLabelStyle("Arial", 10); // Add axis title using 10pts Arial Bold Italic font c.yAxis().setTitle(name, "Arial Bold", 10); //================================================================================ // Add data to chart //================================================================================ // Add a line layer with the given data, with a line width of 2 pixels. LineLayer layer = c.addLineLayer(); layer.setLineWidth(2); layer.setXData(timeStamps); layer.addDataSet(dataSeries, color, name); //================================================================================ // Configure axis scale and labelling //================================================================================ // For the automatic axis labels, set the minimum spacing to 30 pixels for the y axis. c.yAxis().setTickDensity(30); if (xAxisScale == null) { // If xAxisScale is given, then use it to synchronize with other charts. c.xAxis().copyAxis(xAxisScale); } else { // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); } // Hide the x-axis if it is not visible. if (!xAxisVisible) { c.xAxis().setColors(Chart.Transparent, Chart.Transparent); } //================================================================================ // Output the chart //================================================================================ return c; } // // Draw the MultiChart // private void drawChart(WebChartViewer viewer) { // // Data to draw the chart. In this demo, the data buffer will be filled by a random data // generator. In real life, the data is probably stored in a buffer (eg. a database table, a // text file, or some global memory) and updated by other means. // // We use a data buffer to emulate the last 240 samples. int sampleSize = 240; double[] dataSeries1 = new double[sampleSize]; double[] dataSeries2 = new double[sampleSize]; double[] dataSeries3 = new double[sampleSize]; DateTime[] timeStamps = new DateTime[sampleSize]; // Our pseudo random number generator DateTime firstDate = DateTime.Now.AddSeconds(-timeStamps.Length); for(int i = 0; i < timeStamps.Length; ++i) { timeStamps[i] = firstDate.AddSeconds(i); double p = timeStamps[i].Ticks / 10000000; dataSeries1[i] = Math.Cos(p * 2.1) * 10 + 1 / (Math.Cos(p) * Math.Cos(p) + 0.01) + 20; dataSeries2[i] = 100 * Math.Sin(p / 27.7) * Math.Sin(p / 10.1) + 150; dataSeries3[i] = 100 * Math.Cos(p / 6.7) * Math.Cos(p / 11.9) + 150; } // The MultiChart, initially set to a height 10 pixels as the top margin. MultiChart m = new MultiChart(640, 10); // This first chart is responsible for setting up the x-axis scale. XYChart xyc = drawXYChart(viewer, timeStamps, dataSeries1, "Alpha", 0xff0000, null, false); Axis xAxisScale = xyc.xAxis(); // Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc); m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()); // All other charts synchronize their x-axes with that of the first chart. xyc = drawXYChart(viewer, timeStamps, dataSeries2, "Beta", 0x008800, xAxisScale, false); // Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc); m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()); // The last chart displays the x-axis. xyc = drawXYChart(viewer, timeStamps, dataSeries3, "Gamma", 0x0000ff, xAxisScale, true); // Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc); m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()); // Set the combined plot area to be the bounding box of the plot areas of the 3 charts m.setMainChart(m); // Output the chart viewer.Image = m.makeWebImage(Chart.SVG); // Output Javascript chart model to the browser to suppport tracking cursor viewer.ChartModel = m.getJsChartModel(); } // // Page Load event handler // protected void Page_Load(object sender, EventArgs e) { // // This script handles both the full page request, as well as the subsequent partial updates // (AJAX chart updates). We need to determine the type of request first before we processing it. // if (WebChartViewer.IsPartialUpdateRequest(Page)) { // Is a partial update request. // The .NET platform will not restore the states of the controls before or during Page_Load, // so we need to restore the state ourselves WebChartViewer1.LoadViewerState(); // Draw the chart in partial update mode drawChart(WebChartViewer1); // Output the chart immediately and then terminate the page life cycle (PartialUpdateChart // will cause Page_Load to terminate immediately without running the following code). WebChartViewer1.PartialUpdateChart(); } // // If the code reaches here, it is a full page request. // drawChart(WebChartViewer1); } </script> <!DOCTYPE html> <html> <head> <title>Real Time MultiChart</title> <script type="text/javascript" src="cdjcv.js"></script> </head> <body style="margin:0px"> <script type="text/javascript"> // // Execute the following initialization code after the web page is loaded // JsChartViewer.addEventListener(window, 'load', function() { var viewer = JsChartViewer.get('<%=WebChartViewer1.ClientID%>'); // Draw track cursor when mouse is moving over plotarea. Hide it when mouse leaves plot area. viewer.attachHandler(["MouseMovePlotArea", "TouchStartPlotArea", "TouchMovePlotArea", "ChartMove", "PostUpdate", "Now"], function(e) { this.preventDefault(e); // Prevent the browser from using touch events for other actions multiTrackLineLabel(viewer, viewer.getPlotAreaMouseX()); }); // When the chart is being updated, by default, an "Updating" box will pop up. In this example, we // will disable this box. viewer.updatingMsg = ""; }); // // Draw track line for a MultiChart // function multiTrackLineLabel(viewer, mouseX) { // Remove all previously drawn tracking object viewer.hideObj("all"); // Use a loop to draw track labels for the XYCharts inside the MultiChart for (var i = 0; i < viewer.getChartCount(); ++i) // Only the bottom chart (i == viewer.getChartCount() - 1) needs x-axis label. xyChartTrackLabel(viewer, mouseX, viewer.getChart(i), i, i == viewer.getChartCount() - 1); } // // Draw xy chart track label // function xyChartTrackLabel(viewer, mouseX, c, id, needXAxisLabel) { // The plot area var plotArea = c.getPlotArea(); // The XYChart API object obtains the various coordinates relative to the top-left corner // of the XYChart. However, it needs to draw the track cursor on the MultiChart. So we need // to obtain the coordinates of the XYChart top-left corner inside the MultiChart. var originX = c.getAbsOffsetX(); var originY = c.getAbsOffsetY(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. var xValue = c.getNearestXValue(mouseX); var xCoor = originX + c.getXCoor(xValue); // Draw a vertical track line at the x-position viewer.drawVLine("trackLine_" + id, xCoor, originY + plotArea.getTopY(), originY + plotArea.getBottomY(), "black 1px dotted"); // Only the last chart needs to draw the x-axis label if (needXAxisLabel) { viewer.showTextBox("xAxisLabel_" + id, xCoor, originY + plotArea.getBottomY() + 5, JsChartViewer.Top, c.xAxis().getFormattedLabel(xValue, "hh:nn:ss"), "font:bold 13px Arial;color:#FFFFFF;background-color:#000000;padding:0px 3px"); } // Iterate through all layers to draw the data labels for (var i = 0; i < c.getLayerCount(); ++i) { var layer = c.getLayerByZ(i); // The data array index of the x-value var xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (var j = 0; j < layer.getDataSetCount(); ++j) { var dataSet = layer.getDataSetByZ(j); // Get the color and position of the data label var color = dataSet.getDataColor(); var yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis()); // Draw a track dot with a label next to it for visible data points in the plot area if ((yCoor != null) && (yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color != null)) { viewer.showTextBox("dataPoint_" + id + "_" + i + "_" + j, xCoor, originY + yCoor, JsChartViewer.Center, viewer.htmlRect(7, 7, color)); viewer.showTextBox("dataLabel" + id + "_" + i + "_" + j, xCoor + 5, originY + yCoor, JsChartViewer.Left, dataSet.getValue(xIndex).toPrecision(4), "padding:0px 3px;font:bold 13px Arial;background-color:" + color + ";color:#FFFFFF;-webkit-text-size-adjust:100%;"); } } } } // // Executes once every second to update the countdown display. Updates the chart when the countdown reaches 0. // function timerTick() { // Get the update period and the time left var updatePeriod = parseInt(document.getElementById("UpdatePeriod").value); var timeLeft = Math.min(parseInt(document.getElementById("TimeRemaining").innerHTML), updatePeriod) - 1; if (timeLeft == 0) // Can update the chart now JsChartViewer.get('<%=WebChartViewer1.ClientID%>').partialUpdate(); else if (timeLeft < 0) // Reset the update period timeLeft += updatePeriod; // Update the countdown display document.getElementById("TimeRemaining").innerHTML = timeLeft; } window.setInterval("timerTick()", 1000); </script> <table cellspacing="0" cellpadding="0" border="0"> <tr> <td align="right" colspan="2" style="background:#000088; color:#ffff00; padding:0px 4px 2px 0px;"> <a style="color:#FFFF00; font:italic bold 10pt Arial; text-decoration:none" href="http://www.advsofteng.com/"> Advanced Software Engineering </a> </td> </tr> <tr valign="top"> <td style="width:150px; background:#c0c0ff; border-right:black 1px solid; border-bottom:black 1px solid;"> <br /> <br /> <div style="font: 9pt Verdana; padding:10px;"> <b>Update Period</b><br /> <select id="UpdatePeriod" style="width:130px"> <option value="5" selected="selected">5</option> <option value="10">10</option> <option value="20">20</option> <option value="30">30</option> <option value="60">60</option> </select> </div> <div style="font:9pt Verdana; padding:10px;"> <b>Time Remaining</b><br /> <div style="width:128px; border:#888888 1px inset;"> <div style="margin:3px" id="TimeRemaining">0</div> </div> </div> </td> <td> <div style="font: bold 20pt Arial; margin:5px 0px 0px 5px;"> Real Time MultiChart </div> <hr style="border:solid 1px #000080" /> <div style="padding:0px 5px 5px 10px"> <!-- ****** Here is the chart image ****** --> <chart:WebChartViewer id="WebChartViewer1" runat="server" /> </div> </td> </tr> </table> </body> </html>

[ASP.NET Web Forms - VB Version] NetWebCharts\VBNetASP\realtimemultichart.aspx
(Click here on how to convert this code to code-behind style.)
<%@ Page Language="VB" Debug="true" %> <%@ Import Namespace="ChartDirector" %> <%@ Register TagPrefix="chart" Namespace="ChartDirector" Assembly="netchartdir" %> <script runat="server"> ' ' Draw a single chart ' Private Function drawXYChart(viewer As WebChartViewer, timeStamps As DateTime(), _ dataSeries As Double(), name As String, color As Integer, xAxisScale As Axis, _ xAxisVisible As Boolean) As XYChart ' Only the last chart has an x-axis Dim xAxisHeight As Integer = 25 If Not xAxisVisible Then xAxisHeight = 0 End If ' Create an XYChart object of size 640 x 120 pixels (excluding x-axis height) Dim c As XYChart = New XYChart(640, 120 + xAxisHeight) ' Set the plotarea at (55, 10) with width 85 pixels less than chart width, and height 20 pixels ' less than chart height. Use a vertical gradient from light blue (f0f6ff) to sky blue (a0c0ff) ' as background. Set border to transparent and grid lines to white (ffffff). c.setPlotArea(55, 10, c.getWidth() - 85, c.getHeight() - 20 - xAxisHeight, _ c.linearGradientColor(0, 10, 0, c.getHeight() - 20 - xAxisHeight, &Hf0f6ff, &Ha0c0ff), -1, _ Chart.Transparent, &Hffffff, &Hffffff) ' As the data can lie outside the plotarea in a zoomed chart, we need enable clipping. c.setClipping() ' Add a legend box at (55, 5) using horizontal layout. Use 8pts Arial Bold as font. Set the ' background and border color to Transparent and use line style legend key. Dim b As LegendBox = c.addLegend(55, 5, False, "Arial Bold", 10) b.setBackground(Chart.Transparent) b.setLineStyleKey() ' Set the x and y axis stems to transparent and the label font to 10pt Arial c.xAxis().setColors(Chart.Transparent) c.yAxis().setColors(Chart.Transparent) c.xAxis().setLabelStyle("Arial", 10) c.yAxis().setLabelStyle("Arial", 10) ' Add axis title using 10pts Arial Bold Italic font c.yAxis().setTitle(name, "Arial Bold", 10) '================================================================================ ' Add data to chart '================================================================================ ' Add a line layer with the given data, with a line width of 2 pixels. Dim layer As LineLayer = c.addLineLayer() layer.setLineWidth(2) layer.setXData(timeStamps) layer.addDataSet(dataSeries, color, name) '================================================================================ ' Configure axis scale and labelling '================================================================================ ' For the automatic axis labels, set the minimum spacing to 30 pixels for the y axis. c.yAxis().setTickDensity(30) If xAxisScale Is Nothing Then ' If xAxisScale is given, then use it to synchronize with other charts. c.xAxis().copyAxis(xAxisScale) Else ' Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}") End If ' Hide the x-axis if it is not visible. If Not xAxisVisible Then c.xAxis().setColors(Chart.Transparent, Chart.Transparent) End If '================================================================================ ' Output the chart '================================================================================ Return c End Function ' ' Draw the MultiChart ' Private Sub drawChart(viewer As WebChartViewer) ' ' Data to draw the chart. In this demo, the data buffer will be filled by a random data ' generator. In real life, the data is probably stored in a buffer (eg. a database table, a text ' file, or some global memory) and updated by other means. ' ' We use a data buffer to emulate the last 240 samples. Dim sampleSize As Integer = 240 Dim dataSeries1(sampleSize - 1) As Double Dim dataSeries2(sampleSize - 1) As Double Dim dataSeries3(sampleSize - 1) As Double Dim timeStamps(sampleSize - 1) As Date ' Our pseudo random number generator Dim firstDate As Date = DateTime.Now.AddSeconds(-timeStamps.Length) For i As Integer = 0 To UBound(timeStamps) timeStamps(i) = firstDate.AddSeconds(i) Dim p As Double = timeStamps(i).Ticks / 10000000 dataSeries1(i) = Math.Cos(p * 2.1) * 10 + 1 / (Math.Cos(p) * Math.Cos(p) + 0.01) + 20 dataSeries2(i) = 100 * Math.Sin(p / 27.7) * Math.Sin(p / 10.1) + 150 dataSeries3(i) = 100 * Math.Cos(p / 6.7) * Math.Cos(p / 11.9) + 150 Next ' The MultiChart, initially set to a height 10 pixels as the top margin. Dim m As MultiChart = New MultiChart(640, 10) ' This first chart is responsible for setting up the x-axis scale. Dim xyc As XYChart = drawXYChart(viewer, timeStamps, dataSeries1, "Alpha", &Hff0000, Nothing, _ False) Dim xAxisScale As Axis = xyc.xAxis() ' Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc) m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()) ' All other charts synchronize their x-axes with that of the first chart. xyc = drawXYChart(viewer, timeStamps, dataSeries2, "Beta", &H008800, xAxisScale, False) ' Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc) m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()) ' The last chart displays the x-axis. xyc = drawXYChart(viewer, timeStamps, dataSeries3, "Gamma", &H0000ff, xAxisScale, True) ' Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc) m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()) ' Set the combined plot area to be the bounding box of the plot areas of the 3 charts m.setMainChart(m) ' Output the chart viewer.Image = m.makeWebImage(Chart.SVG) ' Output Javascript chart model to the browser to suppport tracking cursor WebChartViewer1.ChartModel = m.getJsChartModel() End Sub ' ' Page Load event handler ' Private Sub Page_Load(sender As System.Object, e As System.EventArgs) ' ' This script handles both the full page request, as well as the subsequent partial updates ' (AJAX chart updates). We need to determine the type of request first before we processing it. ' If WebChartViewer.IsPartialUpdateRequest(Page) Then ' Is a partial update request. ' The .NET platform will not restore the states of the controls before or during Page_Load, ' so we need to restore the state ourselves WebChartViewer1.LoadViewerState() ' Draw the chart in partial update mode drawChart(WebChartViewer1) ' Output the chart immediately and then terminate the page life cycle (PartialUpdateChart ' will cause Page_Load to terminate immediately without running the following code). WebChartViewer1.PartialUpdateChart() End If ' ' If the code reaches here, it is a full page request. ' drawChart(WebChartViewer1) End Sub </script> <!DOCTYPE html> <html> <head> <title>Real Time MultiChart</title> <script type="text/javascript" src="cdjcv.js"></script> </head> <body style="margin:0px"> <script type="text/javascript"> // // Execute the following initialization code after the web page is loaded // JsChartViewer.addEventListener(window, 'load', function() { var viewer = JsChartViewer.get('<%=WebChartViewer1.ClientID%>'); // Draw track cursor when mouse is moving over plotarea. Hide it when mouse leaves plot area. viewer.attachHandler(["MouseMovePlotArea", "TouchStartPlotArea", "TouchMovePlotArea", "ChartMove", "PostUpdate", "Now"], function(e) { this.preventDefault(e); // Prevent the browser from using touch events for other actions multiTrackLineLabel(viewer, viewer.getPlotAreaMouseX()); }); // When the chart is being updated, by default, an "Updating" box will pop up. In this example, we // will disable this box. viewer.updatingMsg = ""; }); // // Draw track line for a MultiChart // function multiTrackLineLabel(viewer, mouseX) { // Remove all previously drawn tracking object viewer.hideObj("all"); // Use a loop to draw track labels for the XYCharts inside the MultiChart for (var i = 0; i < viewer.getChartCount(); ++i) // Only the bottom chart (i == viewer.getChartCount() - 1) needs x-axis label. xyChartTrackLabel(viewer, mouseX, viewer.getChart(i), i, i == viewer.getChartCount() - 1); } // // Draw xy chart track label // function xyChartTrackLabel(viewer, mouseX, c, id, needXAxisLabel) { // The plot area var plotArea = c.getPlotArea(); // The XYChart API object obtains the various coordinates relative to the top-left corner // of the XYChart. However, it needs to draw the track cursor on the MultiChart. So we need // to obtain the coordinates of the XYChart top-left corner inside the MultiChart. var originX = c.getAbsOffsetX(); var originY = c.getAbsOffsetY(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. var xValue = c.getNearestXValue(mouseX); var xCoor = originX + c.getXCoor(xValue); // Draw a vertical track line at the x-position viewer.drawVLine("trackLine_" + id, xCoor, originY + plotArea.getTopY(), originY + plotArea.getBottomY(), "black 1px dotted"); // Only the last chart needs to draw the x-axis label if (needXAxisLabel) { viewer.showTextBox("xAxisLabel_" + id, xCoor, originY + plotArea.getBottomY() + 5, JsChartViewer.Top, c.xAxis().getFormattedLabel(xValue, "hh:nn:ss"), "font:bold 13px Arial;color:#FFFFFF;background-color:#000000;padding:0px 3px"); } // Iterate through all layers to draw the data labels for (var i = 0; i < c.getLayerCount(); ++i) { var layer = c.getLayerByZ(i); // The data array index of the x-value var xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (var j = 0; j < layer.getDataSetCount(); ++j) { var dataSet = layer.getDataSetByZ(j); // Get the color and position of the data label var color = dataSet.getDataColor(); var yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis()); // Draw a track dot with a label next to it for visible data points in the plot area if ((yCoor != null) && (yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color != null)) { viewer.showTextBox("dataPoint_" + id + "_" + i + "_" + j, xCoor, originY + yCoor, JsChartViewer.Center, viewer.htmlRect(7, 7, color)); viewer.showTextBox("dataLabel" + id + "_" + i + "_" + j, xCoor + 5, originY + yCoor, JsChartViewer.Left, dataSet.getValue(xIndex).toPrecision(4), "padding:0px 3px;font:bold 13px Arial;background-color:" + color + ";color:#FFFFFF;-webkit-text-size-adjust:100%;"); } } } } // // Executes once every second to update the countdown display. Updates the chart when the countdown reaches 0. // function timerTick() { // Get the update period and the time left var updatePeriod = parseInt(document.getElementById("UpdatePeriod").value); var timeLeft = Math.min(parseInt(document.getElementById("TimeRemaining").innerHTML), updatePeriod) - 1; if (timeLeft == 0) // Can update the chart now JsChartViewer.get('<%=WebChartViewer1.ClientID%>').partialUpdate(); else if (timeLeft < 0) // Reset the update period timeLeft += updatePeriod; // Update the countdown display document.getElementById("TimeRemaining").innerHTML = timeLeft; } window.setInterval("timerTick()", 1000); </script> <table cellspacing="0" cellpadding="0" border="0"> <tr> <td align="right" colspan="2" style="background:#000088; color:#ffff00; padding:0px 4px 2px 0px;"> <a style="color:#FFFF00; font:italic bold 10pt Arial; text-decoration:none" href="http://www.advsofteng.com/"> Advanced Software Engineering </a> </td> </tr> <tr valign="top"> <td style="width:150px; background:#c0c0ff; border-right:black 1px solid; border-bottom:black 1px solid;"> <br /> <br /> <div style="font: 9pt Verdana; padding:10px;"> <b>Update Period</b><br /> <select id="UpdatePeriod" style="width:130px"> <option value="5" selected="selected">5</option> <option value="10">10</option> <option value="20">20</option> <option value="30">30</option> <option value="60">60</option> </select> </div> <div style="font:9pt Verdana; padding:10px;"> <b>Time Remaining</b><br /> <div style="width:128px; border:#888888 1px inset;"> <div style="margin:3px" id="TimeRemaining">0</div> </div> </div> </td> <td> <div style="font: bold 20pt Arial; margin:5px 0px 0px 5px;"> Real Time MultiChart </div> <hr style="border:solid 1px #000080" /> <div style="padding:0px 5px 5px 10px"> <!-- ****** Here is the chart image ****** --> <chart:WebChartViewer id="WebChartViewer1" runat="server" /> </div> </td> </tr> </table> </body> </html>

[ASP.NET MVC - Controller] NetMvcCharts\Controllers\RealtimemultichartController.cs
using System; using System.Web.Mvc; using ChartDirector; namespace NetMvcCharts.Controllers { public class RealtimemultichartController : Controller { // // Draw a single chart // private XYChart drawXYChart(RazorChartViewer viewer, DateTime[] timeStamps, double[] dataSeries, string name, int color, Axis xAxisScale, bool xAxisVisible) { // Only the last chart has an x-axis int xAxisHeight = 25; if (!xAxisVisible) { xAxisHeight = 0; } // Create an XYChart object of size 640 x 120 pixels (excluding x-axis height) XYChart c = new XYChart(640, 120 + xAxisHeight); // Set the plotarea at (55, 10) with width 85 pixels less than chart width, and height 20 // pixels less than chart height. Use a vertical gradient from light blue (f0f6ff) to sky // blue (a0c0ff) as background. Set border to transparent and grid lines to white (ffffff). c.setPlotArea(55, 10, c.getWidth() - 85, c.getHeight() - 20 - xAxisHeight, c.linearGradientColor(0, 10, 0, c.getHeight() - 20 - xAxisHeight, 0xf0f6ff, 0xa0c0ff), -1, Chart.Transparent, 0xffffff, 0xffffff); // As the data can lie outside the plotarea in a zoomed chart, we need enable clipping. c.setClipping(); // Add a legend box at (55, 5) using horizontal layout. Use 8pts Arial Bold as font. Set the // background and border color to Transparent and use line style legend key. LegendBox b = c.addLegend(55, 5, false, "Arial Bold", 10); b.setBackground(Chart.Transparent); b.setLineStyleKey(); // Set the x and y axis stems to transparent and the label font to 10pt Arial c.xAxis().setColors(Chart.Transparent); c.yAxis().setColors(Chart.Transparent); c.xAxis().setLabelStyle("Arial", 10); c.yAxis().setLabelStyle("Arial", 10); // Add axis title using 10pts Arial Bold Italic font c.yAxis().setTitle(name, "Arial Bold", 10); //================================================================================ // Add data to chart //================================================================================ // Add a line layer with the given data, with a line width of 2 pixels. LineLayer layer = c.addLineLayer(); layer.setLineWidth(2); layer.setXData(timeStamps); layer.addDataSet(dataSeries, color, name); //================================================================================ // Configure axis scale and labelling //================================================================================ // For the automatic axis labels, set the minimum spacing to 30 pixels for the y axis. c.yAxis().setTickDensity(30); if (xAxisScale == null) { // If xAxisScale is given, then use it to synchronize with other charts. c.xAxis().copyAxis(xAxisScale); } else { // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); } // Hide the x-axis if it is not visible. if (!xAxisVisible) { c.xAxis().setColors(Chart.Transparent, Chart.Transparent); } //================================================================================ // Output the chart //================================================================================ return c; } // // Draw the MultiChart // private void drawChart(RazorChartViewer viewer) { // // Data to draw the chart. In this demo, the data buffer will be filled by a random data // generator. In real life, the data is probably stored in a buffer (eg. a database table, a // text file, or some global memory) and updated by other means. // // We use a data buffer to emulate the last 240 samples. int sampleSize = 240; double[] dataSeries1 = new double[sampleSize]; double[] dataSeries2 = new double[sampleSize]; double[] dataSeries3 = new double[sampleSize]; DateTime[] timeStamps = new DateTime[sampleSize]; // Our pseudo random number generator DateTime firstDate = DateTime.Now.AddSeconds(-timeStamps.Length); for(int i = 0; i < timeStamps.Length; ++i) { timeStamps[i] = firstDate.AddSeconds(i); double p = timeStamps[i].Ticks / 10000000; dataSeries1[i] = Math.Cos(p * 2.1) * 10 + 1 / (Math.Cos(p) * Math.Cos(p) + 0.01) + 20; dataSeries2[i] = 100 * Math.Sin(p / 27.7) * Math.Sin(p / 10.1) + 150; dataSeries3[i] = 100 * Math.Cos(p / 6.7) * Math.Cos(p / 11.9) + 150; } // The MultiChart, initially set to a height 10 pixels as the top margin. MultiChart m = new MultiChart(640, 10); // This first chart is responsible for setting up the x-axis scale. XYChart xyc = drawXYChart(viewer, timeStamps, dataSeries1, "Alpha", 0xff0000, null, false); Axis xAxisScale = xyc.xAxis(); // Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc); m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()); // All other charts synchronize their x-axes with that of the first chart. xyc = drawXYChart(viewer, timeStamps, dataSeries2, "Beta", 0x008800, xAxisScale, false); // Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc); m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()); // The last chart displays the x-axis. xyc = drawXYChart(viewer, timeStamps, dataSeries3, "Gamma", 0x0000ff, xAxisScale, true); // Add the XYChart to the MultiChart and increase the MultiChart height m.addChart(0, m.getHeight(), xyc); m.setSize(m.getWidth(), m.getHeight() + xyc.getHeight()); // Set the combined plot area to be the bounding box of the plot areas of the 3 charts m.setMainChart(m); // Output the chart viewer.Image = m.makeWebImage(Chart.SVG); // Output Javascript chart model to the browser to suppport tracking cursor viewer.ChartModel = m.getJsChartModel(); } public ActionResult Index() { RazorChartViewer viewer = ViewBag.Viewer = new RazorChartViewer(HttpContext, "chart1"); // // This script handles both the full page request, as well as the subsequent partial updates // (AJAX chart updates). We need to determine the type of request first before we processing // it. // if (RazorChartViewer.IsPartialUpdateRequest(Request)) { // Is a partial update request. drawChart(viewer); return Content(viewer.PartialUpdateChart()); } // // If the code reaches here, it is a full page request. // drawChart(viewer); return View(); } } }

[ASP.NET MVC - View] NetMvcCharts\Views\Realtimemultichart\Index.cshtml
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Real Time MultiChart</title> @Scripts.Render("~/Scripts/cdjcv.js") </head> <body style="margin:0px"> <script type="text/javascript"> // // Execute the following initialization code after the web page is loaded // JsChartViewer.addEventListener(window, 'load', function() { var viewer = JsChartViewer.get('@ViewBag.Viewer.ID'); // Draw track cursor when mouse is moving over plotarea. Hide it when mouse leaves plot area. viewer.attachHandler(["MouseMovePlotArea", "TouchStartPlotArea", "TouchMovePlotArea", "ChartMove", "PostUpdate", "Now"], function(e) { this.preventDefault(e); // Prevent the browser from using touch events for other actions multiTrackLineLabel(viewer, viewer.getPlotAreaMouseX()); }); // When the chart is being updated, by default, an "Updating" box will pop up. In this example, we // will disable this box. viewer.updatingMsg = ""; }); // // Draw track line for a MultiChart // function multiTrackLineLabel(viewer, mouseX) { // Remove all previously drawn tracking object viewer.hideObj("all"); // Use a loop to draw track labels for the XYCharts inside the MultiChart for (var i = 0; i < viewer.getChartCount(); ++i) // Only the bottom chart (i == viewer.getChartCount() - 1) needs x-axis label. xyChartTrackLabel(viewer, mouseX, viewer.getChart(i), i, i == viewer.getChartCount() - 1); } // // Draw xy chart track label // function xyChartTrackLabel(viewer, mouseX, c, id, needXAxisLabel) { // The plot area var plotArea = c.getPlotArea(); // The XYChart API object obtains the various coordinates relative to the top-left corner // of the XYChart. However, it needs to draw the track cursor on the MultiChart. So we need // to obtain the coordinates of the XYChart top-left corner inside the MultiChart. var originX = c.getAbsOffsetX(); var originY = c.getAbsOffsetY(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. var xValue = c.getNearestXValue(mouseX); var xCoor = originX + c.getXCoor(xValue); // Draw a vertical track line at the x-position viewer.drawVLine("trackLine_" + id, xCoor, originY + plotArea.getTopY(), originY + plotArea.getBottomY(), "black 1px dotted"); // Only the last chart needs to draw the x-axis label if (needXAxisLabel) { viewer.showTextBox("xAxisLabel_" + id, xCoor, originY + plotArea.getBottomY() + 5, JsChartViewer.Top, c.xAxis().getFormattedLabel(xValue, "hh:nn:ss"), "font:bold 13px Arial;color:#FFFFFF;background-color:#000000;padding:0px 3px"); } // Iterate through all layers to draw the data labels for (var i = 0; i < c.getLayerCount(); ++i) { var layer = c.getLayerByZ(i); // The data array index of the x-value var xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (var j = 0; j < layer.getDataSetCount(); ++j) { var dataSet = layer.getDataSetByZ(j); // Get the color and position of the data label var color = dataSet.getDataColor(); var yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis()); // Draw a track dot with a label next to it for visible data points in the plot area if ((yCoor != null) && (yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color != null)) { viewer.showTextBox("dataPoint_" + id + "_" + i + "_" + j, xCoor, originY + yCoor, JsChartViewer.Center, viewer.htmlRect(7, 7, color)); viewer.showTextBox("dataLabel" + id + "_" + i + "_" + j, xCoor + 5, originY + yCoor, JsChartViewer.Left, dataSet.getValue(xIndex).toPrecision(4), "padding:0px 3px;font:bold 13px Arial;background-color:" + color + ";color:#FFFFFF;-webkit-text-size-adjust:100%;"); } } } } // // Executes once every second to update the countdown display. Updates the chart when the countdown reaches 0. // function timerTick() { // Get the update period and the time left var updatePeriod = parseInt(document.getElementById("UpdatePeriod").value); var timeLeft = Math.min(parseInt(document.getElementById("TimeRemaining").innerHTML), updatePeriod) - 1; if (timeLeft == 0) // Can update the chart now JsChartViewer.get('@ViewBag.Viewer.ID').partialUpdate(); else if (timeLeft < 0) // Reset the update period timeLeft += updatePeriod; // Update the countdown display document.getElementById("TimeRemaining").innerHTML = timeLeft; } window.setInterval("timerTick()", 1000); </script> <table cellspacing="0" cellpadding="0" border="0"> <tr> <td align="right" colspan="2" style="background:#000088; color:#ffff00; padding:0px 4px 2px 0px;"> <a style="color:#FFFF00; font:italic bold 10pt Arial; text-decoration:none" href="http://www.advsofteng.com/"> Advanced Software Engineering </a> </td> </tr> <tr valign="top"> <td style="width:150px; background:#c0c0ff; border-right:black 1px solid; border-bottom:black 1px solid;"> <br /> <br /> <div style="font: 9pt Verdana; padding:10px;"> <b>Update Period</b><br /> <select id="UpdatePeriod" style="width:130px"> <option value="5" selected="selected">5</option> <option value="10">10</option> <option value="20">20</option> <option value="30">30</option> <option value="60">60</option> </select> </div> <div style="font:9pt Verdana; padding:10px;"> <b>Time Remaining</b><br /> <div style="width:128px; border:#888888 1px inset;"> <div style="margin:3px" id="TimeRemaining">0</div> </div> </div> </td> <td> <div style="font: bold 20pt Arial; margin:5px 0px 0px 5px;"> Real Time MultiChart </div> <hr style="border:solid 1px #000080" /> <div style="padding:0px 5px 5px 10px"> <!-- ****** Here is the chart image ****** --> @Html.Raw(ViewBag.Viewer.RenderHTML()) </div> </td> </tr> </table> </body> </html>