Halo, Kali ini saya akan membagikan tutorial HTML Canvas + JavaScript untuk membuat simple image filter. Ini merupakan lanjutan dari seri LKS Nasional 2021 Web Technologies.
Seperti di seri-seri sebelumnya, anda dapat melihat source code dan juga soal dari tutorial ini di repository saya:
Simple Image Filter dengan Canvas
Canvas adalah sebuah teknologi canggih dari HTML 5 yang memungkinkan kita untuk melakukan berbagai hal yang berhubungan dengan grafis. Membuat objek gambar, mengubah ukuran gambar, hingga membuat sebuah game interaktif. Jika anda belum pernah mengenal canvas sama sekali, saya sarankan untuk membaca referensi HTML Canvas di w3schools.
Dalam soal speedtest ini kita dituntut untuk dapat membuat sebuah filter image "darken" dan "lighten" di dalam HTML Canvas. Untuk gambar yang akan digunakan tersedia dalam modul (file media dalam repository github saya). Tampilan yang diinginkan adalah kurang lebih berikut ini:
Membuat Struktur HTML
Pertama-tama tentunya kita harus menyiapkan struktur HTML yang memiliki layout seperti gambar diatas:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simple Image Filter</title>
</head>
<body>
<main>
<canvas id="canvas" height="320px" width="460px"></canvas>
<div>
Image:
<select id="image">
<option value="athena.jpg">Image:</option>
<option value="athena.jpg">Athena.jpg</option>
<option value="mona-lisa.jpg">mona-lisa.jpg</option>
<option value="theKiss.jpg">theKiss.jpg</option>
<option value="young-pearl.jpg">young-pearl.jpg</option>
</select>
Filter:
<select id="filter">
<option value="">filter</option>
<option value="darker">Darker</option>
<option value="lighter">Lighter</option>
</select>
</div>
</main>
</body>
</html>
Kita membuat sebuah elemen canvas dengan ukuran height 320px dan width 460px (sesuai dengan requirements soal). Selanjutnya membuat select
untuk image dan juga filter. Disini kita menambahkan id untuk element canvas
dan select
agar mudah kita targetkan elementnya dengan JavaScript. Perhatikan di select
ber id image, value disitu adalah daftar image yang akan kita tampilkan, ketika diubah canvas akan merender image tersebut. Masukan semua gambar yang akan digunakan ke dalam folder assets
agar lebih rapi.
Membuat Filter dengan JavaScript
Disini adalah langkah yang paling penting, kita akan menggunakan JavaScript untuk mengakses objek canvas
yang tersedia. Disini saya akan menggunakan class
agar mudah mengisolasi dan menggunakan kembali fungsi yang ada. Silahkan membuat sebuah class
bernama CanvasFilter
di dalam file berekstensi js (disini saya akan menamainya canvas-filter.js
):
class CanvasFilter {
// Method atau fungsi akan kita taruh disini
}
Selanjutnya kita akan membuat constructor
(method/fungsi yang akan dipanggil ketika class
di panggil). Di dalam constructor
ini kita akan memberikan sebuah argumen yang akan berisikan dom
canvas
yang kita gunakan:
constructor(dom){
this.ctx = dom.getContext('2d');
this.image = new Image();
var self = this;
this.image.onload=function(){
self.renderImage()
}
this.filter = '';
}
Informasi
di dalam variable image kita memanggil new Image, Image disini adalah sebuah alias dari document.createElement('img') yang akan membuat sebuah objek dom Image baru.
Disana kita menyimpan context
dari canvas
nya kedalam variable ctx
yang berada didalam class
tersebut. Juga ada variable image
yang akan menyimpan image yang akan di draw nantinya. Kita juga membuat variable lokal self
, variable ini berguna untuk kode dibawahnya.
onload
berisikan fungsi yang dipanggil ketika objek image yang telah kita buat tadi src (source imagenya) sudah terload oleh browser. Kita tidak menggunakan this
didalam callback function karena akan menimbulkan error (ketika menggunakan this
didalam callback function objek image, this
yang akan digunakan adalah this
dari objek image, bukan this
dari tempat memanggilnya / canvasFilter
). Method renderImage
akan kita buat nanti.
Selanjutnya, kita akan membuat method untuk mengubah jenis filter dan gambar yang akan di draw/render:
setImage(url){
this.image.src = url;
this.render();
}
setFilter(filter){
this.filter = filter;
this.draw();
this.renderImage();
}
Didalam method setImage
kita mengatur src (source) dari objek Image yang sudah kita buat sebelumnya. Perhatikan juga di kedua method tersebut kita memanggil this.render()
yang memanggil method render di class ini sendiri (CanvasFilter
). Method render akan kita gunakan sebagai method yang akan merender ulang content dari canvas setiap kali setImage
atau setFilter
dipanggil. Dibawah ini adalah method render
serta renderImage
:
render(){
this.ctx.fillStyle = "#42c78b";
this.ctx.fillRect(0, 0, 460, 320);
}
renderImage(){
this.ctx.drawImage(this.image, 10, 10, 210, 300);
if(this.filter){
this.ctx.drawImage(this.image, 240, 10, 210, 300);
switch(this.filter){
case 'darker':
this.ctx.fillStyle = "rgba(0, 0, 0, 0.6)";
break;
case 'lighter':
this.ctx.fillStyle="rgba(255, 255, 255, 0.6)";
break;
}
this.ctx.fillRect(240, 10, 210, 300);
}
}
Di method render
kita hanya akan melakukan resetting canvas dengan background berwarna #42c78b
(hijau). fillStyle
berfungsi untuk mendefinisikan warna yang akan kita gunakan. Kita menggunakan fungsi fillRect
untuk melakukan fill warna berbentuk rectangle (atau kotak).
Syntaxnya fillRect(x, y, w, h)
. x
berisikan koordinat sumbu x (horizontal) tempat awal rectangle akan dibentuk, y
berisikan koordinat sumbu y (vertikal) tempat awal rectangle akan dibentuk. Jika kita isikan masing masing 0 maka rectangle akan dibentuk diawali dari pojok kiri atas canvas. w
adalah width (panjang) dari rectangle yang akan kita buat, h
adalah height (tinggi) dari rectangle yang akan kita buat. Di awal sudah saya jelaskan jika kita membuat objek canvas dengan width 460px dan height 320px. Jadi untuk menutupi seluruh objek canvas menjadi hijau kita gunakan fillRect(0, 0, 460, 320)
.
Didalam method renderImage
kita menggunakan fungsi drawImage
dari canvas context. Syntaxnya drawImage(image_object, x, y, w, h)
. image_object
adalah objek image/dom image yang akan kita lakukan drawing (disini kita menggunakan this.image yang sudah kita definisikan di awal. lalu x
,y
,w
,h
sama artinya seperti fungsi fillReact
.
Didalam method renderImage
kita juga melakukan rendering filter (didalam blok if(this.filter) ). Untuk melakukan filter darker kita gunakan warna rgba(0, 0, 0, 0.6)
berarti read = 0, green = 0, blue = 0, alpha = 0.6 atau warna hitam dengan opacity 0.6. Sedangkan filter lighter kita gunakan warna rgba(255, 255, 255, 0.6)
atau putih dengan opacity 0.6.
Jika belum faham logic dari kode-kode diatas cobalah untuk mempraktekkannya sambil memahaminya.
Selanjutnya silahkan ubah file html yang kita buat di awal tadi, source canvas-filter.js
tadi di dalam tag head:
<head>
<!-- KODE LAIN YANG SUDAH ADA SEBELUMNYA -->
<script src="canvas-filter.js"></script>
</head>
Buat juga sebuah kode javascript dibawah (sebelum tag body ditutup) untuk memanggil class CanvasFilter
yang sudah kita source:
<script>
const canvasFilter = new CanvasFilter(document.getElementById('canvas'));
canvasFilter.setImage('assets/athena.jpg');
document.getElementById('image').addEventListener('change',function(event){
canvasFilter.setImage('assets/'+event.target.value);
});
document.getElementById('filter').addEventListener('change',function(event){
canvasFilter.setFilter(event.target.value);
})
</script>
Lihat, di script tersebut kita panggil class CanvasFilter
ke dalam variable canvasFilter
, kita masukan dom dari canvas (menggunakan getElementById
) sebagai constructor class tersebut.
Lalu kita init gambar awal yang dipilih (sesuai requirements dari soal) assets/athena,jpg
Disitu juga kita membuat event listener untuk select dengan id #image
, ketika opsi selectnya berubah yang dipilih kita memanggil method setImage
dari class CanvasFilter
yang sudah kita init, kita tambahkan prefix assets/
karena semua image sudah kita masukan kedalam folder assets tersebut.
Ada juga event listener untuk select dengan id #filter
, yang akan memanggil method setFilter
dari class yang sudah kita init tadi.
Hasil Akhir Kode
index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simple Image Filter</title>
<script src="canvas-filter.js"></script>
</head>
<body>
<main>
<canvas id="canvas" height="320px" width="460px"></canvas>
<div>
Image:
<select id="image">
<option value="athena.jpg">Image:</option>
<option value="athena.jpg">Athena.jpg</option>
<option value="mona-lisa.jpg">mona-lisa.jpg</option>
<option value="theKiss.jpg">theKiss.jpg</option>
<option value="young-pearl.jpg">young-pearl.jpg</option>
</select>
Filter:
<select id="filter">
<option value="">filter</option>
<option value="darker">Darker</option>
<option value="lighter">Lighter</option>
</select>
</div>
</main>
<script>
const canvasFilter = new CanvasFilter(document.getElementById('canvas'));
canvasFilter.setImage('assets/athena.jpg');
document.getElementById('image').addEventListener('change',function(event){
canvasFilter.setImage('assets/'+event.target.value);
});
document.getElementById('filter').addEventListener('change',function(event){
canvasFilter.setFilter(event.target.value);
})
</script>
</body>
</html>
canvas-filter.js
:
class CanvasFilter {
constructor(dom){
this.ctx = dom.getContext('2d');
this.image = new Image();
var self = this;
this.image.onload=function(){
self.renderImage()
}
this.filter = '';
}
setImage(url){
this.image.src = url;
this.render();
}
setFilter(filter){
this.filter = filter;
this.render();
this.renderImage();
}
render(){
this.ctx.fillStyle = "#42c78b";
this.ctx.fillRect(0, 0, 460, 320);
}
renderImage(){
this.ctx.drawImage(this.image, 10, 10, 210, 300);
if(this.filter){
this.ctx.drawImage(this.image, 240, 10, 210, 300);
switch(this.filter){
case 'darker':
this.ctx.fillStyle = "rgba(0, 0, 0, 0.6)";
break;
case 'lighter':
this.ctx.fillStyle="rgba(255, 255, 255, 0.6)";
break;
}
this.ctx.fillRect(240, 10, 210, 300);
}
}
}
Silahkan coba lihat hasilnya di browser, kurang lebih akan berjalan sesuai dengan requirements soal yang ada.
Kesimpulan
Pembuatan filter image ini bisa dibilang cukup mudah bagi mereka yang sudah cukup memahami javascript dan sedikit memahami penggunaan canvas dengan javascript. Karena kita hanya menggunakan fungsi drawImage
dan fillRect
pada tutorial diatas.
Mungkin ada cara lain yang dapat digunakan untuk mencapai target dari soal ini, yang lebih cepat maupun lebih mudah.
Jangan ragu untuk menghubungi saya untuk berdiskusi maupun bertanya!
Terima kasih telah membaca seri ke 3 dari Pembahasan Soal LKS Nasional 2021 Web Technologies!