首先回答 bretddog:
JapaneseCandleStick 图上的 FindNearestPoint 似乎是个问题;当我在图表窗格中单击时,它不会返回最近柱的索引,但我相信它会选择具有最接近 Y 值的索引,无论它在 x 轴上有多远。有时它在鼠标右侧,有时在鼠标左侧。这是它的工作方式吗?
我自己制作了这个自定义函数,所以我想没关系..仍然很高兴理解 FindNearestPoint 为什么会这样
我不使用 JapaneseCandleStick,而是使用 Line,但我认为这是同一种问题。ZedGraph 使用坐标,所以使用点,而不是函数,所以要确定最近的“曲线”,它应该插值,而且似乎很难做到这一点。
不过,对于线条图形,我开发了一个函数来获取最近的曲线。因此,我在每条曲线的每个连续点之间进行了直线插值,并使用数学距离来确定最近的曲线。代码是:
''' <summary>
''' To obtain the nearest curve and its index on ZedGraph stick
''' </summary>
''' <param name="GraphPane">The graphpane on wich you are working</param>
''' <param name="PointLocation">Mouse location</param>
''' <param name="NearestCurve">Reference of the nearest curve</param>
''' <param name="NearestCurveIndex">Index of the nearest curve</param>
''' <returns>True if a curve is found</returns>
''' <remarks></remarks>
Private Function FindNearestCurve(ByVal GraphPane As ZedGraph.GraphPane, ByVal PointLocation As System.Drawing.Point, ByRef NearestCurve As CurveItem, ByRef NearestCurveIndex As Integer) As Boolean
Try
Dim MinDist As Double = -1 'error if < 0
Dim DistTemp As Double
Dim a, b As Double
Dim Curve As CurveItem
Dim ValX, ValY As Double
Dim NormX, NormY As Double
'ini
NearestCurveIndex = -1
GraphPane.ReverseTransform(PointLocation, ValX, ValY) 'To use real values
NormX = GraphPane.XAxis.Scale.Max - GraphPane.XAxis.Scale.Min 'To normalize value when we haven't orthonormal axis
NormY = GraphPane.YAxis.Scale.Max - GraphPane.YAxis.Scale.Min 'To normalize value when we haven't orthonormal axis
'We looking for the nearest curve
For j = 0 To GraphPane.CurveList.Count - 1
Curve = GraphPane.CurveList.Item(j)
If Curve.IsVisible = True Then
'We generate all coefficient (a and b) of straight line interpolation (equation y=ax+b)
For i = 0 To Curve.NPts - 2 '-2 because we work on intervals
'we check if interval is close to the point (to prevent case where the complete interpolation curve is the nearest curve but the real segment is far to the point)
If (Curve.Points.Item(i + 1).Y >= ValY And Curve.Points.Item(i).Y <= ValY) Or
(Curve.Points.Item(i + 1).Y <= ValY And Curve.Points.Item(i).Y >= ValY) Or
(Curve.Points.Item(i + 1).X >= ValX And Curve.Points.Item(i).X <= ValX) Or
(Curve.Points.Item(i + 1).X <= ValX And Curve.Points.Item(i).X >= ValX) Then
'We calculate straight line interpolation coefficient a and b
'Vertical line case
If (Curve.Points.Item(i + 1).X / NormX - Curve.Points.Item(i).X / NormX) = 0 Then
'We calculate directly the distance
DistTemp = Math.Abs(Curve.Points.Item(i).X / NormX - ValX / NormX)
Else 'All other case
'a = (yi+1 - yi) / (xi+1 - xi)
a = (Curve.Points.Item(i + 1).Y / NormY - Curve.Points.Item(i).Y / NormY) / (Curve.Points.Item(i + 1).X / NormX - Curve.Points.Item(i).X / NormX)
'b = yi - a*xi
b = Curve.Points.Item(i).Y / NormY - a * Curve.Points.Item(i).X / NormX
'We calculate the minimum distance between the point and all straight line interpolation
DistTemp = Math.Abs(a * ValX / NormX - ValY / NormY + b) / Math.Sqrt(1 + a * a)
End If
'We test if it's the minimum and save corresponding curve
If MinDist = -1 Then
MinDist = DistTemp 'first time
NearestCurveIndex = j
ElseIf DistTemp < MinDist Then
MinDist = DistTemp
NearestCurveIndex = j
End If
End If
Next
End If
Next
'Return the result
If NearestCurveIndex >= 0 And NearestCurveIndex < GraphPane.CurveList.Count Then
NearestCurve = GraphPane.CurveList.Item(NearestCurveIndex)
Return True
Else
NearestCurve = Nothing
NearestCurveIndex = -1
Return False
End If
Catch ex As Exception
NearestCurve = Nothing
NearestCurveIndex = -1
Return False
End Try
End Function
我已经测试过这个函数,它似乎工作得很好,但我不能保证在所有情况下(事实上,如果曲线的第一个/最后一个点是最近的点,它就不会被检测到)。关于使用的一些说明:
- 仅在可见曲线上工作,要删除它,请删除If Curve.IsVisible = True Then line ;
- 我在计算之前对 X、Y 值进行了归一化,以防止与非正交轴不一致;
- 当有错误时,返回False并且你有NearestCurve = Nothing和NearestCurveIndex = -1;
- 您要拖动的线光标应该是曲线(无论是to点还是更多),而不是LineObj;
- 间隔是否接近的测试是代码的薄弱部分,我认为它应该会发生一些错误(我已经确定了一个 - 罕见的 - 案例,如前所述)。如果您的垂直线不完美(因此 a 系数非常大),也会出现问题。
最后,我不确定这段代码是否针对速度进行了优化,但我并没有冻结。最好的方法应该是将函数集成到 ZedGraph 类中,并在调用Add函数时计算每个系数(a 和 b),这样就不用每次都计算它们(所以每次鼠标移动)。
所以我希望这些代码能帮助一些人创建一个可移动的光标,这是 ZedGraph 中非常缺少的东西。