2009-12-15 5 views
16

Ist es möglich zu erkennen, ob der Client ein bestimmtes Unicode-Zeichen unterstützt oder wenn es als fehlendes Glyphenfeld gerendert wird?Ermitteln der individuellen Unicode-Zeichenunterstützung mit JavaScript

Wichtig: Unterstützung in so vielen Browsern wie möglich

Nicht wichtig: Effizienz, Geschwindigkeit oder Eleganz

Die einzige Methode, die ich versuchen, eine Leinwand denken kann, verwendet, so dass ich dachte, ich würde fragen bevor ich anfange, diese Straße hinunterzugehen.

Danke!

Edit: Dies ist nicht zur Verwendung auf einer öffentlichen Website bestimmt; Ich versuche nur eine Liste von Zeichen zu erstellen, die von jedem Browser unterstützt werden.

+2

Warum ist diese Frage Community Wiki? –

+0

Ich wusste nicht, dass es einen Nachteil beim Markieren eines Frage-Community-Wikis gab. Mein Fehler. –

+1

Die Anzahl der Zeichen, die von einem Browser angezeigt werden, hängt mehr von den Zeichensätzen ab, die der Benutzer installiert hat, als von dem jeweiligen Browser. So gut wie alle Browser unterstützen Unicode, und die meisten Zeichen benötigen keine besondere Behandlung. –

Antwort

-3

Wenn Sie die Browserunterstützung maximieren möchten, möchten Sie sich wahrscheinlich nicht auf Javascript verlassen. Viele mobile Browser unterstützen es nicht einmal.

Wenn der Browser keinen Zeichensatz unterstützt, was ist der Fall? Anzeigen des Inhalts in einer anderen Sprache? Vielleicht verlinkt man die Site, die Sprachen bei Bedarf wechseln würde robuster.

+1

Ich versuche eine Liste von Zeichen zu kompilieren, die von jedem Browser unterstützt werden, nicht die Unterstützung für eine öffentliche Seite zu maximieren. –

8

Dies ist eher eine wilde Idee als eine wirkliche Antwort:

Wenn Sie ein Zeichen finden können, das Sie immer als fehlende Glyphen-Box machen wußte, dass Sie die gleiche Technik wie diese javascript font detector --render verwenden könnten das Zeichen und die fehlende Glyphbox außerhalb des Bildschirms und vergleichen ihre Breiten. Wenn sie unterschiedlich sind, wissen Sie, dass der Charakter nicht als fehlende Glyphenbox gerendert wird. Natürlich wird dies bei Schriften mit fester Breite überhaupt nicht funktionieren, und es könnte viele feste Negative für andere Schriften geben, bei denen viele Zeichen die gleiche Breite haben.

+0

Danke! Das hilft sehr. Natürlich funktioniert es nicht für Charaktere, die die gleiche Breite und Höhe wie eine fehlende Glyphenbox haben, aber es ist ein Schritt in die richtige Richtung. –

+1

das wird nicht für jedes Zeichen funktionieren, aber wenn Sie die Schriftgröße erhöhen, sollten Sie gute Ergebnisse erzielen. Ich mag diese Antwort immer noch ... eine Art wierd aber könnte es funktionieren :-) – TheHippo

+0

@Hippo - das ist ein guter Punkt: da die Schriften vom Bildschirm gerendert werden, könntest du sie wirklich sehr groß machen. – Annie

-2

Sie können jedes Zeichen mit der Methode charCodeAt() auswerten. Dies gibt den Unicode-Zeichenwert zurück. Je nachdem, was Sie tun, können Sie den Bereich, den Sie akzeptieren möchten, als "Gültige" Zeichen einschränken ... Wenn Sie das Zeichen in der "Box" kopieren, können Sie einen Zeichenübersetzer im Web verwenden, um zu sehen, was der entsprechende Unicode-Wert ist.

Hier ist eine, die ich gegoogelt und gefunden: enter link description here

2

Nicht sicher, ob es auf geht nach vorn verlassen kann (Browser könnte sich ändern, was für nicht unterstützte Zeichen angezeigt wird), noch bin ich, dass sicher, dass diese optimiert ist (wie ich Ich habe kein gutes Verständnis für die idealen Grenzen, die hier zu messen sind), aber der folgende Ansatz (Zeichnen von Text in Canvas und Betrachten des Ergebnisses als Bild) kann, falls überprüft, eine zuverlässigere und genauere Überprüfung liefern, als dies möglich wäre Breite. Der gesamte Code am Anfang ist nur eine Browser-Erkennung, die wir verwenden müssen, da eine Merkmalserkennung nicht möglich ist.

(function() { 

// http://www.quirksmode.org/js/detect.html 
var BrowserDetect = { 
    init: function() { 
     this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; 
     this.version = this.searchVersion(navigator.userAgent) 
      || this.searchVersion(navigator.appVersion) 
      || "an unknown version"; 
     this.OS = this.searchString(this.dataOS) || "an unknown OS"; 
    }, 
    searchString: function (data) { 
     for (var i=0;i<data.length;i++) { 
      var dataString = data[i].string; 
      var dataProp = data[i].prop; 
      this.versionSearchString = data[i].versionSearch || data[i].identity; 
      if (dataString) { 
       if (dataString.indexOf(data[i].subString) != -1) 
        return data[i].identity; 
      } 
      else if (dataProp) 
       return data[i].identity; 
     } 
    }, 
    searchVersion: function (dataString) { 
     var index = dataString.indexOf(this.versionSearchString); 
     if (index == -1) return; 
     return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); 
    }, 
    dataBrowser: [ 
     { 
      string: navigator.userAgent, 
      subString: "Chrome", 
      identity: "Chrome" 
     }, 
     { string: navigator.userAgent, 
      subString: "OmniWeb", 
      versionSearch: "OmniWeb/", 
      identity: "OmniWeb" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "Apple", 
      identity: "Safari", 
      versionSearch: "Version" 
     }, 
     { 
      prop: window.opera, 
      identity: "Opera", 
      versionSearch: "Version" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "iCab", 
      identity: "iCab" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "KDE", 
      identity: "Konqueror" 
     }, 
     { 
      string: navigator.userAgent, 
      subString: "Firefox", 
      identity: "Firefox" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "Camino", 
      identity: "Camino" 
     }, 
     {  // for newer Netscapes (6+) 
      string: navigator.userAgent, 
      subString: "Netscape", 
      identity: "Netscape" 
     }, 
     { 
      string: navigator.userAgent, 
      subString: "MSIE", 
      identity: "Explorer", 
      versionSearch: "MSIE" 
     }, 
     { 
      string: navigator.userAgent, 
      subString: "Gecko", 
      identity: "Mozilla", 
      versionSearch: "rv" 
     }, 
     {  // for older Netscapes (4-) 
      string: navigator.userAgent, 
      subString: "Mozilla", 
      identity: "Netscape", 
      versionSearch: "Mozilla" 
     } 
    ], 
    dataOS : [ 
     { 
      string: navigator.platform, 
      subString: "Win", 
      identity: "Windows" 
     }, 
     { 
      string: navigator.platform, 
      subString: "Mac", 
      identity: "Mac" 
     }, 
     { 
       string: navigator.userAgent, 
       subString: "iPhone", 
       identity: "iPhone/iPod" 
     }, 
     { 
      string: navigator.platform, 
      subString: "Linux", 
      identity: "Linux" 
     } 
    ] 

}; 
BrowserDetect.init(); 


/** 
* Checks whether a given character is supported in the specified font. If the 
* font argument is not provided, it will default to sans-serif, the default 
* of the canvas element 
* @param {String} chr Character to check for support 
* @param {String} [font] Font Defaults to sans-serif 
* @returns {Boolean} Whether or not the character is visually distinct from characters that are not supported 
*/ 
function characterInFont (chr, font) { 
    var data, 
     size = 10, // We use 10 to confine results (could do further?) and minimum required for 10px 
     x = 0, 
     y = size, 
     canvas = document.createElement('canvas'), 
     ctx = canvas.getContext('2d'); 
    // Necessary? 
    canvas.width = size; 
    canvas.height = size; 

    if (font) { // Default of canvas is 10px sans-serif 
     font = size + 'px ' + font; // Fix size so we can test consistently 
     /** 
     // Is there use to confining by this height? 
     var d = document.createElement("span"); 
     d.font = font; 
     d.textContent = chr; 
     document.body.appendChild(d); 
     var emHeight = d.offsetHeight; 
     document.body.removeChild(d); 
     alert(emHeight); // 19 after page load on Firefox and Chrome regardless of canvas height 
     //*/ 
    } 

    ctx.fillText(chr, x, y); 
    data = ctx.getImageData(0, 0, ctx.measureText(chr).width, canvas.height).data; // canvas.width 
    data = Array.prototype.slice.apply(data); 

    function compareDataToBox (data, box, filter) { 
     if (filter) { // We can stop making this conditional if we confirm the exact arrays will continue to work, or otherwise remove and rely on safer full arrays 
      data = data.filter(function (item) { 
       return item != 0; 
      }); 
     } 
     return data.toString() !== box; 
    } 

    var missingCharBox; 
    switch (BrowserDetect.browser) { 
     case 'Firefox': // Draws nothing 
      missingCharBox = ''; 
      break; 
     case 'Opera': 
      //missingCharBox = '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,73,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,197,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,73,0,0,0,0'; 
      missingCharBox = '197,255,255,255,255,73,36,36,36,36,36,36,36,36,197,255,255,255,255,73'; 
      break; 
     case 'Chrome': 
      missingCharBox = '2,151,255,255,255,255,67,2,26,2,26,2,26,2,26,2,26,2,26,2,26,2,26,2,151,255,255,255,255,67'; 
      break; 
     case 'Safari': 
      missingCharBox = '17,23,23,23,23,5,52,21,21,21,21,41,39,39,39,39,39,39,39,39,63,40,40,40,40,43'; 
      break; 
     default: 
      throw 'characterInFont() not tested successfully for this browser'; 
    } 
    return compareDataToBox(data, missingCharBox, true); 
} 

// EXPORTS 
((typeof exports !== 'undefined') ? exports : this).characterInFont = characterInFont; 

}()); 

var r1 = characterInFont('a', 'Arial'); // true 
var r2 = characterInFont('\uFAAA', 'Arial'); // false 
alert(r1); 
alert(r2); 

UPDATE 1

ich für moderne Firefox zu aktualisieren versucht (um zu versuchen, für die erwarteten hexadezimalen Ziffern innerhalb der Leinwand zu überprüfen), und überprüft, um sicherzustellen, im Gegensatz zu meinem Code über die Leinwand (und passendes Muster) war gerade groß genug, um das breiteste Zeichen pro context.measureText() aufzunehmen (U + 0BCC von meinen Tests, obwohl vermutlich abhängig von Schriftart, in meinem Fall "Arial Unicode MS"). Per https://bugzilla.mozilla.org/show_bug.cgi?id=442133#c9 reagiert jedoch measureText derzeit irrtümlich auf den Zoom nur für die unbekannten Zeichen. Nun, wenn nur einer den Zoom in JavaScript-Canvas simulieren könnte, um diese Messungen (und nur diese Messungen) zu beeinflussen ...

-Code verfügbar Referenz bei https://gist.github.com/brettz9/1f061bb2ce06368db3e5

+0

Brett's Lösung funktioniert nicht mehr in Firefox, da es heutzutage den hexadezimalen Unicode-Codepunkt in einer Box anzeigt, wenn es kein Zeichen finden kann. –

+0

@AnonymousCoward: aktualisiert mit einem anderen Hindernis für Firefox im Moment ... –

Verwandte Themen