首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在MultiScaleImage上保持相对位置

在MultiScaleImage上保持相对位置
EN

Stack Overflow用户
提问于 2010-10-16 11:01:13
回答 2查看 1.2K关注 0票数 2

在看到this instructions后,我实现了以下Silverlight应用程序,以下是我的代码:

代码语言:javascript
复制
public partial class MainPage : UserControl
{
    private Point lastMousePos = new Point();
    private double zoom = 1;
    private Point lastMouseLogicaPos = new Point();
    private Point lastMouseViewPort = new Point();
    private bool duringDrag = false;
    private bool duringOpen = false;
    private List<Dot> dots = new List<Dot>();
    private bool addDot = false;

    public MainPage()
    {
        InitializeComponent();

        this.MouseMove += delegate(object sender, MouseEventArgs e)
        { this.lastMousePos = e.GetPosition(this.ZoomImage); };

        ZoomImage.MouseWheel += new MouseWheelEventHandler(ZoomImage_MouseWheel);
        this.ZoomImage.UseSprings = false;
    }

    private void ZoomImage_MouseWheel(object sender, MouseWheelEventArgs e)
    {
        double newzoom = zoom;

        if (e.Delta > 0)
        { newzoom /= 1.3; }
        else
        { newzoom *= 1.3; }

        Point logicalPoint = this.ZoomImage.ElementToLogicalPoint(this.lastMousePos);
        this.ZoomImage.ZoomAboutLogicalPoint(zoom / newzoom, logicalPoint.X, logicalPoint.Y);

        zoom = newzoom;
        e.Handled = true;
    }

    private void ZoomImage_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        lastMouseLogicaPos = e.GetPosition(LayoutRoot);
        lastMouseViewPort = this.ZoomImage.ViewportOrigin;

        foreach (var dot in this.dots)
        { dot.LastMouseLogicPos = e.GetPosition(LayoutRoot); }

        if (!this.addDot)
        { duringDrag = true; }
    }

    private void ZoomImage_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if (this.addDot)
        {
            Dot dot = new Dot(this.lastMouseLogicaPos.X, this.lastMouseLogicaPos.Y) 
                                { Name = "Dot" + (this.dots.Count + 1).ToString() };

            this.dots.Add(dot);
            this.DotCanvas.Children.Add(dot);
        }
        else
        { duringDrag = false; }
    }

    private void ZoomImage_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (duringDrag)
        {
            double zoomFactor = 1 / this.ZoomImage.ViewportWidth;
            Point newPoint = lastMouseViewPort;
            Point thisMouseLogicalPos = e.GetPosition(LayoutRoot);
            newPoint.X += (lastMouseLogicaPos.X - thisMouseLogicalPos.X) / (this.ZoomImage.ActualWidth * zoomFactor);
            newPoint.Y += (lastMouseLogicaPos.Y - thisMouseLogicalPos.Y) / (this.ZoomImage.ActualWidth * zoomFactor);
            this.ZoomImage.ViewportOrigin = newPoint;

            foreach (var dot in this.dots)
            {
                Point dotLogicPoint = this.ZoomImage.ElementToLogicalPoint(new Point(dot.X, dot.Y));
                thisMouseLogicalPos = e.GetPosition(LayoutRoot);

                dotLogicPoint.X -= (dot.LastMouseLogicPos.X - thisMouseLogicalPos.X) / ((1 / 1.8) * this.ZoomImage.ViewportWidth);
                dotLogicPoint.Y -= (dot.LastMouseLogicPos.Y - thisMouseLogicalPos.Y) / (this.ZoomImage.ActualWidth * this.ZoomImage.ViewportWidth);

                dot.X = (this.ZoomImage.LogicalToElementPoint(locLogicPoint).X);
                dot.Y = (this.ZoomImage.LogicalToElementPoint(locLogicPoint).Y);
            }
        }
    }

    private void ZoomImage_ImageOpenSucceeded(object sender, System.Windows.RoutedEventArgs e)
    { duringOpen = true; }

    private void ZoomImage_MotionFinished(object sender, System.Windows.RoutedEventArgs e)
    {
        if (duringOpen)
        { duringOpen = false; }
    }

    private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        this.addDot = !this.addDot;

        if (this.addDot)
        { this.btnAddDot.Content = "Click on Image"; }
        else
        { this.btnAddDot.Content = "Add Dot"; }
    }
}

这样,我就可以在MultiScaleImage上缩放和平移,并将我的自定义Dot对象添加到DotCanvas画布中。下面是XAML:

代码语言:javascript
复制
<UserControl x:Class="DeepZoomSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" Width="800" Height="600">

<Grid x:Name="LayoutRoot" Background="Black" Margin="0,0,-98,-86">

    <MultiScaleImage x:Name="ZoomImage" Source="GeneratedImages/dzc_output.xml" 
                     Margin="8,8,0,0" MouseLeftButtonDown="ZoomImage_MouseLeftButtonDown" 
                     MouseLeftButtonUp="ZoomImage_MouseLeftButtonUp" MouseMove="ZoomImage_MouseMove" ImageOpenSucceeded="ZoomImage_ImageOpenSucceeded" 
                     MotionFinished="ZoomImage_MotionFinished" Height="584" VerticalAlignment="Top" HorizontalAlignment="Left" Width="784"/>

    <Canvas x:Name="DotCanvas" HorizontalAlignment="Left" Height="584" Margin="8" VerticalAlignment="Top" Width="784" MouseLeftButtonUp="LocationCanvas_MouseLeftButtonUp"/>
    <Button x:Name="btnAddDot" Content="Add Location" HorizontalAlignment="Right" Height="44" Margin="0,0,24,24" VerticalAlignment="Bottom" Width="112" Click="Button_Click"/>

</Grid>

现在,问题是,当我平移和缩放时,由于点被放置在MultiScateImage (ZoomImage对象)上的画布中,点将停留在画布上它们各自的位置。此代码在图像平移和缩放时尝试将点保持在适当的位置,但未进行一些尝试。

这是应用程序的图片,周围的蓝点是我的自定义Dot对象:

主要的问题是,当用户缩放和平移时,如何将点保持在图像上的相对位置。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-10-20 16:31:39

这很棘手,但绝对可以做到,我最近为一个类似的应用程序做了同样的事情。我不会说谎,我花了几个小时才让它工作,所以准备一些令人头疼的事情吧。

基本上涉及到两件事:

1.将点定位在正确的位置

数学在这里是你的朋友。您必须创建一些方法,将基于multiScaleImage的坐标转置为画布(即视口)坐标。

首先,您必须深入了解ViewPortOrigin和ViewPortWidth (this是一个很好的开始)。他们有几个警告(例如。我似乎记得viewPortHeight必须乘以图像比率才能得到实际值-or类似的值)。

给你指出解决方案:你必须减去viewPortOrigin,然后乘/除viewPortWidth。如果你有耐心(和幸运;-),今晚我会看看我的项目并发布一些代码,但如果你真的理解这些参数是很好的,-otherwise它将是棘手的调试和故障排除。

在浏览multiscaleImage时,我在周围放置了一些文本块,并始终显示viewportWidth/Origin/等,这对我理解所发生的事情有很大帮助。

编辑:你很幸运,我记得这个-so这里有一些代码应该会有帮助。再一次,我建议你不要在不了解的情况下复制和粘贴,因为你不会走得那么远。

代码语言:javascript
复制
private Point CanvasToDeepZoom(MultiScaleImage msi, Point absoluteInsideCanvas)
{
    // the only non-logical (to me) step: viewportOrigin.Y must be multiplied by the aspectRatio
    var ViewportHeight = msi.ViewportWidth * msi.AspectRatio * msi.ActualHeight / msi.ActualWidth;

    var relativeToCanvas = new Point(
        absoluteInsideCanvas.X / msi.ActualWidth,
        absoluteInsideCanvas.Y / msi.ActualHeight);

    return new Point(
        msi.ViewportOrigin.X + msi.ViewportWidth * relativeToCanvas.X,
        msi.ViewportOrigin.Y * msi.AspectRatio + ViewportHeight * relativeToCanvas.Y);
}


private Point DeepZoomToCanvas(MultiScaleImage msi, Point relativeInsideDeepZoom)
{
    var ViewportHeight = msi.ViewportWidth * msi.AspectRatio * msi.ActualHeight / msi.ActualWidth;

    var relativeToCanvas = new Point(
        (relativeInsideDeepZoom.X - msi.ViewportOrigin.X) / msi.ViewportWidth,
        (relativeInsideDeepZoom.Y - msi.ViewportOrigin.Y * msi.AspectRatio) / ViewportHeight);

    return new Point(
        relativeToCanvas.X * msi.ActualWidth,
        relativeToCanvas.Y * msi.ActualHeight);
 }

2.在缩放和平移动画过程中保持点的同步。

基本的想法是循环一个0秒长的动画,在缩放/平移的整个持续时间内不断更新点的位置(如果我没记错的话是1.5秒)。该技术在here中得到了很好的解释。在该博客中,您还可以找到针对您的特定问题的其他有用资源。

票数 1
EN

Stack Overflow用户

发布于 2012-04-24 22:25:03

如果你看到Deep Zoom Composer,它还允许你设置超链接区域,并有模板来生成源码项目。因此,这些点可以是图像本身(使用图像集合,这样您甚至可以通过编程方式打开/关闭子图像SubMultiScaleImage,如果我记得很清楚的话是通过编程实现的),并在它们上有超链接,让MultiScaleImage处理集合,并在单击超链接时通知您(参见生成的代码)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3947494

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档