Selalu jadi Anda, Canvas2D

Aaron Krajeski
Aaron Krajeski

Di dunia shader, mesh, dan filter, Canvas2D mungkin tidak membuat Anda bersemangat. 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).

API ini memang sedikit tertinggal dalam hal gambar 2D yang canggih. Untungnya, kami telah bekerja keras mengimplementasikan fitur-fitur baru di Canvas2D untuk mengimbangi CSS, menyederhanakan ergonomi, dan meningkatkan performa.

Bagian 1: mempelajari CSS

CSS memiliki beberapa perintah gambar yang sangat hilang dari Canvas2D. Dengan API baru ini, kami telah menambahkan beberapa fitur yang paling banyak diminta:

Persegi panjang membulat

Persegi panjang bulat: landasan internet, komputasi, dekat, peradaban.

Baik serius, persegi panjang bersudut tumpul sangat berguna: seperti tombol, balon chat, thumbnail, balon kata-kata, dan banyak lagi. Membuat persegi panjang membulat di Canvas2D selalu dapat dilakukan, hanya saja 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 yang sedang dan sederhana:

Persegi panjang yang membulat.

Dengan API baru, terdapat metode roundRect().

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

Jadi, pernyataan di atas dapat sepenuhnya diganti dengan:

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

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

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

Lihat demo untuk bermain-main.

Gradien Kerucut

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.

Tapi 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 mengecewakan. Chrome telah menambahkan beberapa atribut baru ke rendering teks Canvas2D:

Semua atribut ini cocok dengan atribut CSS-nya yang memiliki 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:

Konteks direset

Untuk menjelaskan cara menghapus kanvas, saya telah menulis fungsi kecil yang konyol untuk menggambar pola retro:

draw90sPattern();

Pola retro segitiga dan persegi.

Bagus! Sekarang saya selesai dengan pola itu, saya ingin mengosongkan kanvas dan menggambar yang lain. Tunggu, bagaimana kita menghapus kanvas lagi? Baiklah! Tentu saja ctx.clearRect().

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

Hah... itu tidak berhasil. Baiklah! 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 yang dilakukan garis ekstra itu di sini? Lalu, kenapa warnanya merah muda? Mari kita periksa StackOverflow.

canvas.width = canvas.width;

Kenapa ini konyol? Mengapa ini sangat sulit?

Yah, tidak lagi. Dengan API baru, kami memiliki berbagai terobosan yang sederhana, elegan, dan indah:

ctx.reset();

Maaf karena begitu lama.

Filter

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

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

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

Yang mengacaukan pola kita cukup bagus:

Pola retro dengan efek buram diterapkan.

Namun, bagaimana jika Anda ingin melakukan hal di atas tetapi tetap dalam JavaScript dan tidak main-main dengan string? Dengan API baru, hal ini sepenuhnya mungkin 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 pai! Cobalah dan mainkan parameternya 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 terperinci atas situs mereka dan memungkinkan kecepatan frame yang paling indah:

Akan sering dibaca

Gunakan getImageData() untuk membaca kembali data piksel dari kanvas. Prosesnya bisa sangat lambat. API baru ini memberi Anda cara menandai kanvas secara eksplisit untuk membaca kembali (misalnya, untuk efek generatif). Hal ini memungkinkan Anda mengoptimalkan berbagai hal di balik layar dan menjaga agar 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 });

Kehilangan konteks

Mari membuat tab yang sedih menjadi senang lagi! Jika klien kehabisan memori GPU atau beberapa bencana lainnya menimpa kanvas Anda, kini Anda 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 kerugian kanvas, WhatWG memiliki penjelasan yang bagus di wikinya.

Kesimpulan

Baik Anda pengguna baru Canvas2D, Anda telah menggunakannya selama bertahun-tahun, atau Anda sudah tidak menggunakannya selama bertahun-tahun, saya di sini akan memberi tahu Anda untuk melihat kembali kanvas. API ini adalah pintu berikutnya yang sudah ada selama ini.

Ucapan terima kasih

Banner besar oleh Sandie Clarke di Unsplash.