Hi there,
I’d like to provide some additional methods to help you achieve your goal. I'll walk you through it step by step. You can find the complete code below.
1.- Make the trigger be, instead of a button click, the chart Afterdraw (in my previous reply I was using a click as an example)
Code: Select all
tChart1.AfterDraw += TChart1_AfterDraw; // AfterDraw instead of a click, this way it updates every time a rectangle is drawn
2.- You
can disable the zooming when drawing rectangles through click/move:
Code: Select all
tChart1.Zoom.Direction = Steema.TeeChart.ZoomDirections.None;
Doing so will not draw a rectangle anymore, which won't trigger AfterDraw.
Simply add "tChart1.Invalidate();" after the MouseUp event is done.
Again, this is optional. If zooming doesn't bother you, there's no need for this.
Code: Select all
private void TChart1_MouseUp(object sender, MouseEventArgs e)
{
up = new Point(e.X, e.Y);
tChart1.Invalidate();
}
3.- You can also draw a rectangle that "stays locked" to make clear what zone was selected.
First, declare a rectangle
Then, when tChart1_AfterDraw is called:
Code: Select all
int startX = Math.Min(down.X, up.X);
int endX = Math.Max(down.X, up.X);
int startY = Math.Min(down.Y, up.Y);
int endY = Math.Max(down.Y, up.Y);
rectangle = new Rectangle(startX, startY, endX - startX, endY - startY);
rectangle.Location = new Point(startX, startY);
using (Pen pen = new Pen(Color.Red, 2))
{
tChart1.Chart.Graphics3D.Pen.Color = Color.Red;
tChart1.Chart.Graphics3D.Pen.Width = 1;
tChart1.Graphics3D.Brush.Transparency = 100;
tChart1.Graphics3D.Rectangle(rectangle);
}
4.- Improved the loop functionality and efficiency
First, thanks to this, you can draw rectangles in many directions, not just bottomLeft -> topRight
Code: Select all
double minX = tChart1.Axes.Bottom.CalcPosPoint(startX);
double maxX = tChart1.Axes.Bottom.CalcPosPoint(endX);
double minY = tChart1.Axes.Left.CalcPosPoint(endY);
double maxY = tChart1.Axes.Left.CalcPosPoint(startY);
Then, thanks to properties like myPoints.FirstVisibleIndex and LastvisibleIndex, we can exclude the points that are not shown on screen (maybe you scrolled or zoomed, you don't want to analyze the points that are 100% not selected inside your rectangle)
Also, the condition to check if a point has been selected or not, also improved to work with rectangles drawn in different directions
Code: Select all
List<PointF> pointsInsideRectangle = new List<PointF>();
// Improved loop range, excluding those that don't appear on screen
for (int i = myPoints.FirstVisibleIndex; i <= myPoints.LastVisibleIndex; i++)
{
//Get X & Y values of the point at index i
double xValue = myPoints.XValues[i];
double yValue = myPoints.YValues[i];
if (minX <= xValue
&& maxX >= xValue
&& minY <= yValue
&& maxY >= yValue)
{
//The point x and y is inside the rectangle.
pointsInsideRectangle.Add(new PointF((float)xValue, (float)yValue));
}
}
Finally, an example on how to work with the data obtained:
Code: Select all
//Example (data treatment is up to you)
label1.Text = $"Selected points: {pointsInsideRectangle.Count}";
foreach (PointF p in pointsInsideRectangle)
{
Console.WriteLine($"({p.X},{p.Y})");
}
As promised, here is the full code of the example.
Code: Select all
public partial class Form1 : Form
{
Point down, up;
Points myPoints;
Rectangle rectangle;
public Form1()
{
InitializeComponent();
//Events setup
tChart1.MouseDown += TChart1_MouseDown;
tChart1.MouseUp += TChart1_MouseUp;
tChart1.AfterDraw += TChart1_AfterDraw; // AfterDraw instead of a click, this way it updates every time a rectangle is drawn
//Series setup
myPoints = new Points(tChart1.Chart);
myPoints.FillSampleValues(30);
tChart1.Zoom.Direction = Steema.TeeChart.ZoomDirections.None;
}
private void TChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
int startX = Math.Min(down.X, up.X);
int endX = Math.Max(down.X, up.X);
int startY = Math.Min(down.Y, up.Y);
int endY = Math.Max(down.Y, up.Y);
rectangle = new Rectangle(startX, startY, endX - startX, endY - startY);
rectangle.Location = new Point(startX, startY);
tChart1.Chart.Graphics3D.Pen.Color = Color.Red; // Color
tChart1.Chart.Graphics3D.Pen.Width = 1; // Width
tChart1.Graphics3D.Brush.Transparency = 100; // Make Brush transparent so it doesn't cover the chart
tChart1.Graphics3D.Rectangle(rectangle); // Finally draw rectangle
double minX = tChart1.Axes.Bottom.CalcPosPoint(startX);
double maxX = tChart1.Axes.Bottom.CalcPosPoint(endX);
double minY = tChart1.Axes.Left.CalcPosPoint(endY);
double maxY = tChart1.Axes.Left.CalcPosPoint(startY);
//Example: storing what points(X,Y) are inside the rectangle.
List<PointF> pointsInsideRectangle = new List<PointF>();
// Improved loop range, excluding those that don't appear on screen
for (int i = myPoints.FirstVisibleIndex; i <= myPoints.LastVisibleIndex; i++)
{
//Get X & Y values of the point at index i
double xValue = myPoints.XValues[i];
double yValue = myPoints.YValues[i];
if (minX <= xValue
&& maxX >= xValue
&& minY <= yValue
&& maxY >= yValue)
{
//The point x and y is inside the rectangle.
pointsInsideRectangle.Add(new PointF((float)xValue, (float)yValue));
}
}
//Example (data treatment is up to you)
label1.Text = $"Selected points: {pointsInsideRectangle.Count}";
foreach (PointF p in pointsInsideRectangle)
{
Console.WriteLine($"({p.X},{p.Y})");
}
}
private void TChart1_MouseDown(object sender, MouseEventArgs e)
{
down = new Point(e.X, e.Y);
rectangle = new Rectangle(0,0,0,0); //Optional, not really needed
}
private void TChart1_MouseUp(object sender, MouseEventArgs e)
{
up = new Point(e.X, e.Y);
tChart1.Invalidate();
}
}
And this is how it looks like:
- AreaCapture1.png (40.99 KiB) Viewed 34865 times
If you have any further questions or if there's anything else I can assist you with, please don't hesitate to reach out.
Regards,
Edu