I'm using C# chart control to draw a nyquist plot. Now i want data points appear on the curve each time the user moves the mouse on it. So i used hit test method in GetToolTipText event.
private void BodePlot_GetToolTipText(object sender, ToolTipEventArgs e)
{
HitTestResult result = BodePlot.HitTest(e.X, e.Y);
selectDataPoint = null;
if (result.ChartElementType == ChartElementType.DataPoint)
{
selectDataPoint = (DataPoint)result.Object;
e.Text = selectDataPoint.ToString();
}
{
The problem is only a part of the curve shows values, others don't. When i use e.Text = result.Object.ToString(); to get the object on which the mouse is pointing to, here what i found :
Instead of showing the data points, the text on tooltip show custom label. So i guess the reason is that the curve is covered by the labels of x and y axis.
The only solution that i found is disabling the x and y axis, with that everything works fine. But i want to keep those axes, so how can i make those labels hide under the curve.
Your analysis is likely correct. The way to go around this would be to provide HitTest() with the optional third argument which define the desired element type.
public HitTestResult HitTest (
int x,
int y,
ChartElementType requestedElement
)
This should return underlying data points even if other elements are overlapping them.
Related
I am using EyeShot 12. I am creating a rectangle using EyeShot Line Entity, it has 2 dimensions along length and breadth.
My functionality involves changing the Dimension Text by using the action->SelectByPick, then picking anyone of the dimension and changing its value by bringing up a TextBox so that user can add the value. Here the TextBox pops-up on the location of mouse pointer.
Going further I click on Tab (keypad button) to switch to next dimension and also making sure that particular Dimension gets highlighted. But my concern is I am unable to locate the TextBox next to that highlighted dimension.
I am able to locate the position of existing Line(corresponding to the selected dimension) in Eyeshot coordinates but TextBox requires screen coordinates value for Positioning it exactly.
So I am using control.PointToScreen to convert eyeshot coordinates into screen but it return a Point which is same as to the Eyeshot coordinates.
code:
foreach (Entity ent in model1.Entities)
{
if (ent.Selected)
{
Line lin = (Line)ent;
Point3D midpt = lin.MidPoint;
string newpt1X = midpt.X.ToString();
string newpt1Y = midpt.Y.ToString();
System.Drawing.Point startPtX = model1.PointToScreen(new
System.Drawing.Point(int.Parse(newpt1X) + 20, int.Parse(newpt1Y) + 20));
TextBox tb = new TextBox();
tb.Text = "some text";
tb.Width = 50;
tb.Location = startPtX;
model1.Controls.Add(tb);
}
I looked for other results but everyone triggers to PointToScreen to get this convertion.
Hoping somebody can point what I am doing.
Thanks in advance
Suraj
You made your object (TextBox) a child of the ViewportLayout therefore you need the point relative to it. But the controls are not in the world coordinate but screen coordinate based on their parent.
What you actually need is two (2) conversion.
// first grab the entity point you want
// this is a world point in 3D. I used your line entity
// of your loop here
var entityPoint = ((Line)ent).MidPoint;
// now use your Viewport to transform the world point to a screen point
// this screen point is actually a point on your real physical monitor(s)
// so it is very generic, it need further conversion to be local to the control
var screenPoint = model1.WorldToScreen(entityPoint);
// now create a window 2d point
var window2Dpoint = new System.Drawing.Point(screenPoint.X, screenPoint.Y);
// now the point is on the complete screen but you want to know
// relative to your viewport where that is window-wise
var pointLocalToViewport = model1.PointToClient(window2Dpoint);
// now you can setup the textbox position with this point as it's local
// in X, Y relative to the model control.
tb.Left = pointLocalToViewport.X;
tb.Top = pointLocalToViewport.Y;
// then you can add the textbox to the model1.Controls
This question already has answers here:
get mark position in ms charts on mouse click
(2 answers)
Closed 6 years ago.
I'm working whit charts on c#.
I would like to know a way of get the iten (the spline) clicked on the chart to do something like change color or hide.
You can check the clicked item using HitTest, as suggested..:
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
HitTestResult result = chart1.HitTest(e.X, e.Y);
// now do what you want with the data..:
if (result.Series != null && result.PointIndex >= 0)
Text = "X = " + result.Series.Points[result.PointIndex].XValue +
" Y = " + result.Series.Points[result.PointIndex].YValues[0];
}
To help the user you can indicate a possible hit:
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
HitTestResult result = chart1.HitTest(e.X, e.Y);
Cursor = result.Series != null ? Cursors.Hand : Cursors.Default;
}
Do your users a favor by making the spline lines a little larger:
eachOfYourSeries.BorderWidth = 4;
Of course the chart you show makes a controlled clicking impossible without zooming in first..
Now if all you want is hiding a Series or changing its Color the HitTestResult is good enough:
result.Series.Enabled = flase;
or
result.Series.Color = Color.Fuchsia;
But to access the clicked values, it may not be..:
Note that especially a Spline or a Line graph, need only very few DataPoints to create their lines; so the result from HitTest simply is not enough; it will tell you which series was clicked and also the closest DataPoint but to get at the correct values you still may need to convert the pixels to data values.
So instead of the HitTest result you may prefer to use the handy function PixelPositionToValue:
float px = (float)yourChartArea.AxisX.PixelPositionToValue(e.X);
This will get all the values between the actual DataPoints. Of course you can do the same for the Y-Values:
float py = (float)yourChartArea.AxisY.PixelPositionToValue(e.Y);
Note that you can only use these function when the chart is not busy with determining the layout; officially this is only during any of the three Paint events. But I found that in practice a mouse event is also fine. You will get a null value when the chart is not ready..
I am experiencing a weird problem with a render transform in WPF. The project I'm working on needs to display a clicked user point over an image. When the user clicks a point, a custom control is placed at the location of their click. The image should then be able to be scaled around any point using the mouse wheel, and the custom control should be translated (not scaled) to the correct location.
To do this, I follow the MouseWheel event as follows:
private void MapPositioner_MouseWheel(object sender, MouseWheelEventArgs e)
{
Point location = Mouse.GetPosition(MainWindow.Instance.imageMap);
MainWindow.Instance.imageMap.RenderTransform = null;
ScaleTransform st = new ScaleTransform(scale + (e.Delta < 0 ? -0.2 : 0.2), scale += (e.Delta < 0 ? -0.2 : 0.2));
st.CenterX = location.X;
st.CenterY = location.Y;
TransformGroup tg = new TransformGroup();
tg.Children.Add(st);
//tg.Children.Add(tt);
MainWindow.Instance.imageMap.RenderTransform = tg;
if (scale <= 1)
{
MainWindow.Instance.imageMap.RenderTransform = null;
}
if (TransformationChanged != null)
TransformationChanged();
}
Then, I implemented an event handler in the custom control for the TransformationChanged event seen at the end of the above code block as follows:
private void Instance_TransformationChanged()
{
//check image coords
//
if (MainWindow.Instance.imageMap.RenderTransform != null)
{
if (MainWindow.Instance.imageMap.RenderTransform != Transform.Identity)
{
Transform st = MainWindow.Instance.imageMap.RenderTransform;
Point image = MainWindow.VideoOverlayCanvas.TransformToVisual(MainWindow.Instance.MapImage).Transform(loc2);
Point trans = st.Transform(image);
Point final = MainWindow.Instance.MapImage.TransformToVisual(MainWindow.VideoOverlayCanvas).Transform(trans);
// selected = anchor2;
// final = ClipToOverlay(final);
// selected = null;
connector.X2 = final.X;
connector.Y2 = final.Y;
Canvas.SetLeft(anchor2, final.X);
Canvas.SetTop(anchor2, final.Y);
}
}
else
{
connector.X2 = loc2.X;
connector.Y2 = loc2.Y;
Canvas.SetLeft(anchor2, loc2.X);
Canvas.SetTop(anchor2, loc2.Y);
}
}
This way, I can ensure that the custom control's position is updated only after the new transform is set. Note that since I am applying the transform to the point, there is no scaling done to the control, the effect is that it is translated to the point it should. This works fine as long as the user is only scaling around one point. If they change that point, it doesnt work.
Here are some images that show the problem:
User clicks a point
user zooms out, what happened here?
after zooming out (all the way out in this case) it looks ok
I've been messing with this for about two days now, so I apologize if my code looks messy. I know this is a pretty obscure question so any help would be appreciated.
Thanks,
Max
If anyone is looking for an answer to this, because of deadlines, I had to write a workaround by having the user pan with the right mouse button and zoom with the mouse wheel. This way zooming always happens around the center of the image, so the controls are always lined up. I'm still looking for answers to the original question though if anyone can figure it out
Thanks,
Max
I'm not sure what's wrong with your transform, but have you considered an alternate approach? For example, you might want to add a transparent canvas set to stay at the same size as the image, z-order above the image (explicitly set or just put the Canvas element just after the image element). Then you can just use Canvas.SetLeft and Canvas.SetTop to place the user control where the user clicked, and to move it around. A lot easier than using a transform.
I have two ChartArea objects in a Chart (System.Windows.Forms.DataVisualization.Charting is what I'm using).
One is a Point graph, and the other is a RangeBar graph. The horizontal axis on the RangeBar graph is actually the Y axis, so I cannot just use something like this:
Chart1.ChartAreas["Chart Area 2"].AlignWithChartArea = "Default";
I've figured out how to zoom both charts and keep them aligned, but when I try to scroll both charts by clicking on the scrollbar on one of the horizontal axes, I can't quite get it to line up. They almost line up, but they're off by maybe a second or so (the horizontal axis in both graphs is time).
Here's what I have:
private void theChart_AxisViewChanged(object sender, ViewEventArgs e)
{
if (e.ChartArea == theChart.ChartAreas["MyPointChartArea"])
{
theChart.ChartAreas["MyRangeBarChartArea"].AxisY.ScaleView.Position = e.NewPosition;
theChart.ChartAreas["MyRangeBarChartArea"].AxisY.ScaleView.Size = e.NewSize;
theChart.ChartAreas["MyRangeBarChartArea"].AxisY.ScaleView.SizeType = e.NewSizeType;
}
if (e.ChartArea == theChart.ChartAreas["MyRangeBarChartArea"])
{
theChart.ChartAreas["MyPointChartArea"].AxisX.ScaleView.Position = e.NewPosition;
theChart.ChartAreas["MyPointChartArea"].AxisX.ScaleView.Size = e.NewSize;
theChart.ChartAreas["MyPointChartArea"].AxisX.ScaleView.SizeType = e.NewSizeType;
}
}
What else do I need to do to get the charts to line up? The physical extent of the charts is the same. It's just the data that are slightly misaligned.
Thanks for any help.
I am using ZedGraph to draw my plots in C#. I need to know which bar (in bar chart) was clicked by a mouse. How can I do that? Is there any way to get a bar by a point and for example change bar`s color?
Use MouseClick event and find the X and Y coordinates of the point where you clicked:
zg1.MouseClick+=new MouseEventHandler(zg1_MouseClick3);
private void zg1_MouseClick3(object sender, MouseEventArgs e)
{
PointF pt = (PointF)e.Location;
double x,y;
((ZedGraphControl)sender).MasterPane[0].ReverseTransform(pt, out x, out y);
// Do something with X and Y
}
Note, that I assumed we are operating on first pane (index 0) but if it is not your case, then you'll have to find which pane was clicked (see this example).
When you have X and Y position you should easily be able to guess which bar was clicked and do whatever you need with that information.