每周源代码18 – Deep Zoom(SeaDragon)Silverlight 2 MultiScaleImage鼠标滚轮缩放及平移

每周源代码18 – Deep Zoom(SeaDragon)Silverlight 2 MultiScaleImage鼠标滚轮缩放及平移

  • Comments 0

[原文发表地址]  The Weekly Source Code 18 - Deep Zoom (Seadragon) Silverlight 2 MultiScaleImage Mouse Wheel Zooming and Panning Edition

[原文发表时间]  2008-03-08 04:14

亲爱的读者,请阅读我的系列博文《每周源代码》的第十八篇。以下是我本周在Mix阅读及编写的代码。

我在研究Silverlight 2中的Deep Zoom,却发现居然没有支持鼠标滑轮框外的平移,缩放功能的“Hello DeepZoom World!”的样本这简直太令人讨厌了。而Vertigo的样本示例则和我想要的效果一样。你可以在这里查看我做的Deep Zoom示例样本,或者点击右边的图片。

Silverlight Project Test Page - Windows Internet Explorer (4)我们可以通过好几种方法让Silverlight支持鼠标滑轮。鼠标滑轮事件源于浏览器而非Silverlight本身(在我看来,这正如同你希望的那样,因为Silverlight内置于浏览器,它不能取代其特性)。

所以,你可以使用Adomas的Javascript代码,辅以Jeff Prosise编写好的代码进入Silverlight,调用方法。事件会在JavaScript中处理,Zoom函数也通过JavaScript的桥调用,转换成Silverlight的托管代码。

当然,你也可以调用内部托管代码,为DOM(JavaScript事件)设置管理处理,就像Pete Blois使用鼠标滑轮帮助器类进行操作那样。我直接从Pete的博客上下载了这个类并将其添加到了我的项目中。这非常棒,无需任何外部JavaScript文件。所有的事件都是由托管代码处理的。

   1: if (HtmlPage.IsEnabled) {
   2: HtmlPage.Window.AttachEvent("DOMMouseScroll", this.HandleMouseWheel);
   3: HtmlPage.Window.AttachEvent("onmousewheel", this.HandleMouseWheel);
   4: HtmlPage.Document.AttachEvent("onmousewheel", this.HandleMouseWheel);
   5: }

此外,我还在Yasser博客中Yasser MakramJohn的评论里截取了我最需要的代码段。

我看过很多用鼠标点击或者用键盘下键来实现缩放效果的示例,但我还想支持鼠标滑轮事件,就像在Mix中显示的那样。

这个更完整的样本将提供你:

• 拖动以平移

• 点击以放大,Shift点击以缩小

• 用鼠标滑轮来进行缩放

• 无需依靠JavaScript – 所有操作都是在管理代码中完成的。

首先,从DeepZoom的输出编辑器开始(我用这台机器上的Windows Wallpapers在编辑器中编写DeepZoom图像),然后将结果导出的文件夹结构拷贝至某处(为方便起见,我把它放在bin/debug下,不过你可以随意,只要源属性在XAML中整齐地排列):

   1: <UserControl
   2: xmlns="http://schemas.microsoft.com/client/2007"
   3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4: x:Class="SilverlightApplication1.Page"
   5: Width="800" Height="600" >
   6:  
   7: <Grid
   8:  
   9: x:Name="LayoutRoot"
  10: Background="Gray">
  11: <MultiScaleImage 
  12: x:Name="msi"
  13: ViewportWidth="1.0"
  14: Source="http://www.yourdomain.com/foo/items.bin" />
  15: </Grid>
  16: </UserControl>

注意事项:你可以在MultiScaleImage上设置一个很酷的转换。设置UseSprings="false",它可以关掉缩放的动画效果。为什么要这么操作呢?因为特定的放大缩小动画让DeepZoom有机会能展示它的轻巧视觉操控和图像间的转换。当动画产生时,你不太会注意到平铺视图间的转换。当然,我很想搞清楚这一切到底是怎么实现的,所以我很喜欢看其中的转换。

你要知道现在是早上4点,所以这个代码有点儿靠不住,考虑也许不周全,因为我只在上面花了一个小时的时间。我想知道读者怎样利用这段代码,将其改进为一个经典的范本。这个示例还不够完善,我其实有点迟疑要不要把它贴在这里,因为它很杂乱,不过这也很有趣,不是吗?至少我觉得它行之有效。

有一个需要指出的是, control的名称是“msi”,它通过x:name=”msi”在上述的XAML中设定,这样你就可以看到我引用属性,比如下面XAML代码中的msi.thisandthat。还有,下面的“using akadia”是从我页面引用的Pete的MouseHandler代码的命名空间。

我的代码通过匿名委托连接了一连串constructor里的事件,它们一同调用了单一Zoom()辅助方法。

   1: using System; 
   2: using System.Windows; 
   3: using System.Windows.Controls; 
   4: using System.Windows.Documents; 
   5: using System.Windows.Ink; 
   6: using System.Windows.Input; 
   7: using System.Windows.Media; 
   8: using System.Windows.Media.Animation; 
   9: using System.Windows.Shapes; 
  10: using System.Windows.Threading; 
  11: using akadia; 
  12:  
  13: namespace SilverlightApplication1 
  14: { 
  15: public partial class Page : UserControl 
  16: { 
  17: Point lastMousePos = new Point(); 
  18:  
  19: double _zoom = 1; 
  20: bool mouseButtonPressed = false; 
  21: bool mouseIsDragging = false; 
  22: Point dragOffset; 
  23: Point currentPosition; 
  24:  
  25: public double ZoomFactor 
  26: { 
  27: get { return _zoom; } 
  28: set { _zoom = value; } 
  29: } 
  30:  
  31: public Page() 
  32: { 
  33: this.InitializeComponent(); 
  34:  
  35: this.MouseMove += delegate(object sender, MouseEventArgs e) 
  36: { 
  37: if (mouseButtonPressed) 
  38: { 
  39: mouseIsDragging = true; 
  40: } 
  41:  
  42: this.lastMousePos = e.GetPosition(this.msi);
  43:  
  44: }; 
  45:  
  46: this.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e) 
  47:  
  48: { 
  49:  
  50: mouseButtonPressed = true; 
  51: mouseIsDragging = false; 
  52: dragOffset = e.GetPosition(this); 
  53: currentPosition = msi.ViewportOrigin; 
  54:  
  55: }; 
  56:  
  57: this.msi.MouseLeave += delegate(object sender, MouseEventArgs e) 
  58: { 
  59: mouseIsDragging = false; 
  60:  
  61: }; 
  62:  
  63: this.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e) 
  64: { 
  65: mouseButtonPressed = false; 
  66: if (mouseIsDragging == false) 
  67: { 
  68: bool shiftDown = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; 
  69:  
  70: ZoomFactor = 2.0; 
  71: if(shiftDown) ZoomFactor = 0.5; //back out when shift is down 
  72: Zoom(ZoomFactor, this.lastMousePos); 
  73:  
  74: } 
  75:  
  76: mouseIsDragging = false; 
  77:  
  78: }; 
  79:  
  80: this.MouseMove += delegate(object sender, MouseEventArgs e) 
  81: { 
  82: if (mouseIsDragging) 
  83: { 
  84:  
  85: Point newOrigin = new Point(); 
  86: newOrigin.X = currentPosition.X - (((e.GetPosition(msi).X - dragOffset.X) / msi.ActualWidth) * msi.ViewportWidth); 
  87: newOrigin.Y = currentPosition.Y - (((e.GetPosition(msi).Y - dragOffset.Y) / msi.ActualHeight) * msi.ViewportWidth); 
  88: msi.ViewportOrigin = newOrigin; 
  89: } 
  90: }; 
  91:  
  92: new MouseWheelHelper(this).Moved += delegate(object sender, MouseWheelEventArgs e) 
  93: { 
  94:  
  95: e.Handled = true; 
  96: if (e.Delta > 0) 
  97: ZoomFactor = 1.2; 
  98: else 
  99: ZoomFactor = .80; 
 100:  
 101: Zoom(ZoomFactor, this.lastMousePos); 
 102:  
 103: }; 
 104:  
 105: } 
 106:  
 107: public void Zoom(double zoom, Point pointToZoom) 
 108:  
 109: { 
 110:  
 111: Point logicalPoint = this.msi.ElementToLogicalPoint(pointToZoom); 
 112: this.msi.ZoomAboutLogicalPoint(zoom, logicalPoint.X, logicalPoint.Y); 
 113:  
 114: } 
 115:  
 116: } 
 117:  
 118: }

我也碰到一个麻烦,不过因为我还没安装Silverlight 2 Beta 1工具安装程序Silverlight 2 Beta 1工具安装程序故障排除),我还没在调试器上试过。我刚在Expression Blend 2.5和Notepad2中创建了它。我太享受这过程了,都不想停下来去安装其他东西了。

  • 我发现当我应该用一个absolute factor的时候,我却用了相对计算的ZoomFactor。
  • 第三,我想避免图像平移出可视范围(就是说我不想大家迷失方向),而且我希望能给缩小放大设置合理的上限/下限。
  • 不要忘了在主机IIS上将.xap文件设置为mime 类型应用/ x-silverlight-app

 

这一切实在太棒了,而且也不难。我也会在上午再琢磨下还有没有其他办法实现此操作。

 

Leave a Comment
  • Please add 1 and 2 and type the answer here:
  • Post