1

我正在使用画布元素在 WPF 中绘制程序。我想要实现的是一个带有可拖动端点的滚动条。Adobe 的 After Effects 视频编辑软件中就是这类滚动条的示例。

这种滚动条的基本功能是它能够滚动比它的容器更大的内容,但左右端点都可以拖动以动态改变内容的比例。

我在绘图程序中实现了一个类似的滚动条;用户应该能够拖动入点和出点(画布中的矩形),并且绘图画布应该通过缩放到所需范围来对此做出响应。我需要的信息:

  • 总图的宽度(图点的数量)
  • 容器的宽度(静态,600px)
  • 入点和出点相对于滚动条画布总宽度的百分比

链接到当前屏幕截图

有了这些信息,我创建了一个 MatrixTransform,使用 ScaleAt() 方法缩放容器内的绘图画布,使其与下面滚动条中的入点和出点匹配。为此,我使用了以下代码。resetTransform 每秒调用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
}

期望:一切都应该正常工作,并且当绘图点的数量随着时间的推移而增长时,绘制的图形会很好地缩放。现实:移动点时图形会缩放,但不具有代表性;此外,添加的情节点越多,整个画布向右移动的越多,我似乎对转换的控制就越少。现在的算法可能是错误的方法来获得我需要的结果,但我花了很多时间思考如何正确地做到这一点。

更新

我已经上传了一个视频,以便更清楚地了解互动。在视频中,您可以清楚地看到画布向右移动。 截屏视频

我应该如何缩放画布(绘图)以适应两个边界?

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
    }

因此,与其围绕中心点缩放,我应该首先平移图像,然后用一个因子围绕画布的原点缩放。这意味着画布的另一侧正好是 plot.Height 像素(增加了一些缩放)

现在一切似乎都很好,但是因为我使用的是自定义控件(画布中的可拖动矩形),我注意到这些矩形并不总是触发 mousse 事件。

由于它超出了这个问题的范围,我已经在这篇文章中进一步描述了这个问题

于 2012-10-16T23:00:37.470 回答