最初にbretddogに答える:
これは、JapaneseCandleStickグラフのFindNearestPointに問題があるようです。グラフペインをクリックしても、最も近いバーのインデックスは返されませんが、x軸上でどれだけ離れていても、代わりに最も近いY値のインデックスが選択されると思います。マウスの右側にあるバーの場合もあれば、マウスの左側にあるバーの場合もあります。これはそれが機能することを意図した方法ですか?
このカスタム関数を自分で作成したので、大丈夫だと思います。それでも、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 = TrueThenline ;を削除します。
- 非正規直交軸との不一致を防ぐために、計算の前にX、Y値を正規化しました。
- エラーが発生した場合は、Falseを返すと、 NearestCurve=NothingおよびNearestCurveIndex=-1になります。
- ドラッグするラインカーソルは、LineObjではなく、曲線(ポイント以上)である必要があります。
- 間隔が近いかどうかのテストはコードの弱点であり、いくつかの間違いが発生するはずだと思います(前述のように、1つ-まれな-ケースをすでに特定しました)。垂直線が完全ではない場合(係数が非常に大きい場合)にも問題が発生する可能性があります。
最後に、このコードが速度に最適化されているかどうかはわかりませんが、私は自分の側でフリーズすることはありません。最良の方法は、関数をZedGraphクラスに統合し、Add関数が呼び出されたときに各係数(aおよびb)を計算して、毎回計算しないようにすることです(つまり、各マウスが移動します)。
したがって、コードが、ZedGraphには非常に欠けている移動可能なカーソルを作成するのに役立つことを願っています。