Опубликован: 24.03.2009 | Доступ: свободный | Студентов: 2283 / 115 | Оценка: 4.24 / 3.93 | Длительность: 17:47:00
Лекция 11:

Мультимедиа, рукописный ввод и Deep Zoom

Первый проект Deep Zoom

Чтобы использовать Deep Zoom, создадим новое приложение Silverlight. Прежде чем делать что-либо еще, необходимо скомпилировать приложение. При этом будет создан каталог ClientBin в проекте Веб-приложения. Сделав это, закройте решение.

Теперь в Windows Explorer скопируйте каталог, содержащий файл dzc output.xml и подпапки с фраг-ментированными изображениями, в папку ClientBin Веб-приложения. Сделав это, вновь откройте решение. Solution Explorer вашего проекта будет выглядеть примерно так, как показано на рис. 11.25.

 Добавление данных Deep Zoom в Веб приложение

Рис. 11.25. Добавление данных Deep Zoom в Веб приложение

Теперь, чтобы сформировать визуальное представление содержимого Deep Zoom, необходимо просто добавить MultiScaleImage в Page.xaml и в качестве значения его свойства Source задать путь к файлу dzc output.xml (в данном случае, этот файл располагается в /dzcsample/dzc output.xml ), а также необходимые ширину и высоту. Посмотрим, как будет выглядеть ваш Page.xaml:

<UserControl x:Class="DZCSampleApp.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xm lns:x=" http://schemas.microsoft.com/winfx/2006/xam l"
Width = "400" Height="300">
<Canvas>
<MultiScaleImage Source="dzcsample/dzc_output.xml" Height="300" Width="400" /> </Canvas> </UserControl>

Итак, при выполнении этого приложения элемент управления MultiScaleImage будет формировать визуальное представление верхнего элемента в SceneGraph, увеличивая его от оригинального масштаба изображения до заданных ширины и высоты (в данном случае, 400 * 300).

Как видите, в приложении нет автоматической реализации управления мышью, поэтому мы не можем перемещаться по изображению или менять его масштаб. Как это делается, будет рассмотрено в следующем разделе

Использование мыши и логических координат в Deep Zoom

Как и все остальные элементы управления Silverlight, MultiScaleImage может объявлять функции для обработки событий. Например, для перемещения изображения используются обычные события мыши: MouseLeftButtonDown, MouseLeftButtonUp и Mouse Move, - и обрабатываются они так же, как это делается при перемещении любого элемента методом "drag-and-drop". Сначала, рассмотрим XAML для MultiScaleImage, определяющий эти события:

<UserControl x:Class="DeepZoomSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xa ml/presentation" 
  xm lns:x=" http://schemas.microsoft.com/winfx/2006/xam l" Width = "640" Height="480"> <Canvas>
<MultiScaleImage x:Name="dz" Source="dzcsample/dzc_output.xml" 
  MouseLeftButtonDown = "MultiScaleImage  MouseLeftButtonDown" MouseLeftButtonUp="MultiScaleImage  MouseLeftButtonUp" 
  MouseMove="MultiScaleImage  MouseMove" Height="480" Width = "640"></MultiScaleImage> </Canvas> </UserControl>

И теперь рассмотрим каждый из этих обработчиков событий более подробно. Прежде всего, есть код, общий для них всех, который обеспечивает отслеживание текущего состояния мыши и просматриваемых в настоящий момент координат MultiScaleImage:

bool dragging = false; double dx = 0; double dy = 0; Point p0; Point p1; Point pLast;

Теперь посмотрим, что происходит, когда пользователь щелкает изображение кнопкой мыши:

private void MultiScaleImage MouseLeftButtonDown( object sender, MouseButtonEventArgs e) 
{
 dragging = true;
 p0 = dz.ElementToLogicalPoint(new Point(0, 0));
 p1 = dz.ElementToLogicalPoint(new Point(640, 480));
 dx = 0;
 dy = 0;
 double x = e.GetPosition(null).X;
 double y = e.GetPosition(null).Y;
 pLast = dz.ElementToLogicalPoint(new Point(x, y));
}

Предполагается, что пользователь удерживает кнопку мыши и двигает мышью, поэтому задаем Буле-вому свойству dragging (перетягивание) значение true. Теперь необходимо получить текущие координаты видимой части изображения. Вспомним, что для верхнего изображения задана позиция (0,0), или x = 0 and y = 0, и его высота и ширина заданы равными 1. Это логические координаты и логические размеры.

В Silverlight логические координаты верхнего левого угла и нижнего правого угла окна можно получить с помощью метода ElementToLogicalPoint (Логическая точка элемента), передав в него физические координаты. Итак, представим, что изображение было увеличено и немного передвинуто. Теперь если вызвать этот API для физической точки (0,0), т.е. верхнего левого угла видимой в данный момент части изображения,будет возвращена логическая точка, представляющая положение это точки на полном изображении. Чтобы получить координаты нижнего правого угла, делаем то же самое для точки, координаты которой соответствуют ширине и высоте физического экрана (в данном случае, 640 * 480).

Мы хотим отслеживать изменение размеров относительно осей х и у, поэтому задаем переменным dx и dy значение 0. Зачем это сделано, станет понятно через мгновение.

Кроме того, необходимо получать логические координаты курсора мыши. Для этого вызывается API ElementToLogicalPoint, в него передается текущее положение мыши (которое можно получить из объекта MouseEventArgs, передаваемого в эту функцию) и возвращаемые результаты сохраняются в переменной pLast.

Итак, что происходит, когда пользователь начинает перетягивание, удерживая кнопку мыши нажатой? Мы хотим получить эффект перемещения по изображению. Вот код, реализующий это:

private void MultiScaleImage  MouseMove(
object sender, MouseEventArgs e) { if (dragging) { if (e!=null) 
  { double x = e.GetPosition(null).X; double y = e.GetPosition(null).Y;
Point pCurrent = dz.ElementToLogicalPoint(new Point(x, y)); if (pLast! = null) 
  { dx += (pCurrent.X - pLast.X); dy += (pCurrent.Y - pLast.Y); Point origin = 
     new Point(p0.X - dx, p0.Y - dy); dz.ViewportOrigin = origin; } pLast = pCurrent; } } }

Событие MouseMove формируется независимо от того, удерживается кнопка мыши или нет, поэтому для обозначения перетягивания используем переменную dragging. Итак, если пользователь выполняет перетягивание, и MouseEventArgs не null, будет выполняться весь остальной код.

В данном случае, мы извлекаем текущие координаты мыши и сохраняем их логические эквиваленты (полученные с помощью метода ElementToLogicalPoint элемента управления) в точке pCurrent. Теперь если pLast не null, значит, пользователь выполняет перетягивание, и мышь переместилась относительно ее предыдущего положения. Итак, чтобы получить изменение логических координат, произошедшее в результате перемещения мыши из предыдущей точки в текущую, мы просто вычисляем разницу (дельту) между предыдущими и текущими координатами относительно обеих осей (х и у). После этого задаем для свойства Origin (Начало отсчета) элемента управления MultiScaleImage исходные координаты с учетом дельта по х и у. Это обеспечит эффект "перемещения" изображения при перемещении мышью, хотя мы, по сути, просто изменяем координаты верхнего левого угла отображаемой части изображения. По завершении перемещения необходимо просто задать положение Last (Последний) как Current, чтобы, когда пользователь вновь начнет двигать мышью, вычисления производились относительно этой точки, а не той, в которой пользователь нажмет кнопку мыши.

Наконец, необходимо, чтобы после того, как пользователь отпустит кнопку мыши, все вернулось в исходное состояние. Сделать это довольно просто. Рассмотрим код:

private void MultiScaleImage  MouseLeftButtonUp( object sender, MouseButtonEventArgs e) {
dragging = false;
p0 = new Point();
p1 = new Point();
pLast = new Point();
dx = 0;
dy = 0; }

Эти три простые функции обеспечивают пользователю возможность перетягивать изображение и перемещаться по нему независимо от степени его увеличения. В следующем разделе будет показано, как с помощью колеса мыши увеличивать и уменьшать изображение и, таким образом, открывать части изображения, скрытые при других степенях увеличения.

Создание функциональности масштабирования с использованием колеса мыши

Проблемой при создании приложений Deep Zoom является то, что стандартным средством изменения масштаба, де факто, является колесо мыши, но Silverlight и .NET не обрабатывают события колеса мыши. Что же можно сделать? Существует два варианта. Первый - использовать JavaScript вместо C#, потому что браузер может перехватывать перемещения колеса мыши и формировать события в ответ на его прокручивание. Второй вариант - использовать браузер как мост к Silverlight, т.е. браузер должен будет перехватывать событие и затем информировать .NET об этом. Вся дальнейшая обработка будет осуществляться в .NET. Все намного проще, чем кажется!

Прежде всего, необходимо обеспечить возможность использования API браузера в Silverlight, поэтому не забудьте включить в код следующую строку:

using System.Windows.Browser;

Затем в конструкторе Page элемент управления должен быть зарегистрирован как поддерживающий сценарии. Методы элементы управления, обозначенные как ScriptableMember (Участник, поддерживающий сценарии), доступны из JavaScript. Вот как это делается:

public Page() {
InitializeComponent();
HtmlPage.RegisterScriptableObject("MySilverlightObject", this); }

Далее требуется перехватывать события колеса мыши на этой странице. Для этого сначала добавляем вызов handleLoad в тег <Body>, чтобы обеспечить выполнение JavaScript-кода при формировании визуального представления страницы:

<body style=" height: 100%; margin :0;" onload = "handleLoad();">
...
</body>

Затем в JavaScript-функции handleLoad задается событие:

function handleLoad() 
{
 window.onmousewheel = document.onmousewheel = onMouseWheel;
 if (window.addEventListener)
 { 
  window.addEventListener('DOMMouseScroll', onMouseWheel, false);
 } 
}

Тем самым определяем, что JavaScript-функция onMouseWheel (При прокручивании колеса мыши) будет выполняться при любом прокручивании колеса мыши.

function onMouseWheel() 
{
 if(!event)
 { event = window.event;
 }
 var slPlugin = $get("Xaml1");
 slPlugin.content.MySilverlightObject.dz_MouseWheel( event.clientX, event.clientY, event.wheelDelta);
}

Эта функция просто принимает ссылку на элемент управления Silverlight (в данном случае, при создании ему присваивается имя Xaml1) и затем вызывает функцию выделенного кода, определенную для него. Для вызова используется синтаксис <ИмяКомпонента>.content.<ИмяОбъекта>.<ИмяФункции>.

<ИмяКомпонента> - это переменная, определенная в JavaScript как ссылка на объект Silverlight. <ИмяОбъекта> - это имя, заданное для объекта при его регистрации (ее можно увидеть в конструкторе Page() ). <ИмяФункции> - это имя вызываемой функции. Эта функция должна быть соответствующим образом описана, чтобы JavaScript "видел" ее. В данном случае, вызывается функция dz MouseWheel, рассмотрим ее:

[ScriptableMember]
public void dz  MouseWheel(double x, double y, int delta)
{
 double dZoomFactor=1.33;
 if (delta < 0) dZoomFactor= 1/1.33;
 Point pz = dz.ElementToLogicalPoint(new Point(x, y));
 dz.ZoomAboutLogicalPoint(dZoomFactor, pz.X, pz.Y); 
}

Прежде всего, как видите, она обозначена ScriptableMember, т.е. JavaScript может видеть и вызывать ее. Функция JavaScript передает текущие координаты мыши и дельта, возникающие в результате изменения масштаба. Дельта будет иметь положительное значение при прокручивании колеса вперед и отрицательное значение при прокручивании назад.

Масштабный коэффициент каждого прокручивания колеса задан равным 33% (но он может быть любым), таким образом, переменной dZoomFactor (Масштабный коэффициент) задается значение 1.33 при увеличении и 1/1.33 при уменьшении масштаба.

Далее требуется, чтобы изменение размеров происходило вокруг текущего положения курсора мыши на изображении. Это очень просто сделать, преобразовав координаты курсора мыши в логическую точку с помощью метода ElementToLogicalPoint элемента управления MultiScaleImage. Имея координаты и коэффициент масштабирования, вызываем метод ZoomAboutLogicalPoint (Масштабирование вокруг логической точки), чтобы обеспечить изменение размеров MultiScaleImage.

Коллекции в Deep Zoom

Кроме возможности увеличения и уменьшения изображения, можно также создавать коллекции изображений и работать с ними в масштабируемой среде.

Возможно, вы заметили, что при экспорте изображений из редактора Deep Zoom всегда предлагалась опция Create Collection (Создать коллекцию). Как следует из ее имени, эта опция обеспечивает создание коллекции изображений. Посмотрим на рис. 11.26. Как видите, я разместил в рабочей области множество изображений. Теперь давайте посмотрим, как их можно экспортировать в виде коллекции.

Для работы с изображениями коллекции Silverlight предлагает коллекцию SubImages (Множество изображений). Обратите внимание, что при формировании визуального представления страницы полный набор изображений не будет загружаться, поэтому эта коллекция будет пустой в этот момент. Чтобы иметь возможность работать с коллекцией, необходимо описать событие ImageOpenSucceeded (Изображение открыто успешно). Это событие будет формироваться в случае успешной загрузки и отображения.

 Создание коллекции Deep Zoom

Рис. 11.26. Создание коллекции Deep Zoom

Рассмотрим XAML:

<MultiScaleImage x:Name="dz"
           Source="dzcsample/dzc_output .xml"
           ImageOpenSucceeded = "dz ImageOpenSucceeded"
           Height="480" Width="640">
</MultiScaleImage>

В этот момент коллекция SubImages будет заполнена и может использоваться для работы с отдельными рисунками, ее составляющими. Рассмотрим пример изменения месторасположения изображений:

private void dz ImageOpenSucceeded(object sender, RoutedEventArgs e) 
{
  int nImages = dz.SubImages.Count;
  for (int lp = 0; lp < nImages; lp++)
  { 
   dz.SubImages[lp].ViewportOrigin = new Point(lp*0.1, lp*0.1);
  }
}

Как видите, процесс абсолютно аналогичен тому, который использовался ранее для работы с одним рисунком. В данном случае, каждое изображение перемещается путем использования SubImages[lp,], где lp - это переменная цикла, которая может принимать значения от 0 до числа, соответствующего количеству изображений в коллекции. Результаты представлены на рис. 11.27. Обратите внимание на разницу между этой и исходной компоновками, которая представлена на рис. 11.26.

 Компоновка коллекции изображений

Рис. 11.27. Компоновка коллекции изображений

Заключение

В этой длинной лекции представлены три наиболее мощных элемента управления, предлагаемые Silver-light 2. Сначала был подробно рассмотрен элемент управления MediaElement и то, как можно использовать Silverlight для воспроизведения и трансформации видео- и/или аудиосодержимого, включая программирование прозрачности, маркеры, динамические маркеры и т.д. Затем вы познакомились с рукописными примечаниями и устройствами, поддерживающими их, а также тем, как Silverlight может обеспечить поддержку рукописного ввода на Веб-страницах. Наконец, вашему вниманию была представлена технология Deep Zoom и реализация этой новой возможности в Silverlight. Вы научились создавать сцены и коллекции, расширенные функциональностью глубокого масштабирования.