ZedGraph - How to make a horizontal line drag-able?

bretddog picture bretddog · Sep 30, 2010 · Viewed 6.9k times · Source

I have some straight horizontal lines that I want the user be able to drag vertically. How would this be possible? I think the best parameter for line selection would be a fixed number of pixels near the line. So if mouse is +/- 2 pixels, I should change the mouse cursor and make the line drag-able.. I see the CurveItem class has properties IsSelectable and IsSelected. Will these have any function in solving this issue? I can’t really understand what they are for from reading the class documentation..


EDIT:

It seems that the FindNearestPoint (and FindNearestObject) only search actual points. How would I make selection to work along the whole section of a straight line? I guess I would need to make make my own custom "Find" routine that loops through all the lines I want to check, and for each calculate it's imaginary Y-point based on the mouse X position (?) I'm also thinking about sloped lines for this purpose, for horizontal/vertical lines it will be slightly simpler. At least it seems this is needed for a curveItem, but I assume the same must be done for selecting (at mid-section of) a LineObj?

I actually didn't know about the LineObj existed. It seems the LineObj is not possible to change the X2/Y2 coordinates, as they are ReadOnly. So is it at all possible to drag the X2/Y2 point of a LineObj?


EDIT 2:

It seems to be an issue with the FindNearestPoint on a JapaneseCandleStick graph; When I click in the graph pane, it does not return the index of the nearest bar, but I believe it instead selects the index with the closest Y-value, no matter how far away on the x axis it is. Sometimes it's a bar to the right of the mouse, sometimes to the left of the mouse. Is this the way it's meant to work?

I made this custom function myself, so I guess it's ok.. Still it would be nice to understand why the FindNearestPoint acts this way.

This is the code on mouseDown:

   ' Find nearest curve point:
   Dim ciNearestCurve As CurveItem
   Dim iNearestCurve As Integer
   Dim b As Boolean = zgc.GraphPane.FindNearestPoint(mousePt, zgc.GraphPane.CurveList, ciNearestCurve, iNearestCurve)
   If b Then
       With ciNearestCurve(iNearestCurve)
           Debug.Print(Date.FromOADate(.X) & " " & .Y & " " & .Z)
       End With

Answer

Gacek picture Gacek · Oct 1, 2010

Take a look on this tutorial on dragging the points with mouse.

If you are using a LineObj instead of a curve, take a look on the FindNearestObject method.

Also if you want to make some "area of sensitivity" for clicking, this method should help you to transform mouse coordinates in pixels to pane scale coordinates.

The main idea is to:
- subscribe for MouseDown, MouseUp and MouseMove events
- in the handler for MouseDown event check if clicked point is near the curve/graph object you want to move
- do the change in similar way that it is shown in example from the first link

EDIT
Regarding your edit:
Let's assume you have a horizontal curve myCurve containing two points. Using FindNearestPoint you can find nearest clicked point and the curve containing this point.

So you have:

// mousePt is where you clicked
CurveItem nearestCurve = null;
int nearestID = -1;

myPane.FindNearestPoint(mousePt, out nearestCurve, out nearestID);
if(nearestCurve!=null)
   // remember the curve somewhere. 

Next handle the MouseMove and MouseUp events to find out how much you need to move your curve. You need to know only the change in Y (or Y2) direction as the curve is horizontal and you probably do not want to move it along X axis.

When you'll find out how much you need to move your curve (dy), just do:

for(int i=0; i<nearestCurve.Points.Count; i++)
    nearestCurve.Points[i].Y += dy;

Regarding your second question, in the documentation for LineObj.Location.Y2 you have:

Note that the Y2 position is stored internally as a Height offset from Y.

And Width/Height properties can be set easily, so you can do it this way.