Najlepszy sposób na wykrycie, że HTML5 <canvas> nie jest obsługiwany

139

Standardowym sposobem radzenia sobie z sytuacjami, w których przeglądarka nie obsługuje <canvas>tagu HTML5, jest osadzenie niektórych treści zastępczych, takich jak:

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

Ale reszta strony pozostaje taka sama, co może być nieodpowiednie lub wprowadzające w błąd. Chciałbym znaleźć sposób na wykrycie braku obsługi płótna, aby móc odpowiednio przedstawić resztę mojej strony. Co byś polecił?

mózgów
źródło

Odpowiedzi:

217

Oto technika używana w Modernizr i praktycznie w każdej innej bibliotece, która wykonuje prace na płótnie:

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

Ponieważ pytanie było do wykrywania kiedy to nie obsługiwane, polecam go używać tak:

if (!isCanvasSupported()){ ...
Paula Irisha
źródło
14
Dlaczego występuje podwójna negacja (!!)?
16
Jeśli Płótno nie jest tam elem.getContext == undefined. !undefined = true, a !true = falsewięc to pozwala nam zwrócić wartość logiczną zamiast undefined lub kontekst.
Rich Bradshaw,
1
@ 2astalavista Podwójny negatyw (!!) jest jak rzucanie. Przekształca stwierdzenie prawda lub fałsz w wartość logiczną. Na przykład: var i = 0. i zwraca wartość false, ale typeof i zwraca „number”. typeof !! i zwraca „boolean”.
Użytkownik 2,
Innym sposobem „rzutowania” na wartości logiczne jest: undefined ? true : false(choć trochę dłuższe).
vcapra1
1
Należy zauważyć, że istnieją różne rodzaje wsparcia płótna. Wczesne implementacje przeglądarek nie obsługiwały toDataURL. Opera Mini obsługuje tylko podstawowe renderowanie płótna bez obsługi tekstowego interfejsu API . W ten sposób można wykluczyć Operę Mini , tylko w celach informacyjnych.
hexalys
103

Istnieją dwie popularne metody wykrywania obsługi kanwy w przeglądarkach:

  1. Sugestia Matta, aby sprawdzić, czy istnieje getContext, również używana w podobny sposób przez bibliotekę Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Sprawdzanie istnienia HTMLCanvasElementinterfejsu zgodnie ze specyfikacjami WebIDL i HTML . Takie podejście zostało również zalecane w poście na blogu zespołu IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

Moja rekomendacja jest odmianą tego ostatniego (patrz Dodatkowe uwagi ) z kilku powodów:

  • Każda znana przeglądarka obsługująca kanwę - w tym IE 9 - implementuje ten interfejs;
  • Jest bardziej zwięzłe i od razu oczywiste, co robi kod;
  • getContextPodejście jest znacznie wolniejsze we wszystkich przeglądarkach , ponieważ polega na tworzeniu elementu HTML. Nie jest to idealne rozwiązanie, gdy trzeba wycisnąć jak najwięcej wydajności (na przykład w bibliotece takiej jak Modernizr).

Nie ma zauważalnych korzyści z zastosowania pierwszej metody. Oba podejścia można sfałszować, ale nie jest to przypadkowe.

Dodatkowe uwagi

Wciąż może być konieczne sprawdzenie, czy można pobrać kontekst 2D. Podobno niektóre przeglądarki mobilne mogą zwracać wartość true dla obu powyższych sprawdzeń, ale zwracają w nullprzypadku .getContext('2d'). Dlatego Modernizr sprawdza również wynik .getContext('2d'). Jednak WebIDL i HTML - znowu - daje nam inną lepszą, szybszą opcję:

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Zauważ, że możemy całkowicie pominąć sprawdzanie elementu canvas i przejść od razu do sprawdzania obsługi renderowania 2D. CanvasRenderingContext2DInterfejs jest również częścią specyfikacji HTML.

Państwo musi użyć getContextpodejście do wykrywania WebGL wsparcia, ponieważ, mimo że przeglądarka może wspierać WebGLRenderingContext, getContext()może zwrócić NULL jeśli przeglądarka nie jest w stanie współpracować z GPU z powodu problemów ze sterownikami i nie ma wdrożenie oprogramowania. W takim przypadku sprawdzenie interfejsu najpierw pozwala pominąć sprawdzanie 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
    }
}

Porównanie wydajności

Wydajność tego getContextpodejścia jest o 85-90% wolniejsza w przeglądarkach Firefox 11 i Opera 11 oraz o około 55% wolniejsza w Chromium 18.

    Prosta tabela porównawcza, kliknij, aby uruchomić test w przeglądarce

Andy E.
źródło
10
Nokia S60 i Blackberry Storm to jedne z urządzeń, które będą fałszywie pozytywne w wykrywanych przez Ciebie płótnach 2D. Niestety, telefony komórkowe stają się bardzo owłosione, a sprzedawcy nie przestrzegają zasad. :( Więc kończymy na bardziej kompletnych (tj. Wolniejszych) testach, aby zapewnić dokładne wyniki.
Paul Irish,
@Paul: to ciekawe, ja testowałem emulatory BlackBerry Storm, wszystkie z nich wrócił falsezarówno swoim przykładem i kopalni, wydaje się, że nie zapewniają CanvasRenderingContext2Dinterfejs. Jak dotąd nie mogłem przetestować S60, nadal jestem bardzo ciekawy i może to zrobić wkrótce.
Andy E
1
To interesujące, ale jeśli test trwa poniżej stu milisów, czy nie jest w porządku? Wyobrażam sobie, że i tak wszystkie są znacznie szybsze niż to. Jeśli zapamiętasz funkcję, która to testuje, zapłacisz tylko raz.
Drew Noakes
1
Sprawdziłem twój benchmark i nawet „powolne” podejście można wykonać ~ 800 000 razy na sekundę. Ponownie, jeśli wynik jest zapisany w pamięci podręcznej, wówczas decyzja, które podejście zastosować, powinna opierać się na solidności, a nie wydajności (zakładając, że istnieje różnica w odporności).
Drew Noakes
@DrewNoakes: tak, prawie zawsze powinieneś wybierać kompatybilność zamiast szybkości. Mój argument jest taki, że odrzucam twierdzenia Paula dotyczące zgodności, oparte na moich własnych testach w co najmniej jednej z przeglądarek z problemami, o których wspomniał w swoim komentarzu. Nie udało mi się przetestować drugiej przeglądarki, ale nie jestem przekonany, że wystąpił problem. Zawsze należy dążyć do uzyskania najlepszej możliwej wydajności bez poświęcania kompatybilności. Nie mówię o mikro-optymalizacji, ale jeśli przeprowadzasz setki testów i wszystkie są niezoptymalizowane, to tak, może to mieć znaczenie.
Andy E
13

Zwykle sprawdzam, getContextkiedy tworzę obiekt płótna.

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

Jeśli jest obsługiwany, możesz kontynuować konfigurację kanwy i dodać ją do DOM. To jest prosty przykład Progresywnego Wzmocnienia , który ja (osobiście) wolę od Graceful Degradation.

Matt
źródło
Czy to zbłąkany , contextw drugiej linii?
brainjam
7
@brainjam - Nie, używam tej zmiennej pod koniec kodu. Staram się przestrzegać „zaleceń” JSLint (w tym przypadku .. tylko 1 varinstrukcja na funkcję).
Matt,
6

Dlaczego nie spróbować modernizr ? Jest to biblioteka JS, która zapewnia możliwość wykrywania.

Zacytować:

Czy kiedykolwiek chciałeś robić instrukcje if w swoim CSS, aby uzyskać dostęp do fajnych funkcji, takich jak border-radius? Cóż, z Modernizrem możesz to osiągnąć!

Frozenskys
źródło
2
Test, którego używamy w modernizr, jest następujący: return !!document.createElement('canvas').getContext To zdecydowanie najlepszy sposób testowania.
Paul Irish
4
Modernizr jest użyteczną biblioteką, ale byłoby trochę marnotrawstwem ściąganie całej biblioteki tylko po to, aby wykryć obsługę kanwy. Jeśli potrzebujesz również wykryć inne funkcje, polecam to.
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
źródło
1

Może tu występować problem - niektórzy klienci nie obsługują wszystkich metod płótna.

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
źródło
0

Możesz użyć skryptu canisuse.js, aby wykryć, czy Twoja przeglądarka obsługuje kanwę, czy nie

caniuse.canvas()
Beka
źródło
0

Jeśli chcesz uzyskać kontekst swojego płótna, równie dobrze możesz użyć go jako testu:

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
źródło