// // Draw the track line with legend // private void crossHair(XYChart c, int mouseX, int mouseY) { //System.Threading.Thread.Sleep(500); // Clear the current dynamic layer and get the DrawArea object to draw on it. DrawArea d = c.initDynamicLayer(); // The plot area object PlotArea plotArea = c.getPlotArea(); // Draw a vertical line and a horizontal line as the cross hair d.vline(plotArea.getTopY(), plotArea.getBottomY(), mouseX, d.dashLineColor(0x000000, 0x0101)); d.hline(plotArea.getLeftX(), plotArea.getRightX(), mouseY, d.dashLineColor(0x000000, 0x0101)); // Draw y-axis label string label = "<*block,bgColor=FFFFDD,margin=3,edgeColor=000000*>" + c.formatValue(c.getYValue( mouseY, c.yAxis()), "{value|P4}") + "<*/*>"; TTFText t = d.text(label, "Arial Bold", 8); t.draw(plotArea.getLeftX() - 5, mouseY, 0x000000, Chart.Right); // Draw x-axis label label = "<*block,bgColor=FFFFDD,margin=3,edgeColor=000000*>" + c.formatValue(c.getXValue(mouseX), "{value|P4}") + "<*/*>"; t = d.text(label, "Arial Bold", 8); t.draw(mouseX, plotArea.getBottomY() + 5, 0x000000, Chart.Top); }
// // Draw the differences between the track lines // void drawTrackDiff(XYChart c, Dictionary <string, double> log0, Dictionary <string, double> log1) { double x0, x1; if (!((null != log0) && log0.TryGetValue("x", out x0) && (null != log1) && log1.TryGetValue("x", out x1))) { return; } // Two columns in the table var leftCol = new System.Text.StringBuilder(); var rightCol = new System.Text.StringBuilder(); leftCol.Append("Change in x: "); rightCol.Append(c.formatValue(x1 - x0, "{value|2}")); // Iterate through all layers to draw the data labels for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { var dataSetName = layer.getDataSet(j).getDataName(); double v0, v1; if (!(log0.TryGetValue(dataSetName, out v0) && log1.TryGetValue(dataSetName, out v1))) { continue; } leftCol.Append("\nChange in ").Append(dataSetName).Append(": "); rightCol.Append("\n").Append(c.formatValue(v1 - v0, "{value|2}")); } } string table = "<*block,bgColor=80ffffff,margin=4*><*block*>" + leftCol.ToString() + "<*/*><*block,halign=right*>" + rightCol.ToString() + "<*/*><*/*>"; TTFText t = c.getDrawArea().text(table, "Arial", 10); t.draw(c.getPlotArea().getRightX() - t.getWidth(), c.getPlotArea().getTopY(), 0x000000); }
// // Draw track line with data labels // private void trackLineLabel(XYChart c, int mouseX) { // Clear the current dynamic layer and get the DrawArea object to draw on it. DrawArea d = c.initDynamicLayer(); // The plot area object PlotArea plotArea = c.getPlotArea(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. double xValue = c.getNearestXValue(mouseX); int xCoor = c.getXCoor(xValue); // Draw a vertical track line at the x-position d.vline(plotArea.getTopY(), plotArea.getBottomY(), xCoor, d.dashLineColor(0x000000, 0x0101)); // Draw a label on the x-axis to show the track line position. string xlabel = "<*font,bgColor=000000*> " + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") + " <*/font*>"; TTFText t = d.text(xlabel, "Arial Bold", 8); // Restrict the x-pixel position of the label to make sure it stays inside the chart image. int xLabelPos = Math.Max(0, Math.Min(xCoor - t.getWidth() / 2, c.getWidth() - t.getWidth())); t.draw(xLabelPos, plotArea.getBottomY() + 6, 0xffffff); // Iterate through all layers to draw the data labels for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // The data array index of the x-value int xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); // Get the color and position of the data label int color = dataSet.getDataColor(); int 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 >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color != Chart.Transparent)) { d.circle(xCoor, yCoor, 4, 4, color, color); string label = "<*font,bgColor=" + color.ToString("x") + "*> " + c.formatValue( dataSet.getValue(xIndex), "{value|P4}") + " <*/font*>"; t = d.text(label, "Arial Bold", 8); // Draw the label on the right side of the dot if the mouse is on the left side the // chart, and vice versa. This ensures the label will not go outside the chart image. if (xCoor <= (plotArea.getLeftX() + plotArea.getRightX()) / 2) { t.draw(xCoor + 5, yCoor, 0xffffff, Chart.Left); } else { t.draw(xCoor - 5, yCoor, 0xffffff, Chart.Right); } } } } }
//Main code for creating chart. //Note: the argument chartIndex is unused because this demo only has 1 chart. public void createChart(WinChartViewer viewer, int chartIndex) { // // This example demonstrates creating a histogram with a bell curve from raw data. About // half of the code is to sort the raw data into slots and to generate the points on the // bell curve. The remaining half of the code is the actual charting code. // // Generate a random guassian distributed data series as the input data for this // example. RanSeries r = new RanSeries(66); double[] samples = r.getGaussianSeries(200, 100, 10); // // Classify the numbers into slots. In this example, the slot width is 5 units. // int slotSize = 5; // Compute the min and max values, and extend them to the slot boundary. ArrayMath m = new ArrayMath(samples); double minX = Math.Floor(m.min() / slotSize) * slotSize; double maxX = Math.Floor(m.max() / slotSize) * slotSize + slotSize; // We can now determine the number of slots int slotCount = (int)((maxX - minX + 0.5) / slotSize); double[] frequency = new double[slotCount]; // Count the data points contained in each slot for (int i = 0; i < samples.Length; ++i) { int slotIndex = (int)((samples[i] - minX) / slotSize); frequency[slotIndex] = frequency[slotIndex] + 1; } // // Compute Normal Distribution Curve // // The mean and standard deviation of the data double mean = m.avg(); double stdDev = m.stdDev(); // The normal distribution curve (bell curve) is a standard statistics curve. We need to // vertically scale it to make it proportion to the frequency count. double scaleFactor = slotSize * samples.Length / stdDev / Math.Sqrt(6.2832); // In this example, we plot the bell curve up to 3 standard deviations. double stdDevWidth = 3.0; // We generate 4 points per standard deviation to be joined with a spline curve. int bellCurveResolution = (int)(stdDevWidth * 4 + 1); double[] bellCurve = new double[bellCurveResolution]; for (int i = 0; i < bellCurveResolution; ++i) { double z = 2 * i * stdDevWidth / (bellCurveResolution - 1) - stdDevWidth; bellCurve[i] = Math.Exp(-z * z / 2) * scaleFactor; } // // At this stage, we have obtained all data and can plot the chart. // // Create a XYChart object of size 600 x 360 pixels XYChart c = new XYChart(600, 360); // Set the plotarea at (50, 30) and of size 500 x 300 pixels, with transparent // background and border and light grey (0xcccccc) horizontal grid lines c.setPlotArea(50, 30, 500, 300, Chart.Transparent, -1, Chart.Transparent, 0xcccccc); // Display the mean and standard deviation on the chart c.addTitle("Mean = " + c.formatValue(mean, "{value|1}") + ", Standard Deviation = " + c.formatValue(stdDev, "{value|2}"), "Arial"); // Set the x and y axis label font to 12pt Arial c.xAxis().setLabelStyle("Arial", 12); c.yAxis().setLabelStyle("Arial", 12); // Set the x and y axis stems to transparent, and the x-axis tick color to grey // (0x888888) c.xAxis().setColors(Chart.Transparent, Chart.TextColor, Chart.TextColor, 0x888888); c.yAxis().setColors(Chart.Transparent); // Draw the bell curve as a spline layer in red (0xdd0000) with 2-pixel line width SplineLayer bellLayer = c.addSplineLayer(bellCurve, 0xdd0000); bellLayer.setXData2(mean - stdDevWidth * stdDev, mean + stdDevWidth * stdDev); bellLayer.setLineWidth(2); // No tooltip is needed for the spline layer bellLayer.setHTMLImageMap("{disable}"); // Draw the histogram as bars in blue (0x6699bb) with dark blue (0x336688) border BarLayer histogramLayer = c.addBarLayer(frequency, 0x6699bb); histogramLayer.setBorderColor(0x336688); // The center of the bars span from minX + half_bar_width to maxX - half_bar_width histogramLayer.setXData2(minX + slotSize / 2.0, maxX - slotSize / 2.0); // Configure the bars to touch each other with no gap in between histogramLayer.setBarGap(Chart.TouchBar); // Use rounded corners for decoration histogramLayer.setRoundedCorners(); // Tool tip for the histogram histogramLayer.setHTMLImageMap("", "", "title='{value}'"); // ChartDirector by default will extend the x-axis scale by 0.5 unit to cater for the // bar width. It is because a bar plotted at x actually occupies (x +/- half_bar_width), // and the bar width is normally 1 for label based x-axis. However, this chart is using // a linear x-axis instead of label based. So we disable the automatic extension and add // a dummy layer to extend the x-axis scale to cover minX to maxX. c.xAxis().setIndent(false); c.addLineLayer2().setXData(minX, maxX); // For the automatic y-axis labels, set the minimum spacing to 40 pixels. c.yAxis().setTickDensity(40); // Output the chart viewer.Chart = c; // Include tool tip for the chart viewer.ImageMap = c.getHTMLImageMap("clickable"); }
// // Draw the track box with legend // private void trackBoxLegend(XYChart c, int mouseX, int mouseY) { // Clear the current dynamic layer and get the DrawArea object to draw on it. DrawArea d = c.initDynamicLayer(); // The plot area object PlotArea plotArea = c.getPlotArea(); // Get the data x-value that is nearest to the mouse double xValue = c.getNearestXValue(mouseX); // Compute the position of the box. This example assumes a label based x-axis, in which the // labeling spacing is one x-axis unit. So the left and right sides of the box is 0.5 unit from // the central x-value. int boxLeft = c.getXCoor(xValue - 0.5); int boxRight = c.getXCoor(xValue + 0.5); int boxTop = plotArea.getTopY(); int boxBottom = plotArea.getBottomY(); // Draw the track box d.rect(boxLeft, boxTop, boxRight, boxBottom, 0x000000, Chart.Transparent); // Container to hold the legend entries ArrayList legendEntries = new ArrayList(); // Iterate through all layers to build the legend array for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // The data array index of the x-value int xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); // Build the legend entry, consist of the legend icon, the name and the data value. double dataValue = dataSet.getValue(xIndex); if ((dataValue != Chart.NoValue) && (dataSet.getDataColor() != Chart.Transparent)) { legendEntries.Add(dataSet.getLegendIcon() + " " + dataSet.getDataName() + ": " + c.formatValue(dataValue, "{value|P4}")); } } } // Create the legend by joining the legend entries if (legendEntries.Count > 0) { legendEntries.Reverse(); string legend = "<*block,bgColor=FFFFCC,edgeColor=000000,margin=5*><*font,underline=1*>" + c.xAxis().getFormattedLabel(xValue) + "<*/font*><*br*>" + String.Join("<*br*>", (string[]) legendEntries.ToArray(typeof(string))) + "<*/*>"; // Display the legend at the bottom-right side of the mouse cursor, and make sure the legend // will not go outside the chart image. TTFText t = d.text(legend, "Arial Bold", 8); t.draw(Math.Min(mouseX + 12, c.getWidth() - t.getWidth()), Math.Min(mouseY + 18, c.getHeight() - t.getHeight()), 0x000000, Chart.TopLeft); } }
// // Draw the chart and display it in the given viewer. // private void drawChart(WPFChartViewer viewer) { // Create an XYChart object 600 x 270 pixels in size, with light grey (f4f4f4) // background, black (000000) border, 1 pixel raised effect, and with a rounded frame. XYChart c = new XYChart(600, 270, 0xf4f4f4, 0x000000, 1); c.setRoundedFrame(0xffffff); // Set the plotarea at (55, 62) and of size 520 x 175 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(55, 62, 520, 175, 0xffffff, -1, -1, 0xcccccc, 0xcccccc); c.setClipping(); // Add a title to the chart using 15 pts Times New Roman Bold Italic font, with a light // grey (dddddd) background, black (000000) border, and a glass like raised effect. c.addTitle("Field Intensity at Observation Satellite", "Times New Roman Bold Italic", 15 ).setBackground(0xdddddd, 0x000000, Chart.glassEffect()); // Add a legend box at the top of the plot area with 9pts Arial Bold font. We set the // legend box to the same width as the plot area and use grid layout (as opposed to // flow or top/down layout). This distributes the 3 legend icons evenly on top of the // plot area. LegendBox b = c.addLegend2(55, 33, 3, "Arial Bold", 9); b.setBackground(Chart.Transparent, Chart.Transparent); b.setWidth(520); // Configure the y-axis with a 10pts Arial Bold axis title c.yAxis().setTitle("Intensity (V/m)", "Arial Bold", 10); // Configure the x-axis to auto-scale with at least 75 pixels between major tick and 15 // pixels between minor ticks. This shows more minor grid lines on the chart. c.xAxis().setTickDensity(75, 15); // Set the axes width to 2 pixels c.xAxis().setWidth(2); c.yAxis().setWidth(2); // Now we add the data to the chart DateTime lastTime = timeStamps[timeStamps.Length - 1]; if (lastTime != DateTime.MinValue) { // Set up the x-axis scale. In this demo, we set the x-axis to show the last 240 // samples, with 250ms per sample. c.xAxis().setDateScale(lastTime.AddSeconds( -dataRateTimer.Interval.TotalSeconds * timeStamps.Length), lastTime); // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); // Create a line layer to plot the lines LineLayer layer = c.addLineLayer2(); // The x-coordinates are the timeStamps. layer.setXData(timeStamps); // The 3 data series are used to draw 3 lines. Here we put the latest data values // as part of the data set name, so you can see them updated in the legend box. layer.addDataSet(dataSeriesA, 0xff0000, "Alpha: <*bgColor=FFCCCC*>" + c.formatValue(dataSeriesA[dataSeriesA.Length - 1], " {value|2} ")); layer.addDataSet(dataSeriesB, 0x00cc00, "Beta: <*bgColor=CCFFCC*>" + c.formatValue(dataSeriesB[dataSeriesB.Length - 1], " {value|2} ")); layer.addDataSet(dataSeriesC, 0x0000ff, "Gamma: <*bgColor=CCCCFF*>" + c.formatValue(dataSeriesC[dataSeriesC.Length - 1], " {value|2} ")); } // Assign the chart to the WinChartViewer viewer.Chart = c; }
// // Draw the track line with legend // private void trackLineLegend(XYChart c, int mouseX) { // Clear the current dynamic layer and get the DrawArea object to draw on it. DrawArea d = c.initDynamicLayer(); // The plot area object PlotArea plotArea = c.getPlotArea(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. double xValue = c.getNearestXValue(mouseX); int xCoor = c.getXCoor(xValue); // Draw a vertical track line at the x-position d.vline(plotArea.getTopY(), plotArea.getBottomY(), xCoor, 0xaaaaaa); // Container to hold the legend entries var legendEntries = new List <string>(); // Iterate through all layers to build the legend array for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // The data array index of the x-value int xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); // We are only interested in visible data sets with names string dataName = dataSet.getDataName(); int color = dataSet.getDataColor(); if ((!string.IsNullOrEmpty(dataName)) && (color != Chart.Transparent)) { // Build the legend entry, consist of the legend icon, name and data value. double dataValue = dataSet.getValue(xIndex); legendEntries.Add("<*block*>" + dataSet.getLegendIcon() + " " + dataName + ": " + (( dataValue == Chart.NoValue) ? "N/A" : c.formatValue(dataValue, "{value|P4}")) + "<*/*>"); // Draw a track dot for data points within the plot area int yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis()); if ((yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY())) { d.circle(xCoor, yCoor, 4, 4, color, color); } } } } // Create the legend by joining the legend entries legendEntries.Reverse(); string legendText = "<*block,maxWidth=" + plotArea.getWidth() + "*><*block*><*font=Arial Bold*>[" + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") + "]<*/*> " + String.Join( " ", legendEntries) + "<*/*>"; // Display the legend on the top of the plot area TTFText t = d.text(legendText, "Arial Bold", 10); t.draw(plotArea.getLeftX() + 5, plotArea.getTopY() - 3, 0x000000, Chart.BottomLeft); }
/// <summary> /// Draw the chart and display it in the given viewer. /// </summary> private void drawChart(WinChartViewer viewer) { // Create an XYChart object 600 x 270 pixels in size, with light grey (f4f4f4) // background, black (000000) border, 1 pixel raised effect, and with a rounded frame. XYChart c = new XYChart(600, 270, 0xf4f4f4, 0x000000, 1); c.setRoundedFrame(Chart.CColor(BackColor)); // Set the plotarea at (55, 62) and of size 520 x 175 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(55, 62, 520, 175, 0xffffff, -1, -1, 0xcccccc, 0xcccccc); c.setClipping(); // Add a title to the chart using 15 pts Times New Roman Bold Italic font, with a light // grey (dddddd) background, black (000000) border, and a glass like raised effect. c.addTitle("Realtime Chart Demonstration", "Times New Roman Bold Italic", 15 ).setBackground(0xdddddd, 0x000000, Chart.glassEffect()); // Add a legend box at the top of the plot area with 9pts Arial Bold font. We set the // legend box to the same width as the plot area and use grid layout (as opposed to // flow or top/down layout). This distributes the 3 legend icons evenly on top of the // plot area. LegendBox b = c.addLegend2(55, 33, 3, "Arial Bold", 9); b.setBackground(Chart.Transparent, Chart.Transparent); b.setWidth(520); // Configure the y-axis with a 10pts Arial Bold axis title c.yAxis().setTitle("Price (USD)", "Arial Bold", 10); // Configure the x-axis to auto-scale with at least 75 pixels between major tick and 15 // pixels between minor ticks. This shows more minor grid lines on the chart. c.xAxis().setTickDensity(75, 15); // Set the axes width to 2 pixels c.xAxis().setWidth(2); c.yAxis().setWidth(2); // Now we add the data to the chart. Access to the data buffer should be synchronized // because the data buffer may be updated by another thread at real time DateTime lastTime = timeStamps[timeStamps.Length - 1]; if (lastTime != DateTime.MinValue) { // Set up the x-axis to show the time range in the data buffer c.xAxis().setDateScale(lastTime.AddSeconds( -dataRateTimer.Interval * timeStamps.Length / 1000), lastTime); // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); // Create a line layer to plot the lines LineLayer layer = c.addLineLayer2(); // The x-coordinates are the timeStamps. layer.setXData(timeStamps); // The 3 data series are used to draw 3 lines. Here we put the latest data // values as part of the data set name, so you can see them updated in the // legend box. layer.addDataSet(dataSeriesA, 0xff0000, "Software: <*bgColor=FFCCCC*>" + c.formatValue(dataSeriesA[dataSeriesA.Length - 1], " {value|2} ")); layer.addDataSet(dataSeriesB, 0x00cc00, "Hardware: <*bgColor=CCFFCC*>" + c.formatValue(dataSeriesB[dataSeriesB.Length - 1], " {value|2} ")); layer.addDataSet(dataSeriesC, 0x0000ff, "Services: <*bgColor=CCCCFF*>" + c.formatValue(dataSeriesC[dataSeriesC.Length - 1], " {value|2} ")); // // To show the capabilities of ChartDirector, we are add a movable threshold // line to the chart and dynamically print a warning message on the chart if // a data value exceeds the threshold // // Add a red mark line to the chart, with the mark label shown at the left of // the mark line. double threshold = (double)alarmThreshold.Value; Mark m = c.yAxis().addMark(threshold, 0xff0000, "Alarm = " + threshold); m.setAlignment(Chart.Left); m.setBackground(0xffcccc); if ((dataSeriesC[dataSeriesC.Length - 1] > threshold) || (dataSeriesB[dataSeriesB.Length - 1] > threshold)) { // Add an alarm message as a custom text box on top-right corner of the // plot area if the latest data value exceeds threshold. c.addText(575, 62, "Alarm - Latest Value Exceeded Threshold", "Arial Bold Italic", 10, 0xffffff, Chart.TopRight).setBackground(0xdd0000); } // Fill the region above the threshold as semi-transparent red (80ff8888) c.addInterLineLayer(layer.getLine(1), m.getLine(), unchecked ((int)0x80ff8888), Chart.Transparent); c.addInterLineLayer(layer.getLine(2), m.getLine(), unchecked ((int)0x80ff8888), Chart.Transparent); } // Set the chart image to the WinChartViewer winChartViewer1.Image = c.makeImage(); }
// // Draw track line with axis labels // private void trackLineAxis(XYChart c, int mouseX) { // Clear the current dynamic layer and get the DrawArea object to draw on it. DrawArea d = c.initDynamicLayer(); // The plot area object PlotArea plotArea = c.getPlotArea(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. double xValue = c.getNearestXValue(mouseX); int xCoor = c.getXCoor(xValue); // The vertical track line is drawn up to the highest data point (the point with smallest // y-coordinate). We need to iterate all datasets in all layers to determine where it is. int minY = plotArea.getBottomY(); // Iterate through all layers to find the highest data point for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // The data array index of the x-value int xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); double dataPoint = dataSet.getPosition(xIndex); if ((dataPoint != Chart.NoValue) && (dataSet.getDataColor() != Chart.Transparent)) { minY = Math.Min(minY, c.getYCoor(dataPoint, dataSet.getUseYAxis())); } } } // Draw a vertical track line at the x-position up to the highest data point. d.vline(Math.Max(minY, plotArea.getTopY()), plotArea.getBottomY() + 6, xCoor, d.dashLineColor( 0x000000, 0x0101)); // Draw a label on the x-axis to show the track line position d.text("<*font,bgColor=000000*> " + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") + " <*/font*>", "Arial Bold", 8).draw(xCoor, plotArea.getBottomY() + 6, 0xffffff, Chart.Top); // Iterate through all layers to build the legend array for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // The data array index of the x-value int xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); // The positional value, axis binding, pixel coordinate and color of the data point. double dataPoint = dataSet.getPosition(xIndex); Axis yAxis = dataSet.getUseYAxis(); int yCoor = c.getYCoor(dataPoint, yAxis); int color = dataSet.getDataColor(); // Draw the axis label only for visible data points of named data sets if ((dataPoint != Chart.NoValue) && (color != Chart.Transparent) && (yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY())) { // The axis label consists of 3 parts - a track dot for the data point, an axis label, // and a line joining the track dot to the axis label. // Draw the line first. The end point of the line at the axis label side depends on // whether the label is at the left or right side of the axis (that is, on whether the // axis is on the left or right side of the plot area). int xPos = yAxis.getX() + ((yAxis.getAlignment() == Chart.Left) ? -4 : 4); d.hline(xCoor, xPos, yCoor, d.dashLineColor(color, 0x0101)); // Draw the track dot d.circle(xCoor, yCoor, 4, 4, color, color); // Draw the axis label. If the axis is on the left side of the plot area, the labels // should right aligned to the axis, and vice versa. d.text("<*font,bgColor=" + color.ToString("x") + "*> " + c.formatValue(dataPoint, "{value|P4}") + " <*/font*>", "Arial Bold", 8).draw(xPos, yCoor, 0xffffff, (( yAxis.getAlignment() == Chart.Left) ? Chart.Right : Chart.Left)); } } } }
// // Draw the chart // 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; } // Create an XYChart object 600 x 320 pixels in size XYChart c = new XYChart(600, 320); // Set the plotarea at (55, 60) and of size 520 x 235 pixels with transparent background and // border. 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(55, 60, 520, 235, -1, -1, Chart.Transparent, 0xcccccc, 0xcccccc); c.setClipping(); // Add a title to the chart using dark grey (0x333333) 20pt Arial Bold font c.addTitle("Realtime Chart with Snapshot", "Arial Bold", 20, 0x333333); // Add a legend box at the top of the plot area using horizontal layout. Use 10pt Arial Bold // font, transparent background and border, and line style legend icon. LegendBox b = c.addLegend(55, 30, false, "Arial Bold", 10); b.setBackground(Chart.Transparent, 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 y-axis title using 12pt Arial font c.yAxis().setTitle("Y-Axis Title Placeholder", "Arial", 12); // For the automatic x and y axis labels, set the minimum spacing to 75 and 30 pixels. c.xAxis().setTickDensity(75); c.yAxis().setTickDensity(30); // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); // Create a line layer to plot the lines LineLayer layer = c.addLineLayer2(); // The x-coordinates are the timeStamps. layer.setXData(timeStamps); // The 3 data series are used to draw 3 lines. Here we put the latest data values as part of // the data set name, so you can see them updated in the legend box. layer.addDataSet(dataSeries1, 0xff0000, c.formatValue(dataSeries1[dataSeries1.Length - 1], "Alpha: {value|2}")); layer.addDataSet(dataSeries2, 0x00cc00, c.formatValue(dataSeries2[dataSeries2.Length - 1], "Beta: {value|2}")); layer.addDataSet(dataSeries3, 0x0000ff, c.formatValue(dataSeries3[dataSeries3.Length - 1], "Gamma: {value|2}")); // Determine the output format if (Request["download"] == "pdf") { viewer.Image = c.makeWebImage(Chart.PDF); } else { viewer.Image = c.makeWebImage(Chart.PNG); } }
// draw track line with data labels private void trackLineLabel(XYChart c, int mouseX) { DrawArea d = c.initDynamicLayer(); PlotArea plotArea = c.getPlotArea(); double xValue = c.getNearestXValue(mouseX); int xCoor = c.getXCoor(xValue); d.vline(plotArea.getTopY(), plotArea.getBottomY(), xCoor, d.dashLineColor(0x000000, 0x0101)); // container to hold the legned entries ArrayList legendEntries = new ArrayList(); for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); int xIndex = layer.getXIndexOf(xValue); // iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); // we are only interested in visibale sets with names string dataName = dataSet.getDataName(); int color = dataSet.getDataColor(); if ((!string.IsNullOrEmpty(dataName)) && (color != Chart.Transparent)) { // Build the legend entry, consist of the legend icon, name and data value. double dataValue = dataSet.getValue(xIndex); legendEntries.Add("<*block*>" + dataSet.getLegendIcon() + " " + dataName + ": " + (( dataValue == Chart.NoValue) ? "N/A" : c.formatValue(dataValue, "{value|P4}")) + "<*/*>"); // Draw a track dot for data points within the plot area int yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis()); if ((yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY())) { d.circle(xCoor, yCoor, 4, 4, color, color); } } } } // Create the legend by joining the legend entries legendEntries.Reverse(); string legendText = "<*block,maxWidth=" + plotArea.getWidth() + "*><*block*><*font=Arial Bold*>[" + c.xAxis().getFormattedLabel(xValue, "{value|P4") + "]<*/*> " + String.Join( " ", (string[])legendEntries.ToArray(typeof(string))) + "<*/*>"; // Display the legend on the top of the plot area TTFText t = d.text(legendText, "Arial", 8); t.draw(plotArea.getLeftX() + 5, plotArea.getTopY() - 3, 0x000000, Chart.BottomLeft); }
/// <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; }
private void DrawChart(RazorChartViewer viewer) { //Currently this has been implemented to skip random amount of records //from the list, because I dont have an live updating database int sampleSize = 250; Random rnd = new Random(); int skip = rnd.Next(1, 10); var data = stripData.Skip(skip).Take(sampleSize).ToList(); double[] dataSeries1 = new double[sampleSize]; double[] dataSeries2 = new double[sampleSize]; double[] dataSeries3 = new double[sampleSize]; DateTime[] timeStamps = new DateTime[sampleSize]; DateTime firstDate = DateTime.Now.AddSeconds(-timeStamps.Length); for (int i = 0; i < timeStamps.Length; ++i) { timeStamps[i] = firstDate.AddSeconds(i); dataSeries1[i] = data[i].FHR1; dataSeries2[i] = data[i].FHR2; dataSeries3[i] = data[i].TOCO1; } XYChart c = new XYChart(1200, 400, 0xf4f4f4, 0x000000, 0); c.setRoundedFrame(); // Set the plotarea at (55, 62) and of size 520 x 175 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(55, 62, 800, 300, 0xffffff, -1, -1, 0xcccccc, 0xcccccc); c.setClipping(); // Add a title to the chart using 15pt Times New Roman Bold Italic font, with a light grey // (dddddd) background, black (000000) border, and a glass like raised effect. c.addTitle("Field Intensity at Observation Satellite", "Times New Roman Bold Italic", 15 ).setBackground(0xdddddd, 0x000000, Chart.glassEffect()); // Add a legend box at the top of the plot area with 9pt Arial Bold font. We set the legend // box to the same width as the plot area and use grid layout (as opposed to flow or top/down // layout). This distributes the 3 legend icons evenly on top of the plot area. LegendBox b = c.addLegend2(55, 33, 3, "Arial Bold", 9); b.setBackground(Chart.Transparent, Chart.Transparent); b.setWidth(520); // Configure the y-axis with a 10pt Arial Bold axis title c.yAxis().setTitle("Intensity (V/m)", "Arial Bold", 10); // Configure the x-axis to auto-scale with at least 75 pixels between major tick and 15 // pixels between minor ticks. This shows more minor grid lines on the chart. c.xAxis().setTickDensity(75, 15); // Set the axes width to 2 pixels c.xAxis().setWidth(2); c.yAxis().setWidth(2); // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); // Create a line layer to plot the lines LineLayer layer = c.addLineLayer2(); // The x-coordinates are the timeStamps. layer.setXData(timeStamps); // The 3 data series are used to draw 3 lines. Here we put the latest data values as part of // the data set name, so you can see them updated in the legend box. layer.addDataSet(dataSeries1, 0xff0000, c.formatValue(dataSeries1[dataSeries1.Length - 1], "Alpha: <*bgColor=FFCCCC*> {value|2} ")); layer.addDataSet(dataSeries2, 0x00cc00, c.formatValue(dataSeries2[dataSeries2.Length - 1], "Beta: <*bgColor=CCFFCC*> {value|2} ")); layer.addDataSet(dataSeries3, 0x0000ff, c.formatValue(dataSeries3[dataSeries3.Length - 1], "Gamma: <*bgColor=CCCCFF*> {value|2} ")); // Output the chart viewer.Image = c.makeWebImage(Chart.PNG); }
// // Draw finance chart track line with legend // private void trackFinance(MultiChart m, int mouseX) { // Clear the current dynamic layer and get the DrawArea object to draw on it. DrawArea d = m.initDynamicLayer(); // It is possible for a FinanceChart to be empty, so we need to check for it. if (m.getChartCount() == 0) { return; } // Get the data x-value that is nearest to the mouse int xValue = (int)(((XYChart)m.getChart(0)).getNearestXValue(mouseX)); // Iterate the XY charts (main price chart and indicator charts) in the FinanceChart XYChart c = null; for (int i = 0; i < m.getChartCount(); ++i) { c = (XYChart)m.getChart(i); // Variables to hold the legend entries string ohlcLegend = ""; ArrayList legendEntries = new ArrayList(); // Iterate through all layers to find the highest data point for (int j = 0; j < c.getLayerCount(); ++j) { Layer layer = c.getLayerByZ(j); int xIndex = layer.getXIndexOf(xValue); int dataSetCount = layer.getDataSetCount(); // In a FinanceChart, only layers showing OHLC data can have 4 data sets if (dataSetCount == 4) { double highValue = layer.getDataSet(0).getValue(xIndex); double lowValue = layer.getDataSet(1).getValue(xIndex); double openValue = layer.getDataSet(2).getValue(xIndex); double closeValue = layer.getDataSet(3).getValue(xIndex); if (closeValue != Chart.NoValue) { // Build the OHLC legend ohlcLegend = "Open: " + c.formatValue(openValue, "{value|P4}") + ", High: " + c.formatValue(highValue, "{value|P4}") + ", Low: " + c.formatValue(lowValue, "{value|P4}") + ", Close: " + c.formatValue(closeValue, "{value|P4}"); // We also draw an upward or downward triangle for up and down days and the % // change double lastCloseValue = layer.getDataSet(3).getValue(xIndex - 1); if (lastCloseValue != Chart.NoValue) { double change = closeValue - lastCloseValue; double percent = change * 100 / closeValue; string symbol = ((change >= 0) ? "<*font,color=008800*><*img=@triangle,width=8,color=008800*>" : "<*font,color=CC0000*><*img=@invertedtriangle,width=8,color=CC0000*>"); ohlcLegend = ohlcLegend + " " + symbol + " " + c.formatValue(change, "{value|P4}") + " (" + c.formatValue(percent, "{value|2}") + "%)<*/font*>" ; } // Use a <*block*> to make sure the line does not wrap within the legend entry ohlcLegend = "<*block*>" + ohlcLegend + " <*/*>"; } } else { // Iterate through all the data sets in the layer for (int k = 0; k < layer.getDataSetCount(); ++k) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(k); string name = dataSet.getDataName(); double value = dataSet.getValue(xIndex); if ((!string.IsNullOrEmpty(name)) && (value != Chart.NoValue)) { // In a FinanceChart, the data set name consists of the indicator name and its // latest value. It is like "Vol: 123M" or "RSI (14): 55.34". As we are // generating the values dynamically, we need to extract the indictor name // out, and also the volume unit (if any). // The unit character, if any, is the last character and must not be a digit. string unitChar = name.Substring(name.Length - 1); if (unitChar.CompareTo("0") >= 0 && unitChar.CompareTo("9") <= 0) { unitChar = ""; } // The indicator name is the part of the name up to the colon character. int delimiterPosition = name.IndexOf(":"); if (delimiterPosition != -1) { name = name.Substring(0, delimiterPosition); } // In a FinanceChart, if there are two data sets, it must be representing a // range. if (dataSetCount == 2) { // We show both values in the range in a single legend entry value = layer.getDataSet(0).getValue(xIndex); double value2 = layer.getDataSet(1).getValue(xIndex); name = name + ": " + c.formatValue(Math.Min(value, value2), "{value|P3}") + " - " + c.formatValue(Math.Max(value, value2), "{value|P3}"); } else { // In a FinanceChart, only the layer for volume bars has 3 data sets for // up/down/flat days if (dataSetCount == 3) { // The actual volume is the sum of the 3 data sets. value = layer.getDataSet(0).getValue(xIndex) + layer.getDataSet(1 ).getValue(xIndex) + layer.getDataSet(2).getValue(xIndex); } // Create the legend entry name = name + ": " + c.formatValue(value, "{value|P3}") + unitChar; } // Build the legend entry, consist of a colored square box and the name (with // the data value in it). legendEntries.Add("<*block*><*img=@square,width=8,edgeColor=000000,color=" + dataSet.getDataColor().ToString("x") + "*> " + name + "<*/*>"); } } } } // Get the plot area position relative to the entire FinanceChart PlotArea plotArea = c.getPlotArea(); int plotAreaLeftX = plotArea.getLeftX() + c.getAbsOffsetX(); int plotAreaTopY = plotArea.getTopY() + c.getAbsOffsetY(); // The legend is formed by concatenating the legend entries. legendEntries.Reverse(); string legendText = String.Join(" ", (string[])legendEntries.ToArray(typeof(string))); // Add the date and the ohlcLegend (if any) at the beginning of the legend legendText = "<*block,valign=top,maxWidth=" + (plotArea.getWidth() - 5) + "*><*font=Arial Bold*>[" + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") + "]<*/font*> " + ohlcLegend + legendText; // Draw a vertical track line at the x-position d.vline(plotAreaTopY, plotAreaTopY + plotArea.getHeight(), c.getXCoor(xValue) + c.getAbsOffsetX(), d.dashLineColor(0x000000, 0x0101)); // Display the legend on the top of the plot area TTFText t = d.text(legendText, "Arial", 8); t.draw(plotAreaLeftX + 5, plotAreaTopY + 3, 0x000000, Chart.TopLeft); } }
void drawTrackLine(XYChart c, int lineX, Dictionary <string, double> log) { // The drawarea and plotarea objects DrawArea d = c.getDrawArea(); PlotArea plotArea = c.getPlotArea(); // Get the data x-value that is nearest to the mouse, and find its pixel coordinate. double xValue = c.getNearestXValue(lineX); int xCoor = c.getXCoor(xValue); // Draw empty track line if it is ahead of the data if ((currentIndex <= 0) || ((xCoor < lineX) && (xValue >= chartTimeLimit))) { d.vline(plotArea.getTopY(), plotArea.getBottomY(), lineX, 0x888888); return; } // Draw a vertical track line at the x-position d.vline(plotArea.getTopY(), plotArea.getBottomY(), xCoor, 0x888888); // Draw a label on the x-axis to show the track line position. string xlabel = "<*font,bgColor=000000*> " + c.xAxis().getFormattedLabel(xValue, "nn:ss.ff") + " <*/font*>"; TTFText t = d.text(xlabel, "Arial Bold", 10); log["x"] = xValue; // Restrict the x-pixel position of the label to make sure it stays inside the chart image. int xLabelPos = Math.Max(0, Math.Min(xCoor - t.getWidth() / 2, c.getWidth() - t.getWidth())); t.draw(xLabelPos, plotArea.getBottomY() + 6, 0xffffff); // Iterate through all layers to draw the data labels for (int i = 0; i < c.getLayerCount(); ++i) { Layer layer = c.getLayerByZ(i); // The data array index of the x-value int xIndex = layer.getXIndexOf(xValue); // Iterate through all the data sets in the layer for (int j = 0; j < layer.getDataSetCount(); ++j) { ChartDirector.DataSet dataSet = layer.getDataSetByZ(j); // Get the color and position of the data label int color = dataSet.getDataColor(); int 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 >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color != Chart.Transparent) && (!string.IsNullOrEmpty(dataSet.getDataName()))) { d.circle(xCoor, yCoor, 4, 4, color, color); string label = "<*font,bgColor=" + color.ToString("x") + "*> " + c.formatValue( dataSet.getValue(xIndex), "{value|P4}") + " <*/font*>"; t = d.text(label, "Arial Bold", 10); log[dataSet.getDataName()] = dataSet.getValue(xIndex); // Draw the label on the right side of the dot if the mouse is on the left side the // chart, and vice versa. This ensures the label will not go outside the chart image. if (xCoor <= (plotArea.getLeftX() + plotArea.getRightX()) / 2) { t.draw(xCoor + 5, yCoor, 0xffffff, Chart.Left); } else { t.draw(xCoor - 5, yCoor, 0xffffff, Chart.Right); } } } } }
//Main code for creating chart. //Note: the argument chartIndex is unused because this demo only has 1 chart. public void createChart(WPFChartViewer viewer, int chartIndex) { // The data for the line chart double[] data0 = { 410, 420, 500, 590 }; double[] data1 = { 500, 370, 680, 850 }; string[] labels = { "Q1", "Q2", "Q3", "Q4" }; // Create a XYChart object of size 600 x 400 pixels XYChart c = new XYChart(600, 400); // Add a title to the chart using 18pt Times Bold Italic font ChartDirector.TextBox title = c.addTitle("Product Line Global Revenue", "Times New Roman Bold Italic", 18); // Tentatively set the plotarea at (50, 55) and of (chart_width - 100) x (chart_height - // 150) pixels in size. Use a vertical gradient color from sky blue (aaccff) t0 light // blue (f9f9ff) as background. Set both horizontal and vertical grid lines to dotted // semi-transprent black (aa000000). PlotArea plotArea = c.setPlotArea(50, 55, c.getWidth() - 100, c.getHeight() - 150, c.linearGradientColor(0, 55, 0, 55 + c.getHeight() - 150, 0xaaccff, 0xf9fcff), -1, -1, c.dashLineColor(unchecked ((int)0xaa000000), Chart.DotLine), -1); // Set y-axis title using 12 points Arial Bold Italic font, and set its position 10 // pixels from the axis. c.yAxis().setTitle("Revenue (USD millions)", "Arial Bold Italic", 12); c.yAxis().setTitlePos(Chart.Left, 10); // Set y-axis label style to 10 points Arial Bold and axis color to transparent c.yAxis().setLabelStyle("Arial Bold", 10); c.yAxis().setColors(Chart.Transparent); // Set y-axis tick density to 30 pixels. ChartDirector auto-scaling will use this as the // guideline when putting ticks on the y-axis. c.yAxis().setTickDensity(30); // Add a bar layer to the chart with side layout BarLayer layer = c.addBarLayer2(Chart.Side); // Add two data sets to the bar layer layer.addDataSet(data0, 0xff6600, "FY 2007"); layer.addDataSet(data1, 0x0088ff, "FY 2008"); // Use soft lighting effect with light direction from the left layer.setBorderColor(Chart.Transparent, Chart.softLighting(Chart.Left)); // Set the x axis labels c.xAxis().setLabels(labels); // Convert the labels on the x-axis to a CDMLTable CDMLTable table = c.xAxis().makeLabelTable(); // Set the default left/right margins to 5 pixels and top/bottom margins to 3 pixels. // Set the default font size to 10 points ChartDirector.TextBox cellStyle = table.getStyle(); cellStyle.setMargin2(5, 5, 4, 3); cellStyle.setFontSize(10); // Set the first row to use Arial Bold font, with a light grey (eeeeee) background. ChartDirector.TextBox firstRowStyle = table.getRowStyle(0); firstRowStyle.setFontStyle("Arial Bold"); firstRowStyle.setBackground(0xeeeeee, Chart.LineColor); // // We can add more information to the table. In this sample code, we add the data series // and the legend icons to the table. // // Add 3 more rows to the table. Set the background of the 2nd row to light grey // (eeeeee). table.appendRow(); table.appendRow().setBackground(0xeeeeee, Chart.LineColor); table.appendRow(); // Put the values of the 2 data series in the first 2 rows. Put the percentage // differences in the 3rd row. for (int i = 0; i < data0.Length; ++i) { table.setText(i, 1, (data0[i]).ToString()); table.setText(i, 2, (data1[i]).ToString()); double percentageDiff = 100.0 * (data1[i] - data0[i]) / data0[i]; // Use red or green color depending on whether the difference is positive or // negative string formatString = "<*color=008800*>+{value|1}%"; if (percentageDiff < 0) { formatString = "<*color=cc0000*>{value|1}%"; } table.setText(i, 3, c.formatValue(percentageDiff, formatString)); } // Insert a column on the left for the legend icons using Arial Bold font. table.insertCol(0).setFontStyle("Arial Bold"); // The top cell is set to transparent, so it is invisible table.getCell(0, 0).setBackground(Chart.Transparent, Chart.Transparent); // The next 2 cells are set to the legend icons and names of the 2 data series table.setText(0, 1, layer.getLegendIcon(0) + " FY 2007"); table.setText(0, 2, layer.getLegendIcon(1) + " FY 2008"); // The last cell is set to "Change" table.setText(0, 3, "Change"); // Append a column on the right for the total values. table.appendCol(); // Put "Total" in the top cell as the heading of this column table.setText(table.getColCount() - 1, 0, "Total"); // The next two cells are the total of the data series double total0 = new ArrayMath(data0).sum(); double total1 = new ArrayMath(data1).sum(); table.setText(table.getColCount() - 1, 1, (total0).ToString()); table.setText(table.getColCount() - 1, 2, (total1).ToString()); // The last cell is the percentage differences of the total double totalPercentageDiff = (total1 - total0) / total0 * 100; // Use red or green color depending on whether the difference is positive or negative string totalFormatString = "<*color=008800*>+{value|1}%"; if (totalPercentageDiff < 0) { totalFormatString = "<*color=cc0000*>{value|1}%"; } table.setText(table.getColCount() - 1, 3, c.formatValue(totalPercentageDiff, totalFormatString)); // // We now demonstrate how to adjust the plot area positions, to allow space for the // newly inserted left and right columns in the table. // // We layout the axis first in order to get the axis metrics (including table metrics) c.layoutAxes(); // If the first column is wider than the left y-axis, we need to reserve for some left // margin to ensure the first column stays within the chart. int leftMargin = 0; if (table.getColWidth(0) > c.yAxis().getThickness()) { leftMargin = table.getColWidth(0) - c.yAxis().getThickness(); } // Similarly, we need to reserve some right margin for the last column int rightMargin = table.getColWidth(table.getColCount() - 1); // Adjust the plot area size, such that the bounding box (inclusive of axes) using the // given left and right margin, plus 2 more pixels. Put the plot area 10 pixels below // the title and use 2 pixels as the bottom margin. from the left, right and bottom // edge, and is just under the legend box. c.packPlotArea(leftMargin + 2, title.getHeight() + 10, c.getWidth() - 3 - rightMargin, c.getHeight() - 3); // After determining the exact plot area position, we may adjust title position so that // it is centered relative to the plot area (instead of the chart) title.setPos(plotArea.getLeftX() + (plotArea.getWidth() - title.getWidth()) / 2, title.getTopY()); // Output the chart viewer.Chart = c; //include tool tip for the chart viewer.ImageMap = c.getHTMLImageMap("clickable", "", "title='Revenue in {xLabel} {dataSetName}: US$ {value}M'"); }
// // Draw the chart // 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; } // Create an XYChart object 600 x 270 pixels in size, with light grey (f4f4f4) background, // black (000000) border, 1 pixel raised effect, and with a rounded frame. XYChart c = new XYChart(600, 270, 0xf4f4f4, 0x000000, 0); c.setRoundedFrame(); // Set the plotarea at (55, 62) and of size 520 x 175 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(55, 62, 520, 175, 0xffffff, -1, -1, 0xcccccc, 0xcccccc); c.setClipping(); // Add a title to the chart using 15pt Times New Roman Bold Italic font, with a light grey // (dddddd) background, black (000000) border, and a glass like raised effect. c.addTitle("Field Intensity at Observation Satellite", "Times New Roman Bold Italic", 15 ).setBackground(0xdddddd, 0x000000, Chart.glassEffect()); // Add a legend box at the top of the plot area with 9pt Arial Bold font. We set the legend // box to the same width as the plot area and use grid layout (as opposed to flow or top/down // layout). This distributes the 3 legend icons evenly on top of the plot area. LegendBox b = c.addLegend2(55, 33, 3, "Arial Bold", 9); b.setBackground(Chart.Transparent, Chart.Transparent); b.setWidth(520); // Configure the y-axis with a 10pt Arial Bold axis title c.yAxis().setTitle("Intensity (V/m)", "Arial Bold", 10); // Configure the x-axis to auto-scale with at least 75 pixels between major tick and 15 // pixels between minor ticks. This shows more minor grid lines on the chart. c.xAxis().setTickDensity(75, 15); // Set the axes width to 2 pixels c.xAxis().setWidth(2); c.yAxis().setWidth(2); // Set the x-axis label format c.xAxis().setLabelFormat("{value|hh:nn:ss}"); // Create a line layer to plot the lines LineLayer layer = c.addLineLayer2(); // The x-coordinates are the timeStamps. layer.setXData(timeStamps); // The 3 data series are used to draw 3 lines. Here we put the latest data values as part of // the data set name, so you can see them updated in the legend box. layer.addDataSet(dataSeries1, 0xff0000, c.formatValue(dataSeries1[dataSeries1.Length - 1], "Alpha: <*bgColor=FFCCCC*> {value|2} ")); layer.addDataSet(dataSeries2, 0x00cc00, c.formatValue(dataSeries2[dataSeries2.Length - 1], "Beta: <*bgColor=CCFFCC*> {value|2} ")); layer.addDataSet(dataSeries3, 0x0000ff, c.formatValue(dataSeries3[dataSeries3.Length - 1], "Gamma: <*bgColor=CCCCFF*> {value|2} ")); // Output the chart viewer.Image = c.makeWebImage(Chart.PNG); }