Cara terbaik untuk mendeteksi bahwa HTML5 <canvas> tidak didukung

139

Cara standar untuk menangani situasi di mana browser tidak mendukung <canvas>tag HTML5 adalah dengan menyematkan beberapa konten mundur seperti:

<canvas>Your browser doesn't support "canvas".</canvas>

Tetapi sisa halaman tetap sama, yang mungkin tidak sesuai atau menyesatkan. Saya ingin beberapa cara mendeteksi kanvas yang tidak mendukung sehingga saya dapat menyajikan sisa halaman saya sesuai. Apa yang akan kamu rekomendasikan?

brainjam
sumber

Jawaban:

217

Ini adalah teknik yang digunakan dalam Modernizr dan pada dasarnya setiap perpustakaan lain yang melakukan pekerjaan kanvas:

function isCanvasSupported(){
  var elem = document.createElement('canvas');
  return !!(elem.getContext && elem.getContext('2d'));
}

Karena pertanyaan Anda adalah untuk deteksi ketika tidak didukung, saya sarankan menggunakannya seperti:

if (!isCanvasSupported()){ ...
Paul Irish
sumber
14
Mengapa negasi ganda (!!) adalah singkatan?
16
Jika Kanvas tidak ada elem.getContext == undefined,. !undefined = true, dan !true = false, jadi ini memungkinkan kita mengembalikan bool, daripada yang tidak didefinisikan atau konteksnya.
Rich Bradshaw
1
@ 2astalavista Negatif ganda (!!) seperti casting. Itu mengubah pernyataan truey atau falsey menjadi boolean. Sebagai contoh: var i = 0. saya mengevaluasi ke false, tetapi typeof saya mengembalikan "angka". typeof !! saya mengembalikan "boolean".
User2
Cara lain untuk "melemparkan" ke boolean adalah: undefined ? true : false(meskipun sedikit lebih panjang).
vcapra1
1
Saya harus mencatat bahwa ada berbagai jenis dukungan kanvas. Implementasi browser awal tidak mendukung toDataURL. Dan Opera Mini hanya mendukung rendering kanvas dasar tanpa dukungan API teks . Opera Mini dapat dikecualikan dengan cara ini , hanya untuk referensi silang.
hexalys
103

Ada dua metode populer untuk mendeteksi dukungan kanvas di browser:

  1. Saran Matt untuk memeriksa keberadaan getContext, juga digunakan dengan cara serupa oleh perpustakaan Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Memeriksa keberadaan HTMLCanvasElementantarmuka, sebagaimana ditentukan oleh spesifikasi WebIDL dan HTML . Pendekatan ini juga direkomendasikan dalam posting blog dari tim IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

Rekomendasi saya adalah variasi dari yang terakhir (lihat Catatan Tambahan ), karena beberapa alasan:

  • Setiap kanvas yang dikenal yang mendukung kanvas - termasuk IE 9 - mengimplementasikan antarmuka ini;
  • Ini lebih ringkas dan langsung jelas apa yang dilakukan kode;
  • The getContextpendekatan secara signifikan lebih lambat di semua browser , karena melibatkan menciptakan sebuah elemen HTML. Ini tidak ideal ketika Anda perlu memeras kinerja sebanyak mungkin (di perpustakaan seperti Modernizr, misalnya).

Tidak ada manfaat nyata untuk menggunakan metode pertama. Kedua pendekatan dapat dipalsukan, tetapi ini tidak mungkin terjadi secara kebetulan.

catatan tambahan

Mungkin masih perlu untuk memeriksa bahwa konteks 2D dapat diambil. Dilaporkan, beberapa browser seluler dapat mengembalikan true untuk kedua pemeriksaan di atas, tetapi kembali nulluntuk .getContext('2d'). Inilah sebabnya mengapa Modernizr juga memeriksa hasilnya .getContext('2d'). Namun, WebIDL & HTML - lagi - memberi kami pilihan lain yang lebih baik, lebih cepat :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Perhatikan bahwa kita dapat melewatkan memeriksa elemen kanvas sepenuhnya dan langsung memeriksa dukungan rendering 2D. The CanvasRenderingContext2Dantarmuka juga merupakan bagian dari spesifikasi HTML.

Anda harus menggunakan getContextpendekatan untuk mendeteksi dukungan WebGL karena, meskipun browser dapat mendukung WebGLRenderingContext, getContext()dapat mengembalikan nol jika browser tidak dapat berinteraksi dengan GPU karena masalah driver dan tidak ada implementasi perangkat lunak. Dalam hal ini, memeriksa antarmuka terlebih dahulu memungkinkan Anda melewati pemeriksaan untuk getContext:

var cvsEl, ctx;
if (!window.WebGLRenderingContext)
    window.location = "http://get.webgl.org";
else {
    cvsEl = document.createElement("canvas");
    ctx = cvsEl.getContext("webgl") || cvsEl.getContext("experimental-webgl");

    if (!ctx) {
        // Browser supports WebGL, but cannot create the context
    }
}

Perbandingan Kinerja

Performa dari getContextpendekatan ini adalah 85-90% lebih lambat di Firefox 11 dan Opera 11 dan sekitar 55% lebih lambat di Chromium 18.

    Tabel perbandingan sederhana, klik untuk menjalankan tes di browser Anda

Andy E
sumber
10
Nokia S60 dan Blackberry Storm adalah beberapa di antara perangkat yang akan false positive pada kanvas 2D yang Anda usulkan. Sayangnya, ponsel menjadi sangat berbulu dan vendor tidak mengikuti aturan. :( Jadi kami berakhir dengan tes yang lebih lengkap (yaitu lebih lambat) untuk memastikan hasil yang akurat.
Paul Irish
@ Paul: itu menarik, saya menguji emulator BlackBerry Storm, semuanya dikembalikan falseuntuk contoh Anda dan milik saya, sepertinya mereka tidak menyediakan CanvasRenderingContext2Dantarmuka. Saya belum dapat menguji S60 sampai sekarang, saya masih sangat penasaran dan mungkin akan segera melakukannya.
Andy E
1
Ini menarik, tetapi selama tes masuk di bawah seratus atau lebih mili, bukankah itu bagus? Saya membayangkan bahwa mereka semua jauh lebih cepat dari itu. Jika Anda memoise fungsi yang menguji untuk ini maka Anda hanya perlu membayar biaya satu kali.
Drew Noakes
1
Saya menjalankan benchmark Anda dan bahkan pendekatan 'lambat' dapat dilakukan ~ 800.000 kali per detik. Sekali lagi, jika hasilnya di-cache maka keputusan mengenai pendekatan mana yang harus digunakan didasarkan pada ketahanan, bukan kinerja (dengan asumsi ada perbedaan dalam ketahanan.)
Drew Noakes
@DrewNoakes: ya, Anda harus selalu mencari kompatibilitas dengan kecepatan. Argumen saya adalah bahwa saya menyangkal klaim kompatibilitas oleh Paul, berdasarkan pengujian saya sendiri di setidaknya salah satu browser masalah yang ia sebutkan dalam komentarnya. Saya tidak dapat menguji browser lain tetapi saya tetap tidak yakin bahwa ada masalah. Anda harus selalu bertujuan untuk mendapatkan kinerja terbaik, tanpa mengorbankan kompatibilitas. Saya tidak berbicara tentang pengoptimalan mikro, tetapi jika Anda menjalankan ratusan tes dan semuanya tidak dioptimalkan, ya, itu bisa membuat perbedaan.
Andy E
13

Saya biasanya menjalankan pemeriksaan getContextketika saya membuat objek kanvas saya.

(function () {
    var canvas = document.createElement('canvas'), context;
    if (!canvas.getContext) {
        // not supported
        return;
    }

    canvas.width = 800;
    canvas.height = 600;
    context = canvas.getContext('2d');
    document.body.appendChild(canvas);
}());

Jika didukung, maka Anda dapat melanjutkan pengaturan kanvas dan menambahkannya ke DOM. Ini adalah contoh sederhana Peningkatan Progresif , yang saya (secara pribadi) sukai daripada Degradasi Anggun.

Mat
sumber
Apakah itu menyimpang , contextdi baris kedua?
brainjam
7
@ brainjam - Tidak, saya menggunakan variabel itu di dekat akhir kode. Saya mencoba mengikuti 'rekomendasi' JSLint (dalam hal ini .. hanya 1 varpernyataan per fungsi).
Matt
6

Mengapa tidak mencoba modernizr ? Ini adalah pustaka JS yang menyediakan kemampuan deteksi.

Mengutip:

Pernahkah Anda ingin melakukan pernyataan if di CSS Anda untuk ketersediaan fitur keren seperti radius batas? Nah, dengan Modernizr Anda dapat mencapai hal itu!

Frozenskys
sumber
2
Tes yang kami gunakan dalam modernizr adalah ini: return !!document.createElement('canvas').getContext Itu jelas cara terbaik untuk menguji.
Paul Irish
4
Modernizr adalah perpustakaan yang bermanfaat, tetapi akan sedikit membuang-buang waktu untuk menarik seluruh perpustakaan hanya untuk mendeteksi dukungan kanvas. Jika Anda perlu mendeteksi fitur lain juga maka saya akan merekomendasikannya.
Daniel Cassidy
5
try {
    document.createElement("canvas").getContext("2d");
    alert("HTML5 Canvas is supported in your browser.");
} catch (e) {
    alert("HTML5 Canvas is not supported in your browser.");
}
Sheikh Ali
sumber
1

Mungkin ada gotcha di sini- beberapa klien tidak mendukung semua metode kanvas.

var hascanvas= (function(){
    var dc= document.createElement('canvas');
    if(!dc.getContext) return 0;
    var c= dc.getContext('2d');
    return typeof c.fillText== 'function'? 2: 1;
})();

alert(hascanvas)
kennebec
sumber
0

Anda dapat menggunakan skrip canisuse.js untuk mendeteksi apakah browser Anda mendukung kanvas atau tidak

caniuse.canvas()
Beka
sumber
0

Jika Anda akan mendapatkan konteks kanvas Anda, Anda sebaiknya menggunakannya sebagai ujian:

var canvas = document.getElementById('canvas');
var context = (canvas.getContext?canvas.getContext('2d'):undefined);
if(!!context){
  /*some code goes here, and you can use 'context', it is already defined*/
}else{
  /*oof, no canvas support :(*/
}
Callum Hynes
sumber