2009-12-15 63 views
16

是否可以檢測客戶端是否支持特定的Unicode字符,或者它是否會呈現爲缺失的字形框?使用JavaScript檢測單個Unicode字符支持

重要提示:在儘可能多的瀏覽器支持儘可能

不重要:效率,速度,或優雅

我能想到的是用帆布嘗試的唯一方法,所以我想我會問在我開始走下那條路之前。

謝謝!

編輯:這不適用於公共網站;我只是想編譯每個瀏覽器支持的字符列表。

+2

爲什麼這個問題社區wiki? – 2009-12-15 23:25:11

+0

我沒有意識到標記問題社區wiki有一個缺點。我的錯。 – 2009-12-17 00:22:55

+1

由瀏覽器顯示的一組字符更多取決於用戶安裝的字體而非瀏覽器。幾乎所有的瀏覽器都支持Unicode,大多數字符不需要任何特殊處理。 – 2010-01-06 01:33:21

回答

-3

如果您想最大化瀏覽器支持,您可能不希望依賴任何JavaScript。許多移動瀏覽器甚至不支持它。

如果瀏覽器不支持字符集,什麼是回退?用另一種語言顯示內容?也許鏈接一個網站,按需轉換語言將更加強大。

+1

我想編譯每個瀏覽器支持的字符列表,而不是最大限度地支持公共頁面。 – 2009-12-17 00:23:54

8

這是不是一個真正的答案更野生的想法:

如果你能找到你知道總是呈現爲缺失字形箱一個字符,你可以使用同樣的技術,因爲這javascript font detector --render字符和缺失的字形框外並比較它們的寬度。如果它們不同,那麼你就知道這個角色並不是呈現爲缺失的字形框。當然,這對固定寬度的字體根本不起作用,並且對於其中許多字符具有相同寬度的其他字體,它可能有很多固定的否定。

+0

謝謝!這有很大幫助。當然,它不適用於與缺失的字形框寬度和高度相同的任何字符,但這是朝正確方向邁出的一步。 – 2009-12-17 00:25:38

+1

這不適用於每個角色,但是如果您提高字體大小,您應該可以獲得理想的效果。我仍然喜歡這個答案...一些奇怪的,但它可以工作:-) – TheHippo 2009-12-17 01:50:27

+0

@Hippo - 這是一個很好的觀點:因爲字體被渲染出屏幕,你可以使它們真的非常巨大。 – Annie 2009-12-17 02:00:34

-2

您可以始終使用charCodeAt()方法評估每個字符。這將返回unicode字符值。根據你在做什麼,你可以將你想接受的範圍限制爲「有效」的字符......如果你複製了「盒子」中的字符,你可以使用Web上的字符翻譯器來查看相應的unicode值是。

這裏有一個,我用Google搜索,發現:enter link description here

2

不能確定它是否能在前進的依據(瀏覽器可能會改變什麼是顯示了不支持的字符),我也沒有肯定,這是優化(如我對這裏測量的理想邊界沒有很好的理解),但是如果審查的話,以下方法(在畫布上繪製文本並將結果作爲圖像進行檢查)可以提供比檢查更爲可靠和準確的檢查寬度。所有的代碼在開始時只是瀏覽器檢測,我們必須使用,因爲功能檢測是不可能的。

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

更新1

我嘗試更新的現代火狐(嘗試檢查畫布內的預期十六進制數字),並檢查,以確保,不像我上面的代碼,畫布(和模式來匹配它)只是足夠大,以適應每context.measureText()(U + 0BCC從我的測試,儘管可能依賴於字體,在我的情況下「Arial Unicode MS」)的最寬字符。每https://bugzilla.mozilla.org/show_bug.cgi?id=442133#c9,但是,measureText目前錯誤地響應縮放只有未知的字符。現在,如果只有一個人可以模擬JavaScript canvas中的縮放以影響這些度量(並且僅影響這些度量)......

可供參考的代碼https://gist.github.com/brettz9/1f061bb2ce06368db3e5

+0

Brett的解決方案現在不再適用於Firefox,因爲它現在在找不到字符時在一個框中顯示十六進制Unicode代碼點。 – 2014-06-20 21:09:15

+0

@AnonymousCoward:此刻更新了Firefox的另一個障礙...... – 2014-06-22 10:53:51