Tuvalde tipografik efektler

Michael Fırsatı
Michael Deal

Geçmişim

<canvas>, farkındalığımı 2006'da Firefox 2.0 sürümü yayınlandığında girdi. Ajaxian hakkında, dönüşüm matrisini açıklayan bir makale bana ilk <canvas> web uygulamam olan Color Sphere'i (2007) oluşturma konusunda ilham verdi. Renklerin ve temel grafik öğelerin dünyasına adım attım. Tarayıcıda "Boyadan daha iyi" bir uygulama oluşturmak amacıyla Sketchpad'in (2007-2008) oluşturulmasına ilham verdim. Bu denemeler nihayetinde, uzun zamandır arkadaşım Charles Pritchard ile yeni bir startup olan Mugtug'un ortaya çıkmasıyla sonuçlandı. Darkroom'u HTML5 <canvas> için geliştiriyoruz. Karanlık oda, piksel tabanlı filtrelerin gücünü vektör tabanlı tipografi ve çizimle birleştiren, yıkıcı olmayan bir fotoğraf paylaşımı uygulamasıdır.

Giriş

Kanvas banner grafiği.

<canvas>, JavaScript programcılarına ekranlarındaki renkler, vektörler ve pikseller, yani monitörün görsel yapısı üzerinde tam kontrol sağlar.

Aşağıdaki örnekler <canvas> aracında fazla ilgi çekmeyen bir alanla ilgilidir: metin efektleri oluşturma. <canvas> ürününde oluşturulabilecek metin efektlerinin çeşitliliği düşünebileceğiniz kadar kapsamlı. Bu demolarda, nelerin mümkün olduğuna dair bir alt bölümden bahsedilmektedir. Bu makalede "metin" üzerinde çalışsak da, yöntemler tüm vektör nesnelerine uygulanabilir; böylece oyunlarda ve diğer uygulamalarda heyecan verici görseller oluşturabilirsiniz:

<canvas> ürününde Metin Gölgeleri.
<canvas> ürününde kırpma maskeleri oluşturma, <canvas> ürününde metrikleri bulma ve gölge özelliğini kullanma CSS benzeri metin efektleri.
Neon-gökkuşağı, zebra yansıması - zincirleme efektler.
globalCompositeOperation, createDoğrusalGradient ve createPattern kullanımına ilişkin <canvas> örneğinde Photoshop benzeri metin efektleri.
<canvas> için iç ve dış gölgeler
Az bilinen bir özelliği açığa çıkarma: Gölgenin tersini (iç gölge) oluşturmak için saat yönünde ve saat yönünün tersine sarma tekniğini kullanma.
Spaceage - üretici etkisi.
Hareket hissi yaratmak için hsl() renk döngüsü ve window.requestAnimationFrame kullanarak <canvas> ürününde üretken tabanlı metin efekti.

Tuval'de Metin Gölgeleri

CSS3 özelliklerine (kenarlık yarıçapı, web gradyanları ve diğerleriyle birlikte) en sevdiğim eklemelerden biri gölge oluşturma yeteneğidir. CSS ve <canvas> gölgeleri arasındaki farkları anlamak önemlidir.

CSS iki yöntem kullanır: div, span vb. kutu öğeleri için box-shadow, metin içeriği içinse text-shadow değerine.

<canvas>, tek 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.stroText vb. <canvas> ürününde gölge oluşturmak için şu dört mülke dokunun:

ctx.shadowColor = "red" // dize
Gölgenin rengi; RGB, RGBA, HSL, HEX ve diğer girişler geçerlidir.
ctx.shadowOffsetX = 0; // tamsayı
Gölgenin metinle ilişkili olarak yatay mesafesi.
ctx.shadowOffsetY = 0; // tam sayı
Gölgenin metinle ilişkili dikey mesafesi.
ctx.shadowBlur = 10; // tam sayı
Gölgede bulanıklaştırma efekti, değer ne kadar büyük olursa bulanıklık da o kadar yüksek olur.

Başlamak için <canvas> ürününün CSS efektlerini nasıl emüle edebileceğini görelim. Google Görseller'de "css text-shadow" aramasının, Line25, Stereoscopic ve Shadow 3D gibi emülasyon kullanabildiğimiz birkaç harika demosu oldu.

CSS 3D Grafiği

Stereoskopik 3D efekti (daha fazla bilgi için Anaglif resmine bakın), basit bir kod satırı örneğidir ve oldukça kullanışlıdır. CSS'nin aşağıdaki satırıyla, 3D kırmızı/camgöbeği gözlüklerle görüntülendiğinde (3D filmlerde size verdikleri tür) derinlik yanılsaması oluşturabiliriz:

text-shadow: -0.06em 0 0 red, 0.06em 0 0 cyan;

Bu dizeyi <canvas> biçimine dönüştürürken dikkat edilecek iki nokta vardır:

  1. Gölge bulanıklaştırma (üçüncü değer) yoktur; bu nedenle, fillText aynı sonuçları oluşturacağından gerçekte gölge çalıştırmanız gerekmez:
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>
  1. EM'ler <canvas> tarafından desteklenmediğinden PX'e dönüştürülmeleri gerekir. DOM'de aynı yazı tipi özelliklerine sahip bir öğe oluşturup, genişliği ölçülecek biçime ayarlayarak PT, PC, EM, EX, PX ve diğer biçimler arasındaki dönüştürmeye ilişkin dönüşüm oranını bulabiliriz. veya örneğin, EM -> PX dönüşümünü yakalamak için DOM öğesini "yükseklik: 1em" ile ölçeriz. Her birinin ofset değeri olarak,
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 çoğaltmayı önleme

Line25'te bulunan Neon efekti gibi daha karmaşık bir örnekte, efektin düzgün bir şekilde emüle edilmesi içinshadowBlur özelliğinin kullanılması gerekir. Neon etkisi birden çok gölgeye dayandığından bir sorunla karşılaşırız. <canvas> ürününde her vektör nesnesi yalnızca bir gölgeye sahip olabilir. Bu nedenle, birden fazla gölge çizmek için metnin birden fazla versiyonunu kendi üzerine çizmeniz gerekir. Bu da alfa çarpıma ve sonuç olarak kenarlarda pürüzlülüğe yol açar.

Neon grafik

Gölgeyi görüntülerken metni gizlemek için ctx.fillStyle = "rgba(0,0,0,0)" veya "transparent" öğesini çalıştırmayı denedim... ancak, bu girişim işe yaramadı. Gölge, fillStyle alfasının çarpımı olduğu için, gölge hiçbir zaman fillStyle'dan daha opak olamaz.

Neyse ki bu durumu atlatmanın bir yolu var. Gölge uzaklığını metinden çizerek (bu sayede üst üste gelmemeleri için) metni ekranın kenarından başka bir yere 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 çevresinden kırpma

Bunu biraz temizlemek için bir kırpma yolu ekleyerek (gölgenin çizilmesine izin verirken) fillText'in ilk başta çizilmesini engelleyebiliriz. Metni çevreleyen bir kırpma yolu oluşturmak için, metnin yüksekliğini (bir baskı makinesinde "M" harfinin eskiden "em-height" olarak adlandırıldığı) ve genişliğini bilmemiz gerekir. Genişliği ctx.measureText().width kullanarak alabiliriz, ancak ctx.measureText().height mevcut değil.

Neyse ki, CSS hack-ardry aracılığıyla (CSS ölçümlerini kullanarak eski <canvas> uygulamalarını düzeltmenin daha fazla yolu için Tipografi Metrikleri'ne bakın), aynı yazı tipi özelliklerini kullanarak <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, kukla şekli kaldırırken "gölgeyi" içine alarak kırpma yolu olarak kullanılacak bir dikdörtgen oluşturabiliriz.

ctx.rect(0, 0, width, emHeight);
ctx.clip();

Hepsini bir araya getirme ve ilerledikçe optimize etme: Gölgede bulanıklık yoksa fillText aynı efekt için kullanılabilir. Böylece kırpma maskesini ayarlama zahmetinden kurtulmuş oluruz:

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);

Bu <canvas> komutlarının tamamını manuel olarak girmek istemeyeceğiniz için demo kaynağına basit bir metin gölgesi ayrıştırıcı ekledim. Bu şekilde, CSS komutlarını besleyebilir ve <canvas> komutları oluşturmasını sağlayabilirsiniz. Artık <canvas> öğelerimizin ilişkilendirilebileceği bir dizi stil var. Bu gölge efektleri, WebFonts'tan SVG'lerden içe aktarılan karmaşık şekillere ve üretken vektör şekillerine kadar tüm vektör nesnelerinde kullanılabilir.

Tuval efektlerinde metin gölgesi

Aralık (piksel ittiğinde teğet)

Makalenin bu bölümünü yazarken Stereoskopik örnek beni meraklandırdı. <canvas> ve biraz farklı perspektiflerden çekilmiş iki resim kullanarak bir 3D film ekranı efekti oluşturmak ne kadar zor olurdu? Anlaşılan, çok zor değil. Aşağıdaki çekirdek, ilk görüntünün kırmızı kanalını (veriler) ikinci resmin camgöbeği kanalıyla (veri2) birleştirir:

data[i] = data[i] * 255 / 0xFF;
data[i+1] = 255 * data2[i+1] / 0xFF;
data[i+2] = 255 * data2[i+2] / 0xFF;

Şimdi, birinin sadece iki iPhone'u alnına yapıştırması ve aynı anda "video kaydet" seçeneğini tıklaması yeterlidir. Böylece, HTML5 kullanarak kendi 3D filmlerimizi yapabiliriz. Gönüllü var mı?

3D gözlük

Neon-gökkuşağı, zebra yansıması—zincirleme efektleri

<canvas> işlevinde birden fazla efekt zinciri oluşturmak basit olabilir ancak globalCompositeoperasyonu (GCO) hakkında temel düzeyde bilgi sahibi olmak gerekir. İşlemleri GIMP (veya Photoshop) ile karşılaştırmak için: <canvas> daha koyu içinde 12 GCO vardır ve daha açık olan katman 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ı" (ya da bizim örneğimizde, kod dizelerini) yeni ve heyecan verici şekillerde birleştirerek:

Zincirleme efekt grafikleri

globalCompositeOperation grafiği, çalışan GCO modlarını gösterir. Bu grafikte, nelerin beklendiğini ayrıntılı olarak görmek için renk spektrumunun büyük bir kısmı ve birden fazla alfa şeffaflık seviyesi kullanılmaktadır. Metinsel açıklamalar için Mozilla 'nın globalCompositeOperation referansına göz atmanızı öneririz. Daha fazla araştırma için Porter Duff 'ın Compositing Digital Images (Dijital Resimleri Oluşturma) bölümünde operasyonun nasıl işlediğini öğrenebilirsiniz.

En sevdiğim mod globalCompositeTransaction="lighter". Daha hafif, eklenen pikselleri ışığın karışmasına benzer bir ş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 genel Alfa değerine ayarlandığında daha hassas kontrol ve daha pürüzsüz kenarlar sağlayan heyecan verici bir özelliktir. Lighter pek çok amaçla kullanıldı. En son http://weavesilk.com/ adresinde bulunan HTML5 masaüstü arka plan içerik oluşturucusu benim. Demolarımdan biri olan Nefes Alan Galaksiler (JS1k) da daha açık modu kullanıyor. Bu iki örnekten yola çıkarak desenler çizerek bu modun nasıl etki yarattığını görmeye başlıyorsunuz.

globalCompositeOperation tarayıcı işleme.

Neon-Gökkuşağı Ses Dalgalanması Efekti

Aşağıdaki demoda, globalCompositeoperasyonu (kaynak giriş, açık ve koyu) kullanarak efektleri birbirine bağlayarak, kenarları titreşen ve Photoshop benzeri neon-gökkuşağı parıltısı elde edeceğiz. Bu demo, gölgeyi metinden ayırmak için aynı stratejinin kullanıldığı "<canvas> içindeki Metin Gölgeleri" demosunun bir ilerlemesidir (önceki bölüme bakın):

Gökkuşağı Sapması
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ıma Efekti

Zebra Yansıma efekti, WebDesignerWall 'un sayfanıza CSS ile nasıl renklendirebileceğinizle ilgili mükemmel kaynağından esinlenmiştir. Bu, fikri biraz daha ileri taşır ve metin için, iTunes'da görebileceğiniz gibi bir "yansıtma" oluşturur. Efekt, fillColor (beyaz), createPattern (zebra.png) ve linearGradient (shine) özelliklerini birleştirir. Bu, her bir vektör nesnesine birden fazla dolgu türü uygulama yeteneğini gösterir:

Zebra efekti
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> teknik özellikleri, "iç" ve "dış" gölgelerin konusuyla ilgili değildir. Aslında, ilk bakışta "iç" gölgenin desteklenmediğini bekleyebilirsiniz. Bu doğru değildir. Bu özelliği etkinleştirmek biraz karmaşıktır ;) F1LT3R tarafından yakın zamanda yayınlanan bir yayında önerildiği gibi, 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örtgen çizerek bir "iç gölge" oluşturur ve ardından zıt sarım kurallarını kullanarak bir kesme şekli çizerek şeklin tersini oluşturursunuz.

Aşağıdaki örnek, iç-shadow ve fillStyle'ın aynı anda renk+gradyanı+desen ile stilize edilmesine olanak tanır. Desen dönüşünü tek tek belirtebilirsiniz; zebra çizgilerinin artık birbirine dik konumda olduğuna dikkat edin. Sınırlayıcı kutunun boyutu için bir kırpma maskesi kullanılır. Böylece, kesim şeklinin içini doldurmak için çok büyük bir kapsayıcıya duyulan ihtiyaç ortadan kalkar. Böylece, gölgenin gereksiz kısımlarının işlenmesi önlenerek hız artırılır.

İç/dış gölgeler
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 örneklerden göreceğiniz gibi, globalCompositeoperasyonu kullanarak etkileri zincir haline getirebiliyoruz. Böylece daha ayrıntılı efektler (maskeleme ve karıştırma kullanarak) üretebiliyoruz. Ekran tam size göre ;)

Boşluk: Üretken efektler

<canvas> ürününde, 0x2708 unicode karakterinden geçilir:

Unicode grafiti

... bu gölgeli örneğe değiştirelim:

Gölgeli örnek

...ince bir lineWidth (0,25) ile ctx.strokeText() için birden fazla çağrı yapılmasıyla, x ofseti ve alfanın yavaşça azaltılarak vektör öğelerimize hareket hissi verilmesiyle gerçekleştirilebilir.

XY konumlarını bir sinüs/kosinüs dalgasına eşleyerek ve HSL özelliğini kullanarak renkler arasında geçiş yaparak, bu "biohazard" örneği gibi daha ilginç efektler oluşturabiliriz:

HSL bisiklet efekti

HSL: Ton, Doygunluk, Açıklık (1978)

HSL, CSS3 özelliklerinde yeni desteklenen bir biçimdir. HEX'in bilgisayarlar için tasarlandığı yerlerde, HSL kullanıcıların okuyabileceği şekilde tasarlanmıştır.

HSL'nin kolaylığını gösteriyor; renk spektrumunda geçiş yapmak için "tonu" 360'tan artırırdık; renk tonu silindir biçiminde spektrumla eşleştirilir. Açıklık, rengin ne kadar koyu/açık olduğunu kontrol eder; %0 değeri siyah pikseli, %100 değeri ise beyaz bir pikseli belirtir. Doygunluk, bir rengin ne kadar parlak veya canlı olduğunu kontrol eder. Griler %0 doygunluk ile, canlı renkler ise %100 değeri kullanılarak oluşturulur.

HSL Grafiği

HSL yeni bir standart olduğundan, renk alanı dönüştürmesiyle mümkün olan eski tarayıcıları desteklemeye devam etmek isteyebilirsiniz. Aşağıdaki kod bir HSL nesnesini { H: 360, S: 100, L: 100} kabul eder ve bir RGB nesnesi { R: 255, G: 255, B: 255 } oluşturur. Burada, rgb veya rgba dizenizi oluşturmak için bu değerleri kullanabilirsiniz. Daha ayrıntılı bilgi için Wikipedia 'nın HSL ile ilgili bilgilendirici makalesine bakı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

Eskiden JavaScript'te animasyon oluşturmak için setTimeout ve setInterval olmak üzere iki seçenek kullanılıyordu.

window.requestAnimationFrame, bunların ikisinin de yerini alacak yeni standarttır. Tarayıcının, mevcut kaynaklara göre animasyonları düzenlemesine izin vererek dünya elektriğinden (ve bilgisayarınızın birkaç sinyalde) tasarruf etmesini sağlarsınız. Bazı önemli özellikler şunlardır:

  • Bir kullanıcı kare içerdiğinde animasyon, gereksiz kaynakların kullanılmasını önlemek için yavaşlayabilir veya tamamen durabilir.
  • 60 FPS'de kare hızı için bir sınır sınırı vardır. Bunun nedeni, animasyonun insanların fark edebileceği seviyeden çok daha yüksek olmasıdır (30 FPS ile çoğu insan, animasyonu "değişken" olarak görür).

Bu yazının hazırlandığı sırada, requestAnimationFrame kullanmak için tedarikçiye özel ön eklerin kullanılması gerekir. Paul Ireland, akıllı animasyon için requestAnimationFrame dosyasında çapraz satıcı desteğine sahip bir dolgu 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);
        };
})();

Bunu biraz daha ileri götürerek, daha iddialı olan bu yeni standarda geçerken eski tarayıcıları daha fazla destekleyecek requestAnimationFrame.js gibi bir çoklu dolguyla bağlantılandırabilir (üzerinde çalışılması gereken birkaç özellik vardır).

(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);
})();
Not Bulanıklığı Grafiği
Animasyon Grafiği
Matrix Grafiği

Kaynak kodu

Tarayıcı satıcı alanı genelinde sağlanan destek sayesinde <canvas>'in geleceği konusunda hiç şüphe yok ki <canvas>, PhoneGap kullanılarak iPhone/Android/Masaüstü yürütülebilir dosyalarına da taşınabilir veya

Titanyum.