using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ChartDirector;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private const int sampleSize = 10;
private DateTime[] timeStamps = new DateTime[sampleSize];
private static double counter ;
private double[] counters = new double[sampleSize];
private double[] dataSeriesA = new double[sampleSize];
private double[] dataSeriesB = new double[sampleSize];
private double[] dataSeriesC = new double[sampleSize];
private DateTime nextDataTime = DateTime.Now;
//
// Controls in the form
// *** Automatically generated by Windows Form Designer ***
//
private System.Windows.Forms.Label topLabel;
private System.Windows.Forms.RadioButton runPB;
private System.Windows.Forms.RadioButton freezePB;
private System.Windows.Forms.Label updatePeriodLabel;
private System.Windows.Forms.NumericUpDown samplePeriod;
private System.Windows.Forms.Label alarmThresholdLabel;
private System.Windows.Forms.NumericUpDown alarmThreshold;
private System.Windows.Forms.Label simulatedMachineLabel;
private System.Windows.Forms.Label valueALabel;
private System.Windows.Forms.Label valueA;
private System.Windows.Forms.Label valueBLabel;
private System.Windows.Forms.Label valueB;
private System.Windows.Forms.Label valueCLabel;
private System.Windows.Forms.Label valueC;
private System.Windows.Forms.Panel leftPanel;
private System.Windows.Forms.Label separator;
private ChartDirector.WinChartViewer winChartViewer1;
private System.Windows.Forms.Timer dataRateTimer;
private System.Windows.Forms.Timer chartUpdateTimer;
private System.Windows.Forms.ContextMenu rightClickContextMenu;
private System.Windows.Forms.MenuItem copyMenuItem;
//private System.ComponentModel.IContainer components;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
counter = 0;
// Data generation rate
dataRateTimer.Interval = 20;
// Chart update rate
chartUpdateTimer.Interval = (int)samplePeriod.Value;
// Initialize data buffer. In this demo, we just set the initial state to no data.
/* for (int i = 0; i < timeStamps.Length; ++i)
timeStamps[i] = DateTime.MinValue;*/
/*
for (int i = 0; i < counters.Length; ++i)
counters[i] = i;
*/
// Enable RunPB button
runPB.Checked = true;
// Now can start the timers for data collection and chart update
dataRateTimer.Start();
chartUpdateTimer.Start();
}
private void runPB_CheckedChanged(object sender, System.EventArgs e)
{
// Update the colors of the buttons depends on their states
runPB.BackColor = runPB.Checked ? Color.LightGreen : runPB.Parent.BackColor;
freezePB.BackColor = freezePB.Checked ? Color.LightGreen : freezePB.Parent.BackColor;
// Enable chart update if the Run button is active.
chartUpdateTimer.Enabled = runPB.Checked;
}
/// <summary>
/// Updates the chartUpdateTimer interval if the user selects another interval.
/// </summary>
private void samplePeriod_ValueChanged(object sender, System.EventArgs e)
{
chartUpdateTimer.Interval = (int)samplePeriod.Value;
}
/// <summary>
/// Updates the threshold value if the user modifies the threshold.
/// </summary>
private void alarmThreshold_ValueChanged(object sender, System.EventArgs e)
{
winChartViewer1.updateViewPort(true, false);
}
/// <summary>
/// Handler for Right Click/Copy
/// </summary>
private void copyMenuItem_Click(object sender, System.EventArgs e)
{
// Just copy existing image to the clipboard
Clipboard.SetDataObject(winChartViewer1.Image, true);
}
/// <summary>
/// The data generator - invoke once every 250ms
/// </summary>
private void dataRateTimer_Tick(object sender, System.EventArgs e)
{
//do
{
// This is our formula for the data generator
double p = nextDataTime.Ticks / 10000000.0 * 4;
double dataA = 20 + Math.Cos(p * 129241) * 10 + 1 / (Math.Cos(p) * Math.Cos(p) + 0.01);
double dataB = 150 + 100 * Math.Sin(p / 27.7) * Math.Sin(p / 10.1);
double dataC = 150 + 100 * Math.Cos(p / 6.7) * Math.Cos(p / 11.9);
/* double dataA = 20;
double dataB = 330;
double dataC = 100;
*/
// Now we shift the data into the array
shiftData(dataSeriesA, dataA);
shiftData(dataSeriesB, dataB);
shiftData(dataSeriesC, dataC);
shiftData(counters, counter);
//shiftData(timeStamps, nextDataTime);
counter=counter+1;
// Update nextDataTime
nextDataTime = nextDataTime.AddMilliseconds(dataRateTimer.Interval);
}
// while (nextDataTime < DateTime.Now);
// We provide some visual feedback to the numbers generated, so you can see the
// data being updated.
// valueA.Text = dataSeriesA[dataSeriesA.Length - 1].ToString(".##");
//valueB.Text = dataSeriesB[dataSeriesB.Length - 1].ToString(".##");
//valueC.Text = dataSeriesC[dataSeriesC.Length - 1].ToString(".##");
}
/// <summary>
/// Utility to shift a double value into an array
/// </summary>
private void shiftData(double[] data, double newValue)
{
for (int i = 1; i < data.Length; ++i)
data[i - 1] = data[i];
data[data.Length - 1] = newValue;
}
/// <summary>
/// Utility to shift a DataTime value into an array
/// </summary>
private void shiftData(DateTime[] data, DateTime newValue)
{
for (int i = 1; i < data.Length; ++i)
data[i - 1] = data[i];
data[data.Length - 1] = newValue;
}
/// <summary>
/// The chartUpdateTimer Tick event - this updates the chart periodicially.
/// </summary>
private void chartUpdateTimer_Tick(object sender, System.EventArgs e)
{
winChartViewer1.updateViewPort(true, false);
}
/// <summary>
/// The viewPortChanged event handler.
/// </summary>
private void winChartViewer1_ViewPortChanged(object sender, ChartDirector.WinViewPortEventArgs e)
{
drawChart(winChartViewer1);
}
/// <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}");
// Create a line layer to plot the lines
LineLayer layer = c.addLineLayer2();
// The x-coordinates are the timeStamps.
// layer.setXData(timeStamps);
layer.setXData(counters);
// 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();
}
}
}
|