Sebuah halaman dapat menampilkan grafis melalui tiga jalan yang berbeda, yaitu berkas gambar jadi dengan img, markup vektor dengan svg, dan permukaan gambar prosedural dengan canvas. Topik ini membandingkan ketiganya dari sisi sumber gambarnya, kemampuan interaksi, aksesibilitas, dan pemeliharaannya, lalu menutup dengan tabel keputusan untuk memilih alat yang tepat. Satu grafik batang nilai ulangan yang sama digunakan pada seluruh contoh agar watak setiap pendekatan mudah diperbandingkan.
img untuk gambar statis#
Elemen img menampilkan berkas gambar yang sudah jadi, biasanya hasil ekspor dari alat gambar atau pengolah grafis. Browser hanya menampilkan berkasnya apa adanya, dan halaman tidak memiliki celah untuk mengubah bentuk, warna, atau isi gambarnya. Kesederhanaan itu menjadi keunggulan utama img, karena berkasnya tersimpan dalam cache browser, tidak menambah biaya penguraian markup, dan perilakunya identik di semua browser modern.
Aksesibilitasnya juga paling sederhana, yaitu satu atribut alt yang mendeskripsikan isi gambar. Batas img terletak pada sifat statisnya, yaitu isi grafis hanya berubah apabila berkas diganti dengan berkas lain, sehingga elemen ini tidak cocok untuk grafis yang bergantung pada data halaman. Atribut loading, width, dan height berlaku seperti pada img lainnya, karena elemen ini berperilaku sama apa pun isi berkasnya. Versi baru grafisnya juga cukup menimpa berkas lama dengan nama yang sama, sehingga halaman tidak perlu disunting. Grafik batang berikut disimpan sebagai berkas SVG dan ditampilkan melalui img.
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="160" viewBox="0 0 240 160" role="img" aria-labelledby="judul-grafis-vektor">
<title id="judul-grafis-vektor">Grafik batang nilai ulangan tanpa label angka</title>
<rect width="240" height="160" fill="#fafafa"/>
<rect x="40" y="90" width="36" height="50" fill="#64b5f6"/>
<rect x="102" y="60" width="36" height="80" fill="#64b5f6"/>
<rect x="164" y="40" width="36" height="100" fill="#64b5f6"/>
<line x1="24" y1="140" x2="216" y2="140" stroke="#555555" stroke-width="2"/>
</svg><img src="grafis-vektor.svg" alt="Grafik batang nilai ulangan" width="240" height="160">svg untuk grafis berlabel#
Elemen svg menulis grafis sebagai markup yang terdiri atas bentuk, lintasan (path), dan teks. Karena berbentuk vektor, gambarnya tetap tajam pada ukuran tampil apa pun, dan karena berada di dalam pohon DOM, setiap batangnya adalah elemen yang dapat digayai CSS serta menerima event JavaScript. Teks di dalam svg juga merupakan teks sungguhan yang dapat dibaca pembaca layar dan ikut terindeks, sehingga grafis berlabel seperti diagram dan bagan lebih baik ditulis dengan svg daripada diekspor menjadi berkas gambar.
<svg width="240" height="160" viewBox="0 0 240 160" role="img"
aria-label="Grafik batang nilai ulangan, ketuk batangnya untuk membaca nilainya">
<rect width="240" height="160" fill="#fafafa"></rect>
<rect class="batang" data-nilai="70" x="40" y="70" width="36" height="70" fill="#64b5f6"></rect>
<rect class="batang" data-nilai="80" x="102" y="60" width="36" height="80" fill="#64b5f6"></rect>
<rect class="batang" data-nilai="100" x="164" y="40" width="36" height="100" fill="#64b5f6"></rect>
<line x1="24" y1="140" x2="216" y2="140" stroke="#555555" stroke-width="2"></line>
</svg>
<p id="ket-svg">Klik salah satu batang untuk membaca nilainya.</p>Setiap batang membawa atribut data-nilai, dan skrip singkat cukup dipasang pada kelasnya untuk menampilkan nilai batang yang diklik. Gaya CSS dari halaman juga menjangkau setiap batangnya, misalnya warna isinya diubah melalui aturan kelas, sedangkan svg yang dimuat melalui img tidak menerima gaya halaman sama sekali. Interaksi semacam ini tidak mungkin dilakukan pada img, sedangkan dengan svg markupnya tetap dapat dibaca dan disunting secara langsung. Biayanya adalah markup yang lebih panjang, sehingga grafis yang kompleks biasanya dihasilkan oleh alat atau skrip, bukan ditulis tangan seluruhnya.
canvas untuk gambar prosedural#
Elemen canvas menyediakan permukaan piksel yang isinya sepenuhnya digambar oleh JavaScript melalui konteks gambar, umumnya konteks 2d. Setelah perintah gambar dijalankan, hasilnya berupa kumpulan piksel yang tidak menyimpan objek apa pun, sehingga tidak ada batang atau garis yang dapat diklik, digayai, atau dibaca mesin. Untuk mengubah gambarnya, skrip menggambar ulang seluruh permukaan, dan untuk animasi, penggambaran ulang itu dijalankan pada setiap bingkai. Aksesibilitasnya memerlukan kerja tambahan, misalnya teks pengganti di luar kanvas atau deskripsi yang disisipkan pada DOM.
Karena isinya dihitung oleh skrip, pekerjaan menarik justru terjadi sebelum menggambar, yaitu menghitung koordinat setiap bentuknya. Skrip berikut menghitung titik-titik kurva sinus yang kelak digambar ke kanvas, dan skripnya murni JavaScript sehingga dapat dieksekusi langsung.
// menghitung titik kurva sinus sebelum digambar ke canvas
const lebar = 240;
const tengahY = 80;
const amplitudo = 40;
for (let x = 0; x <= lebar; x += 30) {
const y = tengahY - amplitudo * Math.sin((x / lebar) * Math.PI * 2);
console.log(`(${x}, ${y.toFixed(1)})`);
}(0, 80.0)
(30, 51.7)
(60, 40.0)
(90, 51.7)
(120, 80.0)
(150, 108.3)
(180, 120.0)
(210, 108.3)
(240, 80.0)Keluaran memperlihatkan sembilan titik yang bergerak naik dan turun di sekitar nilai 80 piksel dengan simpangan 40 piksel. Setiap pasangan koordinat pada keluaran itu menjadi pusat satu titik pada kanvas. Skrip penggambarnya memerlukan browser sehingga hanya ditampilkan di sini.
// tidak-dijalankan
const kanvas = document.getElementById("kanvas");
const konteks = kanvas.getContext("2d");
konteks.fillStyle = "#fafafa";
konteks.fillRect(0, 0, kanvas.width, kanvas.height);
konteks.fillStyle = "#ef5350";
for (let x = 0; x <= 240; x += 6) {
const y = 80 - 40 * Math.sin((x / 240) * Math.PI * 2);
konteks.beginPath();
konteks.arc(x, y, 3, 0, Math.PI * 2);
konteks.fill();
}Pola perulangan pada kedua skrip itu sama persis, yaitu rumus yang sama menghasilkan titik-titik yang sama, dan perbedaannya hanya pada penanganan keluarannya. Skrip pertama mencetaknya ke terminal, sedangkan skrip kedua mengubahnya menjadi piksel pada permukaan kanvas.
Tabel keputusan memilih alat#
Ketiga alat tersebut berdampingan tanpa saling menggantikan, dan pilihannya ditentukan oleh watak kontennya. Tabel berikut merangkum perbedaannya.
| Aspek | img | svg | canvas |
|---|---|---|---|
| Sumber grafis | Berkas jadi hasil ekspor | Markup vektor yang ditulis | Perintah gambar dari JavaScript |
| Skala dan ketajaman | Bergantung resolusi berkas | Tajam pada semua ukuran | Bergantung resolusi kanvas |
| Interaksi | Tidak ada | Event DOM pada setiap elemen | Seluruh permukaan digambar ulang oleh skrip |
| Aksesibilitas | Teks alt | Teks dan atribut di dalam markup | Perlu kerja tambahan |
| Perubahan isi | Ganti berkasnya | Sunting atau hasilkan markupnya | Gambar ulang lewat skrip |
Aturan keputusannya mengikuti urutan pertanyaan tersebut. Gunakan img bila grafisnya statis dan sudah jadi, karena alat ini paling ringan dan paling aksesibel. Gunakan svg bila grafisnya perlu label, gaya dari CSS, atau interaksi per bentuk, misalnya bagan dan diagram. Gunakan canvas hanya bila gambar memang prosedural atau berubah setiap bingkai, misalnya visualisasi data yang mengalir, permainan, dan pengolahan piksel. Kebutuhan yang melintasi dua alat juga lazim, misalnya kanvas untuk animasinya dan svg untuk tombol-tombol kendalinya.
Contoh berkas utuh#
Berkas berikut menampilkan ketiga pendekatan pada satu halaman dengan data yang sama. Simpan grafis.html bersama grafis-vektor.svg dalam satu folder, lalu buka grafis.html di browser dan coba ketiga panelnya. Panel img menampilkan berkas grafis-vektor.svg yang diam, panel svg menampilkan batang yang dapat diklik karena setiap batangnya elemen DOM, dan panel canvas menampilkan kurva titik yang digambar JavaScript saat halaman dibuka.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>Tiga cara menampilkan grafis</title>
<style>
body { font-family: sans-serif; max-width: 40rem; margin: 0 auto; padding: 0 1rem; }
section { margin-bottom: 2rem; }
img, svg, canvas { border: 1px solid #bbbbbb; border-radius: 4px; display: block; }
#ket-svg { min-height: 1.2em; color: #555555; }
</style>
</head>
<body>
<h1>Tiga cara menampilkan grafis</h1>
<section>
<h2>img</h2>
<img src="grafis-vektor.svg" alt="Grafik batang nilai ulangan" width="240" height="160">
<p>Berkas jadi yang tidak dapat diubah dari halaman.</p>
</section>
<section>
<h2>svg</h2>
<svg width="240" height="160" viewBox="0 0 240 160" role="img"
aria-label="Grafik batang nilai ulangan, ketuk batangnya untuk membaca nilainya">
<rect width="240" height="160" fill="#fafafa"></rect>
<rect class="batang" data-nilai="70" x="40" y="70" width="36" height="70" fill="#64b5f6"></rect>
<rect class="batang" data-nilai="80" x="102" y="60" width="36" height="80" fill="#64b5f6"></rect>
<rect class="batang" data-nilai="100" x="164" y="40" width="36" height="100" fill="#64b5f6"></rect>
<line x1="24" y1="140" x2="216" y2="140" stroke="#555555" stroke-width="2"></line>
</svg>
<p id="ket-svg">Klik salah satu batang untuk membaca nilainya.</p>
</section>
<section>
<h2>canvas</h2>
<canvas id="kanvas" width="240" height="160"></canvas>
<p>Titik-titik kurva digambar JavaScript saat halaman dibuka.</p>
</section>
<script>
// svg: setiap batang adalah elemen DOM yang dapat menerima event
const ketSvg = document.getElementById("ket-svg");
document.querySelectorAll(".batang").forEach((batang) => {
batang.addEventListener("click", () => {
ketSvg.textContent = "Nilai batang yang diklik: " + batang.dataset.nilai;
});
});
// canvas: piksel digambar sekali, tidak ada objek yang tersisa
const kanvas = document.getElementById("kanvas");
const konteks = kanvas.getContext("2d");
konteks.fillStyle = "#fafafa";
konteks.fillRect(0, 0, kanvas.width, kanvas.height);
konteks.fillStyle = "#ef5350";
for (let x = 0; x <= 240; x += 6) {
const y = 80 - 40 * Math.sin((x / 240) * Math.PI * 2);
konteks.beginPath();
konteks.arc(x, y, 3, 0, Math.PI * 2);
konteks.fill();
}
</script>
</body>
</html>Ketiga panelnya berbagi satu ukuran yang sama, yaitu 240 kali 160 piksel, sehingga perbedaan yang terlihat murni berasal dari alatnya, bukan dari ukurannya. Perhatikan pula bahwa hanya panel svg yang memberi umpan balik saat diklik, dan hal itu persis mengikuti tabel keputusan di atas. Ubah ukuran jendelanya, dan hanya panel svg yang menyesuaikan diri, sedangkan isi canvas tetap berukuran 240 kali 160 piksel karena buffer gambarnya tidak ikut berubah. Perbedaan itu menegaskan bahwa kanvas perlu digambar ulang oleh skrip setiap kali ukurannya berubah.
Kesalahan umum#
Memilih canvas untuk ikon dan diagram statis. Isinya tidak dapat digayai CSS, tidak memberi aksesibilitas apa pun, dan tampak buram ketika diskalakan, sedangkan svg melayani semua kebutuhan itu. Cadangkan canvas untuk gambar yang benar-benar prosedural.
Menaruh teks penting hanya di dalam kanvas. Piksel pada canvas tidak terbaca pembaca layar dan tidak ikut terindeks, sehingga informasinya hilang bagi sebagian pengguna. Sediakan teks pengganti di luar kanvas, misalnya paragraf ringkasan atau tabel datanya.
Mengharapkan perubahan CSS pada isi kanvas. Gaya pada elemen canvas hanya mengubah kotaknya, seperti bingkai dan ukuran tampil, sedangkan isi gambar tetap apa adanya. Perubahan isi dilakukan dengan menggambar ulang melalui skrip.
Menganggap grafis svg di berkas terpisah tetap interaktif. Skrip dan gaya di dalam berkas SVG yang dimuat melalui img tidak berjalan, karena img menampilkan gambarnya sebagai benda statis. Interaksi per bentuk menuntut svg yang ditulis inline di dalam halaman.
Ringkasan#
imgmenampilkan berkas jadi denganaltsebagai satu-satunya keterlibatan halaman, dan paling tepat untuk grafis statis.svgmenulis grafis sebagai markup vektor di dalam DOM, sehingga tajam di semua ukuran, dapat digayai, dapat berinteraksi, dan terbaca pembaca layar.canvasmenggambar piksel melalui JavaScript tanpa menyimpan objek, sehingga cocok untuk gambar prosedural dan animasi, dengan aksesibilitas yang dikerjakan sendiri.- Pemilihannya mengikuti watak konten, yaitu statis untuk
img, berlabel dan interaktif untuksvg, serta berubah terus untukcanvas.
Referensi#
- Elemen canvas — MDN Web Docs — Dokumentasi elemen canvas beserta konteks gambar 2d-nya.
- Canvas tutorial — MDN Web Docs — Panduan menggambar bentuk, teks, dan animasi pada canvas.
- SVG tutorial — MDN Web Docs — Panduan menulis grafis vektor berupa markup SVG.
- HTML: canvas — HTML Living Standard — WHATWG — Spesifikasi resmi elemen canvas dan konteks penggambarannya.