I want to know the area capture information.
-
- Newbie
- Posts: 9
- Joined: Fri Oct 22, 2021 12:00 am
I want to know the area capture information.
Hi, I have a question about T-chart.(Steema TeeChart for .NET Source Code 2023 4.2023.06.14 (.NET8 Compile))
While dragging and specifing some points(series) in chart, I need to get (x,y) points value in dragged area.
Is there any function or a way that I can use for it?
If so, plz let me know.(With example would be the best)
Thank you.
While dragging and specifing some points(series) in chart, I need to get (x,y) points value in dragged area.
Is there any function or a way that I can use for it?
If so, plz let me know.(With example would be the best)
Thank you.
Re: I want to know the area capture information.
Hello,
There are multiple ways to achieve this. I'll show you an example.
First, declare two Points, for example, "up" and "down".
Then, through these events we can give values to those points.
I made the trigger be a button-click, but you can do it however you need.
Like so:
Please note that I'm only demonstrating how to display the number of selected points and outputting this to the console. You should handle your data in whatever way best suits your needs.
Additionally, when getting my "xMin, xMax, yMin, yMax", I am assuming I will always draw the rectangle (mouse down, mouse up) the same way: from bottom left to top right. If you plan to drag a rectangle in different ways, you may want to improve how you decide which value is which (x max, x min.. etc) to avoid possible errors. For example:
If you need any further assistance, if the example wasn't clear enough, or if you notice any errors or mistakes, please don't hesitate to reach out.
Regards,
Edu
There are multiple ways to achieve this. I'll show you an example.
First, declare two Points, for example, "up" and "down".
Code: Select all
Point down, up;
Code: Select all
tChart1.MouseDown += TChart1_MouseDown;
tChart1.MouseUp += TChart1_MouseUp;
Code: Select all
private void TChart1_MouseDown(object sender, MouseEventArgs e)
{
down = new Point(e.X, e.Y);
}
private void TChart1_MouseUp(object sender, MouseEventArgs e)
{
up = new Point(e.X, e.Y);
}
Like so:
Code: Select all
private void button1_Click(object sender, EventArgs e)
{
double xMin = tChart1.Axes.Bottom.CalcPosPoint(down.X);
double xMax = tChart1.Axes.Bottom.CalcPosPoint(up.X);
double yMin = tChart1.Axes.Left.CalcPosPoint(down.Y);
double yMax = tChart1.Axes.Left.CalcPosPoint(up.Y);
//Example: storing what points(X,Y) are inside the rectangle.
List<PointF> points = new List<PointF>();
for (int i = 0; i< myPoints.Count; i++)
{
double x = myPoints.XValues[i];
double y = myPoints.YValues[i];
if (x >= xMin && x <= xMax && y >= yMin && y <= yMax)
{
//The point x and y is inside the rectangle.
points.Add(new PointF((float)x,(float)y));
}
}
//Example
label1.Text = $"Selected points: {points.Count}";
foreach (PointF p in points)
{
Console.WriteLine($"({p.X},{p.Y})");
}
}
Additionally, when getting my "xMin, xMax, yMin, yMax", I am assuming I will always draw the rectangle (mouse down, mouse up) the same way: from bottom left to top right. If you plan to drag a rectangle in different ways, you may want to improve how you decide which value is which (x max, x min.. etc) to avoid possible errors. For example:
Code: Select all
private void Alternative()
{
double xMin, xMax, yMin, yMax;
if (tChart1.Axes.Bottom.CalcPosPoint(down.X) > tChart1.Axes.Bottom.CalcPosPoint(up.X))
{
xMin = tChart1.Axes.Bottom.CalcPosPoint(down.X);
xMax = tChart1.Axes.Bottom.CalcPosPoint(up.X);
}
else
{
xMin = tChart1.Axes.Bottom.CalcPosPoint(up.X);
xMax = tChart1.Axes.Bottom.CalcPosPoint(down.X);
}
// Then do the same with Y ...
}
Regards,
Edu
Edu
Steema Support
Steema Support
Re: I want to know the area capture information.
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)
2.- You can disable the zooming when drawing rectangles through click/move:
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.
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:
4.- Improved the loop functionality and efficiency
First, thanks to this, you can draw rectangles in many directions, not just bottomLeft -> topRight
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
Finally, an example on how to work with the data obtained:
As promised, here is the full code of the example.
And this is how it looks like:
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
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
Code: Select all
tChart1.Zoom.Direction = Steema.TeeChart.ZoomDirections.None;
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();
}
First, declare a rectangle
Code: Select all
Rectangle rectangle;
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);
}
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);
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));
}
}
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();
}
}
Regards,
Edu
Edu
Steema Support
Steema Support
-
- Newbie
- Posts: 9
- Joined: Fri Oct 22, 2021 12:00 am
Re: I want to know the area capture information.
I'm sorry I didn't tell you in advance. My environment is wpf and c#.net8.
private void TChart1_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
up= new System.Drawing.Point(e.X); // An error occurs in the e.X part.
}
private void TChart1_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
up= new System.Drawing.Point(e.X); // An error occurs in the e.X part.
}
Re: I want to know the area capture information.
Hello,
Don't worry! The difference isn't really that big.
Things to note:
1.- The point constructor for WPF takes two doubles
2.- When dealing with MouseButtonEventArgs, we can't use e.X or e.Y.
>> Instead, we can use e.GetPosition((UIElement)sender
For example:
3.- When getting the values for startX, endX, startY and endY, since we get those from a Point, now we have to add a cast to int
4.- If you wanted to create a visible Rectangle (like I showed before), the method is a bit different too:
Everything else is pretty much exactly as in the examples I mentioned above.
If there's anything else I can help you with, please let me know.
Regards,
Edu
Don't worry! The difference isn't really that big.
Things to note:
1.- The point constructor for WPF takes two doubles
2.- When dealing with MouseButtonEventArgs, we can't use e.X or e.Y.
>> Instead, we can use e.GetPosition((UIElement)sender
For example:
Code: Select all
private void TChart1_MouseDown1(object sender, MouseButtonEventArgs e)
{
down = e.GetPosition((UIElement)sender);
}
private void TChart1_MouseUp(object sender, MouseButtonEventArgs e)
{
up = e.GetPosition((UIElement)sender);
tChart1.Invalidate();
}
Code: Select all
int startX = (int)Math.Min(down.X, up.X);
int endX = (int)Math.Max(down.X, up.X);
int startY = (int)Math.Min(down.Y, up.Y);
int endY = (int)Math.Max(down.Y, up.Y);
Code: Select all
//(inside TChart1_AfterDraw(object sender, IGraphcis3D g)
g.Pen.Color = System.Drawing.Color.Blue; // How to change color
g.Brush.Transparency = 100; // Transparency so it doesn't block vision
g.Rectangle(startX, startY, endX, endY); // Draw rectangle
If there's anything else I can help you with, please let me know.
Regards,
Edu
Edu
Steema Support
Steema Support
-
- Newbie
- Posts: 9
- Joined: Fri Oct 22, 2021 12:00 am
Re: I want to know the area capture information.
Thank you for your response.
When I tested the sample, I had some additional inquiries.
How do I erase the square?
function does not have a clear option.
I only want to highlight some points in the series included in the square and try to redraw the chart.
Is it possible to refresh only the corresponding points or series from a large amount of data?
Thanks
When I tested the sample, I had some additional inquiries.
How do I erase the square?
function does not have a clear option.
I only want to highlight some points in the series included in the square and try to redraw the chart.
Is it possible to refresh only the corresponding points or series from a large amount of data?
Thanks
Re: I want to know the area capture information.
Hello again,
Made a showcase for you: In this example, I want to have a button that erases the rectangle after I click it
Please note that this is a basic example to demonstrate how you can control the flow of your program. You have the flexibility to trigger actions using various methods, such as key presses, different conditions, or other input mechanisms beyond a simple boolean check. The specific approach you choose will depend on how you want your program to behave and the user experience you envision. Feel free to explore and implement the method that best suits your needs.
1.- Setting up series
2.- Inside the loop in the afterdraw function, add the values to our new highlighted series
3.- inside a button or after drawing a rectangle or wherever you want, make the first series invisible.
Keep in mind that if you use this approach, you'll have to empty the highlightedSeries after every other area selection, or else you'd be carrying over values from your previous select.
Also note that if you make the first series invisible, the chart will automatically move its axes to fit the new data points, making your square be "in the wrong place". To solve this issue, you can use properties like the following to lock in place your chart
Other approaches: You could even have a secondary tChart, which would be empty at first and then you could add the points highlighted on the main tChart.
There are many ways to implement these features, and the best approach will ultimately depend on your specific needs and preferences. I wanted to provide you with a few options to consider, but feel free to explore and choose the one that works best for you.
If there's anything else I can assist you with, or if you'd like to explore other approaches, please don't hesitate to let me know!
Regards,
Edu
You can always use g.Rectangle again to erase the previous rectangle. If your values are 0,0,0,0 the rectangle will be invisible (so basically erasing the previous one)When I tested the sample, I had some additional inquiries.
How do I erase the square?
function does not have a clear option.
Made a showcase for you: In this example, I want to have a button that erases the rectangle after I click it
Code: Select all
bool shouldRectangleBeDeleted = false;
private void button_Click(object sender, RoutedEventArgs e)
{
shouldRectangleBeDeleted = true;
tChart1.Invalidate();
}
private void TChart1_AfterDraw(object sender, IGraphics3D g)
{
int startX = (int)Math.Min(down.X, up.X);
int endX = (int)Math.Max(down.X, up.X);
int startY = (int)Math.Min(down.Y, up.Y);
int endY = (int)Math.Max(down.Y, up.Y);
g.Brush.Transparency = 100;
g.Pen.Color = System.Drawing.Color.Blue;
if (shouldRectangleBeDeleted)
{
g.Rectangle(0, 0, 0, 0); // inviisble rectangle
shouldRectangleBeDeleted = false; // reset boolean check after erasing
}
else
g.Rectangle(startX, startY, endX, endY);
}
You can, for example, create another Series and populate them as you "find data points inside the rectangle". Then, make the first series ("myPoints") invisible, for example. Here are some lines of code to guide you:I only want to highlight some points in the series included in the square and try to redraw the chart.
Is it possible to refresh only the corresponding points or series from a large amount of data?
1.- Setting up series
Code: Select all
Points myPoints;
Points myHighlightedPoints;
myPoints = new Points(tChart1.Chart);
myHighlightedPoints = new Points(tChart1.Chart);
Code: Select all
if (minX <= xValue && maxX >= xValue && minY <= yValue && maxY >= yValue)
{
//The point x and y is inside the rectangle.
pointsInsideRectangle.Add(new Point((float)xValue, (float)yValue));
myHighlightedPoints.Add(xValue, yValue); // add to highlighted series
}
Code: Select all
myPoints.Visible = false;
Also note that if you make the first series invisible, the chart will automatically move its axes to fit the new data points, making your square be "in the wrong place". To solve this issue, you can use properties like the following to lock in place your chart
Code: Select all
tChart1.Axes.Bottom.Maximum = 100; // Example value
tChart1.Axes.Left.Maximum = 100;
tChart1.Axes.Automatic = false;
There are many ways to implement these features, and the best approach will ultimately depend on your specific needs and preferences. I wanted to provide you with a few options to consider, but feel free to explore and choose the one that works best for you.
If there's anything else I can assist you with, or if you'd like to explore other approaches, please don't hesitate to let me know!
Regards,
Edu
Edu
Steema Support
Steema Support