1

私は、canvas要素を使用してWPFでプログラムをプロットする作業をしています。私が達成したいのは、ドラッグ可能な端点を備えたスクロールバーです。これらの種類のスクロールバーの例は、AdobeのAfterEffectsビデオ編集ソフトウェアにあります。

このようなスクロールバーの基本的な機能は、コンテナよりも大きいコンテンツをスクロールできることですが、左右のエンドポイントをドラッグして、コンテンツのスケールを動的に変更できます。

プロットプログラムに同様のスクロールバーを実装しました。ユーザーは、インポイントとアウトポイント(キャンバス内の長方形)をドラッグできる必要があり、プロットキャンバスは、目的の範囲にスケーリングすることでこれに応答する必要があります。これに必要な情報:

  • プロット全体の幅(プロットポイントの量)
  • コンテナの幅(静的、600px)
  • スクロールバーキャンバスの全幅に対するインポイントとアウトポイントのパーセンテージ

現在のスクリーンショットへのリンク

この情報を使用して、ScaleAt()メソッドを使用してMatrixTransformを作成し、コンテナー内のプロットキャンバスをスケーリングして、下のスクロールバーのインポイントとアウトポイントに一致させます。このために、私は次のコードを使用しました。resetTransformは、着信データに対応するために1秒間にFPSと呼ばれ、XMAXとYMAXはこれを反映するために他の場所で更新されます。

public void resetTransform(Boolean useSlider = false)
{
    //Add transformgroup to plot
    double yscale = plot.Height / view.YMAX; //YMAX is maximum plot value received
    double xscale = plot.Width / view.XMAX; //XMAX is total ammount of plotted points
    Matrix m = new Matrix(1, 0, 0, 1, 0, 0);
    if (useSlider)
    {
        double maxVal = zoomBar.ActualWidth - outPoint.Width;
        double outP = Canvas.GetLeft(outPoint); //points position relative to the scrollbar
        double inP = Canvas.GetLeft(inPoint);
        double center = (((outP + inP) / 2) / maxVal) * plot.ActualWidth;
        double delta = (outP-inP);
        double factor = (maxVal/delta) * xscale;
        double mappedinP = (inP / maxVal) * view.XMAX;

        double anchorOut = (outP / maxVal) * view.XMAX;
        double anchorIn = (inP / maxVal) * view.XMAX;

        m.ScaleAt(factor, -yscale,center,0); //scale around the center point, 
        m.Translate(0, plot.Height); //to compensate the flipped graph, move it back down
    }
    scale = new ScaleTransform(m.M11, m.M22, 0, 0); //save scale factors in a scaletransform for reference
    signals.scaleSignalStrokes(scale); //Scale the plotlines to compensate for canvas scaling
    MatrixTransform matrixTrans = new MatrixTransform(m); //Create matrixtransform
    plot.RenderTransform = matrixTrans; //Apply to canvas
}

期待:すべてが機能するはずであり、プロットポイントの量が時間の経過とともに増加すると、プロットされたグラフは適切にスケーリングされます。現実:グラフはポイントを移動すると拡大縮小されますが、代表的なものではありません。さらに、追加されるプロットポイントが多いほど、キャンバス全体が右にシフトし、変換に対する制御が弱くなるように見えます。現在のアルゴリズムは、おそらく私が必要とする結果を得るための間違ったアプローチですが、私はこれを正しく行う方法を考えるのにかなりの時間を費やしました。

アップデート

インタラクションをより明確に示すために、ビデオをアップロードしました。ビデオでは、キャンバスが右にシフトしているのがはっきりとわかります。 スクリーンキャプチャビデオ

2つの境界内に収まるようにキャンバス(プロット)をどのように拡大縮小する必要がありますか?

4

1 に答える 1

1

それで、いくつかの苦労の後で、私はこの問題を解決するための正しいアルゴリズムを見つけました。調整されたバージョンのresetTransform関数を以下に投稿します。

    //Reset graph transform
    public void resetTransform(Boolean useSlider = false)
    {
        double yscale = plot.Height / view.YMAX; //YMAX is maximum plot value received
        double xscale = plot.Width / view.XMAX; //XMAX is total ammount of plotted points
        Matrix m = new Matrix(1, 0, 0, 1, 0, 0);
        if (useSlider)
        {
            double maxVal = zoomBar.ActualWidth - outPoint.Width;
            double outP = Canvas.GetLeft(outPoint); //points position relative to the scrollbar
            double inP = Canvas.GetLeft(inPoint);
            double delta = (outP-inP);
            double factor = (maxVal/delta) * xscale;

            anchorOut = (outP / maxVal) * view.XMAX; //Define anchorpoint coordinates
            anchorIn = (inP / maxVal) * view.XMAX;
            double center = (anchorOut +anchorIn)/2; //Define centerpoint

            m.Translate(-anchorIn, 0); //Move graph to inpoint
            m.ScaleAt(factor, -yscale,0,0); //scale around the inpoint, with a factor so that outpoint is plot.Height(=600px) further away
            m.Translate(0, plot.Height); //to compensate the flipped graph, move it back down
        }
            scale = new ScaleTransform(m.M11, m.M22, 0, 0); //save scale factors in a scaletransform for reference
            signals.scaleSignalStrokes(scale); //Scale the plotlines to compensate for canvas scaling
            MatrixTransform matrixTrans = new MatrixTransform(m); //Create matrixtransform
            plot.RenderTransform = matrixTrans; //Apply to canvas
    }

したがって、中心点を中心に拡大縮小するのではなく、最初に画像を平行移動してから、係数を使用してキャンバスの原点を中心に拡大縮小する必要があります。これは、キャンバスの反対側が正確にプロットされていることを意味します。高さピクセル離れています(スケーリングが追加されています)

今はすべて正常に機能しているようですが、カスタムコントロール(キャンバス内のドラッグ可能な長方形)を使用しているため、これらの長方形が常にムースイベントを発生させるとは限らないことに気付きました。

この質問の範囲外であるため、この投稿でこの問題についてさらに説明しました

于 2012-10-16T23:00:37.470 に答える