0

Canvas の背景として方眼紙のようなグリッドを描画しようとしています。このグリッドは、キャンバスをスケーリングしてズームを実装できるため、私が見つけたこれを行う方法のほとんどの説明とは異なります。私がやりたいことは、グリッド線の一連のスケール、つまり 10^n 単位ごとです。次に、ズームによってグリッド線が接近するにつれて、グリッド線がフェードアウトするはずです。言い換えると、n が大きい場合、そのグリッドに関連付けられた線は、n が小さい場合よりも暗く/太くする必要があります。

これは WinForms で簡単に実行できました。OnPaint をオーバーライドし、線の色を次のグリッド線までの距離の関数として定義することで実装しました。離れている線は、近くにある線よりも重い重みが与えられました。

WPFでこれを行う方法がわかりません。グリッド線の間隔に応じて StrokeThickness を持つ線を作成することで、この動作を取得できますが、これは StrokeThickness とスケーリング値の狭い範囲でのみ機能します。非常に重いウェイトを持つ線を定義できれば機能しますが、StrokeThickness は小さくなります。

OnRender を使用してカスタム コントロールを実装してこれを行うことも困難です。これは、レンダリング中にコントロールのスケールを取得する信頼できる方法が見つからないためです (ScaleTransform は親コントロールの 1 つの一部であり、直接の親ではありません)。

この目標を達成する方法についての考えは大歓迎です!

4

1 に答える 1

2

グリッドをキャンバスに追加するのではなく、グリッドを含む別のコントロールの上にキャンバスを積み重ねることでこれを解決しました。

<Grid>
    <Canvas x:Name="GridLayer"/>
    <Canvas x:Name="DrawingLayer" />
</Grid>

ズーム イベントが発生すると、GridLayer を再描画するだけです。

これにより、必要な線だけを描くことができ、希望どおりに正確に描くことができました。私の場合、膨大な数のグリッド線が存在する可能性があるため、非常に重要です。線を必要以上に長く/高く描く必要はありませんでした。 . この方法で、多くの CPU 時間を節約できました。

もう 1 つ注意すべき点は、独自のズーム コードを実装したことです。線の幅を同じにしたかったので、RenderTransform や ViewBox は使用しませんでした。私がしたことは、パンとズームレベルをサポートするために左上隅の座標を追跡することだけでした。これらの変更のいずれかが行われるとすぐに、キャンバスを再描画します。2 つの関数を作成しました。1 つは Canvas 上の座標をグラフ座標に変換し、もう 1 つはその逆を行います。最初の方法では、カーソル座標をグラフ座標に変換できます。2 番目の方法では、グラフの座標をポイントに変換し、キャンバス上に描画するために使用できます。

テストされていないコードと、軸の向きに関する多くの仮定:

Point Graph2Canvas(Point graphPoint)
{
    var canvasPoint = new Point(graphPoint);
    canvasPoint.X *= zoomLevel;
    canvasPoint.Y *= zoomLevel;
    canvasPoint.X -= topLeft.X;
    canvasPoint.Y -= topLeft.Y;
    return canvasPoint;
}

これは最適化できます。実際には、ポイントのコレクションに対して同じことを行う関数をさらに作成しました。

追加:

最終的に、次のようなはるかに複雑なセットアップになりました。

<Grid>
    <Canvas x:Name="BackgroundLayer"/>
    <Canvas x:Name="GridLayer"/>
    <Canvas x:Name="AxisLayer"/>
    <Canvas x:Name="DrawingLayer" />
    <Canvas x:Name="SelectionBoxLayer"/>
    <Canvas x:Name="CursorLayer"/>
</Grid>
于 2013-08-23T08:33:44.140 に答える