每日一库:tinycon.js
tinycon.js是一款类似做提示的js库,通过favicon创建提示,不支持的浏览器则用title,其实chrome下有类似的技术Desktop Notification
地址:https://github.com/tommoor/tinycon
附带简单的源码注释:
<html> <head> <link rel="icon" href="favicon.ico"> <title>Tinycon</title> <script> /*! * Tinycon - A small library for manipulating the Favicon * Tom Moor, http://tommoor.com * Copyright (c) 2012 Tom Moor * MIT Licensed * @version 0.5 */ (function(){ var Tinycon = {}; var currentFavicon = null; var originalFavicon = null; var originalTitle = document.title; //原来title,fallback 不支持的浏览器 var faviconImage = null; var canvas = null; var options = {}; var defaults = { width: 7, height: 9, font: '10px arial', colour: '#ffffff', background: '#F03D25', fallback: true, abbreviate: true //使简短;缩简;缩略 }; var ua = (function () { //浏览器嗅探 var agent = navigator.userAgent.toLowerCase(); // New function has access to 'agent' via closure return function (browser) { return agent.indexOf(browser) !== -1; }; }()); var browser = { ie: ua('msie'), chrome: ua('chrome'), webkit: ua('chrome') || ua('safari'), safari: ua('safari') && !ua('chrome'), mozilla: ua('mozilla') && !ua('chrome') && !ua('safari') }; // private methods var getFaviconTag = function(){ //获取icon标签 var links = document.getElementsByTagName('link'); for(var i=0, len=links.length; i < len; i++) { if ((links[i].getAttribute('rel') || '').match(/\bicon\b/)) { return links[i]; } } return false; }; var removeFaviconTag = function(){ //移出icon标签 var links = document.getElementsByTagName('link'); var head = document.getElementsByTagName('head')[0]; for(var i=0, len=links.length; i < len; i++) { var exists = (typeof(links[i]) !== 'undefined'); if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/)) { head.removeChild(links[i]); } } }; var getCurrentFavicon = function(){ //获取icon标签href if (!originalFavicon || !currentFavicon) { var tag = getFaviconTag(); originalFavicon = currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico'; } return currentFavicon; }; var getCanvas = function (){ if (!canvas) { canvas = document.createElement("canvas"); canvas.width = 16; canvas.height = 16; } return canvas; }; var setFaviconTag = function(url){ removeFaviconTag(); var link = document.createElement('link'); link.type = 'image/x-icon'; link.rel = 'icon'; link.href = url; document.getElementsByTagName('head')[0].appendChild(link); }; var log = function(message){ if (window.console) window.console.log(message); }; var drawFavicon = function(label, colour) { //画Favicon // fallback to updating the browser title if unsupported if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === 'force') { return updateTitle(label); } var context = getCanvas().getContext("2d"); var colour = colour || '#000000'; var src = getCurrentFavicon(); faviconImage = new Image(); faviconImage.onload = function() { // clear canvas context.clearRect(0, 0, 16, 16); // draw original favicon context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, 16, 16); // draw bubble over the top if ((label + '').length > 0) drawBubble(context, label, colour); // refresh tag in page refreshFavicon(); }; // allow cross origin resource requests if the image is not a data:uri // as detailed here: https://github.com/mrdoob/three.js/issues/1305 if (!src.match(/^data/)) { faviconImage.crossOrigin = 'anonymous'; } faviconImage.src = src; }; var updateTitle = function(label) { //不支持的浏览器则显示在title上 if (options.fallback) { if ((label + '').length > 0) { document.title = '(' + label + ') ' + originalTitle; } else { document.title = originalTitle; } } }; var drawBubble = function(context, label, colour) { //画提示文字 // automatic abbreviation for long (>2 digits) numbers if (typeof label == 'number' && label > 99 && options.abbreviate) { label = abbreviateNumber(label); } // bubble needs to be larger for double digits var len = (label + '').length-1; var width = options.width + (6*len); var w = 16-width; var h = 16-options.height; // webkit seems to render fonts lighter than firefox context.font = (browser.webkit ? 'bold ' : '') + options.font; context.fillStyle = options.background; context.strokeStyle = options.background; context.lineWidth = 1; // bubble context.fillRect(w,h,width-1,options.height); // rounded left context.beginPath(); context.moveTo(w-0.5,h+1); context.lineTo(w-0.5,15); context.stroke(); // rounded right context.beginPath(); context.moveTo(15.5,h+1); context.lineTo(15.5,15); context.stroke(); // bottom shadow context.beginPath(); context.strokeStyle = "rgba(0,0,0,0.3)"; context.moveTo(w,16); context.lineTo(15,16); context.stroke(); // label context.fillStyle = options.colour; context.textAlign = "right"; context.textBaseline = "top"; // unfortunately webkit/mozilla are a pixel different in text positioning context.fillText(label, 15, browser.mozilla ? 7 : 6); }; var refreshFavicon = function(){ // check support if (!getCanvas().getContext) return; setFaviconTag(getCanvas().toDataURL()); }; var abbreviateNumber = function(label) { //metric 米制的,公制的,十进制的;度量的;距离的 转换单位 var metricPrefixes = [ ['G', 1000000000], ['M', 1000000], ['k', 1000] ]; for(var i = 0; i < metricPrefixes.length; ++i) { if (label >= metricPrefixes[i][1]) { label = round(label / metricPrefixes[i][1]) + metricPrefixes[i][0]; break; } } return label; }; var round = function (value, precision) { var number = new Number(value); return number.toFixed(precision); }; // public methods Tinycon.setOptions = function(custom){ options = {}; for(var key in defaults){ options[key] = custom.hasOwnProperty(key) ? custom[key] : defaults[key]; } return this; }; Tinycon.setImage = function(url){ currentFavicon = url; refreshFavicon(); return this; }; Tinycon.setBubble = function(label, colour) { label = label || ''; drawFavicon(label, colour); return this; }; Tinycon.reset = function(){ setFaviconTag(originalFavicon); }; Tinycon.setOptions(defaults); window.Tinycon = Tinycon; })(); (function(){ var count = 0; setInterval(function(){ Tinycon.setBubble(++count); }, 1000); })(); </script> </head> <body> </body> </html>