Yazılım.
CevapSitesi.com Beta!
Çözüm Noktası
Facebook, Twitter, Google+ veya e-posta ile paylaşın.
| Sorular | Makaleler | Üyeler | Etiketler  | İletişim
Soru sormak ya da cevap vermek için;
giriş yapın veya üye olun.

Sosyal medya hesaplarınızla da giriş yapabilirsiniz.

Yazılım Makaleleri

0

Canvas ile dönüşüm işlemleri 3: Transform ile Dönüşüm

Canvas çizimlerinde toplu dönüşüm işlemleri için transform ve setTransform yöntemleri kullanılır. transform  yönteminin kullanımı şöyledir:
transform(yatay ölçekleme oranı,
          yatay bükme açısı,
          dikey bükme açısı,
          dikey ölçekleme oranı,
          yatay kaydırma miktarı,
          dikey kaydırma miktarı);          
transform yöntemi çizim kapsamını (tuvali / canvas'ı değil) aynı anda yatay ve dikey olarak ölçeklemek, bükmek ve kaydırmak için kullanılabilir.

transform yöntemi, rotate, translate, scale ile yapılan işlemleri tek seferde yapmanızı sağlar.

transform yöntemi, daha önce rotate, translate, scale ve transform ile yapılmış olan dönüştürme değerleri üzerinden hesaplama yapar. Yani eğer daha önce kapsamı scale ile iki katına ölçeklemişseniz ve transform yönteminde de ölçekleme oranını iki katı olarak bildirmişseniz sonuçta tuval kapsamınız orjinal boyutunun 4 katına ölçeklenmiş olacaktır. Daha önce transform kullanmışsanız, yeni bir transform, önceki transform değerleri ile ulaşılan sonuçlar üzerinden hesaplama yapacaktır.

Örneğin:
ctx.transform(1, 0, 0, 1, 10, 10); // Çizim kapsamını yatay ve dikey 10'ar piksel kaydır
ctx.transform(1, 0, 0, 1, 10, 10);
ctx.transform(1, 0, 0, 1, 10, 10);
Bu işlem sonucunda çizim kapsamı, toplamda 30 piksel sağa ve 30 piksel aşağı kayacaktır.

Ölçekleme ile ilgili örnek verecek olursak:
ctx.transform(2, 0, 0, 1, 0, 0); // Yatay %200 ölçekle.
ctx.transform(2, 0, 0, 1, 0, 0);
ctx.transform(2, 0, 0, 1, 0, 0);

Bu işlem sonucunda çizim kapsamı orjinal boyutunun 8 katına çıkacak ve çizimler normal boyutlarının 8 katı daha büyük ölçeğe göre çizilecektir.

Eğer orijinal ölçülere veya belirli bir ölçüye dönmek isterseniz setTransform yöntemini kullanın. setTransform  yöntemi, dönüşüm değerlerini belirtilen değerlerle değiştirir. Yani önceki değerlere bakmadan dönüşüm yapar. Kullanımı transform yöntemi ile aynıdır.

Orjinal değerlere dönmek isterseniz şunu kullanın.

ctx.setTransform(1, 0, 0, 1, 0, 0);

Şimdi transform yönteminin nasıl çalıştığını biraz açıklayalım.

transform yöntemi dönüşümleri yapabilmek için 3x3 boyutunda bir matris (dizey / matrix) kullanır. Yöntemin parametreleri olarak verdiğimiz değerler bu matrisi oluşturur.

Matris hakkında bilgi almak ve matris hesaplamaları yapmak için şu sayfayı kullanabilirsiniz.

Üstteki kullanımdaki parametreleri,
a = Yatay ölçekleme oranı
b = Yatay bükme açısı
c = Dikey bükme açısı
d = Dikey ölçekleme oranı
e = Yatay kaydırma miktarı
f = Dikey kaydırma miktarı
şeklinde harflerle temsil eder ve kullanımı da şöyle gösterirsek...
transform(a, b, c, d, e, f); 

transform yönteminin kullandığı matrisi şu şekilde ifade edebiliriz.

a
c
e
b
d
f
0
0
1

Transform matrisindeki son satır her zaman 0, 0 ve 1'dir.

Çizim kapsamının (context) varsayılan transform matrisi şu şekilde gösterilen bir birim matristir.

1
0
0
0
1
0
0
0
1

Buradan da görüleceği gibi ölçekleme oranı (a ve d) varsayılan olarak 1 yani %100'dür.

Şimdi transform dönüşümlerini daha iyi anlayabilmek için bu matrislerin yöntem tarafından nasıl kullanıdığına bakalım.

Bir noktanın koordinatları matris ile çarpılarak noktanın yeni koordinatları bulunur ve buna göre çizim yapılır.

Örneğin, noktanın koordinatlarının x=100, y=50 olduğunu varsayarsak bunu bir matrisle şöyle ifade ederiz (1. satır x, 2. satır y değeridir. 3. satır her zaman 1'dir):

 100
 50
 1

transform yöntemi ile yatay olarak %50, dikey olarak %100 ölçeklemek ve dikey olarak 20 piksel kaydırmak istersek şöyle bir kod yazmalıyız:

ctx.transform(0.5, 0, 0, 1, 0, 20);
Bu ifadenin matris karşılığı şöyle olacaktır:

0.5
0
0
0
1
20
0
0
1

Bu iki matrisi birbiriyle çarparsak (yine hatırlatalım şu sayfadan yapabilirsiniz) şöyle bir matris elde ederiz:

50
70
1

Ve neticede aynı noktanın yeni koordinatları x = 50, y =70 olur.

transform yönteminin üstte bahsettiğim gibi önceki transform sonuçları üzerinden hesaplama yaptığına dikkat edin. Yani bundan sonra bir transform daha kullanırsak noktanın yeni koordinatı en son elde edilen matristeki değerler üzerinden hesaplanacaktır. Diğer bir deyişle çarpım sonucu elde edilen son matris (x ve y değerleri), yeni translate ile oluşturulan matrisle çarpılacak ve noktanın yeni koordinatları bulunacaktır.

Şimdi gelelim döndürme işine.

Tuval kapsamını (dolayısıyla çizimi) döndürmek için bükme (skew) parametreleri kullanılır. Döndürme için yatay bükme (b) ve dikey bükme (c) değerleri  radyan cinsinden açılar olarak verilir.

Canvas çizimlerinde radyan açı ölçü biriminin kullanımı ile ilgili olarak bilgi almak için  "Canvas ile daire, çember, yay ve dilimler çizmek" makalesini okuyabilirsiniz. Burada basitçe şöyle açıklayalım: Bir dairede 2 x Π radyan (yani yaklaşık 6.28 radyan) vardır. Buna göre 180 derece = Π radyan, 90 derece = Π / 2 radyan ve 270 derece = 1.5 Π radyandır.

Bükme parametrelerini kendiniz doğrudan değer olarak vermeye çalışmayın. Çünkü doğru bir döndürme için aynı zamanda ölçek de vermelisiniz. Aksi halde büyüyen veya küçülen görüntüler elde edersiniz. Bunun yerine aşağıdaki genel işlemler için kullanılan matrislerden yararlanın.

Çizimi koordinat eksenlerinin merkez noktası etrafında döndürmek çin matris:

cos(açı)
-sin(açı)
0
sin(açı)cos(açı)
0
001

Fonksiyon karşılığı:
var aci = Math.PI / 4; // 45 derece
ctx.translate(Math.cos(aci), Math.sin(aci), -Math.sin(aci), Math.cos(aci), 0, 0);

Çizimi x eksenine göre bükmek için matris:

1
tan(açı)
0
0
1
0
0
0
1

Fonksiyon karşılığı:
var aci = Math.PI / 4; // 45 derece
ctx.translate(1, 0, Math.tan(aci), 1, 0, 0);

Çizimi y eksenine göre bükmek için matris:


1
0
0
tan(açı)
1
0
0
0
1

Fonksiyon karşılğı:

var aci = Math.PI / 4; // 45 derece
ctx.translate(1, Math.tan(aci), 0, 1, 0, 0);

Çizimi ölçeklemek için matris:


Yatay ölçekleme oranı
0
0
0
Dikey ölçekleme oranı
0
0
0
1

Fonksiyon karşılığı:

var yatayOlceklemeOrani = 0.5; // %50
var dikeyOlceklemeOrani = 0.25; // %25
ctx.translate(yatayOlceklemeOrani, 0, 0, dikeyOlceklemeOrani, 0, 0);

Çizimi kaydırmak için matris:


1
0
Yatay kaydırma miktarı
0
1
Dikey kaydırma miktarı
0
0
1

Fonksiyon karşılığı:
var yatayKaydirmaMiktari = 100; // 100 piksel
var dikeyKaydirmaMiktari = 50;
ctx.translate(1, 0, 0, 1, yatayKaydirmaMiktari, dikeyKaydirmaMiktari);

Artık bir örnek verelim. Aşağıdaki örnek bir dörtgeni koordinat eksenlerinin merkez noktası (x=0, y=0) etrafında döndürür.

<canvas id="cnTuval" width="200" height="200" style="border:solid 1px red">
    Tarayıcınız HTML5 desteklemiyor.
</canvas><br />

<script>

    function ciz() {

        var tuval = document.getElementById("cnTuval");
        var ctx = tuval.getContext("2d");

        var aci = Math.PI / 6; // 30 derece
        var sin = Math.sin(aci); // 30 derecenin sinüsü
        var cos = Math.cos(aci); // 30 derecenin kosinüsü

        // Eksenlerin ortasını (x=0, y=0 noktasını) tuvalin ortasına kaydır.
        ctx.translate(100, 100);

        var tekrarSayisi = Math.PI * 2 / aci; // Derece olarak 360 / 30 = 12 kez

        // Yazı tipi belirle
        ctx.font = "14px Arial"

        // Çizgi rengini belirle
        ctx.strokeStyle = "black";

        for (i = 0; i < tekrarSayisi; i++) {

            // İçi mavi, kenarlıkları siyah bir dörtgen çiz
            ctx.fillStyle = "blue";
            ctx.fillRect(0, 0, 100, 30);
            ctx.strokeRect(0, 0, 100, 30);

            // Dörtgenin ucuna beyaz harflerle i'nin değerini yaz.
            ctx.fillStyle = "white";
            ctx.fillText(i, 80, 20);

            // Makalede bahsedilen çizimi koordinat eksenlerinin merkez noktası
            // etrafında döndürmek için kullanılan matrisi tanımla.
            // (Her seferinde çizim kapsamını 30 derece daha döndür.)

            ctx.transform(cos, sin, -sin, cos, 0, 0);
            
        };
    }

    ciz();

</script>
Çıktı şöyle olacaktır:



Döndürme işleminin çizilen mavi kutuların sol üstünden yapıldığına dikkat edin. Eğer kutu içinde bir dönme noktası belirlemek isterseniz, örnekteki

ctx.fillRect(0, 0, 100, 30);
ctx.strokeRect(0, 0, 100, 30);
satırlarını
ctx.fillRect(-15, -15, 100, 30);
ctx.strokeRect(-15, -15, 100, 30);
şeklinde yazabilirsiniz. Tabi metinlerin yerlerini de değiştirmeniz gerekir.

Bir de örneğin animasyonlu bir benzerini verelim.
<canvas id="cnTuval" width="200" height="200" style="border:solid 1px red">
    Tarayıcınız HTML5 desteklemiyor.
</canvas><br />

<script>

    function ciz() {

        var tuval = document.getElementById("cnTuval");
        var ctx = tuval.getContext("2d");

        var aci = Math.PI / 6; // 30 derece
        var sin = Math.sin(aci); // 30 derecenin sinüsü
        var cos = Math.cos(aci); // 30 derecenin kosinüsü

        // Eksenlerin ortasını (x=0, y=0 noktasını) tuvalin ortasına kaydır.
        ctx.translate(100, 100);

        ctx.fillStyle = "blue";

        // Saniyede 10 kez çalıştırılacak bir zamanlayıcı kur ve bildirilen
        // isimsiz fonksiyonu çalıştır.
        setInterval(function () {
            // Tuvalin önceki durumunu sakla (son transform değerleri dahildir).
            ctx.save();
            // setTansform ile varsayılan dönüşüm değerlerini ata.
            ctx.setTransform(1, 0, 0, 1, 0, 0);

            // Tuvali temizle.
            ctx.clearRect(0, 0, 200, 200);

            // Tuvalin save'den önceki durumunu geri yükle
            // (Son transform değerleri de geri yüklenir. Bu şekilde çevirmeye kaldığımız
            // yerden devam edebiliriz.)
            ctx.restore();

            // İçi mavi, kenarlıkları siyah bir dörtgen çiz
            ctx.fillRect(-15, -15, 100, 30);
            ctx.strokeRect(-15, -15, 100, 30);

            // Makalede bahsedilen çizimi koordinat eksenlerinin merkez noktası
            // etrafında döndürmek için kullanılan matrisi tanımla.
            // (Her seferinde 30 derece daha döndür.)

            ctx.transform(cos, sin, -sin, cos, 0, 0);

        }, 100); // 100 milisaniye

    }
    ciz();

</script>

Örneğin çıktısı şöyle olacaktır:





Son olarak transform yöntemi ile neler olup bittiğini tecrübe etmek için şu etkileşimli örnekten yararlanabilirsiniz.




Bu kadar. Lütfen eksik veya hata görürseniz bildirin.



İlgili Makaleler