Tuvalde tipografik efektler

Michael Deal
Michael Deal

Arka planım

<canvas> ile 2006'da Firefox v2.0 yayınlandığında tanıştım. Ajaxian'da dönüşüm matrisini açıklayan bir makale, ilk <canvas> web uygulamam olan Color Sphere'i (2007) oluşturmam için bana ilham verdi. Bu sayede renklerin ve grafik temellerinin dünyasına daldım. Tarayıcıda "Paint'ten daha iyi" bir uygulama oluşturma çabasıyla Sketchpad'i (2007-2008) geliştirmek için ilham aldım. Bu denemeler, uzun süredir arkadaşım olan Charles Pritchard ile birlikte Mugtug adlı girişimi kurmamıza yol açtı. Darkroom'u HTML5'te geliştiriyoruz <canvas>. Darkroom, piksel tabanlı filtrelerin gücünü vektör tabanlı tipografi ve çizimle birleştiren, fotoğrafları bozmadan paylaşmanızı sağlayan bir uygulamadır.

Giriş

Canvas banner grafiği.

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

Aşağıdaki örneklerde, <canvas>'da pek ilgi görmeyen bir alan olan metin efektleri oluşturma ele alınmaktadır. <canvas> ile oluşturulabilecek metin efektlerinin çeşitliliği hayal gücünüzle sınırlıdır. Bu demolarda, mümkün olanların bir kısmı gösterilmektedir. Bu makalede "metin" ile ilgileniyor olsak da yöntemler herhangi bir vektör nesnesine uygulanabilir. Oyunlarda ve diğer uygulamalarda heyecan verici görseller oluşturabilirsiniz:

<canvas> dilinde metin gölgeleri.
<canvas>'te CSS benzeri metin efektleri oluşturma, <canvas>'te metrikleri bulma ve gölge özelliğini kullanma
Neon gökkuşağı, zebra yansıması - zincirleme efektler.
globalCompositeOperation, createLinearGradient, createPattern kullanımına dair <canvas> örnekte Photoshop benzeri metin efektleri.
<canvas> uygulamasında iç ve dış gölgeler
Az bilinen bir özelliği açıklama; gölge efektinin tersini (iç gölge) oluşturmak için saat yönünde ve saat yönünün tersine sarma yöntemini kullanma.
Uzay çağı - üretken efekt.
Üretken tabanlı metin efekti, <canvas> içinde hsl() renk döngüsü ve window.requestAnimationFrame kullanılarak hareket hissi yaratır.

Canvas'ta metin gölgeleri

CSS3 spesifikasyonlarına yapılan en sevdiğim eklemelerden biri (border-radius, web-gradients ve diğerleriyle birlikte) gölge oluşturma özelliğidir. CSS ve <canvas> gölgeleri arasındaki farkları anlamak önemlidir. Özellikle:

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

<canvas> tek bir gölge türüne sahiptir. Bu gölge türü 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> uygulamasında gölge oluşturmak için şu dört özellikten yararlanın:

ctx.shadowColor = "red" // string
Gölgenin rengi; RGB, RGBA, HSL, HEX ve diğer girişler geçerlidir.
ctx.shadowOffsetX = 0; // integer
Gölgenin metne göre yatay uzaklığı.
ctx.shadowOffsetY = 0; // integer
Metne göre gölgenin dikey uzaklığı.
ctx.shadowBlur = 10; // integer
Gölgeye bulanıklaştırma efekti. Değer ne kadar büyük olursa bulanıklık o kadar fazla olur.

Başlamak için <canvas> aracının CSS efektlerini nasıl taklit edebileceğini görelim. Google Görseller'de "css text-shadow" araması yaptığımızda, taklit edebileceğimiz birkaç harika demo bulduk: Line25, Stereoscopic ve Shadow 3D.

CSS 3D Grafik

Stereoskopik 3D efekti (daha fazla bilgi için Anaglif görüntü bölümüne bakın), basit bir kod satırının mükemmel bir şekilde kullanılmasına örnektir. Aşağıdaki CSS satırıyla, 3D kırmızı/mavi gözlüklerle (3D filmlerde verilen türden) bakıldığında 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 edilmesi gereken iki nokta vardır:

  1. Gölge bulanıklığı (üçüncü değer) olmadığından, fillText aynı sonuçları oluşturacağı için gölgeyi çalıştırmaya gerek 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>
  1. EM'ler <canvas> içinde desteklenmediğinden PX'e dönüştürülmeleri gerekir. PT, PC, EM, EX, PX vb. arasındaki dönüşüm oranını, DOM'da aynı yazı tipi özelliklerine sahip bir öğe oluşturup genişliği ölçülecek biçime ayarlayarak bulabiliriz. Örneğin, EM -> PX dönüşümünü yakalamak için DOM öğesini "height: 1em" ile ölçeriz. Sonuçta 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

Line25'te bulunan Neon efekti gibi daha karmaşık bir örnekte, efekti düzgün bir şekilde taklit etmek için shadowBlur özelliği kullanılmalıdır. Neon efekti birden fazla gölgeye dayandığından bir sorunla karşılaşırız. <canvas> uygulamasında her vektör nesnesinin yalnızca bir gölgesi olabilir. Bu nedenle, birden fazla gölge çizmek için metnin birden fazla sürümünü üst üste çizmeniz gerekir. Bu durum, alfa çarpımına ve sonuç olarak pürüzlü kenarlara neden olur.

Neon grafik

Metni gizleyip gölgeyi göstermek için ctx.fillStyle = "rgba(0,0,0,0)" veya "transparent" çalıştırmayı denedim ancak bu deneme başarısız oldu. Gölge, fillStyle alfa değerinin katı olduğundan gölge hiçbir zaman fillStyle'dan daha opak olamaz.

Neyse ki bu sorunu çözmenin bir yolu var. Gölgeyi metinden uzaklaştırarak çizebilir, böylece ikisini birbirinden ayırabilir (üst üste binmemelerini sağlayabilir) ve metni ekranın kenarında 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

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

Neyse ki CSS hileleri sayesinde (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, kırpma yolu olarak kullanmak üzere bir dikdörtgen oluşturabiliriz. Bu dikdörtgen, "gölgeyi" içine alırken yapay şekli kaldırır.

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

Tüm bunları bir araya getirip ilerledikçe optimize edersek gölgede bulanıklık yoksa fillText aynı etki için kullanılabilir ve bizi kırpma maskesini ayarlamaktan kurtarır:

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ısı ekledim. Bu sayede, CSS komutlarını besleyebilir ve <canvas> komutları oluşturmasını sağlayabilirsiniz. Artık <canvas> öğelerimiz, bağlanabileceği çok çeşitli stillere sahip. Bu gölge efektleri, WebFont'lardan SVG'lerden içe aktarılan karmaşık şekillere, üretken vektör şekillerine kadar her türlü vektör nesnesinde kullanılabilir.

Kanvas efektlerinde metin gölgesi

Ara (Pixel'de tasarım yapma hakkında)

Makalenin bu bölümünü yazarken stereoskopik örnek ilgimi çekti. <canvas> ve biraz farklı açılardan çekilmiş iki resim kullanarak 3D film ekranı efekti oluşturmak ne kadar zor olabilir? Görünüşe göre çok zor değil. Aşağıdaki çekirdek, ilk görüntünün (data) kırmızı kanalını ikinci görüntünün (data2) camgöbeği 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;

Şimdi, birinin iki iPhone'u alnına bantlayıp aynı anda "video kaydet"e basması yeterli. Böylece HTML5'te kendi 3D filmlerimizi yapabiliriz. Gönüllü var mı?

3D gözlük

Neon gökkuşağı, zebra yansıması: zincirleme efektler

<canvas> içinde birden fazla efekti zincirlemek basit olabilir ancak globalCompositeOperation (GCO) hakkında temel bilgiye sahip olmak gerekir. İşlemleri GIMP (veya Photoshop) ile karşılaştırmak için: <canvas> içinde 12 GCO vardır. Daha koyu ve daha 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 örneğimizde kod dizelerini) birbirine bağlayarak yeni ve heyecan verici şekillerde birleştirir:

Zincirleme efekt grafikleri

globalCompositeOperation grafiği, GCO modlarının işleyişini gösterir. Bu grafikte, ne bekleneceğini ayrıntılı olarak görmek için renk spektrumunun büyük bir kısmı ve birden fazla alfa şeffaflığı düzeyi kullanılır. Metin açıklamaları için Mozilla 'nın globalCompositeOperation referansına göz atmanızı öneririz. Daha fazla bilgi edinmek için Porter Duff 'ın Compositing Digital Images adlı makalesinde işlemin nasıl çalıştığını öğrenebilirsiniz.

En sevdiğim mod globalCompositeOperation="lighter". Daha açık, eklenen 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 pürüzsüz kenarlar sağladığı için denemesi heyecan verici bir özelliktir. Lighter birçok amaçla kullanıldı. Son zamanlarda en sevdiğim kullanım alanı, http://weavesilk.com/ adresinde bulunan HTML5 masaüstü arka plan oluşturucusu. Demolarımdan biri olan Breathing Galaxies (JS1k) de daha açık modu kullanır. Bu iki örnekten yola çıkarak bu modun nasıl bir etki yarattığını görmeye başlayabilirsiniz.

adresini ziyaret edin.

globalCompositeOperation tarayıcı işleme.

Neon gökkuşağı titreme efekti

Aşağıdaki demoda, globalCompositeOperation (source-in, lighter ve darker) kullanarak efektleri birbirine bağlayarak titrek bir dış çizgiye sahip Photoshop benzeri neon gökkuşağı parıltısı elde edeceğiz. Bu demo, "<canvas>'da Metin Gölgeleri" demosunun devamı niteliğindedir. Gölgeyi metinden ayırmak için aynı stratejiyi kullanır (önceki bölüme bakın):

Gökkuşağı Titremesi
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ıması efekti, WebDesignerWall 'un sayfanızı CSS ile nasıl canlandıracağınızla ilgili mükemmel kaynağından esinlenmiştir. Bu, fikri biraz daha ileriye götürerek metin için bir "yansıma" oluşturur. iTunes'da görebileceğiniz gibi. Efekt, fillColor (beyaz), createPattern (zebra.png) ve linearGradient (parlaklık) özelliklerini birleştirir. Bu, her vektör nesnesine birden fazla dolgu türü uygulama özelliğ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();
};

Tuvalde iç/dış gölgeler

<canvas> spesifikasyonları, "iç" ve "dış" gölgeler konusuna değinmez. Aslında ilk bakışta "iç" gölgenin desteklenmediğini düşünebilirsiniz. Böyle bir durum söz konusu değildir. Yalnızca etkinleştirmek biraz daha zor. ;) F1LT3R'ın yakın tarihli bir yayınında ö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şturun ve ardından ters sarma kurallarını kullanarak bir kesme şekli çizerek şeklin tersini oluşturun.

Aşağıdaki örnekte, inner-shadow ve fillStyle'ın aynı anda renk+gradyan+desen ile stillendirilmesine izin verilmektedir. Desen dönüşünü ayrı ayrı belirtebilirsiniz. Zebra çizgilerinin artık birbirine dik olduğuna dikkat edin. Sınırlayıcı kutu boyutunda bir kırpma maskesi kullanılarak kesilen şekli çevrelemek için çok büyük bir kapsayıcıya duyulan ihtiyaç ortadan kaldırılır. Bu sayede, 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 de görebileceğiniz gibi, globalCompositeOperation'ı kullanarak efektleri birbirine bağlayabilir ve daha ayrıntılı efektler (maskeleme ve karıştırma kullanarak) üretebiliriz. Ekran sizin oyun alanınız.

Uzay çağı: Üretken efektler

<canvas> dilinde, 0x2708 unicode karakterinden başlayarak:

Unicode grafiği

…bu gölgeli örneğe:

Gölgeli örnek

…x-ofset ve alfa değerlerini yavaşça azaltırken ince bir lineWidth (0,25) ile ctx.strokeText() öğesine birden fazla çağrı yaparak elde edilebilir.Bu sayede vektör öğelerimize hareket hissi verilir.

Öğelerin XY konumunu bir sinüs/kosinüs dalgasıyla eşleyerek ve HSL özelliğini kullanarak renkler arasında geçiş yaparak daha ilginç efektler oluşturabiliriz. Örneğin, aşağıdaki "biyolojik tehlike" örneği:

HSL döngü efekti

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 okunabilecek şekilde tasarlanmıştır.

HSL'nin kolaylığını göstermek için renk spektrumunda gezinirken "ton" değerini 360'tan itibaren artırırız. Ton, spektrumla silindirik bir şekilde eşlenir. Açıklık, rengin ne kadar koyu/açık olduğunu kontrol eder. %0 siyah pikseli, %100 ise beyaz pikseli gösterir. Doygunluk, bir rengin ne kadar parlak veya canlı olduğunu kontrol eder. Griler %0 doygunlukla, canlı renkler ise %100 doygunlukla oluşturulur.

HSL Grafiği

HSL yeni bir standart olduğundan eski tarayıcıları desteklemeye devam etmek isteyebilirsiniz. Bu, renk uzayı dönüştürme yoluyla mümkündür. 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 } döndürür. Buradan, 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 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 iki seçenek vardı: setTimeout ve setInterval.

window.requestAnimationFrame, her ikisinin de yerini alacak yeni standarttır. Tarayıcının, animasyonları mevcut kaynaklara göre düzenlemesine olanak tanıyarak dünyayı elektrikten (ve bilgisayarınızı birkaç kalp atışından) kurtarır. Önemli özelliklerden bazıları şunlardır:

  • Kullanıcı kadrajdan çıktığında animasyon yavaşlayabilir veya tamamen durabilir. Bu sayede gereksiz kaynak kullanımı önlenir.
  • Kare hızı 60 FPS ile sınırlıdı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ığı tarih itibarıyla, requestAnimationFrame özelliğini kullanmak için tedarikçiye özel ön ekler gereklidir. Paul Irish, requestAnimationFrame for smart animating (Akıllı animasyon için requestAnimationFrame) makalesinde, tedarikçiler arası desteğe 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);
        };
})();

Daha iddialı olanlar, bu yeni standarda geçerken eski tarayıcıları daha fazla destekleyecek requestAnimationFrame.js gibi bir polyfill ile bunu bir araya getirebilir (ü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);
})();
Notlar Bulanıklaştırma Grafiği
Animasyon Grafiği
Matris Grafiği

Kaynak kodu

Tarayıcı tedarikçileri tarafından desteklendiği için <canvas> geleceği konusunda şüphe yoktur. PhoneGap kullanılarak iPhone/Android/Masaüstü yürütülebilir dosyalarına taşınabilir veya

Titanyum.