Home » , , , , , , » Solusi untuk Masalah Blog Bertema Komik

Solusi untuk Masalah Blog Bertema Komik

Menambahkan Sistem Navigasi pada Komik
Menambahkan Sistem Navigasi pada Komik

Ini soal pengalaman pribadi. Selama Saya berkeliling mencari situs-situs penyedia baca komik online, ada tiga macam jenis penyajian yang Saya temukan. Pertama, situs tersebut menunjukkan setiap halaman komik tunggal pada satu posting. Sehingga jika kita ingin membaca cerita pada halaman berikutnya, kita harus mengeklik tombol Next atau semacamnya untuk memuat posting baru yang berisi satu halaman komik berikutnya.

Ke dua, situs tersebut akan menyajikan semua halaman komik dalam satu posting, sehingga kita bisa membaca dari awal sampai akhir tanpa harus berpindah-pindah halaman. Namun resikonya adalah kita akan kehilangan begitu banyak waktu hanya untuk menunggu semua halaman komik termuat pada posting tersebut. Belum lagi jika situs yang kita kunjungi telah dipenuhi berbagai macam iklan yang akan semakin memperlambat proses muat halaman.
Tidak berbeda dengan konsep penyajian pertama, karena saat kita berpindah-pindah halaman kita harus menunggu bermenit-menit hanya untuk memuat satu gambar saja.

Bagi Saya ini tidak efektif, mengingat yang para pembaca butuhkan pada dasarnya hanyalah halaman komik dan bukan halaman situs secara keseluruhan. Jika waktu kita dihabiskan hanya untuk menunggu seluruh halaman situs termuat, padahal yang sebenarnya kita butuhkan adalah halaman komik, maka resikonya adalah kita akan kehilangan masa-masa mendalami alur cerita.

Solusinya biasanya adalah dengan cara memuat halaman komik secara bertahap. Artinya adalah kita hanya akan melihat satu halaman komik saja pada satu posting, namun saat kita mengeklik tombol halaman berikutnya, kita tidak akan dibawa menuju ke halaman/posting situs baru, melainkan hanya akan berdiam diri pada satu tempat dan menunggu gambar baru selesai termuat pada satu tempat yang sama.

Saya tidak tahu pasti apa teknik yang mereka gunakan untuk itu. Mungkin AJAX. Tapi Saya pikir itu terlalu berlebihan. Kita bisa menggunakan Lightbox! Hanya saja, lightbox yang satu ini tidak menampilkan gambar di atas tabir hitam seperti lightbox pada umumnya. Kita akan menampilkan gambar tepat di atas navigasi, dengan begitu suasana membaca akan tetap terasa seperti halnya saat kita membaca komik biasa.

Konsep dasarnya masih sama seperti tutorial pembuatan lightbox yang pernah Saya tuliskan di sini. Yaitu kita akan menembak URL gambar pada tautan ke dalam elemen <img> setiap kali aksi klik dilakukan:

$('ul a').click(function() {
$('div').html('<img src="' + this.href + '" alt="Loading..."/>');
return false;
});

Di sini kita akan membuat markup yang berbeda agar setiap tautan tampak sebagai navigasi halaman berangka, dan gambar yang termuat akan ditampilkan di atasnya sebagai halaman komik tunggal:

Markup HTML

Yang kita perlukan tidak banyak. Kita hanya akan membuat daftar tautan yang mengarah ke setiap unit halaman komik (halaman komik adalah gambar). Jadi buat saja seperti ini:

<ul class="img-gallery" data-width="750" data-height="1088">
<li><a href="img/01.png">Judul Halaman 1</a></li>
<li><a href="img/02.png">Judul Halaman 2</a></li>
<li><a href="img/03.png">Judul Halaman 3</a></li>
<li><a href="img/04.png">Judul Halaman 4</a></li>
</ul>

Kelas img-gallery digunakan sebagai identitas, sehingga JQuery hanya akan memanipulasi elemen daftar yang memiliki kelas img-gallery saja. data-width digunakan untuk menentukan lebar halaman komik, data-height digunakan untuk menentukan tinggi halaman komik. Ini diperlukan karena kita akan membuat aplikasi yang tidak hanya bisa digunakan untuk menangani satu komik saja per satu posting tapi juga beberapa komik sekaligus dalam ukuran yang berbeda-beda. Dalam satu halaman.

Memulai Manipulasi

Pertama-tama kita akan membungkus grup tautan halaman komik di atas dengan elemen yang kita beri nama .img-show:

$('.img-gallery').each(function() {
$(this).addClass('img-nav').wrap('<div class="img-show"></div>');
});

Saya juga menambahkan kelas baru bernama .img-nav. Itu akan kita gunakan sebagai selektor CSS untuk mengubah tampilan daftar menjadi tampak sebagai navigasi halaman. Sehingga markup HTML akan menjadi seperti ini:

<div class="img-show"> <ul class="img-gallery img-nav" data-width="750" data-height="1088">
<li><a href="img/01.png">Judul Halaman 1</a></li>
<li><a href="img/02.png">Judul Halaman 2</a></li>
<li><a href="img/03.png">Judul Halaman 3</a></li>
<li><a href="img/04.png">Judul Halaman 4</a></li>
</ul>
</div>

Setelah itu sisipkan kontainer kosong yang akan kita gunakan sebagai tempat untuk meletakkan gambar:

$('.img-gallery').each(function() {
$(this).addClass('img-nav').wrap('<div class="img-show"></div>');
$(this).parents('.img-show').prepend('<div class="img-holder"></div>');
});

Sehingga markup HTML akan menjadi seperti ini:

<div class="img-show">
<div class="img-holder"></div> <ul class="img-gallery img-nav" data-width="750" data-height="1088">
<li><a href="img/01.png">Judul Halaman 1</a></li>
<li><a href="img/02.png">Judul Halaman 2</a></li>
<li><a href="img/03.png">Judul Halaman 3</a></li>
<li><a href="img/04.png">Judul Halaman 4</a></li>
</ul>
</div>

Pada dasarnya itu saja markup yang diperlukan untuk membuat aplikasi komik digital ini. Selebihnya hanya tinggal menentukan ukuran dan perintah.
Sekarang kita ringkas semua kode yang terlalu panjang, dan ambil data lebar dan tinggi halaman yang sudah kita simpan di dalam atribut data-width dan data-height:

$('.img-gallery').each(function() {
var w = $(this).data('width'),
h = $(this).data('height');
$(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
var $parent = $(this).parents('.img-show');
$parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
});

Sehingga hasilnya akan menjadi seperti ini:

<div class="img-show" style="width:750px;">
<div class="img-holder" style="height:1088px;"></div>
<ul class="img-gallery img-nav" data-width="750" data-height="1088">
<li><a href="img/01.png">Judul Halaman 1</a></li>
<li><a href="img/02.png">Judul Halaman 2</a></li>
<li><a href="img/03.png">Judul Halaman 3</a></li>
<li><a href="img/04.png">Judul Halaman 4</a></li>
</ul>
</div>

Dimensi halaman sudah tercipta, sekarang saatnya mengubah setiap item tautan menjadi navigasi berangka. Kita akan menggunakan JQuery .each() untuk merayapi semua elemen tautan satu persatu kemudian menyisipkan angka sesuai dengan urutannya, memindah semua teks judul halaman pada masing-masing tautan ke dalam atribut title. Tapi sebelum itu kita atur dulu agar saat halaman pertama kali dibuka, gambar pada navigasi halaman pertama bisa tampil tanpa diperintah:

$('.img-gallery').each(function() {
var w = $(this).data('width'),
h = $(this).data('height');
$(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
var $firstNav = $('li:first a', this), // Mendapatkan tautan pertama dari semua tautan dalam daftar
current = $firstNav.attr('href'), // Mendapatkan nilai href tautan pertama untuk ditampilkan sebagai gambar pada saat pertama kali komik diakses
$parent = $(this).parents('.img-show');
$firstNav.addClass('active'); // Menambahkan kelas active pada tautan pertama
$parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
// Sisipkan gambar (halaman komik) pada elemen .img-holder...
// dengan nilai src yang diambil dari atribut href tautan pertama
$parent.find('.img-holder').addClass('loading').html('<img class="transparent" src="' + current + '" alt="Loading..."/>');
});

Kelas .loading ditambahkan untuk mengaktifkan CSS khusus yang akan memberikan latar berupa gambar animasi loading:

<div class="img-show" syle="width:750px;">
<div class="img-holder loading" style="height:1088px;">
<img class="transparent" src="img/01.png" alt="Loading..."/> </div>
<ul class="img-gallery img-nav" data-width="750" data-height="1088">
<li><a class="active" href="img/01.png">Judul Halaman 1</a></li>
<li><a href="img/02.png">Judul Halaman 2</a></li>
<li><a href="img/03.png">Judul Halaman 3</a></li>
<li><a href="img/04.png">Judul Halaman 4</a></li>
</ul>
</div>
.img-show .img-holder.loading {
background:white url('img/loading.gif') no-repeat 50% 300px;
}

Atur tampilan gambar yang berhasil ditambahkan dengan tingkat transparasi sebesar 0, sehingga gambar akan tampak menghilang dan memperlihatkan latar animasi loading di belakangnya:

$parent.find('img.transparent').css('opacity', 0);

Saat ini gambar masih memuat, saat gambar telah benar-benar berhasil termuat, animasikan tingkat transparasi menuju 1 (opaque) sehingga efek fading akan tercipta setiap kali gambar selesai termuat:

$parent.find('img.transparent').css('opacity', 0).load(function() {
$parent.find('.img-holder').removeClass('loading'); // Singkirkan kelas loading pada kontainer saat gambar telah berhasil dimuat
$(this).animate({opacity:1}, 400); // Animasikan nilai transparasi dari 0 menuju 1
});;

Menyisipkan Angka-Angka

Untuk menyisipkan angka-angka, kita gunakan .each() untuk merayapi semua tautan yang ada kemudian ganti semua teks di dalamnya menjadi angka sesuai dengan urutannya. Di sini Saya juga akan memindah teks asli pada masing-masing tautan ke dalam atribut title, sehingga tidak akan ada yang sia-sia:

$('.img-gallery').each(function() {
var w = $(this).data('width'),
h = $(this).data('height');
$(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
var $firstNav = $('li:first a', this),
current = $firstNav.attr('href'),
$parent = $(this).parents('.img-show');
$firstNav.addClass('active');
$parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
$parent.find('.img-holder').addClass('loading').html('<img class="transparent" src="' + current + '" alt="Loading..."/>');

$('a', this).each(function(i) {
i = i+1; // Proses pengurutan dalam JavaScript dimulai dari nol, untuk mengangkat nilai awal pengurutan, naikkan satu tingkat!
$(this).attr('title', $(this).text()); // Pindahkan semua teks (judul halaman) pada tautan menjadi nilai atribut title pada setiap tautan
$(this).html(i); // Terakhir, sisipkan nomor urut pada masing-masing tautan
});
});

Sehingga hasilnya akan menjadi seperti ini:

<div class="img-show" syle="width:750px;">
<div class="img-holder loading" style="height:1088px;">
<img class="transparent" src="img/01.png" alt="Loading..."/>
</div>
<ul class="img-gallery img-nav" data-width="750" data-height="1088">
<li><a class="active" href="img/01.png" title="Judul Halaman 1">1</a></li>
<li><a href="img/02.png" title="Judul Halaman 2">2</a></li>
<li><a href="img/03.png" title="Judul Halaman 3">3</a></li>
<li><a href="img/04.png" title="Judul Halaman 4">4</a></li>
</ul>
</div>

Memasukkan Perintah

Sekarang kita tambahkan perintah pada setiap navigasi halaman. Jika navigasi halaman diklik, sisipkan nilai href dari navigasi halaman tersebut ke dalam elemen <img>, kemudian atur efek animasi seperti pada efek animasi yang kita buat sebelum ini:

$('a', this).each(function(i) {
i = i+1;
$(this).attr("title", $(this).text());
$(this).html(i);
}).on("click", function() {
var $activeNav = $(this).parents('.img-gallery').find('a.active'),
$activeParent = $(this).parents('.img-show');
// Bergantian mengganti kelas setiap kali klik pada navigasi
$activeNav.removeClass('active');
$(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
$parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
$(this).removeClass('loading').find('img').animate({opacity:1}, 400);
});
return false;
});

Lebar dan Tinggi Halaman yang Berbeda

Tidak semua halaman komik memiliki tinggi dan lebar yang sama. Terkadang mereka juga bisa tampak sebagai gambar lebar berbentuk persegi panjang mendatar. Oleh karena itu menganimasikan tinggi dan lebar kontainer juga penting. Kita bisa mendapatkan lebar dan tinggi gambar saat gambar telah termuat, sehingga kita misa menganimasikan ukuran kontainer sesuai dengan ukuran gambar yang tampil. Modifikasi dilakukan pada saat fungsi telah menunjukkan bahwa gambar sudah termuat:

$('a', this).each(function(i) {
i = i+1;
$(this).attr("title", $(this).text());
$(this).html(i);
}).on("click", function() {
var $activeNav = $(this).parents('.img-gallery').find('a.active'),
$activeParent = $(this).parents('.img-show');
$activeNav.removeClass('active');
$(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
$parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
// Animasikan lebar dan tinggi kontainer setelah gambar termuat
$parent.animate({width:$(this).width()}, 600).find('.img-holder').animate({height:$(this).height()}, 600, function() {
// Setelah animasi tinggi dan lebar selesai dijalankan,
// set nilai transparasi gambar menjadi opaque
$(this).removeClass('loading').find('img').animate({opacity:1}, 400);
});
});
return false;
});

Membuat Halaman Meloncat ke Posisi yang Tepat

Saat menekan tombol navigasi, pada dasarnya kita sedang berada pada posisi halaman paling bawah. Akan sangat merepotkan jika pembaca harus menggulung layar ke atas kembali setiap kali gambar baru termuat, jadi kita buat saja agar halaman meloncat ke atas setiap kali navigasi diklik. Kita gunakan JQuery .scrollTop() untuk urusan ini:

$('a', this).each(function(i) {
i = i+1;
$(this).attr("title", $(this).text());
$(this).html(i);
}).on("click", function() {
var $activeNav = $(this).parents('.img-gallery').find('a.active'),
$activeParent = $(this).parents('.img-show');
$activeNav.removeClass('active');
$('html, body').scrollTop($activeParent.offset().top-40);
$(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
$parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
// Animasikan lebar dan tinggi kontainer setelah gambar termuat
$parent.animate({width:$(this).width()}, 600).find('.img-holder').animate({height:$(this).height()}, 600, function() {
// Setelah animasi tinggi dan lebar selesai dijalankan,
// set nilai transparasi gambar menjadi opaque
$(this).removeClass('loading').find('img').animate({opacity:1}, 400);
});
});
return false;
});

Selesai! Sisanya tinggal merapikan dan memidah semua hal yang berhubungan dengan durasi animasi ke dalam variabel baru, sehingga proses modifikasi kecepatan animasi menjadi lebih mudah dilakukan.


Kode Lengkap

JQuery

$(function() {
$('.img-gallery').each(function() {
var w = $(this).data("width"),
h = $(this).data("height"),
viewport = $('html, body'),
fadeSpeed = 400, // Kecepatan efek fading
resizeSpeed = 600; // Kecepatan efek pelebaran/penyusutan
$(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
var $firstNav = $('li:first a', this),
current = $firstNav.attr('href'),
$parent = $(this).parents('.img-show');
$firstNav.addClass('active');
$parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
$parent.find('.img-holder').addClass('loading').html('<img class="transparent" src="' + current + '" alt="Loading..."/>');
$parent.find('img.transparent').css('opacity', 0).load(function() {
$parent.animate({width:$(this).width()}, resizeSpeed).find('.img-holder').animate({height:$(this).height()}, resizeSpeed, function() {
$(this).removeClass('loading').find('img').animate({opacity:1}, fadeSpeed);
});
});

$('a', this).each(function(i) {
i = i+1;
$(this).attr("title", $(this).text());
$(this).html(i);
}).on("click", function() {
var $activeNav = $(this).parents('.img-gallery').find('a.active'),
$activeParent = $(this).parents('.img-show');
$activeNav.removeClass('active');
viewport.scrollTop($activeParent.offset().top-40);
$(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
$parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
$parent.animate({width:$(this).width()}, resizeSpeed).find('.img-holder').animate({height:$(this).height()}, resizeSpeed, function() {
$(this).removeClass('loading').find('img').animate({opacity:1}, fadeSpeed);
});
});
return false;
});

});
});

CSS

.img-show {
width:400px;
margin:50px auto;
background-color:black;
border:2px solid black;
-webkit-box-shadow:0px 1px 3px rgba(0,0,0,0.2);
-moz-box-shadow:0px 1px 3px rgba(0,0,0,0.2);
box-shadow:0px 1px 3px rgba(0,0,0,0.2);
position:relative;
overflow:hidden;
}

.img-show .img-holder {
background-color:white;
}

.img-show .img-holder.loading {
background:white url('img/loading.gif') no-repeat 50% 300px;
}

.img-show .img-holder img {
display:block;
}

.img-show .img-nav {
margin:0px 0px;
padding:0px 0px;
overflow:hidden;
}

.img-show .img-nav li {
margin:2px 2px 0px 0px;
padding:0px 0px;
float:left;
display:inline;
list-style:none;
}

.img-nav li a {
display:block;
background-color:#ccc;
color:black;
padding:3px 7px;
font:normal 12px Georgia,Serif;
font-style:italic;
text-decoration:none;
}

.img-nav li a.active {
background-color:#900;
color:white;
}

Dasar Kerangka

<ul class="img-gallery" data-width="750" data-height="1000">
<li><a href="img/01.png">Judul Halaman 1</a></li>
<li><a href="img/02.png">Judul Halaman 2</a></li>
<li><a href="img/03.png">Judul Halaman 3</a></li>
</ul>

0 komentar:

Posting Komentar