Selalu jadi Anda, Canvas2D

Aaron Krajeski
Aaron Krajeski

Di dunia shader, mesh, dan filter, Canvas2D mungkin tidak membuat Anda tertarik. Namun seharusnya tidak demikian. 30–40% halaman web memiliki elemen <canvas> dan 98% dari semua kanvas menggunakan konteks rendering Canvas2D. Ada Canvas2D di mobil, di kulkas, dan di luar angkasa (benar-benar).

Memang, API ini sedikit ketinggalan zaman dalam hal gambar 2D canggih. Untungnya, kami telah bekerja keras dalam menerapkan fitur baru di Canvas2D untuk mengimbangi CSS, menyederhanakan ergonomi, dan meningkatkan performa.

Bagian 1: memahami CSS

CSS memiliki beberapa perintah gambar yang sangat tidak ada di Canvas2D. Dengan API baru, kami telah menambahkan banyak fitur yang paling banyak diminta:

Persegi panjang bulat

Persegi panjang membulat: fondasi internet, komputasi, bahkan peradaban.

Baik serius, persegi panjang bersudut tumpul sangat berguna: seperti tombol, balon chat, thumbnail, balon ucapan, dan banyak lagi. Anda selalu dapat membuat persegi panjang membulat di Canvas2D, tetapi sedikit berantakan:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';

const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;

ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();

Semua ini diperlukan untuk persegi panjang membulat yang sederhana dan sederhana:

Persegi panjang membulat.

Dengan API baru, ada metode roundRect().

ctx.roundRect(upper, left, width, height, borderRadius);

Jadi hal di atas bisa sepenuhnya diganti dengan:

ctx.roundRect(10, 10, 200, 100, 20);

Metode ctx.roundRect() juga menggunakan array untuk argumen borderRadius hingga empat angka. Radius ini mengontrol empat sudut persegi panjang membulat dengan cara yang sama seperti untuk CSS. Contoh:

ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);

Lihat demo untuk mencobanya.

Gradien Konikal

Anda telah melihat gradien linear:

const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);

Gradien linear.

Gradien radial:

const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');

ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);

Gradien radial.

Namun, bagaimana dengan gradien kerucut yang bagus?

const grad = ctx.createConicGradient(0, 100, 100);

grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');

ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);

Gradien kerucut.

Pengubah teks

Kemampuan rendering teks Canvas2D sangat tertinggal. Chrome telah menambahkan beberapa atribut baru ke rendering teks Canvas2D:

Semua atribut ini cocok dengan pasangan CSS-nya dengan nama yang sama.

Bagian 2: penyesuaian ergonomis

Sebelumnya, beberapa hal dengan Canvas2D dapat dilakukan, tetapi tidak perlu rumit untuk diterapkan. Berikut beberapa peningkatan kualitas hidup untuk developer JavaScript yang ingin menggunakan Canvas2D:

Reset konteks

Untuk menjelaskan cara menghapus kanvas, saya telah menulis sedikit fungsi lucu untuk menggambar pola retro:

draw90sPattern();

Pola retro segitiga dan persegi.

Bagus! Setelah saya selesai dengan pola itu, saya ingin membersihkan kanvas dan menggambar sesuatu yang lain. Tunggu, bagaimana cara menghapus kanvas lagi? Oh, iya! ctx.clearRect(), tentu saja.

ctx.clearRect(0, 0, canvas.width, canvas.height);

Huh… itu tidak berhasil. Oh, iya! Saya harus mereset transformasi terlebih dahulu:

ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
Kanvas kosong.

Sempurna! Kanvas kosong yang bagus. Sekarang, mari kita mulai menggambar garis horizontal yang bagus:

ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();

Garis horizontal dan diagonal.

Grrrr! Jawaban Anda salah. 😡 Apa fungsi baris tambahan tersebut? Lalu, kenapa warnanya merah muda? Baiklah, mari kita periksa StackOverflow.

canvas.width = canvas.width;

Mengapa hal ini sangat konyol? Mengapa hal ini sangat sulit?

Tidak lagi. Dengan API baru ini, kami memiliki hal inovatif yang sederhana, elegan, dan indah:

ctx.reset();

Maaf, prosesnya memerlukan waktu lama.

Filter

Filter SVG adalah dunia tersendiri. Jika Anda baru mengenalnya, sebaiknya baca The Art Of SVG Filters And Why It Is Awesome, yang menunjukkan beberapa potensinya yang luar biasa.

Filter gaya SVG sudah tersedia untuk Canvas2D. Anda hanya harus meneruskan filter sebagai URL yang mengarah ke elemen filter SVG lain di halaman:

<svg>
  <defs>
    <filter id="svgFilter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
      <feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
      <feColorMatrix type="hueRotate" values="90" />
    </filter>
  </defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);

ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);

Hal ini cukup mengacaukan pola kita:

Pola retro dengan efek buram.

Namun, bagaimana jika Anda ingin melakukan hal di atas, tetapi tetap dalam JavaScript dan tidak perlu repot dengan string? Dengan API baru, hal ini sepenuhnya dapat dilakukan.

ctx.filter = new CanvasFilter([
  { filter: 'gaussianBlur', stdDeviation: 5 },
  {
    filter: 'convolveMatrix',
    kernelMatrix: [
      [-3, 0, 0],
      [0, 0.5, 0],
      [0, 0, 3],
    ],
  },
  { filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);

Semudah itu! Coba dan mainkan parameter dalam demo di sini.

Bagian 3: peningkatan performa

Dengan New Canvas2D API, kami juga ingin meningkatkan performa jika memungkinkan. Kami menambahkan beberapa fitur untuk memberi developer kontrol yang lebih mendetail atas situs mereka dan memungkinkan kecepatan frame yang paling keren:

Akan sering dibaca

Gunakan getImageData() untuk membaca data piksel kembali dari kanvas. Proses ini bisa sangat lambat. API baru ini memberi Anda cara untuk menandai kanvas secara eksplisit untuk dibaca kembali (misalnya, untuk efek generatif). Hal ini memungkinkan Anda mengoptimalkan berbagai hal di balik layar dan menjaga kanvas tetap cepat untuk berbagai kasus penggunaan. Fitur ini telah ada di Firefox selama beberapa waktu dan akhirnya kami menjadikannya bagian dari spesifikasi kanvas.

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });

Hilangnya konteks

Mari kita buat tab yang sedih menjadi bahagia lagi. Jika klien kehabisan memori GPU atau beberapa bencana lain menimpa kanvas, Anda kini dapat menerima callback dan menggambar ulang sesuai kebutuhan:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);

Jika Anda ingin membaca lebih lanjut tentang konteks dan kehilangan kanvas, WHATWG memiliki penjelasan yang bagus di wiki-nya.

Kesimpulan

Baik Anda baru menggunakan Canvas2D, sudah menggunakannya selama bertahun-tahun, atau telah menghindari penggunaannya selama bertahun-tahun, kami ingin menyarankan Anda untuk melihat kembali canvas. Ini adalah API-next-door yang sudah ada selama ini.