Geçmişim
<canvas>
, Firefox 2.0 sürümü kullanıma sunulduğunda 2006 yılında benim de dikkatimi çekti. Ajaxian'da dönüşüm matrisini açıklayan bir makale, ilk <canvas>
web uygulamamı (Color Sphere, 2007) oluşturmam için beni teşvik etti. Bu da beni renk ve grafik primitifleri dünyasına sürükledi. Tarayıcıda "Paint'ten daha iyi" bir uygulama oluşturma çabasıyla Sketchpad'i (2007-2008) oluşturmama ilham verdi.
Bu denemeler, uzun zamandır arkadaşım olan Charles Pritchard ile birlikte Mugtug adlı girişimi kurmama yol açtı. Darkroom'u HTML5 <canvas>
olarak geliştiriyoruz. Darkroom, piksele dayalı filtrelerin gücünü vektör tabanlı yazı tipleri ve çizimlerle birleştiren, fotoğrafları bozmadan paylaşmanızı sağlayan bir uygulamadır.
Giriş

<canvas>
, JavaScript programcılarına ekranlarındaki renkler, vektorlar ve piksellerin (monitörün görsel yapısı) tam kontrolünü verir.
Aşağıdaki örneklerde, <canvas>
'te çok fazla dikkat çekmeyen bir alan ele alınmaktadır: Metin efektleri oluşturma. <canvas>
'te oluşturulabilecek metin efektlerinin çeşitliliği, hayal edebileceğiniz kadar geniştir. Bu demolarda, mümkün olanın bir alt bölümü ele alınmıştır. Bu makalede "metin"le ilgileniyoruz ancak bu yöntemler tüm vektör nesnelerine uygulanabilir. Böylece oyunlarda ve diğer uygulamalarda heyecan verici görseller oluşturabilirsiniz:
<canvas>
'te metin gölgeleri.- CSS benzeri metin efektleri oluşturma, kırpma maskeleri oluşturma,
<canvas>
'da metrikleri bulma ve gölge mülkünü kullanma - Neon-rainbow, zebra-reflection - chaining effects.
- globalCompositeOperation, createLinearGradient, createPattern işlevlerinin kullanıldığı
<canvas>
örneklerde Photoshop benzeri metin efektleri <canvas>
'teki iç ve dış gölgeler- Az bilinen bir özelliği açıklıyor: Gölgenin tersini (iç gölge) oluşturmak için saat yönünde ve saat yönünün tersine sarmalama işlemlerini kullanın.
- Uzay çağı - üretken efekt. Hareket hissi oluşturmak için hsl() renk döngüsü ve
- üretken temelli metin efekti.
<canvas>
'da window.requestAnimationFrame
kullanılarak <canvas>
'da Canvas'ta metin gölgeleri
CSS3 özelliklerine eklenen özelliklerden (border-radius, web-gradients ve diğerleri ile birlikte) gölge oluşturma özelliği benim için en sevdiklerimden biridir. CSS ile <canvas>
gölgeleri arasındaki farkları anlamak önemlidir. Özellikle:
CSS'de iki yöntem kullanılır: div, span vb. gibi kutu öğeler için box-shadow ve metin içeriği için text-shadow.
<canvas>
bir gölge türüne sahiptir; tüm vektör nesneleri için kullanılır: ctx.moveTo, ctx.lineTo, ctx.bezierCurveTo, ctx.quadradicCurveTo, ctx.arc, ctx.rect, ctx.fillText, ctx.strokeText vb.
<canvas>
'te gölge oluşturmak için aşağıdaki dört özelliğe dokunun:
- ctx.shadowColor = "red" // string
- Gölgenin rengi; RGB, RGBA, HSL, HEX ve diğer girişler geçerlidir.
- ctx.shadowOffsetX = 0; // tam sayı
- Gölgenin metne göre yatay mesafesi.
- ctx.shadowOffsetY = 0; // tam sayı
- Gölgenin metne göre dikey mesafesi.
- ctx.shadowBlur = 10; // tam sayı
- Gölgeye bulanıklık efekti. Değer ne kadar büyükse bulanıklık o kadar fazla olur.
Başlangıç olarak <canvas>
'ün CSS efektlerini nasıl taklit edebileceğini görelim.
Google görsellerde "css text-shadow" araması yaptığımızda, örnek alabileceğimiz birkaç harika demo bulduk: Line25, Stereoscopic ve Shadow 3D.

Stereoskopik 3D efekt (daha fazla bilgi için anaglif resim bölümüne bakın), basit bir kod satırının mükemmel bir şekilde kullanıldığına dair bir örnektir. Aşağıdaki CSS satırıyla, 3D kırmızı/siyan camlarla (3D filmlerde size verilen türden) görüntülendiğinde derinlik yanılsaması oluşturabiliriz:
text-shadow: -0.06em 0 0 red, 0.06em 0 0 cyan;
Bu dize <canvas>
olarak dönüştürülürken dikkat edilmesi gereken iki nokta vardır:
- shadow-blur (üçüncü değer) yok. Bu nedenle, fillText aynı sonuçları oluşturacağından shadow'u çalıştırmanın bir anlamı yoktur:
var text = "Hello world!"
ctx.fillStyle = "#000"
ctx.fillText(text, -7, 0);
ctx.fillStyle = "red"
ctx.fillText(text, 0, 0);
ctx.fillStyle = "cyan"
ctx.fillText(text, 7, 0);</pre>
- EM'ler
<canvas>
'te desteklenmediği için PX'lere dönüştürülmelidir. DOM'da aynı yazı tipi özelliklerine sahip bir öğe oluşturup genişliği ölçülecek biçime ayarlayarak PT, PC, EM, EX, PX vb. arasında dönüşüm için dönüşüm oranını bulabiliriz. Örneğin, EM -> PX dönüşümünü yakalamak için DOM öğesini "height: 1em" ile ölçeriz. Elde edilen offsetHeight, her EM 'de kaç PX olduğunu gösterir.
var font = "20px sans-serif"
var d = document.createElement("span");
d.style.cssText = "font: " + font + " height: 1em; display: block"
// the value to multiply PX 's by to convert to EM 's
var EM2PX = 1 / d.offsetHeight;</pre>
Alfa çarpımını önleme
25. satırda bulunan neon efekti gibi daha karmaşık bir örnekte, efekti düzgün bir şekilde taklit etmek için shadowBlur mülkü kullanılmalıdır. Neon efekti birden fazla gölgeye ihtiyaç duyduğundan bir sorunla karşılaşıyoruz.
<canvas>
Bu nedenle, birden fazla gölge çizmek için metnin kendi üzerine birden fazla sürümünü çizmeniz gerekir.
Bu, alfa çarpımı ve sonuç olarak da sivri kenarlara neden olur.

Gölgeyi gösterirken metni gizlemek için ctx.fillStyle = "rgba(0,0,0,0)"
veya "transparent"
komutunu çalıştırmayı denedim ancak bu deneme işe yaramadı. Gölge, fillStyle alfa değerinin çarpımı olduğundan gölge hiçbir zaman fillStyle'den daha opak olamaz.
Neyse ki bu sorunun bir çözümü var. Gölgeyi metinden ayrı çizerek (üst üste binmeyecek şekilde) metni ekranın kenarından gizleyebiliriz:
var text = "Hello world!"
var blur = 10;
var width = ctx.measureText(text).width + blur * 2;
ctx.textBaseline = "top"
ctx.shadowColor = "#000"
ctx.shadowOffsetX = width;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = blur;
ctx.fillText(text, -width, 0);
Metin bloğunun etrafını kırpma
Bu durumu biraz düzeltmek için bir kırpma yolu ekleyerek fillText işlevinin baştan çizilmesini (gölgenin çizilmesine izin verirken) önleyebiliriz.
Metni çevreleyen bir kırpma yolu oluşturmak için metnin yüksekliğini ("em-height" olarak adlandırılır, geçmişte bir baskı makinesinde "M" harfinin yüksekliği olarak bilinirdi) ve metnin genişliğini bilmeniz gerekir.
ctx.measureText().width
kullanarak genişliği alabiliriz ancak ctx.measureText().height
mevcut değildir.
Neyse ki CSS'de hile yaparak (CSS ölçümlerini kullanarak <canvas>
'ın eski uygulamalarını düzeltmenin diğer yolları için Tipografik Metrikler bölümüne bakın) aynı yazı tipi özelliklerine sahip bir <span>
öğesinin offsetHeight
değerini ölçerek metnin yüksekliğini bulabiliriz:
var d = document.createElement("span");
d.font = "20px arial"
d.textContent = "Hello world!"
var emHeight = d.offsetHeight;
Buradan, "gölgeyi" içine alırken boş şekli kaldırarak kırpma yolu olarak kullanılacak bir dikdörtgen oluşturabiliriz.
ctx.rect(0, 0, width, emHeight);
ctx.clip();
Tüm bunları bir araya getirip ilerledikçe optimize ediyoruz. Bir gölgede bulanıklık yoksa fillText aynı etkiyi sağlamak için kullanılabilir. Böylece, kırpma maskesini ayarlama zahmetinden kurtulabiliriz:
var width = ctx.measureText(text).width;
var style = shadowStyles[text];
// add a background to the current effect
ctx.fillStyle = style.background;
ctx.fillRect(0, offsetY, ctx.canvas.width, textHeight - 1)
// parse text-shadows from css
var shadows = parseShadow(style.shadow);
// loop through the shadow collection
var n = shadows.length; while(n--) {
var shadow = shadows[n];
var totalWidth = width + shadow.blur * 2;
ctx.save();
ctx.beginPath();
ctx.rect(offsetX - shadow.blur, offsetY, offsetX + totalWidth, textHeight);
ctx.clip();
if (shadow.blur) { // just run shadow (clip text)
ctx.shadowColor = shadow.color;
ctx.shadowOffsetX = shadow.x + totalWidth;
ctx.shadowOffsetY = shadow.y;
ctx.shadowBlur = shadow.blur;
ctx.fillText(text, -totalWidth + offsetX, offsetY + metrics.top);
} else { // just run pseudo-shadow
ctx.fillStyle = shadow.color;
ctx.fillText(text, offsetX + (shadow.x||0), offsetY - (shadow.y||0) + metrics.top);
}
ctx.restore();
}
// drawing the text in the foreground
if (style.color) {
ctx.fillStyle = style.color;
ctx.fillText(text, offsetX, offsetY + metrics.top);
}
// jump to next em-line
ctx.translate(0, textHeight);
Tüm bu <canvas>
komutlarını manuel olarak girmek istemeyeceğiniz için demo kaynağına basit bir metin gölgesi ayrıştırıcı ekledim. Bu sayede, CSS komutları besleyebilir ve <canvas>
komutları oluşturmasını sağlayabilirsiniz.
Artık <canvas>
öğelerimizle kullanabileceğiniz çok çeşitli stiller var.
Aynı gölge efektleri, Web yazı tiplerinden SVG'lerden içe aktarılan karmaşık şekillere ve üretken vektör şekillerine kadar her türlü vektör nesnesinde kullanılabilir.

Ara (piksel itmeyle ilgili yan not)
Makalenin bu bölümünü yazarken stereoskopik örnek beni meraklandırdı. <canvas>
ve biraz farklı açılardan çekilmiş iki resim kullanarak 3D sinema ekranı efekti oluşturmak ne kadar zor olur? Görünüşe göre çok zor değil. Aşağıdaki çekirdek, ilk resmin (data) kırmızı kanalını ikinci resmin (data2) turkuaz kanalıyla birleştirir:
data[i] = data[i] * 255 / 0xFF;
data[i+1] = 255 * data2[i+1] / 0xFF;
data[i+2] = 255 * data2[i+2] / 0xFF;
Artık iki iPhone'u alnına bantlayan ve aynı anda "video kaydet"i tıklayan herkes HTML5'te kendi 3D filmlerini çekebilir. Gönüllü var mı?

Neon rengi gökkuşağı, zebra yansıması gibi zincirleme efektler
<canvas>
içinde birden fazla efekti zincirlemek basit olabilir ancak globalCompositeOperation (GCO) hakkında temel düzeyde bilgi sahibi olmanız gerekir. İşlemleri GIMP (veya Photoshop) ile karşılaştırmak için: <canvas>
koyu bölümünde 12 GCO vardır ve açık, katman karışım modları olarak düşünülebilir; diğer 10 işlem, katmanlara alfa maskeleri olarak uygulanır (bir katman, diğer katmanın piksellerini kaldırır). globalCompositeOperation, "katmanları" (veya bizim durumumuzda kod dizelerini) birbirine bağlayarak yeni ve heyecan verici şekillerde birleştirir:

globalCompositeOperation grafiği, GCO modlarının işleyişini gösterir. Bu grafikte, neyle karşılaşacağınızı ayrıntılı olarak görmek için renk spektrumunun büyük bir kısmı ve birden fazla alfa şeffaflık seviyesi kullanılır. Metin açıklamaları için Mozilla 'nın globalCompositeOperation referansına göz atmanızı öneririm. Daha fazla bilgi için Porter Duff 'un Compositing Digital Images (Dijital Görüntüleri Birleştirme) adlı kitabında bu işlemin nasıl çalıştığını öğrenebilirsiniz.
En sevdiğim mod globalCompositeOperation="lighter". Işıklandırıcı, ekteki pikselleri ışığın karışmasına benzer şekilde karıştırır. Kırmızı, yeşil ve beyaz ışık tam yoğunlukta olduğunda beyaz ışık görürüz. Özellikle <canvas>
düşük bir globalAlpha değerine ayarlandığında, daha hassas kontrol ve daha yumuşak kenarlar sağlayan bu özellikle denemeler yapmak heyecan vericidir. Lighter'ı birçok alanda kullandım. En sevdiğim kullanım alanı ise http://weavesilk.com/ adresindeki HTML5 masaüstü arka plan oluşturucu.
Demolarımdan biri olan Breathing Galaxies (JS1k) da daha hafif modu kullanır. Bu iki örnekten çizim kalıpları oluşturduğunuzda bu modun ne gibi bir etki yarattığını görmeye başlarsınız.
globalCompositeOperation tarayıcı işleme.
Neon-Gökkuşağı Jitter Efekti
Aşağıdaki demoda, globalCompositeOperation (kaynak-içi, daha açık ve daha koyu) özelliğini kullanarak efektleri birbirine bağlayarak titreyen bir dış çizgiye sahip Photoshop benzeri bir neon-gökkuşağı parıltısı elde edeceğiz.
Bu demo, "<canvas>
'te metin gölgeleri" demosunun bir devamı niteliğindedir. Gölgeyi metinden ayırmak için aynı strateji kullanılır (önceki bölüme bakın):

function neonLightEffect() {
var text = "alert('"+String.fromCharCode(0x2665)+"')";
var font = "120px Futura, Helvetica, sans-serif";
var jitter = 25; // the distance of the maximum jitter
var offsetX = 30;
var offsetY = 70;
var blur = getBlurValue(100);
// save state
ctx.save();
ctx.font = font;
// calculate width + height of text-block
var metrics = getMetrics(text, font);
// create clipping mask around text-effect
ctx.rect(offsetX - blur/2, offsetY - blur/2,
offsetX + metrics.width + blur, metrics.height + blur);
ctx.clip();
// create shadow-blur to mask rainbow onto (since shadowColor doesn't accept gradients)
ctx.save();
ctx.fillStyle = "#fff";
ctx.shadowColor = "rgba(0,0,0,1)";
ctx.shadowOffsetX = metrics.width + blur;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = blur;
ctx.fillText(text, -metrics.width + offsetX - blur, offsetY + metrics.top);
ctx.restore();
// create the rainbow linear-gradient
var gradient = ctx.createLinearGradient(0, 0, metrics.width, 0);
gradient.addColorStop(0, "rgba(255, 0, 0, 1)");
gradient.addColorStop(0.15, "rgba(255, 255, 0, 1)");
gradient.addColorStop(0.3, "rgba(0, 255, 0, 1)");
gradient.addColorStop(0.5, "rgba(0, 255, 255, 1)");
gradient.addColorStop(0.65, "rgba(0, 0, 255, 1)");
gradient.addColorStop(0.8, "rgba(255, 0, 255, 1)");
gradient.addColorStop(1, "rgba(255, 0, 0, 1)");
// change composite so source is applied within the shadow-blur
ctx.globalCompositeOperation = "source-atop";
// apply gradient to shadow-blur
ctx.fillStyle = gradient;
ctx.fillRect(offsetX - jitter/2, offsetY,
metrics.width + offsetX, metrics.height + offsetY);
// change composite to mix as light
ctx.globalCompositeOperation = "lighter";
// multiply the layer
ctx.globalAlpha = 0.7
ctx.drawImage(ctx.canvas, 0, 0);
ctx.drawImage(ctx.canvas, 0, 0);
ctx.globalAlpha = 1
// draw white-text ontop of glow
ctx.fillStyle = "rgba(255,255,255,0.95)";
ctx.fillText(text, offsetX, offsetY + metrics.top);
// created jittered stroke
ctx.lineWidth = 0.80;
ctx.strokeStyle = "rgba(255,255,255,0.25)";
var i = 10; while(i--) {
var left = jitter / 2 - Math.random() * jitter;
var top = jitter / 2 - Math.random() * jitter;
ctx.strokeText(text, left + offsetX, top + offsetY + metrics.top);
}
ctx.strokeStyle = "rgba(0,0,0,0.20)";
ctx.strokeText(text, offsetX, offsetY + metrics.top);
ctx.restore();
};
Zebra Yansıtma Efekti
Zebra yansıması efekti, WebDesignerWall 'ın sayfanızı CSS ile nasıl canlandıracağınızla ilgili mükemmel kaynağından esinlenmiştir. Bu fikir, metin için iTunes'ta göreceğiniz gibi bir "yansıma" oluşturarak fikri biraz daha ileri götürür. Bu efektte fillColor (beyaz), createPattern (zebra.png) ve linearGradient (parlaklık) birleştirilmiştir. Bu, her vektör nesnesine birden fazla dolgu türü uygulayabilme özelliğini gösterir:

function sleekZebraEffect() {
// inspired by - http://www.webdesignerwall.com/demo/css-gradient-text/
var text = "Sleek Zebra...";
var font = "100px Futura, Helvetica, sans-serif";
// save state
ctx.save();
ctx.font = font;
// getMetrics calculates:
// width + height of text-block
// top + middle + bottom baseline
var metrics = getMetrics(text, font);
var offsetRefectionY = -20;
var offsetY = 70;
var offsetX = 60;
// throwing a linear-gradient in to shine up the text
var gradient = ctx.createLinearGradient(0, offsetY, 0, metrics.height + offsetY);
gradient.addColorStop(0.1, '#000');
gradient.addColorStop(0.35, '#fff');
gradient.addColorStop(0.65, '#fff');
gradient.addColorStop(1.0, '#000');
ctx.fillStyle = gradient
ctx.fillText(text, offsetX, offsetY + metrics.top);
// draw reflected text
ctx.save();
ctx.globalCompositeOperation = "source-over";
ctx.translate(0, metrics.height + offsetRefectionY)
ctx.scale(1, -1);
ctx.font = font;
ctx.fillStyle = "#fff";
ctx.fillText(text, offsetX, -metrics.height - offsetY + metrics.top);
ctx.scale(1, -1);
// cut the gradient out of the reflected text
ctx.globalCompositeOperation = "destination-out";
var gradient = ctx.createLinearGradient(0, offsetY, 0, metrics.height + offsetY);
gradient.addColorStop(0.0, 'rgba(0,0,0,0.65)');
gradient.addColorStop(1.0, '#000');
ctx.fillStyle = gradient;
ctx.fillRect(offsetX, offsetY, metrics.width, metrics.height);
// restore back to original transform state
ctx.restore();
// using source-atop to allow the transparent .png to show through to the gradient
ctx.globalCompositeOperation = "source-atop";
// creating pattern from <image> sourced.
ctx.fillStyle = ctx.createPattern(image, 'repeat');
// fill the height of two em-boxes, to encompass both normal and reflected state
ctx.fillRect(offsetX, offsetY, metrics.width, metrics.height * 2);
ctx.restore();
};
Canvas'ta iç/dış gölgeler
<canvas>
özellikleri, "iç" ve "dış" gölgeler konusuna değinmez. İlk bakışta "iç" gölgelerin desteklenmediğini düşünebilirsiniz. Böyle bir durum söz konusu değildir.
Etkinleştirmesi biraz daha zordur ;) F1LT3R 'ın yakın tarihli bir gönderisinde önerildiği gibi, saat yönünde ve saat yönünün tersine sarma kurallarının benzersiz özelliklerini kullanarak iç gölgeler oluşturabilirsiniz. Bunu yapmak için kapsayıcı dikdörtgeni çizerek bir "iç gölge" oluşturur ve ardından ters sarma kurallarını kullanarak bir kesik şekil çizersiniz. Böylece şeklin tersini oluşturursunuz.
Aşağıdaki örnekte, iç gölge ve fillStyle'nin aynı anda renk+gradyan+desen ile stilize edilmesine izin verilir. Desen dönüşümünü ayrı ayrı belirtebilirsiniz. Zebra şeritlerinin artık birbirine dik olduğunu fark edin. Kesme maskesi, sınırlayıcı kutunun boyutunda kullanılır. Böylece, kesme şeklini içine alacak süper büyük bir kapsayıcıya gerek kalmaz. Gölgenin gereksiz bölümlerinin işlenmesini önleyerek hızı artırır.

function innerShadow() {
function drawShape() { // draw anti-clockwise
ctx.arc(0, 0, 100, 0, Math.PI * 2, true); // Outer circle
ctx.moveTo(70, 0);
ctx.arc(0, 0, 70, 0, Math.PI, false); // Mouth
ctx.moveTo(-20, -20);
ctx.arc(30, -30, 10, 0, Math.PI * 2, false); // Left eye
ctx.moveTo(140, 70);
ctx.arc(-20, -30, 10, 0, Math.PI * 2, false); // Right eye
};
var width = 200;
var offset = width + 50;
var innerColor = "rgba(0,0,0,1)";
var outerColor = "rgba(0,0,0,1)";
ctx.translate(150, 170);
// apply inner-shadow
ctx.save();
ctx.fillStyle = "#000";
ctx.shadowColor = innerColor;
ctx.shadowBlur = getBlurValue(120);
ctx.shadowOffsetX = -15;
ctx.shadowOffsetY = 15;
// create clipping path (around blur + shape, preventing outer-rect blurring)
ctx.beginPath();
ctx.rect(-offset/2, -offset/2, offset, offset);
ctx.clip();
// apply inner-shadow (w/ clockwise vs. anti-clockwise cutout)
ctx.beginPath();
ctx.rect(-offset/2, -offset/2, offset, offset);
drawShape();
ctx.fill();
ctx.restore();
// cutout temporary rectangle used to create inner-shadow
ctx.globalCompositeOperation = "destination-out";
ctx.fill();
// prepare vector paths
ctx.beginPath();
drawShape();
// apply fill-gradient to inner-shadow
ctx.save();
ctx.globalCompositeOperation = "source-in";
var gradient = ctx.createLinearGradient(-offset/2, 0, offset/2, 0);
gradient.addColorStop(0.3, '#ff0');
gradient.addColorStop(0.7, '#f00');
ctx.fillStyle = gradient;
ctx.fill();
// apply fill-pattern to inner-shadow
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 1;
ctx.rotate(0.9);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fill();
ctx.restore();
// apply fill-gradient
ctx.save();
ctx.globalCompositeOperation = "destination-over";
var gradient = ctx.createLinearGradient(-offset/2, -offset/2, offset/2, offset/2);
gradient.addColorStop(0.1, '#f00');
gradient.addColorStop(0.5, 'rgba(255,255,0,1)');
gradient.addColorStop(1.0, '#00f');
ctx.fillStyle = gradient
ctx.fill();
// apply fill-pattern
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 0.2;
ctx.rotate(-0.4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fill();
ctx.restore();
// apply outer-shadow (color-only without temporary layer)
ctx.globalCompositeOperation = "destination-over";
ctx.shadowColor = outerColor;
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
ctx.fillStyle = "#fff";
ctx.fill();
};
Bu örneklerde, globalCompositeOperation'u kullanarak efektleri birbirine zincirleyebileceğimizi ve daha ayrıntılı efektler (maskeleme ve harmanlama kullanılarak) oluşturabileceğimizi görebilirsiniz. Ekran sizin için bir deniz incisi ;)
Uzay çağı: Üretken efektler
<canvas>
'te, 0x2708 Unicode karakterinden başlayarak:

…bu gölgeli örneğe:

… ince bir çizgi genişliği (0,25) ile ctx.strokeText()
çağrısı yaparak ve x ofsetini ile alfa değerini yavaş yavaş azaltarak elde edilebilir.Böylece vektör öğelerimize hareket hissi kazandırmış oluruz.
Öğelerin XY konumunu bir sinüs/kosinüs dalgasıyla eşleyerek ve HSL mülkünü kullanarak renklerde geçiş yaparak bu "biyolojik tehlike" örneği gibi daha ilginç efektler oluşturabiliriz:

HSL: Ton, Doygunluk, Parlaklık (1978)
HSL, CSS3 spesifikasyonlarında yeni desteklenen bir biçimdir. HEX, bilgisayarlar için tasarlanmışken HSL, insanlar tarafından okunabilir olacak şekilde tasarlanmıştır.
HSL'nin kolaylığını gösteren görsel. Renk tayfında gezinmek için "tonu" 360'tan artırmamız yeterlidir. Ton, silindirik bir şekilde tayfla eşlenir. Açıklık, rengin ne kadar koyu/açık olduğunu kontrol eder. %0 siyah bir pikseli, %100 ise beyaz bir pikseli gösterir. Doygunluk, bir rengin ne kadar parlak veya canlı olduğunu kontrol eder. Griler %0 doygunlukla, canlı renkler ise %100 değerle oluşturulur.

HSL yeni bir standart olduğundan eski tarayıcıları desteklemeye devam etmek isteyebilirsiniz. Bu, renk alanı dönüştürme aracılığıyla mümkündür. Aşağıdaki kod, { H: 360, S: 100, L: 100} HSL nesnesini kabul eder ve { R: 255, G: 255, B: 255 } RGB nesnesini döndürür. Ardından, rgb veya rgba dizeninizi oluşturmak için bu değerleri kullanabilirsiniz. Daha ayrıntılı bilgi için Wikipedia 'nın HSL ile ilgili makalesine göz atın.
// HSL (1978) = H: Hue / S: Saturation / L: Lightness
HSL_RGB = function (o) { // { H: 0-360, S: 0-100, L: 0-100 }
var H = o.H / 360,
S = o.S / 100,
L = o.L / 100,
R, G, B, _1, _2;
function Hue_2_RGB(v1, v2, vH) {
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return v1 + (v2 - v1) * 6 * vH;
if ((2 * vH) < 1) return v2;
if ((3 * vH) < 2) return v1 + (v2 - v1) * ((2 / 3) - vH) * 6;
return v1;
}
if (S == 0) { // HSL from 0 to 1
R = L * 255;
G = L * 255;
B = L * 255;
} else {
if (L < 0.5) {
_2 = L * (1 + S);
} else {
_2 = (L + S) - (S * L);
}
_1 = 2 * L - _2;
R = 255 * Hue_2_RGB(_1, _2, H + (1 / 3));
G = 255 * Hue_2_RGB(_1, _2, H);
B = 255 * Hue_2_RGB(_1, _2, H - (1 / 3));
}
return {
R: R,
G: G,
B: B
};
};
requestAnimationFrame ile animasyon oluşturma
Geçmişte JavaScript'te animasyon oluşturmak için setTimeout
ve setInterval
olmak üzere iki seçenek vardı.
window.requestAnimationFrame
, her ikisinin de yerini alacak yeni standarttır. Tarayıcının animasyonlarını mevcut kaynaklara göre düzenlemesine olanak tanıyarak dünyayı elektrikten (ve bilgisayarınızı birkaç kalp atışından) kurtarır.
Bazı önemli özellikler şunlardır:
- Bir kullanıcı çerçevenin dışına çıktığında, gereksiz kaynakların kullanılmasını önlemek için animasyon yavaşlayabilir veya tamamen durabilir.
- Kare hızı için 60 FPS'lik bir sınır vardır. Bunun nedeni, insanların fark edebileceği seviyenin çok üzerinde olmasıdır (çoğu insan 30 FPS 'de animasyonun "akıcı" olduğunu görür).
Bu makalenin yazıldığı sırada requestAnimationFrame
kullanmak için tedarikçiye özgü ön ekler gereklidir.
Paul Irish, akıllı animasyon için requestAnimationFrame'te tedarikçi firmalar arası destek sunan bir ara katman oluşturdu:
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
Daha da ileriye gitmek isteyenler, bu yeni standarda geçerken eski tarayıcıları daha fazla destekleyen requestAnimationFrame.js gibi bir poli dolgu ile bunu bir araya getirebilir (bazı özellikler üzerinde çalışılması gerekir).
(function animate() {
var i = 50;
while(i--) {
if (n > endpos) return;
n += definition;
ctx.globalAlpha = (0.5 - (n + startpos) / endpos) * alpha;
if (doColorCycle) {
hue = n + color;
ctx.strokeStyle = "hsl(" + (hue % 360) + ",99%,50%)"; // iterate hue
}
var x = cos(n / cosdiv) * n * cosmult; // cosine
var y = sin(n / sindiv) * n * sinmult; // sin
ctx.strokeText(text, x + xoffset, y + yoffset); // draw rainbow text
}
timeout = window.requestAnimationFrame(animate, 0);
})();



Kaynak kod
Tarayıcı tedarikçi firmalarının desteğiyle <canvas>
'ün geleceği konusunda hiçbir şüphe yok. PhoneGap kullanılarak iPhone/Android/masaüstü yürütülebilir dosyalarına taşınabilir veya