| var FontManager = (function(){ |
| |
| var maxWaitingTime = 5000; |
| var emptyChar = { |
| w: 0, |
| size:0, |
| shapes:[] |
| }; |
| var combinedCharacters = []; |
| //Hindi characters |
| combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366 |
| , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379 |
| , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]); |
| |
| function setUpNode(font, family){ |
| var parentNode = createTag('span'); |
| parentNode.style.fontFamily = family; |
| var node = createTag('span'); |
| // Characters that vary significantly among different fonts |
| node.innerHTML = 'giItT1WQy@!-/#'; |
| // Visible - so we can measure it - but not on the screen |
| parentNode.style.position = 'absolute'; |
| parentNode.style.left = '-10000px'; |
| parentNode.style.top = '-10000px'; |
| // Large font size makes even subtle changes obvious |
| parentNode.style.fontSize = '300px'; |
| // Reset any font properties |
| parentNode.style.fontVariant = 'normal'; |
| parentNode.style.fontStyle = 'normal'; |
| parentNode.style.fontWeight = 'normal'; |
| parentNode.style.letterSpacing = '0'; |
| parentNode.appendChild(node); |
| document.body.appendChild(parentNode); |
| |
| // Remember width with no applied web font |
| var width = node.offsetWidth; |
| node.style.fontFamily = font + ', '+family; |
| return {node:node, w:width, parent:parentNode}; |
| } |
| |
| function checkLoadedFonts() { |
| var i, len = this.fonts.length; |
| var node, w; |
| var loadedCount = len; |
| for(i=0;i<len; i+= 1){ |
| if(this.fonts[i].loaded){ |
| loadedCount -= 1; |
| continue; |
| } |
| if(this.fonts[i].fOrigin === 't' || this.fonts[i].origin === 2){ |
| if(window.Typekit && window.Typekit.load && this.typekitLoaded === 0){ |
| this.typekitLoaded = 1; |
| try{window.Typekit.load({ |
| async: true, |
| active: function() { |
| this.typekitLoaded = 2; |
| }.bind(this) |
| });}catch(e){} |
| } |
| if(this.typekitLoaded === 2) { |
| this.fonts[i].loaded = true; |
| } |
| } else if(this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0){ |
| this.fonts[i].loaded = true; |
| } else{ |
| node = this.fonts[i].monoCase.node; |
| w = this.fonts[i].monoCase.w; |
| if(node.offsetWidth !== w){ |
| loadedCount -= 1; |
| this.fonts[i].loaded = true; |
| }else{ |
| node = this.fonts[i].sansCase.node; |
| w = this.fonts[i].sansCase.w; |
| if(node.offsetWidth !== w){ |
| loadedCount -= 1; |
| this.fonts[i].loaded = true; |
| } |
| } |
| if(this.fonts[i].loaded){ |
| this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent); |
| this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent); |
| } |
| } |
| } |
| |
| if(loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime){ |
| setTimeout(checkLoadedFonts.bind(this),20); |
| }else{ |
| setTimeout(function(){this.loaded = true;}.bind(this),0); |
| |
| } |
| } |
| |
| function createHelper(def, fontData){ |
| var tHelper = createNS('text'); |
| tHelper.style.fontSize = '100px'; |
| tHelper.style.fontFamily = fontData.fFamily; |
| tHelper.textContent = '1'; |
| if(fontData.fClass){ |
| tHelper.style.fontFamily = 'inherit'; |
| tHelper.className = fontData.fClass; |
| } else { |
| tHelper.style.fontFamily = fontData.fFamily; |
| } |
| def.appendChild(tHelper); |
| var tCanvasHelper = createTag('canvas').getContext('2d'); |
| tCanvasHelper.font = '100px '+ fontData.fFamily; |
| return tCanvasHelper; |
| } |
| |
| function addFonts(fontData, defs){ |
| if(!fontData){ |
| this.loaded = true; |
| return; |
| } |
| if(this.chars){ |
| this.loaded = true; |
| this.fonts = fontData.list; |
| return; |
| } |
| |
| var fontArr = fontData.list; |
| var i, len = fontArr.length; |
| for(i=0; i<len; i+= 1){ |
| fontArr[i].loaded = false; |
| fontArr[i].monoCase = setUpNode(fontArr[i].fFamily,'monospace'); |
| fontArr[i].sansCase = setUpNode(fontArr[i].fFamily,'sans-serif'); |
| if(!fontArr[i].fPath) { |
| fontArr[i].loaded = true; |
| }else if(fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3){ |
| var s = createTag('style'); |
| s.type = "text/css"; |
| s.innerHTML = "@font-face {" + "font-family: "+fontArr[i].fFamily+"; font-style: normal; src: url('"+fontArr[i].fPath+"');}"; |
| defs.appendChild(s); |
| } else if(fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1){ |
| //<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'> |
| var l = createTag('link'); |
| l.type = "text/css"; |
| l.rel = "stylesheet"; |
| l.href = fontArr[i].fPath; |
| defs.appendChild(l); |
| } else if(fontArr[i].fOrigin === 't' || fontArr[i].origin === 2){ |
| //<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'> |
| var sc = createTag('script'); |
| sc.setAttribute('src',fontArr[i].fPath); |
| defs.appendChild(sc); |
| } |
| fontArr[i].helper = createHelper(defs,fontArr[i]); |
| this.fonts.push(fontArr[i]); |
| } |
| checkLoadedFonts.bind(this)(); |
| } |
| |
| function addChars(chars){ |
| if(!chars){ |
| return; |
| } |
| if(!this.chars){ |
| this.chars = []; |
| } |
| var i, len = chars.length; |
| var j, jLen = this.chars.length, found; |
| for(i=0;i<len;i+=1){ |
| j = 0; |
| found = false; |
| while(j<jLen){ |
| if(this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch){ |
| found = true; |
| } |
| j += 1; |
| } |
| if(!found){ |
| this.chars.push(chars[i]); |
| jLen += 1; |
| } |
| } |
| } |
| |
| function getCharData(char, style, font){ |
| var i = 0, len = this.chars.length; |
| while( i < len) { |
| if(this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font){ |
| return this.chars[i]; |
| } |
| i+= 1; |
| } |
| if(console && console.warn) { |
| console.warn('Missing character from exported characters list: ', char, style, font); |
| } |
| return emptyChar; |
| } |
| |
| function measureText(char, fontName, size){ |
| var fontData = this.getFontByName(fontName); |
| var tHelper = fontData.helper; |
| //tHelper.textContent = char; |
| return tHelper.measureText(char).width*size/100; |
| //return tHelper.getComputedTextLength()*size/100; |
| } |
| |
| function getFontByName(name){ |
| var i = 0, len = this.fonts.length; |
| while(i<len){ |
| if(this.fonts[i].fName === name) { |
| return this.fonts[i]; |
| } |
| i += 1; |
| } |
| return 'sans-serif'; |
| } |
| |
| function getCombinedCharacterCodes() { |
| return combinedCharacters; |
| } |
| |
| var Font = function(){ |
| this.fonts = []; |
| this.chars = null; |
| this.typekitLoaded = 0; |
| this.loaded = false; |
| this.initTime = Date.now(); |
| }; |
| //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it. |
| Font.getCombinedCharacterCodes = getCombinedCharacterCodes; |
| |
| Font.prototype.addChars = addChars; |
| Font.prototype.addFonts = addFonts; |
| Font.prototype.getCharData = getCharData; |
| Font.prototype.getFontByName = getFontByName; |
| Font.prototype.measureText = measureText; |
| |
| return Font; |
| |
| }()); |