2010-10-16 93 views
2

我採取了以下Silverlight應用程序看到this instructions後,這裏是我的代碼:保持相對位置在MultiScaleImage

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和我的自定義點對象添加到DotCanvas畫布。這裏的XAML:

<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對象),當我平移和縮放點會留在各自的放置在畫布上。此代碼有一些錯過的嘗試,試圖在圖像平移和縮放時保持點的位置。

這裏的應用程序的圖像,藍點周圍是我的自定義點對象:

alt text

主要的問題是,我怎麼能保持其相對位置的點在圖像上,而用戶放大和平底鍋。

+0

點應該在縮放時自動縮放還是保持其大小,並且相對位置縮放和平移? – AnthonyWJones 2010-10-16 12:06:15

+0

我希望他們能夠保持它們的大小,並在縮放和平移時改變他們在MultiScaleImage上的相對位置 – FelixMM 2010-10-16 16:22:51

+0

這很好,可以幫助您避免嚴重的麻煩:-)。保持與源圖像的「本地」分辨率同步的點大小比保持位置同步更棘手。 – 2010-10-20 08:34:07

回答

1

這是棘手的,但絕對可以做到,我最近做了類似的應用程序相同。我不會說謊,我花了幾個小時才搞定它,所以準備好了一些頭疼的事情。

基本上有涉及兩件事情:

1定位在正確的地方

數學是在這裏你的朋友點。您將不得不創建一些方法將基於multiScaleImage的座標轉置到畫布(即視口)座標。

首先,你必須深入ViewPortOrigin和ViewPortWidth理解(this是一個很好的開始)。他們有幾個需要注意的地方(爲前,我似乎記得,viewPortHeight必須由圖像比例相乘得到 - 或者類似的東西實際值)。

爲您指出瞭解決方案:你將不得不viewPortWidth減去viewPortOrigin和乘法/除法。如果你有耐心(和幸運;-))今晚,我會看看我的項目,併發布一些代碼,但它是很好的,如果你真的瞭解這些參數 - 否則這將是棘手的調試和故障排除。

東西幫助了我很多理解發生了什麼事情是把一些周圍的TextBlocks和顯示viewportWidth /產地/等。一直在瀏覽多尺度圖像時。

編輯:你是幸運的,我記得這個 - 所以這裏是一些代碼,應該幫助。同樣,我建議你不要只是複製粘貼&不理解,你就不會走到這一步。

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。在該博客中,您還可以找到針對您的特定問題的其他有用資源。

+0

感謝您的回覆。今天我會檢查後面的鏈接和代碼。 – FelixMM 2010-10-20 21:26:45

0

如果您看到Deep Zoom Composer,它也允許您設置超鏈接區域,並且也有模板來生成源代碼項目。因此,這些點可以是圖像本身(使用圖像集合,這樣你甚至可以打開/關閉子圖像[如果我沒記錯的話是SubMultiScaleImage是編程的),並且有超鏈接,讓MultiScaleImage處理集合並讓你知道什麼時候單擊超鏈接(請參閱生成的代碼)