javascript - HTML5 Canvas: Elemen yang digambar dengan/di-cache untuk drawImage menjadi halus saat diperbesar dan/atau dipindahkan
Saya memang tahu tentang kasus nilai float/integer untuk drawImage's x dan y. Tetapi yang saya butuhkan adalah animasi yang halus dengan kemampuan untuk menyimpan bentuk-bentuk saya.
- Artikel tentang caching jalur kompleks dengan kanvas cadangan
- Artikel tentang
drawImagedengan parameter float
Misalnya, saya ingin menggambar beberapa bentuk kompleks (yaitu SVG-tiger, diubah menjadi perintah-canvas) ke kanvas hanya sekali dan kemudian memindahkannya secara halus dengan ctx.translate dan ctx.drawImage. Saya memerlukan nilai float pada saat itu, karena jika tidak saya mendapatkan pergerakan langkah demi langkah:
Berikut adalah contohnya di JSFiddle:
- Satu: Kecepatan cepat, dengan
Math.floorditerapkan pada parametertranslate(xdanysama dengan waktu dalam detik dikalikan dengan10): Animasi terasa aneh (berurutan, tidak halus). - Dua: Kecepatan lambat, dengan
Math.floorditerapkan pada parametertranslate(xdanysama dengan waktu dalam detik): Animasi terasa aneh (berurutan, tidak mulus). - Tiga: Kecepatan tinggi, tanpa pembulatan, nilai float (
xdanysama dengan waktu dalam detik dikalikan dengan10). Kecepatan tinggi, jadi animasi terlihat bagus. - Empat: Kecepatan lambat, tidak dibulatkan, nilai float (
xdanysama dengan waktu dalam detik). Kecepatan lambat, sehingga animasi terlihat berdenyut. Mengapa?
Kasus terakhir adalah yang membingungkan saya. Apakah saya salah dalam upaya saya dan ada kemungkinan untuk membuat trik caching ini bekerja dengan baik?
Di Firefox, ada properti dari canvas yang bernama mozImageSmoothingEnabled (lihat), tetapi tidak ada bantuan dari itu di browser lain. Dan itu juga menghapus penghalusan jalur.
Cuplikan kode:
var shapeCanvas = null;
var w = 320, h = 240;
var startTime = 0;
function start() {
startTime = Date.now();
var docCanvas = document.getElementById('canvas');
. . .
shapeCanvas = document.createElement('canvas');
. . .
drawShape(shapeCanvas.getContext('2d'));
drawNext(docCanvas.getContext('2d'));
}
function drawNext(ctx) {
var msec = (Date.now() - startTime);
var time = msec / 1000; // seconds passed from start
ctx.clearRect(0, 0, w, h);
ctx.save();
// the lines to change: time | (time * 10) | Math.floor(time * 10)
ctx.translate((time < 500) ? Math.floor(time * 10) : 500,
(time < 500) ? Math.floor(time * 10) : 500);
ctx.drawImage(shapeCanvas, 0, 0);
ctx.restore();
__nextFrame(function() {
drawNext(ctx);
});
}
function drawShape(ctx) {
. . .
}
Jawaban #1
Saya menulis tutorial di tautan pertama Anda.
Hanya untuk meluruskan suasana:
shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';
sebenarnya tidak ada gunanya dilakukan. Tidak ada gunanya menetapkan gaya jika itu hanya kanvas di memori, dan Anda seharusnya memang tidak pernah ingin menetapkan gaya lebar dan tinggi kanvas, itu hanya membingungkan.
Apa yang dikatakan ellisbben dalam komentar itu hampir sama dengan apa yang sedang terjadi.
Mungkin saja untuk mengakalinya dengan beberapa cara hackish, saya yakin. Salah satu caranya mungkin memastikan itu tidak pernah digambar pada piksel integer. Cara lain mungkin menggunakan ctx.scale(.99,.99) sebelum menggambar apa pun agar selalu di-anti-aliased. Sulit untuk mendapatkan solusi yang konsisten di sini karena implementasi anti-aliasing dari browser yang berbeda berbeda-beda.
Berikut beberapa percobaan dari saya:
http://jsfiddle.net/KYZYT/29/
Dua yang pertama adalah bentuk yang digambar dari kanvas dan juga digambar dari PNG
Dua yang kedua adalah pasangan yang sama tetapi diskalakan oleh .99,.99
Yang terakhir adalah yang nyata. Itu masih sedikit buram tetapi terlihat jauh lebih tajam daripada menggunakan gambar-gambar tersebut.
Tidak ada satupun eksperimen saya yang menghasilkan akhir dari detakmu, setidaknya tidak pada tingkat mikroskopis. Saya rasa ini adalah sesuatu yang harus kamu terima jika ingin menganimasikan gambar pixel-perfect ke ruang setengah piksel.
Jika Anda benar-benar merasa tidak bisa hanya menggambar pada piksel sempurna, maka pilihan terbaik kedua Anda untuk konsistensi mungkin adalah menemukan cara untuk memaksa anti-aliasing setiap saat. Memastikan Anda selalu diterjemahkan ke bilangan non-bulat atau sedikit menskalanya adalah kandidat yang layak, tetapi mungkin ada cara lain.
Sejujurnya, pilihan terbaikmu adalah tidak menyimpan cache jalur animasi ini sampai kamu benar-benar membutuhkan kinerjanya. Simpan cache tombol bergaya dan hal statis lain yang kamu buat, tetapi jika kamu memiliki jalur animasi yang perlu bergerak perlahan dan tepat serta terlihat sangat bagus, sebaiknya tetap gunakan versi asli daripada optimasi caching saya kecuali kamu benar-benar membutuhkannya juga untuk itu.
Jawaban #2
Sedikit promosi, tapi: Saya telah mengimplementasikan animasi halus dalam permainan slot HTML5 dengan cara yang sedikit konyol. Gambar yang di-cache dan dihasilkan digambar di kanvas kecil sekali, lalu saya menggunakan translate3d() dengan gaya -moz-transform/-webkit-transform pada kanvas untuk memindahkan, mencerminkan, dan memperbesar gambar.
Pra-generasi
- Buat Gambar
- Gambarkan konten gambar
- Buat objek kanvas di DOM
Fase animasi
- Bersihkan kanvas
- Gambar gambar yang di-cache ke kanvas
- Gunakan transformasi CSS3 (scale3d dan translate3d) untuk memindahkan kanvas.
