Makale Özeti

Bu yazımızda Silverlight 2.0 Beta 2 ile beraber gelen MultiScaleImage kontrolünün kullanımına DeepZoom uygulamaları ile göz atarken sıfırdan kendi uygulamalarımızı geliştirmenin yolunu inceleyeceğiz. Makale sonunda hoş animasyonlu bir örnek ile çalışmamızı sonlandıracağız.

Makale

Silverlight 2.0 ile beraber gelen kontrollerden biri de MultiScaleImage kontrolü. Bu kontrolün yapabildikleri arasında gerçekten çok ilginç uygulamalar var. Genel itibari ile çok büyük boyutta resimlerin istemci tarafında bant genişliğinin en uygun performans ile kullılarak gösterilmesini sağladığını söyleyebiliriz. Örneğin elinizde çok yüksek çözünürlükte 2GB'lık bir fotoğraf var ve bu fotoğrafı istemci tarafında göstermek istiyorsunuz veya elinizde toplam 3GB'lık bir fotoğraf arşivi var ve bunu güzel bir Silverlight galerisi şeklinde kullanıcılarla paylaşmak istiyorsunuz. Fakat uygulamanın çalışırken doğal olarak tüm resimleri yüklememesi hatta sadece o an ekranda gözüken kısımları yüklemesi gerekiyor. Tüm bunları elle tek tek kodlayarak yapabiliriz fakat MultiScaleImage varken aslında herşey çok daha kolay ilerliyor.

Deep Zoom Composer

MultiScaleImage kontrolü içerisinde gösterilecek resimlerin farklı detaylarda gösterilebilmesi ve kullanıcı resme zoom yaptıkça yeni detayların yüklenerek ekranda gösterilebilmesi için arkaplanda resimlerin biraz detaylı bir yapıda hazırlanmış olması gerekiyor. Bu işlemleri otomatik olarak yapabilecek bir uygulama olan Deep Zoom Composer'ı aşağıdaki adresten bilgisayarınıza indirip kurabilirsiniz.

http://www.microsoft.com/downloads/details.aspx?FamilyID=457b17b7-52bf-4bda-87a3-fa8a4673f8bf&DisplayLang=en

Yüklemeyi yapıp yeni bir DeepZoom projesi yarattığınızda programın arayüzündeki "Add Image" düğmesi ile projeye istediğiniz kadar resim ekleyebilirsiniz. Eklediğiniz bu resimleri "Compose" sekmesinde sahneye sürükleyerek istediğiniz şekilde resimleri iç içe veya üst üste koyabilirsiniz. Resimleri ufaltabilir veya büyütebilirsiniz. Unutmayın ki burada bir resmi diğerine göre çok ufak yerleştirseniz de kullanıcı birazdan hazırlayacağımız uygulamada zoom yaparak tüm detayları görebilecek. Yani bir insan resmi koyup gözünün içine de ufacık görünecek şekilde aslında 5MB'lık kocaman bir fotoğraf yerleştirebilirsiniz. Kullanıcı resmi ilk açtığında bu fotoğraf insanın gözünün içinde ufacık olduğu için tamamen yüklenmeyecek ve sadece gözüktüğü kadarı istemciye gönderilecektir. Oysa kullanıcı zoom yaparak gözün içine girip büyük fotoğrafı görmeye başladığında ise detaylar yüklenerek fotoğrafınız tüm çözünürlüğü ile net bir şekilde gözükecektir. DeepZoom Composer'ın kullanımı ile ilgili detaylı bilgiyi sevgili Turhal Temizer'in yazısından edinebilirsiniz.

DeepZoom Composer içerisinde fotoğraflarımız.
DeepZoom Composer içerisinde fotoğraflarımız.

Biz uygulamamızda yukarıdaki gibi fotoğrafları sahneye ekleyip sağ tuş ile gelen menüden de tüm fotoğrafları "Arrange to Grid" diyerek bir tablo içerisindeymiş gibi hizalatalım. Böylece tüm fotoğraflar yan yana ve alt alta sıralanacaktır. Daha önce de bahsettiğim gibi isterseniz fotoğrafları üst üste yerleştirme ve farklı tasarımlar yapma şansınız da var. Örneğin bir mekanın duvarındaki reklamı ayrı bir detaylı fotoğraf olarak koyabilirsiniz. Böylece kullanıcı mekan fotoğrafındaki duvarda yer alan reklama zoom yaptığında aslında daha detaylı farklı bir görsel yüklenmeye başlayacak ve normalde elde edilemeyen bir detay gösterimi yapılabilecektir.

Son olarak DeepZoom Composer içerisinde "Export" bölümüne geçerek artık fotoğraflarımızın gerekli çıktılarını almak istiyoruz. Export esnasında özellikle "Output Type" olarak "Export Images" seçeneğini işaretlemeyi unutmayın. Normalde DeepZoomComposer isterseniz size hazır bir Silverlight projesi de yaratabiliyor fakat bu yazımızda biz kendi uygulamamızı hazırlayacağımız için sadece fotoğrafların düzenlenerek gerekli arşivin oluşturulmasını istiyoruz.

DeepZoom Composer arşivimiz.
DeepZoom Composer arşivimiz.

Yukarıda da gördüğünüz üzere gerekli dosyalar bizim için hazırlanmış. Buradaki XML dosyalarını tek tek inceleyebilirsiniz. Aslında her bir dosya ayrı birer XML dosyasına yönlendiriyor bizi. Arşive eklediğimiz her resim için ayrıca birer XML dosyası yaratılıyor ve bu dosyalar içerisinde resimlerle ilgili konum bilgisi gibi detaylar yer alıyor. Ayrıca her resmimizin farklı boyutlarda kopyaları da klasörler içerisine kopyalanmış durumda. Hatta çok büyük resimler parçalara bölünerek ayrı ayrı dosyalar olarak da kaydedilmiş. MultiScaleImage kontrolünün de gücü zaten buradan geliyor. Kaynaktaki farklı boyuttaki ve parçalardaki fotoğrafları gerçek zamanlı olarak birleştirebiliyor ve otomatik olarak ekranda gözüken detaya uygun hedef dosyaları istemciye yüklüyor. Tüm geçiş efektlerini de tabi ki otomatik olarak yapıyor. Peki artık kaynak dosyalarımız hazır olduğuna göre uygulamamızı da hazırlamaya başlayalım.

Silverlight projemizi yaratalım...

Yeni bir Silverlight projesi yaratarak hemen içerisine bir MultiScaleImage kontrolü yerleştiriyoruz. Şimdilik tasarım anlamında farklı birşey yapmayacağız. Uygulamamızın XAML kodu aşağıdaki gibi basit bir şekilde sonlanıyor.

<UserControl x:Class="SilverlightApplication6.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="1024" Height="768">

    <Grid x:Name="LayoutRoot" Background="White">

        <MultiScaleImage x:Name="DeepZoom"/>

    </Grid>

</UserControl>

DeepZoom adını verdiğim MultiScaleImage kontrolümüzü programlamaya başlayacağız. İlk olarak yapmak istediğimiz işlemleri bir sıralayalım;

  • Fotoğraf arşivimizi kontrole yükleyeceğiz.
  • Fare ile fotoğraf arşivi içerisinde gezilebilmesini sağlayacağız
  • Farenin roller'ı ile zoom ve zoom out yapılabilmesini sağlayacağız
  • Artistik hareketler yapacağız

Listemizdeki tek tek yaparak ilerleyelim. İlk olarak fotoğraf arşivimizi doğrudan kontrolümüze bağlayalım.

[VB]

        DeepZoom.Source = New DeepZoomImageTileSource(New Uri("GeneratedImages/dzc_output.xml", UriKind.Relative))

[C#]

            DeepZoom.Source = new DeepZoomImageTileSource(new Uri("GeneratedImages/dzc_output.xml", UriKind.Relative));

Gördüğünüz üzere doğrudan DeepZoom kontrolümün Source özelliğini değiştiriyorum ve yarattığımız yeni bir DeepZoomImageTileSource nesnesini kendisine atıyoruz. Bu esnada bir önceki adımda DeepZoom Composer'ın bizim için yarattığı arşivden dzc_output.xml dosyasını kaynak olarak gösteriyoruz. DeepZoom Composer'ın yarattığı GeneratedImages klasörünü doğru olarak çalışabilmesi için XAP dosyanız ile aynı konuma kopyalamanız gerekecektir.

Fotoğraf arşivini gezelim.

Sıra geldi fare ile fotoğrafların arasındaki gezintimize başlamaya. Aslında yapacağımız işlem klasik bir Sürükle&Bırak işleminden farklı değil. Fakat bu sefer sürükleyip bıraktıracağımız şey aslında MultiScaleImage kontrolünün ViewPortOrigin'i. Yani bizim bu arşive MultiScaleImage aracılığı ile bakış noktamızı değiştreceğiz.

[VB]

    Dim Tasiniyor = False

    Dim FareKonum As Point

    Dim DeepZoomOrigin As Point

[C#]

        bool Tasiniyor = false;

        Point FareKonum;

        Point DeepZoomOrigin;

Sürükle ve bırak işlemi öncesinde ihtiyacımız olacak global değişkenlerimizi yukarıdaki gibi yaratalım. Sonrasında toplam üç farklı event için kod yazmamız gerekiyor. MouseLeftButtonDown, MouseMove ve MouseLeftButtonUp durumlarında sürükleme işlemini başlatıp durdurmaya karar vereceğiz.

[VB]

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        Tasiniyor = True

        FareKonum = e.GetPosition(Me)

        DeepZoomOrigin = DeepZoom.ViewportOrigin

    End Sub

[C#]

        void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = true;

            FareKonum = e.GetPosition(this);

            DeepZoomOrigin = DeepZoom.ViewportOrigin;

        }

Kullanıcı fare ile sahneye tıkladığında hemen taşınma işlemini başlattığımız için global Tasiniyor değişkenini True yapıyoruz. Böylece ileride yazacağımız MouseMove kodu durumdan haberdar olabilecek. Bir sonraki adımda farenin pozisyonunu ve sonrasında da DeepZoom kontrolünün o anki orijin noktasını kenara not alıyoruz. Bu bilgileri ileriki hesaplamalarımızda kullanacağız.

[VB]

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        If Tasiniyor Then

            Dim YeniDeepZoomOrigin As New Point

            YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth)

            YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth)

            DeepZoom.ViewportOrigin = YeniDeepZoomOrigin

        Else

            FareKonum = e.GetPosition(Me)

        End If

    End Sub

[C#]

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            if (Tasiniyor)

            {

                Point YeniDeepZoomOrigin = new Point();

                YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth);

                YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth);

                DeepZoom.ViewportOrigin = YeniDeepZoomOrigin;

            }

            else

            {

                FareKonum = e.GetPosition(this);

            }

        }

Sahnenin MouseMove durumunda ilk olarak bir taşıma işlemi olup olmadığını kontrol ediyoruz. Eğer taşıma işlemi yoksa FareKonum adındaki ve farenin mevcut konumunu saklayan değişkeni yeniliyoruz. Bunu yapmamızın nedeni ileride yazacağımız zoom işlemleri. Zoom işlemini yaparken farenin konumuna hep ihtiyacımız olacak. Burada sürekli güncel konumu FareKonum'a aktarmak gerekiyor. Eğer taşıma işlemi yapılıyorsa bu sefer de DeepZoom kontrolümüzün ViewPortOrigin'ini uygun şekilde ayarlamamız gerek. Bu amaçla kodumuzda yeni bir Point değişkeni tanımlayarak farenin mevcut konumu, eski konumu ve eski orijin noktası arasında koordinat hesaplamaları yaparak ilerliyoruz.

[VB]

    Private Sub Page_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonUp

        Tasiniyor = False

    End Sub

[C#]

        void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = false;

        }

Son olarak farenin sol tuşu bırakıldığında da taşıma işlemini sonlandırıyoruz. Böylece artık fotoğraf arşivi içerisinde kullanıcılar rahatlıkla gezebilecektir. Sıra geldi zoom meselesine.

Fare ile Zoom-In ve Zoom-Out

Fare ile zoom işlemleri için farenin roller'ını kullanacağız. Detaylar için Silverlight 2.0 içerisinde fare roller'ı kullanmayla ilgili buradaki makleyi inceleyebilirsiniz. İlk olarak DOM üzerinden gerekli eventları Silverlight ile yakalamamız gerekiyor.

[VB]

        System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

[C#]

            System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", FareTekerlekDondu);

FareTekerlekDondu eventı içerisinde aşağıda kodları yazmamız gerekiyor. Bu kodların çok detayına inmeyeceğiz çünkü bir önceki paragrafta bahsettiğim makalede zaten bu konu detayları ile inceleniyor. Bizim için bu kodda önemli olan kısım Zoom işleminin yapıldığı satırlar.

[VB]

    Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs)

        Dim DonMiktar As Integer = 0

        Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject

        'IE ve OPERA

        If Not Gelen.GetProperty("wheelDelta") Is Nothing Then

            'OPERA'da ters!

            If Not Gelen.GetProperty("opera") Is Nothing Then

                DonMiktar = -DonMiktar

            End If

            DonMiktar = Gelen.GetProperty("wheelDelta")

            'Mozilla ve Safari

        ElseIf Not Gelen.GetProperty("detail") Is Nothing Then

            DonMiktar = -Gelen.GetProperty("detail")

        End If

        If DonMiktar > 0 Then

            'Zoom yap

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y)

        Else

            'Uzaklaş

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y)

        End If

 

        If DonMiktar <> 0 Then

            e.PreventDefault()

            Gelen.SetProperty("returnValue", False)

        End If

    End Sub

[C#]

        private void FareTekerlekDondu(object sender, System.Windows.Browser.HtmlEventArgs e)

        {

            int DonMiktar = 0;

            System.Windows.Browser.ScriptObject Gelen = e.EventObject;

            //IE ve OPERA

            if ((Gelen.GetProperty("wheelDelta") != null)) {

                //OPERA'da ters!

                if ((Gelen.GetProperty("opera") != null)) {

                    DonMiktar = -DonMiktar;

                }

                DonMiktar = (int)Gelen.GetProperty("wheelDelta");

            }

            //Mozilla ve Safari

            else if ((Gelen.GetProperty("detail") != null)) {

                DonMiktar = -1 * (int)Gelen.GetProperty("detail");

            }

            if (DonMiktar > 0) {

                //Zoom yap

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

            else {

                //Uzaklaş

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

 

            if (DonMiktar != 0) {

                e.PreventDefault();

                Gelen.SetProperty("returnValue", false);

            }

        }

İlk olarak ElementToLogicalPoint metodu ile elimizdeki fare konumunun DeepZoom içerisinde tam olarak hangi koordinatlara geldiğini buluyoruz. Sonrasında da ZoomAboutLogicalPoint metodu ile zoom işlemini yapıyoruz. Zoom işlemi esnasında bizden üç parametre isteniyor, zoom miktarı, zoomlanacak noktanın X ve Y koordinatları. Böylece basit bir şekilde zoom işlemini de çözmüş olduk.

Atraksyon zamanı!

Yapılacaklar listemizde son bir öğe kaldı :) "Atraksyon". Şimdi biraz hareketli birşeyler yapalım. Eğer uygulamanın başından beridir benimle aynı adımları takip ediyorsunuz şu an DeepZoom kontrolü içerisinde yan yana ve alt alta sıralı onlarca fotoğrafınız var demektir. Peki bu fotoğrafları rastgele karıştıran bir düğme eklesek? Animasyonlarla fotoğraf düğmeye her basıldığında rastgele olarak yerlerini değiştirseler hoş olmaz mıydı? Belki de sizin istediğiniz farklı sıralara bile gelebilirler. Hemen kolları sıvayalım ve XAML'ımıza basit bir düğme ekleyelim.

<UserControl x:Class="SilverlightApplication6.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="1024" Height="768">

    <Grid x:Name="LayoutRoot" Background="White">

        <MultiScaleImage x:Name="DeepZoom"/>

        <Button Height="65" HorizontalAlignment="Right" Margin="0,0,30,19" VerticalAlignment="Bottom" Width="174" Content="Karistis" x:Name="Karistir"/>

    </Grid>

</UserControl>

Artık uygulamamızın XAML kodu yukarıdaki şekilde olacak. Düğmeye tıklandığında DeepZoom kontrolü içerisindeki tüm resimleri alarak sırasını karıştırmamız sonra da animasyonlarla yeni konumlara yerleştirmemiz gerek. İlk olarak resimleri karıştıracak olan kodu yazalım.

[VB]

        Dim FotoList As New List(Of MultiScaleSubImage)

        FotoList = DeepZoom.SubImages.ToList()

 

        For x As Integer = 0 To FotoList.Count - 1

            Dim Simdiki As MultiScaleSubImage = FotoList(x)

            FotoList.RemoveAt(x)

            FotoList.Insert(Rnd() * FotoList.Count, Simdiki)

        Next

[C#]

            List<MultiScaleSubImage> FotoList = new List<MultiScaleSubImage>();

            FotoList = DeepZoom.SubImages.ToList();

            Random Rastgele = new Random();

 

            for (int x = 0; x <= FotoList.Count - 1; x++)

            {

                MultiScaleSubImage Simdiki = FotoList[x];

                FotoList.RemoveAt(x);

                FotoList.Insert(Rastgele.Next(FotoList.Count), Simdiki);

            }

Bir DeepZoom içerisinde tüm resimler birer MultiScaleSubImage olarak bulunuyor. DeepZoom içerisinden tüm listeyi alıp içerisindeki her resmi listeden çıkartıp yeni bir rastgele indeks ile ekliyoruz. Böylece her seferinde sıralamayı rastgele değiştirmiş olduk. Sıra geldi bu sıralama ile resimleri sahnedeki yeni konumlarına birer animasyon ile göndermeye.

[VB]

        Dim KolonSayisi As Integer = 5

        Dim SatirSayisi As Integer = 5

        Dim ToplamEklenen As Integer = 0

 

        For Satir As Integer = 0 To SatirSayisi

            For Kolon As Integer = 0 To KolonSayisi

                If ToplamEklenen <> FotoList.Count Then

 

....................                

 

        ToplamEklenen += 1

                Else

        Exit Sub

                End If

            Next

        Next

[C#]

            int KolonSayisi = 5;

            int SatirSayisi = 5;

            int ToplamEklenen = 0;

 

            for (int Satir = 0; Satir <= SatirSayisi; Satir++)

            {

                for (int Kolon = 0; Kolon <= KolonSayisi; Kolon++)

                {

                    if (ToplamEklenen != FotoList.Count)

                    {

                       

..............................

 

                        ToplamEklenen += 1;

                    }

                    else

                    {

                        break;

                    }

                }

            }

Yukarıdaki kodumuzun orta kısmında birazdan her resmi farklı bir konuma animasyon ile gönderen kodu yazacağız. Fakat onun öncesinde kodun ana yapısını bir inceleyelim. Resimler yan yana ve alt alta sıralayacağımız için aslında bir Grid yapısında görsellik yaratmış olacağız. Kodumuzda KolonSayisi ve SatirSayisi değişkenleri kaç kolon ve satırlık bir sıralama yapılacağını belirliyor. ToplamEklenen değişkeni ise o ana kadar kaç fotoğraf eklediğimizi hafızada tutacak, böylece döngü içerisinde eklenen toplam fotoğraf sayısı elimizdeki fotoğraf sayısına ulaşırsa döngüden çıkacağız. Şimdi gelelim fotoğrafları yeni konumlarına gönderecek animasyonları yaratacak kodumuza.

[VB]

        Dim Foto As MultiScaleSubImage = FotoList(ToplamEklenen)

        Dim MevcutKonum As Point = Foto.ViewportOrigin

        Dim HedefKonum As Point = New Point(-1.14 * Kolon, -0.8 * Satir)

 

        'Animasyonu yaratalım

        Dim Anim As New Storyboard

        Dim NoktaAnim As New PointAnimationUsingKeyFrames

        Dim KeyFrame As New SplinePointKeyFrame

        KeyFrame.Value = HedefKonum

        KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1))

 

        Dim Ivme As New KeySpline

        Ivme.ControlPoint1 = New Point(0, 1)

        Ivme.ControlPoint2 = New Point(1, 1)

        KeyFrame.KeySpline = Ivme

        NoktaAnim.KeyFrames.Add(KeyFrame)

 

        Storyboard.SetTarget(NoktaAnim, Foto)

        Storyboard.SetTargetProperty(NoktaAnim, New PropertyPath("ViewportOrigin"))

 

        Anim.Children.Add(NoktaAnim)

 

        Anim.Begin()

[C#]

        MultiScaleSubImage Foto = FotoList[ToplamEklenen];

        Point MevcutKonum = Foto.ViewportOrigin;

        Point HedefKonum = new Point(-1.14 * Kolon, -0.8 * Satir);

 

        //Animasyonu yaratalım

        Storyboard Anim = new Storyboard();

        PointAnimationUsingKeyFrames NoktaAnim = new PointAnimationUsingKeyFrames();

        SplinePointKeyFrame KeyFrame = new SplinePointKeyFrame();

        KeyFrame.Value = HedefKonum;

        KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1));

 

        KeySpline Ivme = new KeySpline();

        Ivme.ControlPoint1 = new Point(0, 1);

        Ivme.ControlPoint2 = new Point(1, 1);

        KeyFrame.KeySpline = Ivme;

        NoktaAnim.KeyFrames.Add(KeyFrame);

 

        Storyboard.SetTarget(NoktaAnim, Foto);

        Storyboard.SetTargetProperty(NoktaAnim, new PropertyPath("ViewportOrigin"));

 

        Anim.Children.Add(NoktaAnim);

 

        Anim.Begin();

Kodumuz biraz uzun gibi gözükse de aslında özünde yaptığımız şey çok basit. İlk olarak döngümüzle oluşturduğumuz ToplamEklenen sayısı üzerinden o anki resmi FotoList içerisinden bir değişkene alıyoruz. MevcutKonum ve HedefKonum değişkenlerimiz ise fotoğrafın şu anki ve animasyonun sonundaki konumlarını saklıyor. Yeni konum hesaplarken kolon ve satır arası mesafelerle sayıları çarparak yeni konumu rahatlıkla hesaplayabiliyoruz. Artık hedeflediğimiz konum da belli olduğuna göre geriye kaldı eldeki fotoğrafı hedef konuma taşıyacak animasyonu yaratmak. Animasyon yapacağımız şey fotoğrafın ViewportOrigin özelliği ve bu özelliği Point tipinde. Bu nedenle PointAnimationUsingKeyFrame kullanarak hedef KeyFrame'i yaratacağız. Kodumuzda baktığımızda KeyFrame adındaki değişkenimiz 1 saniye sonra ViewPortOrigin değerini değiştiriyor. Ayrıca animasyonu ivme vermek için bir de KeySpline kullanıyoruz. Tüm bu nesnelerin birbirlerine eklenme şekilleri XAML'da bir StoryBoard yaratmaktan farklı değil. Kodumuzun en sonunda artık animasyonumuzu çalıştırmak için Begin metodunu çağırabiliriz.

Herşey bitti

Uygulamamız bitti. Artık istediğimiz kadar fotoğraflarımız arasında geçebilir, zoom yapabilir hatta resimleri bir düğme ile animasyonlu bir şekilde karıştırabiliriz. Uygulamanın tam kodunu aşağıda inceleyebilirsiniz.

[VB]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim Tasiniyor = False

    Dim FareKonum As Point

    Dim DeepZoomOrigin As Point

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        'Kaynağımızı bağlayalım

        DeepZoom.Source = New DeepZoomImageTileSource(New Uri("NewFolder1/dzc_output.xml", UriKind.Relative))

 

        'MouseWheel bağlantısı yapalım

        System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

    End Sub

 

    Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs)

        Dim DonMiktar As Integer = 0

        Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject

        'IE ve OPERA

        If Not Gelen.GetProperty("wheelDelta") Is Nothing Then

            'OPERA'da ters!

            If Not Gelen.GetProperty("opera") Is Nothing Then

                DonMiktar = -DonMiktar

            End If

            DonMiktar = Gelen.GetProperty("wheelDelta")

            'Mozilla ve Safari

        ElseIf Not Gelen.GetProperty("detail") Is Nothing Then

            DonMiktar = -Gelen.GetProperty("detail")

        End If

        If DonMiktar > 0 Then

            'Zoom yap

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y)

        Else

            'Uzaklaş

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y)

        End If

 

        If DonMiktar <> 0 Then

            e.PreventDefault()

            Gelen.SetProperty("returnValue", False)

        End If

    End Sub

 

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        Tasiniyor = True

        FareKonum = e.GetPosition(Me)

        DeepZoomOrigin = DeepZoom.ViewportOrigin

    End Sub

 

    Private Sub Page_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonUp

        Tasiniyor = False

    End Sub

 

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        If Tasiniyor Then

            Dim YeniDeepZoomOrigin As New Point

            YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth)

            YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth)

            DeepZoom.ViewportOrigin = YeniDeepZoomOrigin

        Else

            FareKonum = e.GetPosition(Me)

        End If

    End Sub

 

    Private Sub Karistir_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Karistir.Click

        Dim FotoList As New List(Of MultiScaleSubImage)

        FotoList = DeepZoom.SubImages.ToList()

 

        For x As Integer = 0 To FotoList.Count - 1

            Dim Simdiki As MultiScaleSubImage = FotoList(x)

            FotoList.RemoveAt(x)

            FotoList.Insert(Rnd() * FotoList.Count, Simdiki)

        Next

 

        Dim KolonSayisi As Integer = 5

        Dim SatirSayisi As Integer = 5

        Dim ToplamEklenen As Integer = 0

 

        For Satir As Integer = 0 To SatirSayisi

            For Kolon As Integer = 0 To KolonSayisi

                If ToplamEklenen <> FotoList.Count Then

                    Dim Foto As MultiScaleSubImage = FotoList(ToplamEklenen)

                    Dim MevcutKonum As Point = Foto.ViewportOrigin

                    Dim HedefKonum As Point = New Point(-1.14 * Kolon, -0.8 * Satir)

 

                    'Animasyonu yaratalım

                    Dim Anim As New Storyboard

                    Dim NoktaAnim As New PointAnimationUsingKeyFrames

                    Dim KeyFrame As New SplinePointKeyFrame

                    KeyFrame.Value = HedefKonum

                    KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1))

 

                    Dim Ivme As New KeySpline

                    Ivme.ControlPoint1 = New Point(0, 1)

                    Ivme.ControlPoint2 = New Point(1, 1)

                    KeyFrame.KeySpline = Ivme

                    NoktaAnim.KeyFrames.Add(KeyFrame)

 

                    Storyboard.SetTarget(NoktaAnim, Foto)

                    Storyboard.SetTargetProperty(NoktaAnim, New PropertyPath("ViewportOrigin"))

 

                    Anim.Children.Add(NoktaAnim)

 

                    Anim.Begin()

 

                    ToplamEklenen += 1

                Else

                    Exit Sub

                End If

            Next

        Next

    End Sub

End Class

[C#]

namespace SilverlightApplication1

{

    public partial class Page : UserControl

    {

        bool Tasiniyor = false;

        Point FareKonum;

        Point DeepZoomOrigin;

 

        public Page()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Page_Loaded);

            this.MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown);

            this.MouseLeftButtonUp += new MouseButtonEventHandler(Page_MouseLeftButtonUp);

            this.MouseMove += new MouseEventHandler(Page_MouseMove);

            this.Karistir.Click += new RoutedEventHandler(Karistir_Click);

        }

 

        void Karistir_Click(object sender, RoutedEventArgs e)

        {

            List<MultiScaleSubImage> FotoList = new List<MultiScaleSubImage>();

            FotoList = DeepZoom.SubImages.ToList();

            Random Rastgele = new Random();

 

            for (int x = 0; x <= FotoList.Count - 1; x++)

            {

                MultiScaleSubImage Simdiki = FotoList[x];

                FotoList.RemoveAt(x);

                FotoList.Insert(Rastgele.Next(FotoList.Count), Simdiki);

            }

 

            int KolonSayisi = 5;

            int SatirSayisi = 5;

            int ToplamEklenen = 0;

 

            for (int Satir = 0; Satir <= SatirSayisi; Satir++)

            {

                for (int Kolon = 0; Kolon <= KolonSayisi; Kolon++)

                {

                    if (ToplamEklenen != FotoList.Count)

                    {

                        MultiScaleSubImage Foto = FotoList[ToplamEklenen];

                        Point MevcutKonum = Foto.ViewportOrigin;

                        Point HedefKonum = new Point(-1.14 * Kolon, -0.8 * Satir);

 

                        //Animasyonu yaratalım

                        Storyboard Anim = new Storyboard();

                        PointAnimationUsingKeyFrames NoktaAnim = new PointAnimationUsingKeyFrames();

                        SplinePointKeyFrame KeyFrame = new SplinePointKeyFrame();

                        KeyFrame.Value = HedefKonum;

                        KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1));

 

                        KeySpline Ivme = new KeySpline();

                        Ivme.ControlPoint1 = new Point(0, 1);

                        Ivme.ControlPoint2 = new Point(1, 1);

                        KeyFrame.KeySpline = Ivme;

                        NoktaAnim.KeyFrames.Add(KeyFrame);

 

                        Storyboard.SetTarget(NoktaAnim, Foto);

                        Storyboard.SetTargetProperty(NoktaAnim, new PropertyPath("ViewportOrigin"));

 

                        Anim.Children.Add(NoktaAnim);

 

                        Anim.Begin();

 

                        ToplamEklenen += 1;

                    }

                    else

                    {

                        break;

                    }

                }

            }

 

        }

 

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            if (Tasiniyor)

            {

                Point YeniDeepZoomOrigin = new Point();

                YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth);

                YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth);

                DeepZoom.ViewportOrigin = YeniDeepZoomOrigin;

            }

            else

            {

                FareKonum = e.GetPosition(this);

            }

        }

 

        void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = false;

        }

 

        void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = true;

            FareKonum = e.GetPosition(this);

            DeepZoomOrigin = DeepZoom.ViewportOrigin;

        }

 

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            //Kaynağımızı bağlayalım

            DeepZoom.Source = new DeepZoomImageTileSource(new Uri("NewFolder1/dzc_output.xml", UriKind.Relative));

 

            //MouseWheel bağlantısı yapalım

            System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", FareTekerlekDondu);

        }

 

        private void FareTekerlekDondu(object sender, System.Windows.Browser.HtmlEventArgs e)

        {

            int DonMiktar = 0;

            System.Windows.Browser.ScriptObject Gelen = e.EventObject;

            //IE ve OPERA

            if ((Gelen.GetProperty("wheelDelta") != null)) {

                //OPERA'da ters!

                if ((Gelen.GetProperty("opera") != null)) {

                    DonMiktar = -DonMiktar;

                }

                DonMiktar = (int)Gelen.GetProperty("wheelDelta");

            }

            //Mozilla ve Safari

            else if ((Gelen.GetProperty("detail") != null)) {

                DonMiktar = -1 * (int)Gelen.GetProperty("detail");

            }

            if (DonMiktar > 0) {

                //Zoom yap

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

            else {

                //Uzaklaş

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

 

            if (DonMiktar != 0) {

                e.PreventDefault();

                Gelen.SetProperty("returnValue", false);

            }

        }

    }

}

Hepinize kolay gelsin.

Daron Yöndem
MVP, MCT, MCPD, MCITP, MCTS
MCSD, MCAD, MCDBA, MCP, ACP, ICSD
Blog: http://daron.yondem.com
Sorularınız için: http://daron.yondem.com/tr/sorusor