// // Create chart // private void createChart(RazorChartViewer viewer) { // // We use a random number generator to simulate the data from 9:30am to 4:30pm with one // data point every 4 minutes. The total number of points during that period is 106. (7 // hours x 15 points/hour + 1) // int noOfPoints = 106; // Assume we have not reached the end of the day yet, and only 85 points are available. // Create a random table object of 1 col x 85 rows, using 9 as seed. RanTable rantable = new RanTable(9, 1, 85); // Set the 1st column to start with 1800 and with random delta from -5 to 5. rantable.setCol(0, 1800, -5, 5); // Get the data as the 1st column of the random table double[] data = rantable.getCol(0); // The x-axis labels for the chart string[] labels = { "-", "10am", "-", " ", "-", "12am", "-", " ", "-", "2pm", "-", " ", "-", "4pm", "-" }; // // Now we obtain the data into arrays, we can start to draw the chart using ChartDirector // // Create a XYChart object of size 180 x 180 pixels with a blue background (0x9c9cce) XYChart c = new XYChart(180, 180, 0x9c9cce); // Add titles to the top and bottom of the chart using 7.5pt Arial font. The text is white // 0xffffff on a deep blue 0x31319C background. c.addTitle2(Chart.Top, "STAR TECH INDEX 2003-01-28", "Arial", 7.5, 0xffffff, 0x31319c); c.addTitle2(Chart.Bottom, "LATEST STI:1809.41 (+14.51)", "Arial", 7.5, 0xffffff, 0x31319c); // Set the plotarea at (31, 21) and of size 145 x 124 pixels, with a pale yellow (0xffffc8) // background. c.setPlotArea(31, 21, 145, 124, 0xffffc8); // Add custom text at (176, 21) (top right corner of plotarea) using 11pt Times Bold Italic // font/red (0xc09090) color c.addText(176, 21, "Chart Demo", "Times New Roman Bold Italic", 11, 0xc09090).setAlignment( Chart.TopRight); // Use 7.5pt Arial as the y axis label font c.yAxis().setLabelStyle("", 7.5); // Set the labels on the x axis by spreading the labels evenly between the first point (index // = 0) and the last point (index = noOfPoints - 1) c.xAxis().setLinearScale(0, noOfPoints - 1, labels); // Use 7.5pt Arial as the x axis label font c.xAxis().setLabelStyle("", 7.5); // Add a deep blue (0x000080) line layer to the chart c.addLineLayer(data, 0x000080); // Output the chart viewer.Image = c.makeWebImage(Chart.PNG); // Include tool tip for the chart. The chart starts at 9:30am and each point spans 240 // seconds, so we can compute the time as {x}*240+9.5*3600. viewer.ImageMap = c.getHTMLImageMap("", "", "title='{={x}*240+9.5*3600|h:nna}: {value|2}'"); }
/// <summary> /// Draw the chart. /// </summary> private void drawChart(WinChartViewer viewer) { // // In this demo, we copy the visible part of the data to a separate buffer for chart // plotting. // // Note that if you only have a small amount of data (a few hundred data points), it // may be easier to just plot all data in any case (so the following copying code is // not needed), and let ChartDirector "clip" the chart to the plot area. // // Using ViewPortLeft and ViewPortWidth, get the start and end dates of the view port. DateTime viewPortStartDate = minDate.AddSeconds(Math.Round(viewer.ViewPortLeft * dateRange)); DateTime viewPortEndDate = viewPortStartDate.AddSeconds(Math.Round(viewer.ViewPortWidth * dateRange)); // Get the starting index of the array using the start date int startIndex = Array.BinarySearch(timeStamps, viewPortStartDate); if (startIndex < 0) { startIndex = (~startIndex) - 1; } // Get the ending index of the array using the end date int endIndex = Array.BinarySearch(timeStamps, viewPortEndDate); if (endIndex < 0) { endIndex = ((~endIndex) < timeStamps.Length) ? ~endIndex : timeStamps.Length - 1; } // Get the length int noOfPoints = endIndex - startIndex + 1; // Now, we can just copy the visible data we need into the view port data series DateTime[] viewPortTimeStamps = new DateTime[noOfPoints]; double[] viewPortDataSeriesA = new double[noOfPoints]; double[] viewPortDataSeriesB = new double[noOfPoints]; double[] viewPortDataSeriesC = new double[noOfPoints]; Array.Copy(timeStamps, startIndex, viewPortTimeStamps, 0, noOfPoints); Array.Copy(dataSeriesA, startIndex, viewPortDataSeriesA, 0, noOfPoints); Array.Copy(dataSeriesB, startIndex, viewPortDataSeriesB, 0, noOfPoints); Array.Copy(dataSeriesC, startIndex, viewPortDataSeriesC, 0, noOfPoints); if (viewPortTimeStamps.Length >= 520) { // // Zoomable chart with high zooming ratios often need to plot many thousands of // points when fully zoomed out. However, it is usually not needed to plot more // data points than the resolution of the chart. Plotting too many points may cause // the points and the lines to overlap. So rather than increasing resolution, this // reduces the clarity of the chart. So it is better to aggregate the data first if // there are too many points. // // In our current example, the chart only has 520 pixels in width and is using a 2 // pixel line width. So if there are more than 520 data points, we aggregate the // data using the ChartDirector aggregation utility method. // // If in your real application, you do not have too many data points, you may // remove the following code altogether. // // Set up an aggregator to aggregate the data based on regular sized slots ArrayMath m = new ArrayMath(viewPortTimeStamps); m.selectRegularSpacing(viewPortTimeStamps.Length / 260); // For the timestamps, take the first timestamp on each slot viewPortTimeStamps = m.aggregate(viewPortTimeStamps, Chart.AggregateFirst); // For the data values, aggregate by taking the averages viewPortDataSeriesA = m.aggregate(viewPortDataSeriesA, Chart.AggregateAvg); viewPortDataSeriesB = m.aggregate(viewPortDataSeriesB, Chart.AggregateAvg); viewPortDataSeriesC = m.aggregate(viewPortDataSeriesC, Chart.AggregateAvg); } // // Now we have obtained the data, we can plot the chart. // /////////////////////////////////////////////////////////////////////////////////////// // Step 1 - Configure overall chart appearance. /////////////////////////////////////////////////////////////////////////////////////// // Create an XYChart object 600 x 300 pixels in size, with pale blue (0xf0f0ff) // background, black (000000) border, 1 pixel raised effect, and with a rounded frame. XYChart c = new XYChart(600, 300, 0xf0f0ff, 0, 1); c.setRoundedFrame(Chart.CColor(BackColor)); // Set the plotarea at (52, 60) and of size 520 x 192 pixels. Use white (ffffff) // background. Enable both horizontal and vertical grids by setting their colors to // grey (cccccc). Set clipping mode to clip the data lines to the plot area. c.setPlotArea(52, 60, 520, 192, 0xffffff, -1, -1, 0xcccccc, 0xcccccc); c.setClipping(); // Add a top title to the chart using 15 pts Times New Roman Bold Italic font, with a // light blue (ccccff) background, black (000000) border, and a glass like raised effect. c.addTitle("Zooming and Scrolling Demonstration", "Times New Roman Bold Italic", 15 ).setBackground(0xccccff, 0x0, Chart.glassEffect()); // Add a bottom title to the chart to show the date range of the axis, with a light blue // (ccccff) background. c.addTitle2(Chart.Bottom, "From <*font=Arial Bold Italic*>" + c.formatValue(viewPortStartDate, "{value|mmm dd, yyyy}") + "<*/font*> to <*font=Arial Bold Italic*>" + c.formatValue(viewPortEndDate, "{value|mmm dd, yyyy}") + "<*/font*> (Duration <*font=Arial Bold Italic*>" + Math.Round(viewPortEndDate.Subtract(viewPortStartDate).TotalSeconds / 86400.0) + "<*/font*> days)", "Arial Italic", 10).setBackground(0xccccff); // Add a legend box at the top of the plot area with 9pts Arial Bold font with flow layout. c.addLegend(50, 33, false, "Arial Bold", 9).setBackground(Chart.Transparent, Chart.Transparent); // Set axes width to 2 pixels c.yAxis().setWidth(2); c.xAxis().setWidth(2); // Add a title to the y-axis c.yAxis().setTitle("Price (USD)", "Arial Bold", 9); /////////////////////////////////////////////////////////////////////////////////////// // Step 2 - Add data to chart /////////////////////////////////////////////////////////////////////////////////////// // // In this example, we represent the data by lines. You may modify the code below if // you want to use other representations (areas, scatter plot, etc). // // Add a line layer for the lines, using a line width of 2 pixels Layer layer = c.addLineLayer2(); layer.setLineWidth(2); // Now we add the 3 data series to a line layer, using the color red (ff0000), green // (00cc00) and blue (0000ff) layer.setXData(viewPortTimeStamps); layer.addDataSet(viewPortDataSeriesA, 0xff0000, "Product Alpha"); layer.addDataSet(viewPortDataSeriesB, 0x00cc00, "Product Beta"); layer.addDataSet(viewPortDataSeriesC, 0x0000ff, "Product Gamma"); /////////////////////////////////////////////////////////////////////////////////////// // Step 3 - Set up x-axis scale /////////////////////////////////////////////////////////////////////////////////////// // Set x-axis date scale to the view port date range. c.xAxis().setDateScale(viewPortStartDate, viewPortEndDate); // // In the current demo, the x-axis range can be from a few years to a few days. We can // let ChartDirector auto-determine the date/time format. However, for more beautiful // formatting, we set up several label formats to be applied at different conditions. // // If all ticks are yearly aligned, then we use "yyyy" as the label format. c.xAxis().setFormatCondition("align", 360 * 86400); c.xAxis().setLabelFormat("{value|yyyy}"); // If all ticks are monthly aligned, then we use "mmm yyyy" in bold font as the first // label of a year, and "mmm" for other labels. c.xAxis().setFormatCondition("align", 30 * 86400); c.xAxis().setMultiFormat(Chart.StartOfYearFilter(), "<*font=bold*>{value|mmm yyyy}", Chart.AllPassFilter(), "{value|mmm}"); // If all ticks are daily algined, then we use "mmm dd<*br*>yyyy" in bold font as the // first label of a year, and "mmm dd" in bold font as the first label of a month, and // "dd" for other labels. c.xAxis().setFormatCondition("align", 86400); c.xAxis().setMultiFormat( Chart.StartOfYearFilter(), "<*block,halign=left*><*font=bold*>{value|mmm dd<*br*>yyyy}", Chart.StartOfMonthFilter(), "<*font=bold*>{value|mmm dd}"); c.xAxis().setMultiFormat2(Chart.AllPassFilter(), "{value|dd}"); // For all other cases (sub-daily ticks), use "hh:nn<*br*>mmm dd" for the first label of // a day, and "hh:nn" for other labels. c.xAxis().setFormatCondition("else"); c.xAxis().setMultiFormat(Chart.StartOfDayFilter(), "<*font=bold*>{value|hh:nn<*br*>mmm dd}", Chart.AllPassFilter(), "{value|hh:nn}"); /////////////////////////////////////////////////////////////////////////////////////// // Step 4 - Set up y-axis scale /////////////////////////////////////////////////////////////////////////////////////// if ((viewer.ZoomDirection == WinChartDirection.Horizontal) || (minValue == maxValue)) { // y-axis is auto-scaled - save the chosen y-axis scaled to support xy-zoom mode c.layout(); minValue = c.yAxis().getMinValue(); maxValue = c.yAxis().getMaxValue(); } else { // xy-zoom mode - compute the actual axis scale in the view port double axisLowerLimit = maxValue - (maxValue - minValue) * (viewer.ViewPortTop + viewer.ViewPortHeight); double axisUpperLimit = maxValue - (maxValue - minValue) * viewer.ViewPortTop; // *** use the following formula if you are using a log scale axis *** // double axisLowerLimit = maxValue * Math.Pow(minValue / maxValue, viewer.ViewPortTop + viewer.ViewPortHeight); // double axisUpperLimit = maxValue * Math.Pow(minValue / maxValue, viewer.ViewPortTop); // use the zoomed-in scale c.yAxis().setLinearScale(axisLowerLimit, axisUpperLimit); c.yAxis().setRounding(false, false); } /////////////////////////////////////////////////////////////////////////////////////// // Step 5 - Display the chart /////////////////////////////////////////////////////////////////////////////////////// viewer.Chart = c; }