how to freeze the chart while updating continuously in c# - c#

I am using chart control in my c# application.Using timer updating values in chart at every 1 seconds.Also i enabled scroll bar for the chart , so the scroll bar is keep on adjusting while the values are adding. Actually my requirement is if i drag the scroll bar and hold at any point it has to freeze at that particular point only.It should not adjust when ever i drag and hold the scroll bar at the particular point.How to do that ? Please refer the code below,
int x1=10, x2=10, y1=10, y2=10; //globally declared
private void button1_Click(object sender, EventArgs e) //chart preparation in button click
{
chart1.Series.Clear();
series1.MarkerStyle = MarkerStyle.Circle;
series1.MarkerColor = Color.BlueViolet;
series1.MarkerSize = 7;
series1.Color = System.Drawing.Color.Green;
series1.IsXValueIndexed = true;
series1.YAxisType = AxisType.Primary;
series1.ChartType = SeriesChartType.Line;
this.chart1.Series.Add(series1);
series2.MarkerStyle = MarkerStyle.Circle;
series2.MarkerColor = Color.Orange;
series2.MarkerSize = 7;
series2.Color = System.Drawing.Color.Purple;
series2.IsXValueIndexed = true;
series2.YAxisType = AxisType.Secondary;
series2.ChartType = SeriesChartType.Line;
this.chart1.Series.Add(series2);
chart1.ChartAreas[0].CursorX.AutoScroll = true;
chart1.ChartAreas[0].CursorY.AutoScroll = true;
chart1.ChartAreas[0].AxisX.ScrollBar.Size = 15;
chart1.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;
chart1.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = false;
chart1.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.Series[0].Points.AddXY(x1, y1);
chart1.Series[1].Points.AddXY(x2, y2);
chart1.ChartAreas[0].AxisX.ScaleView.Position = chart1.ChartAreas[0].AxisX.Minimum;// scrollPosition;
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Maximum - nCheck, chart1.ChartAreas[0].AxisX.Maximum);
x1 += 1;
x2 += 1;
nlength++;
if (nlength == 25)
{
nCheck = 30;
chart1.Update();
}
else if (nlength == 50)
nCheck = 50;
timer1.Start();
}
public void createGraph() //called in timer
{
chart1.Series[0].Points.AddXY(x1, y1);
chart1.Series[1].Points.AddXY(x2, y2);
chart1.ChartAreas[0].AxisX.ScaleView.Position = chart1.ChartAreas[0].AxisX.Minimum;// scrollPosition;
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Maximum - nCheck, chart1.ChartAreas[0].AxisX.Maximum);
x1 += 1;
x2 += 1;
nlength++;
if (nlength == 25)
{
nCheck = 30;
chart1.Update();
}
else if(nlength == 50)
nCheck = 50;
}
private void chart1_AxisScrollBarClicked(object sender, ScrollBarEventArgs e)
{
chart1.ChartAreas[0].CursorX.AutoScroll = false;
chart1.ChartAreas[0].CursorY.AutoScroll = false; //here i need to update some code i think so ...
}

As long as the minimum and maximum of an axis is not set, it will auto-adjust to data. Here is an example where a start of user selection fixes the range of x-axis to current view and applies the selection as zoom and frees the axis range again when selection is completed.
double SelectionStartX=0, SelectionEndX=0;
Chart.SelectionRangeChanging += (object sender, CursorEventArgs e) =>
{
//Record selection to be applied as zoom in SelectionRangeChanged event
SelectionStartX = e.ChartArea.CursorX.SelectionStart;
SelectionEndX = e.ChartArea.CursorX.SelectionEnd;
//Stop motion - Fix x-axis range to width of view
e.Axis.Maximum = e.Axis.ScaleView.ViewMaximum;
e.Axis.Minimum = e.Axis.ScaleView.ViewMinimum;
};
Chart.SelectionRangeChanged += (object sender, CursorEventArgs e) =>
{
//Reset previous zooming and apply only last user selected range
if (e.Axis.ScaleView.IsZoomed)
{
e.Axis.ScaleView.ZoomReset();
e.Axis.ScaleView.Zoom(SelectionStartX, SelectionEndX);
}
//Continue motion - Make chart adaptive to data range
e.Axis.Minimum = double.NaN;
e.Axis.Maximum = double.NaN;
};

Related

how to determine the mouse pointer is on tablelayoutpanel cell border c#

I have TableLayoutPanel on windows form. I want mouse pointer cursor style is cross when the pointer on/near the cell border.
Edit I tried with mouse move event. I get the cell positions where the mouse point is moving.But I couldn't use this information and I was stuck. How can achieve that?
Edit: I fixed the problem. It is about size type. The code is working. I'm sharing it for those who have similar demands. Thanx.
bool calcCells = false;
List<float> XCoordinates = new List<float>();
List<float> YCoordinates = new List<float>();
public Form3()
{
InitializeComponent();
// Set the DoubleBuffered property via reflection (if needed)
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
tlp1.GetType().GetProperty("DoubleBuffered", flags).SetValue(tlp1, true);
tlp1.Layout += tlp1_Layout;
tlp1.CellPaint += tlp1_CellPaint;
tlp1.MouseMove += tlp1_MouseMove;
}
// Added the x coordinates of cell borders in a List
private void CreateXCoordinateList()
{
XCoordinates.Clear();
// first and last column sizetype is SizeType.Absoulute.
float tlpWidth = tlp1.Width- tlp1.ColumnStyles[0].Width - tlp1.ColumnStyles[tlp1.ColumnCount-1].Width;
float x = 0;
for (int i = 0; i < tlp1.ColumnCount; i++)
{
if(tlp1.ColumnStyles[i].SizeType==SizeType.Absolute)
x += tlp1.ColumnStyles[i].Width;
else if(tlp1.ColumnStyles[i].SizeType == SizeType.Percent)
{
double k = tlpWidth * tlp1.ColumnStyles[i].Width * 0.01;
x += Convert.ToSingle(k);
}
XCoordinates.Add(x);
}
}
// Added the y coordinates of cell borders in a List
private void CreateYCoordinateList()
{
YCoordinates.Clear();
// first and last row sizetype is SizeType.Absoulute.
float tlpHeight = tlp1.Height - tlp1.RowStyles[0].Height - tlp1.RowStyles[tlp1.RowCount - 1].Height;
float y = 0;
for (int i = 0; i < tlp1.RowCount; i++)
{
if (tlp1.RowStyles[i].SizeType == SizeType.Absolute)
y += tlp1.RowStyles[i].Height;
else if (tlp1.RowStyles[i].SizeType == SizeType.Percent)
{
double k = tlpHeight * tlp1.RowStyles[i].Height*0.01;
y += Convert.ToSingle(k);
}
YCoordinates.Add(y);
}
}
private void tlp1_Layout(object sender, LayoutEventArgs e) => calcCells = true;
private void tlp1_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
if (calcCells)
{
CreateXCoordinateList();
CreateYCoordinateList();
if (e.Column == tlp1.ColumnCount - 1 &&
e.Row == tlp1.RowCount - 1)
calcCells = false;
}
}
private void tlp1_MouseMove(object sender, MouseEventArgs e)
{
//Comparing the mouse pointer position with the cellborder coordinates,
//if the difference is less than and equal to 4, change the cursor style.
float x = e.Location.X;
float y = e.Location.Y;
if (MouseNearCellBorderXAxis(e) || MouseNearCellBorderYAxis(e))
tlp1.Cursor = Cursors.Cross;
else
tlp1.Cursor = Cursors.Default;
}
private bool MouseNearCellBorderXAxis(MouseEventArgs e)
{
float x = e.Location.X;
for (int i = 0; i < XCoordinates.Count; i++)
{
float Border = XCoordinates[i];
double difference = Math.Abs(x - Border);
if (difference <= 4)
return true;
}
return false;
}
private bool MouseNearCellBorderYAxis(MouseEventArgs e)
{
float y = e.Location.Y;
for (int i = 0; i < YCoordinates.Count; i++)
{
float Border = YCoordinates[i];
double difference = Math.Abs(y - Border);
if (difference <= 4)
return true;
}
return false;
}
If I get what you're asking, provided you have controls in the cells of the TableLayoutPanel all one would have to do is set the different cursors one time for:
Main form (Arrow)
Table layout panel (Cross)
The controls therein contained (e.g. Hand)
Everything else should happen on its own.
public MainForm()
{
InitializeComponent();
// MainForm has ARROW
this.Cursor = Cursors.Arrow;
// TableLayoutPanel has CROSS
tableLayoutPanel.Cursor = Cursors.Cross;
int key = 0; string text;
for (int column = 0; column < tableLayoutPanel.ColumnCount; column++)
for (int row = 0; row < tableLayoutPanel.RowCount; row++)
{
switch (++key)
{
case 10: text = "*"; break;
case 11: text = "0"; break;
case 12: text = "#"; break;
default: text = $"{key}"; break;
}
tableLayoutPanel.Controls.Add(new Label
{
BackColor = Color.LightGreen,
Anchor = (AnchorStyles)0xF,
Margin = new Padding(10),
Text = text,
TextAlign = ContentAlignment.MiddleCenter,
// Controls in the table have HAND
Cursor = Cursors.Hand,
});
}
}

C# fix chart size

I'm creating an application which plots data from a serial port. My problem is that sometimes chart size increases when values go below the X axis and, as a result, some values on X axis disappear.
I've set min and max Y axis value, so I wonder how it is possible for the horizontal axis to moves gently downward for a while and then disappear - possibly due to a lack of space?.
It occurs only for first and last label, and sometimes the last grid line disappears too.
Here is piece of code which generate chart values:
int minStress = -200, maxStress=200;
double maxTime=20.0, minTime=0.0;
private void timer1_Tick(object sender, EventArgs e)
{
Stress = serialPort1.ReadLine();
label6.Text = Stress;
StressChart.ChartAreas[0].AxisX.Minimum = minTime;
StressChart.ChartAreas[0].AxisX.Maximum = maxTime;
StressChart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
StressChart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
this.StressChart.Series[0].Points.AddXY((minTime + maxTime) / 2, Stress);
minTime=minTime + TimerInt_2/1000;
maxTime=maxTime + TimerInt_2/1000;
serialPort1.DiscardInBuffer();
}
private void cmbTimerInt_SelectedIndexChanged(object sender, EventArgs e)
{
TimerInt = int.Parse(cmbTimerInt.Text);
TimerInt_2=double.Parse(cmbTimerInt.Text);
timer1.Interval = TimerInt;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
try
{
minStress = int.Parse(textBox1.Text);
}
catch { }
if (minStress < maxStress)
{
StressChart.ChartAreas[0].AxisY.Minimum = minStress;
}
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
try
{
maxStress = int.Parse(textBox2.Text);
}
catch { }
if (maxStress > minStress)
{
StressChart.ChartAreas[0].AxisY.Maximum = maxStress;
}
}
Here is code which sets chart properties:
chartArea1.AxisX.LabelStyle.Format = "0.0";
chartArea1.Name = "ChartArea1";
this.StressChart.ChartAreas.Add(chartArea1);
legend1.Name = "Legend1";
this.StressChart.Legends.Add(legend1);
this.StressChart.Location = new System.Drawing.Point(225, 12);
this.StressChart.Name = "StressChart";
series1.ChartArea = "ChartArea1";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline;
series1.Legend = "Legend1";
series1.Name = "Series1";
this.StressChart.Series.Add(series1);
this.StressChart.Size = new System.Drawing.Size(1175, 426);
this.StressChart.TabIndex = 5;
this.StressChart.Text = "chart1";
chartArea1.AxisX.LabelAutoFitStyle = 0;
chartArea1.AxisY.LabelAutoFitStyle = 0;
chartArea1.AxisX.MajorTickMark.Size = 0;
chartArea1.AxisX.IsMarginVisible = true;
chartArea1.AxisY.IsMarginVisible = true;
The reason of such behaviour was decimal places number of X axis labels. Solution is to round these values down to one decimal place.
minTime = Math.Round(minTime,1) + Math.Round(TimerInt_2/1000,1);
maxTime = Math.Round(maxTime,1) + Math.Round(TimerInt_2/1000,1);

How to draw moving axis table

I'm trying to draw an axis table (x-y) in WPF from code-behind; and I want to give it drag and drop option which can see more of the axis table.
I had created static axis but I don't know how to create a dynamic one?
Can anybody help me with this stuff ?
Thanks.
for (int i = 10; i < 400; i+=10)
{
Line a = new Line();
a.X1 = 0;
a.Y1 = i;
a.X2 = canGraph.Width;
a.Y2 = a.Y1;
a.Stroke = System.Windows.Media.Brushes.Black;
a.StrokeThickness = 0.5;
canGraph.Children.Add(a);
Line b = new Line();
b.X1 = i;
b.Y1 = 0;
b.X2 = i;
b.Y2 = canGraph.Height;
b.Stroke = System.Windows.Media.Brushes.Black;
b.StrokeThickness = 0.5;
canGraph.Children.Add(b);
if (i % 50 == 0)
{
a.StrokeThickness = 1;
b.StrokeThickness = 1;
}
if (i == 200)
{
a.StrokeThickness = 2;
b.StrokeThickness = 2;
}
}
This should get you started. Add event handler(s) to your main axis and canGraph -
...
if (i == 200)
{
a.StrokeThickness = 2;
b.StrokeThickness = 2;
a.MouseLeftButtonDown += A_MouseLeftButtonDown;
}
}
canGraph.MouseLeftButtonUp += CanGraph_MouseLeftButtonUp;
canGraph.MouseMove += CanGraph_MouseMove;
Add following methods -
Line _selectedAxis = null;
private void CanGraph_MouseMove(object sender, MouseEventArgs e)
{
if (_selectedAxis != null)
{
var line = _selectedAxis;
var pos = e.GetPosition(line);
textBlock.Text = $"({pos.X}, {pos.Y})";
line.Y1 = pos.Y;
line.Y2 = pos.Y;
}
}
private void CanGraph_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_selectedAxis = null;
}
private void A_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var line = sender as Line;
_selectedAxis = line;
}
Now hold you main horizontal axis and drag it.
You can do the same for vertical axis as well.
For Zooming
Initialize canGraph.RenderTransform with ScaleTransform and subscribe to MouseWheel event. Note RenderTransformOrigin is set to (0.5, 0.5) to zoom from center instead of top left (default) -
canGraph.RenderTransformOrigin = new Point(0.5, 0.5);
canGraph.RenderTransform = new ScaleTransform();
canGraph.MouseWheel += CanGraph_MouseWheel;
And the function -
private void CanGraph_MouseWheel(object sender, MouseWheelEventArgs e)
{
var transform = canGraph.RenderTransform as ScaleTransform;
var factor = transform.ScaleX;
factor += (e.Delta > 0 ? 1 : (factor == 1 ? 0 : -1));
transform.ScaleX = factor;
transform.ScaleY = factor;
}
I'm guessing you have added Line type object to draw axes, then gave it to window content.
Then just add events, like MouseLeftButtonDown event, or MouseMove event.Add appropriate methods.
Change your object positions on MouseMove event, like:
(For a certain line)
private void MouseMoveMethod(object sender, MouseEventArgs e)
{
var obj = sender as Line;
obj.X1 = e.GetPosition(this).X; //Line start x coordinate
obj.Y1 = e.GetPosition(this).Y; //Line start y coordinate
...
}

MS Chart - updating X axis tick values at run time in line chart

My requirement is in my line graph( which is developed with c# MS Chart), I
always need to display 10 points(samples) at a time. The xaxis has interval value 1.
Initially the Xaxis tick values are (1,2,3,4,5,6,7,8,9,10), After 1 second of time interval, I
have to plot 10 points(samples) starts from 2nd point(i.e. I have to skip 1st
point).Now I need to update the xaxis tick values also , it should be starts from
2,now the xaxis tick values should be like 2,3,4,5,6,7,8,9,10,11). Likewise
After every second the starting value of x axis
tick needs to be increased by 1.
How to update Xaxis tick value in the chart dynamically ?
I am using below code
private void Form1_Load(object sender, EventArgs e)
{
loadCsvFile("C:\\mydata.csv");
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.timer1 = new System.Windows.Forms.Timer(this.components);
chart = new System.Windows.Forms.DataVisualization.Charting.Chart();
chart.Location = new System.Drawing.Point(1, 1);
chart.Size = new System.Drawing.Size(700, 700);
// Add a chartarea called "draw", add axes to it and color the area black
chart.ChartAreas.Add("draw");
numofSamples = 10;
chart.ChartAreas["draw"].AxisX.Minimum = 1;
chart.ChartAreas["draw"].AxisX.Maximum = 10;
chart.ChartAreas["draw"].AxisX.Interval = 1;
chart.ChartAreas["draw"].AxisX.Title = "X Axis";
chart.ChartAreas["draw"].AxisX.MajorGrid.LineColor = System.Drawing.Color.Black;
chart.ChartAreas["draw"].AxisX.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["draw"].AxisY.Minimum = 0;
chart.ChartAreas["draw"].AxisY.Maximum = 1000;
chart.ChartAreas["draw"].AxisY.Interval = 250;
chart.ChartAreas["draw"].AxisY.Title = "Y Axis";
chart.ChartAreas["draw"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["draw"].BackColor = Color.White;
// Create a new function series
chart.Series.Add("Tags");
// Set the type to line
chart.Series["Tags"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
// Color the line of the graph light green and give it a thickness of 3
chart.Series["Tags"].Color = Color.LightGreen;
chart.Series["Tags"].BorderWidth = 3;
chart.Series["Tags"].MarkerStyle = MarkerStyle.Circle;
chart.Series["Tags"].MarkerSize = 10;
chart.Legends.Add("MyLegend");
chart.Legends["MyLegend"].BorderColor = Color.Tomato; // I like tomato juice!
Controls.Add(this.chart);
// hook up timer event
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Start();
}
public void loadCsvFile(string filePath)
{
var reader = new StreamReader(File.OpenRead(filePath));
while (!reader.EndOfStream)
{
List<string> listA = new List<string>();
string line = reader.ReadLine();
mList.Add(line );
}
}
int i = 0;
int n = 0;
private void timer1_Tick(object sender, EventArgs e)
{
if (n > 20)
n = 0;
int j=0;
chart.Series["Tags"].Points.Clear();
for (i=n; i < mList.Count; i++)
{
string l =mList[i];
chart.Series["Tags"].Points.AddY(l);
j++;
if (j == 10)
break;
}
n++;
chart.Update();
}
List<List<string>> mList = new List<List<string>>();

Timer Background transition

I was trying to have my Form's background change when I press a button with a transition.
I figured the most simple and fast way to do this would be to put a white panel over my Form, with a blank backcolor, and to change its alpha component from 0 to 250 then from 250 to 0 when I click the button.
When alpha reaches its maximum value, I want to change the background image.
This technique worked like an hour ago, but now the color does not change at all, and my code is not entirely executed.
Here's the function that is called by the Timer :
private void ChangeIndex(object sender, EventArgs e)
{
if (progressBar.Value == progressBar.Maximum-progressBar.Step)
{
t.Stop();
btnDébut.Enabled = true;
btnFin.Enabled = true;
btnPrécédent.Enabled = true;
btnSuivant.Enabled = true;
if (indiceCourant >= dt.Rows.Count)
{
this.indiceCourant = 0;
}
lblChargement.Visible = false;
progressBar.Visible = false;
RemplitChamps(indiceCourant);
}
progressBar.Step = 10;
progressBar.Maximum = 200;
progressBar.PerformStep();
MessageBox.Show(progressBar.Value.ToString() + " " + pnlFondEcran.BackColor.A.ToString() + " " + progressBar.Maximum.ToString());
if(progressBar.Value <100)
{
this.pnlFondEcran.BackColor = System.Drawing.Color.FromArgb(pnlFondEcran.BackColor.A + progressBar.Maximum/progressBar.Step,255, 255,255);
// i wanna add 24 each time, until alpha=240
}
else
{
MessageBox.Show("error");
this.pnlFondEcran.BackColor = System.Drawing.Color.FromArgb(pnlFondEcran.BackColor.A -progressBar.Maximum / progressBar.Step, 255, 255, 255);
//then substract 24 each time
}
}
The Panel's name is pnlFondEcran.
The progressbar works fine.
The MessageBox.Show(some stuff )'s ouptpur is 0,20,40... to 200, 0, 200.
The progressBar.Value<100 statement is never evaluated until the first last time the function is called, I have no idea why.
Here's the method calling ChangeIndex() :
private void DebutTimer()//lance le timer pour la progressbar
{
lblChargement.Visible = true;
progressBar.Visible = true;
progressBar.Value = 0;
//gestion du timer
t = new System.Windows.Forms.Timer();
t.Interval = 150;
t.Enabled = true;
t.Tick += new EventHandler(ChangeIndex);
t.Start();
//gestion des boutons
btnDébut.Enabled = false;
btnFin.Enabled = false;
btnPrécédent.Enabled = false;
btnSuivant.Enabled = false;
}

Categories