วิธีที่ดีที่สุดในการตรวจสอบว่า HTML5 <canvas> ไม่รองรับ


139

วิธีมาตรฐานในการจัดการกับสถานการณ์ที่เบราว์เซอร์ไม่สนับสนุน<canvas>แท็กHTML5 คือการฝังเนื้อหาทางเลือกเช่น:

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

แต่ส่วนที่เหลือของหน้ายังคงเหมือนเดิมซึ่งอาจไม่เหมาะสมหรือทำให้เข้าใจผิด ฉันต้องการตรวจจับการไม่สนับสนุนผืนผ้าใบบางอย่างเพื่อให้ฉันสามารถนำเสนอส่วนที่เหลือของหน้าเว็บของฉันตามนั้น คุณจะแนะนำอะไร

คำตอบ:


217

นี่คือเทคนิคที่ใช้ใน Modernizr และโดยทั่วไปแล้วห้องสมุดอื่น ๆ ที่ทำงานผ้าใบ:

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

เนื่องจากคำถามของคุณสำหรับการตรวจจับเมื่อไม่ได้รับการสนับสนุนฉันขอแนะนำให้ใช้เช่น:

if (!isCanvasSupported()){ ...

14
ทำไมการปฏิเสธคู่ (!!) หมายถึงอะไร

16
elem.getContext == undefinedหากผ้าใบไม่ได้มี !undefined = trueและ!true = falseดังนั้นสิ่งนี้ช่วยให้เราส่งคืนบูลแทนที่จะไม่ได้กำหนดหรือบริบท
แบรดชอว์รวย

1
@ 2astalavista การลบสองเท่า (!!) เป็นเหมือนการคัดเลือกนักแสดง มันเปลี่ยนข้อความจริงหรือเท็จเป็นบูลีน ตัวอย่างเช่นvar i = 0. ฉันประเมินว่าเป็นเท็จ แต่ typeof ฉันกลับ "จำนวน" typeof !! i ส่งคืน "บูลีน"
ใช้ 2

อีกวิธีในการ "ส่ง" ไปยังบูลีนคือ: undefined ? true : false(แม้ว่าจะยาวขึ้นอีกนิด)
vcapra1

1
ฉันควรสังเกตว่ามีผ้าใบชนิดต่าง ๆ รองรับ toDataURLการใช้งานเบราว์เซอร์ในช่วงต้นไม่สนับสนุน และ Opera Mini เพียง แต่สนับสนุนการแสดงผลผ้าใบขั้นพื้นฐานที่มีไม่มีการสนับสนุน API ข้อความ Opera Mini สามารถแยกออกได้ด้วยวิธีนี้เพื่อการอ้างอิงโยง
hexalys

103

มีสองวิธียอดนิยมในการตรวจหาการสนับสนุน Canvas ในเบราว์เซอร์:

  1. ข้อเสนอแนะของ Matt ในการตรวจสอบการมีอยู่ของgetContextยังใช้ในลักษณะที่คล้ายกันโดยห้องสมุด Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. การตรวจสอบการดำรงอยู่ของHTMLCanvasElementอินเตอร์เฟซที่กำหนดโดยWebIDLและHTMLข้อกำหนด วิธีการนี้ยังได้รับการแนะนำในบล็อกโพสต์จากทีม IE 9

    var canvasSupported = !!window.HTMLCanvasElement;

คำแนะนำของฉันคือการเปลี่ยนแปลงในภายหลัง (ดูหมายเหตุเพิ่มเติม ) ด้วยเหตุผลหลายประการ:

  • เบราว์เซอร์ทุกตัวที่รู้จักกันดีซึ่งสนับสนุนแคนวาส - รวมถึง IE 9 - ใช้ส่วนต่อประสานนี้
  • มันกระชับและชัดเจนในทันทีว่าโค้ดกำลังทำอะไรอยู่
  • getContextวิธีการเป็นอย่างช้าเบราว์เซอร์ทั้งหมดเพราะมันเกี่ยวข้องกับการสร้างองค์ประกอบ HTML สิ่งนี้ไม่เหมาะเมื่อคุณต้องการบีบประสิทธิภาพให้มากที่สุดเท่าที่จะทำได้ (ในไลบรารีเช่น Modernizr เป็นต้น)

ไม่มีประโยชน์ที่เห็นได้ชัดเจนในการใช้วิธีแรก ทั้งสองวิธีสามารถปลอมแปลงได้ แต่สิ่งนี้ไม่น่าจะเกิดขึ้นโดยบังเอิญ

หมายเหตุเพิ่มเติม

อาจยังจำเป็นต้องตรวจสอบว่าสามารถดึงบริบท 2D ได้ ข่าวบางเบราว์เซอร์มือถือสามารถกลับจริงสำหรับการตรวจสอบทั้งสองข้างต้น แต่กลับสำหรับnull .getContext('2d')นี่คือเหตุผลที่ Modernizr ตรวจสอบผลลัพธ์.getContext('2d')ด้วย อย่างไรก็ตาม WebIDL & HTML - อีกครั้ง - ช่วยให้เรามีตัวเลือกที่ดีกว่าและเร็วกว่า :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

โปรดสังเกตว่าเราสามารถข้ามการตรวจสอบองค์ประกอบ Canvas ทั้งหมดและตรงไปที่การตรวจสอบการสนับสนุนการเรนเดอร์ 2D CanvasRenderingContext2Dอินเตอร์เฟซที่เป็นส่วนหนึ่งของข้อกำหนด HTML

คุณต้องใช้getContextวิธีการสำหรับการตรวจสอบ WebGLสนับสนุนเนื่องจากแม้ว่าเบราว์เซอร์อาจสนับสนุนWebGLRenderingContext, getContext()อาจจะกลับnullถ้าเบราว์เซอร์ไม่สามารถที่จะติดต่อกับ GPU เนื่องจากปัญหาคนขับและไม่มีการใช้งานซอฟต์แวร์ ในกรณีนี้การตรวจสอบอินเทอร์เฟซก่อนให้คุณข้ามการตรวจสอบสำหรับ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
    }
}

การเปรียบเทียบประสิทธิภาพ

ประสิทธิภาพของการ getContextวิธีการนั้นช้ากว่า 85-90% ใน Firefox 11 และ Opera 11 และช้ากว่า 55% ใน Chromium 18

    ตารางเปรียบเทียบอย่างง่ายคลิกเพื่อเรียกใช้การทดสอบในเบราว์เซอร์ของคุณ


10
Nokia S60 และ Blackberry Storm เป็นหนึ่งในอุปกรณ์ที่จะตรวจจับการปลอมในรูปแบบ 2D ผ้าใบที่คุณนำเสนอ น่าเสียดายที่มือถือมีขนดกมากและผู้ขายไม่ปฏิบัติตามกฎ :( ดังนั้นเราจึงสิ้นสุดการทดสอบที่สมบูรณ์ยิ่งขึ้น (เช่นช้ากว่า) เพื่อรับรองผลลัพธ์ที่ถูกต้อง
Paul Irish

@Paul: น่าสนใจฉันทดสอบตัวเลียนแบบ BlackBerry Storm พวกเขาทั้งหมดกลับมาfalseสำหรับทั้งตัวอย่างของคุณและของฉันดูเหมือนว่าพวกเขาไม่ได้ให้CanvasRenderingContext2Dอินเทอร์เฟซ ฉันยังไม่สามารถทดสอบ S60 ได้ในตอนนี้ แต่ฉันก็ยังสงสัยอยู่มากและอาจจะทำได้ในไม่ช้า
แอนดี้อี

1
นี่เป็นเรื่องที่น่าสนใจ แต่ตราบใดที่การทดสอบมีค่าน้อยกว่าหนึ่งร้อยมิลลิวินาทีก็ไม่เป็นไร ฉันคิดว่าพวกเขาทั้งหมดเร็วกว่านั้นอยู่ดี หากคุณบันทึกฟังก์ชันที่ทดสอบสิ่งนี้คุณต้องจ่ายเพียงครั้งเดียวเท่านั้น
Drew Noakes

1
ฉันวิ่งเกณฑ์มาตรฐานของคุณและแม้แต่วิธี 'ช้า' ก็สามารถทำได้ ~ 800,000 ครั้งต่อวินาที อีกครั้งหากผลลัพธ์ถูกแคชดังนั้นการตัดสินใจว่าจะใช้วิธีใดควรขึ้นอยู่กับความทนทานไม่ใช่ประสิทธิภาพ (สมมติว่ามีความแตกต่างในความแข็งแกร่ง)
Drew Noakes

@DrewNoakes: ใช่คุณควรเข้ากันได้กับความเร็วมากกว่าทุกครั้ง ข้อโต้แย้งของฉันคือฉันกำลัง refuting การเรียกร้องความเข้ากันได้โดย Paul ตามการทดสอบของฉันเองในเบราว์เซอร์ปัญหาอย่างน้อยหนึ่งปัญหาที่เขากล่าวถึงในความคิดเห็นของเขา ฉันไม่สามารถทดสอบเบราว์เซอร์อื่นได้ แต่ฉันยังไม่มั่นใจว่ามีปัญหา คุณควรตั้งเป้าหมายเพื่อให้ได้ประสิทธิภาพที่ดีที่สุดเท่าที่จะเป็นไปได้โดยไม่ทำให้ความเข้ากันได้ลดลง ฉันไม่ได้พูดถึงการเพิ่มประสิทธิภาพแบบไมโคร แต่ถ้าคุณใช้การทดสอบหลายร้อยครั้งและพวกเขาไม่ได้รับการทดสอบทุกครั้งใช่มันสามารถสร้างความแตกต่างได้
Andy E

13

ฉันมักจะเรียกใช้การตรวจสอบgetContextเมื่อฉันสร้างวัตถุผ้าใบของฉัน

(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);
}());

หากได้รับการสนับสนุนคุณสามารถดำเนินการตั้งค่า Canvas ต่อไปและเพิ่มเข้าใน DOM นี่เป็นตัวอย่างง่าย ๆ ของProgressive Enhancement Enhancementซึ่ง I (ส่วนตัว) ชอบมากกว่าความเสื่อมโทรมที่สง่างาม


นั่นเป็นเร่ร่อน, contextในบรรทัดที่สองหรือไม่?
brainjam

7
@brainjam - ไม่ฉันใช้ตัวแปรนั้นใกล้กับส่วนท้ายของรหัส ฉันพยายามติดตาม'คำแนะนำ' JSLint (ในกรณีนี้ .. เพียง 1 varคำสั่งต่อฟังก์ชั่น)
แมตต์

6

ทำไมไม่ลองmodernizr ? มันเป็นห้องสมุด JS ที่ให้ความสามารถในการตรวจจับ

อ้างถึง:

คุณเคยต้องการที่จะทำ if-statement ใน CSS ของคุณสำหรับความพร้อมของคุณสมบัติที่ยอดเยี่ยมเช่นรัศมีเส้นขอบหรือไม่? ด้วย Modernizr คุณสามารถทำเช่นนั้นได้!


2
การทดสอบที่เราใช้ใน modernizr คือ: return !!document.createElement('canvas').getContext นั่นเป็นวิธีที่ดีที่สุดในการทดสอบ
พอลไอริช

4
Modernizr เป็นห้องสมุดที่มีประโยชน์ แต่มันก็เป็นการสิ้นเปลืองที่จะดึงเข้าไปในห้องสมุดทั้งหมดเพื่อตรวจหาการรองรับผ้าใบ หากคุณต้องการตรวจสอบคุณสมบัติอื่น ๆ ด้วยฉันก็อยากจะแนะนำ
Daniel Cassidy


1

อาจมี gotcha ที่นี่ - ลูกค้าบางคนไม่สนับสนุนวิธีการวาดภาพทั้งหมด

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)

0

คุณสามารถใช้สคริปต์canisuse.jsเพื่อตรวจสอบว่าเบราว์เซอร์ของคุณรองรับ canvas หรือไม่

caniuse.canvas()

0

หากคุณจะได้รับบริบทของผืนผ้าใบของคุณคุณอาจใช้มันเป็นแบบทดสอบ:

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 :(*/
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.