├── runtime.sendMessage_runtime.onMessage_demo ├── popup.html ├── js │ ├── popup.js │ └── background.js └── manifest.json ├── save_all_images ├── main.js ├── manifest.json └── background.js ├── local_messager ├── lm.png ├── manifest.json ├── main.js ├── main.html ├── background.js └── udp.js ├── media_manager ├── logo.png ├── iconfont.woff ├── background.js ├── manifest.json ├── main.html └── main.js ├── weather ├── images │ ├── icon16.png │ ├── icon19.png │ ├── icon38.png │ ├── icon48.png │ └── icon128.png ├── js │ ├── options.js │ └── weather.js ├── options.html ├── manifest.json └── popup.html ├── http_server ├── http_server.png ├── manifest.json ├── tcpServer.js ├── background.js └── tcp.js ├── my_clock ├── images │ ├── icon128.png │ ├── icon16.png │ ├── icon19.png │ ├── icon38.png │ └── icon48.png ├── js │ └── my_clock.js ├── popup.html └── manifest.json ├── usd_price ├── images │ └── icon16.png ├── manifest.json └── js │ └── background.js ├── bitcoin_price ├── images │ └── icon16.png ├── manifest.json └── js │ └── background.js ├── website_status ├── images │ ├── icon128.png │ ├── icon16.png │ ├── icon19.png │ ├── icon38.png │ ├── icon48.png │ ├── offline.png │ └── online.png ├── manifest.json └── js │ └── status.js ├── what_is_my_ip ├── images │ ├── icon128.png │ ├── icon16.png │ ├── icon19.png │ ├── icon38.png │ └── icon48.png ├── popup.html ├── js │ └── my_ip.js └── manifest.json ├── google_translate ├── images │ └── icon16.png ├── js │ ├── content.js │ └── background.js └── manifest.json ├── performance monitor ├── images │ ├── icon128.png │ ├── icon16.png │ └── icon48.png ├── control.js ├── background.js ├── manifest.json ├── main.html ├── main.js └── Chart.js ├── browser_actions_icon ├── images │ ├── icon19_0.png │ ├── icon19_1.png │ ├── icon19_2.png │ ├── icon19_3.png │ ├── icon19_4.png │ ├── icon19_5.png │ ├── icon19_6.png │ ├── icon19_7.png │ ├── icon19_8.png │ ├── icon19_9.png │ ├── icon38_0.png │ ├── icon38_1.png │ ├── icon38_2.png │ ├── icon38_3.png │ ├── icon38_4.png │ ├── icon38_5.png │ ├── icon38_6.png │ ├── icon38_7.png │ ├── icon38_8.png │ ├── icon38_9.png │ ├── icon19_10.png │ ├── icon19_11.png │ ├── icon19_12.png │ ├── icon19_13.png │ ├── icon19_14.png │ ├── icon19_15.png │ ├── icon19_16.png │ ├── icon19_17.png │ ├── icon19_18.png │ ├── icon19_19.png │ ├── icon38_10.png │ ├── icon38_11.png │ ├── icon38_12.png │ ├── icon38_13.png │ ├── icon38_14.png │ ├── icon38_15.png │ ├── icon38_16.png │ ├── icon38_17.png │ ├── icon38_18.png │ └── icon38_19.png ├── js │ └── background.js └── manifest.json ├── cannot_touch ├── manifest.json └── js │ └── cannot_touch.js ├── .gitattributes ├── README.md └── .gitignore /runtime.sendMessage_runtime.onMessage_demo/popup.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /save_all_images/main.js: -------------------------------------------------------------------------------- 1 | [].map.call(document.getElementsByTagName('img'), function(img){ 2 | return img.src; 3 | }); 4 | -------------------------------------------------------------------------------- /local_messager/lm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/local_messager/lm.png -------------------------------------------------------------------------------- /media_manager/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/media_manager/logo.png -------------------------------------------------------------------------------- /weather/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/weather/images/icon16.png -------------------------------------------------------------------------------- /weather/images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/weather/images/icon19.png -------------------------------------------------------------------------------- /weather/images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/weather/images/icon38.png -------------------------------------------------------------------------------- /weather/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/weather/images/icon48.png -------------------------------------------------------------------------------- /http_server/http_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/http_server/http_server.png -------------------------------------------------------------------------------- /media_manager/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/media_manager/iconfont.woff -------------------------------------------------------------------------------- /my_clock/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/my_clock/images/icon128.png -------------------------------------------------------------------------------- /my_clock/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/my_clock/images/icon16.png -------------------------------------------------------------------------------- /my_clock/images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/my_clock/images/icon19.png -------------------------------------------------------------------------------- /my_clock/images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/my_clock/images/icon38.png -------------------------------------------------------------------------------- /my_clock/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/my_clock/images/icon48.png -------------------------------------------------------------------------------- /usd_price/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/usd_price/images/icon16.png -------------------------------------------------------------------------------- /weather/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/weather/images/icon128.png -------------------------------------------------------------------------------- /bitcoin_price/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/bitcoin_price/images/icon16.png -------------------------------------------------------------------------------- /website_status/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/icon128.png -------------------------------------------------------------------------------- /website_status/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/icon16.png -------------------------------------------------------------------------------- /website_status/images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/icon19.png -------------------------------------------------------------------------------- /website_status/images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/icon38.png -------------------------------------------------------------------------------- /website_status/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/icon48.png -------------------------------------------------------------------------------- /website_status/images/offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/offline.png -------------------------------------------------------------------------------- /website_status/images/online.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/website_status/images/online.png -------------------------------------------------------------------------------- /what_is_my_ip/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/what_is_my_ip/images/icon128.png -------------------------------------------------------------------------------- /what_is_my_ip/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/what_is_my_ip/images/icon16.png -------------------------------------------------------------------------------- /what_is_my_ip/images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/what_is_my_ip/images/icon19.png -------------------------------------------------------------------------------- /what_is_my_ip/images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/what_is_my_ip/images/icon38.png -------------------------------------------------------------------------------- /what_is_my_ip/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/what_is_my_ip/images/icon48.png -------------------------------------------------------------------------------- /google_translate/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/google_translate/images/icon16.png -------------------------------------------------------------------------------- /runtime.sendMessage_runtime.onMessage_demo/js/popup.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.sendMessage('Hello', function(response){ 2 | document.write(response); 3 | }); -------------------------------------------------------------------------------- /performance monitor/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/performance monitor/images/icon128.png -------------------------------------------------------------------------------- /performance monitor/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/performance monitor/images/icon16.png -------------------------------------------------------------------------------- /performance monitor/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/performance monitor/images/icon48.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_0.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_1.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_2.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_3.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_4.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_5.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_6.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_7.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_8.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_9.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_0.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_1.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_2.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_3.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_4.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_5.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_6.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_7.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_8.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_9.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_10.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_11.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_12.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_13.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_14.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_15.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_16.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_17.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_18.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon19_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon19_19.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_10.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_11.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_12.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_13.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_14.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_15.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_16.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_17.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_18.png -------------------------------------------------------------------------------- /browser_actions_icon/images/icon38_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sneezry/chrome_extensions_and_apps_programming/HEAD/browser_actions_icon/images/icon38_19.png -------------------------------------------------------------------------------- /runtime.sendMessage_runtime.onMessage_demo/js/background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){ 2 | if(message == 'Hello'){ 3 | sendResponse('Hello from background.'); 4 | } 5 | }); -------------------------------------------------------------------------------- /google_translate/js/content.js: -------------------------------------------------------------------------------- 1 | window.onmouseup = function(){ 2 | var selection = window.getSelection(); 3 | if(selection.anchorOffset != selection.extentOffset){ 4 | chrome.runtime.sendMessage(selection.toString()); 5 | } 6 | } -------------------------------------------------------------------------------- /media_manager/background.js: -------------------------------------------------------------------------------- 1 | chrome.app.runtime.onLaunched.addListener(function() { 2 | chrome.app.window.create('main.html', { 3 | id: 'main', 4 | bounds: { 5 | width: 800, 6 | height: 600 7 | } 8 | }); 9 | }); -------------------------------------------------------------------------------- /weather/js/options.js: -------------------------------------------------------------------------------- 1 | var city = localStorage.city; 2 | city = city?city:'beijing'; 3 | document.getElementById('city').value = city; 4 | document.getElementById('save').onclick = function(){ 5 | localStorage.city = document.getElementById('city').value; 6 | alert('保存成功。'); 7 | } -------------------------------------------------------------------------------- /performance monitor/control.js: -------------------------------------------------------------------------------- 1 | var current_window = chrome.app.window.current(); 2 | 3 | document.getElementById('minimize').onclick = function(){ 4 | current_window.minimize(); 5 | } 6 | 7 | document.getElementById('close').onclick = function(){ 8 | current_window.close(); 9 | } -------------------------------------------------------------------------------- /weather/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 设定城市 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /cannot_touch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "永远点不到的搜索按钮", 4 | "version": "1.0", 5 | "description": "让你永远也点击不到Google的搜索按钮", 6 | "content_scripts": [ 7 | { 8 | "matches": ["*://www.google.com/"], 9 | "js": ["js/cannot_touch.js"] 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /runtime.sendMessage_runtime.onMessage_demo/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "扩展内部通信Demo", 4 | "version": "1.0", 5 | "description": "扩展内部通信Demo", 6 | "browser_action": { 7 | "default_popup": "popup.html" 8 | }, 9 | "background": { 10 | "scripts": [ 11 | "js/background.js" 12 | ] 13 | } 14 | } -------------------------------------------------------------------------------- /browser_actions_icon/js/background.js: -------------------------------------------------------------------------------- 1 | function chgIcon(index){ 2 | if(!index){ 3 | index = 0; 4 | } 5 | else{ 6 | index = index%20; 7 | } 8 | chrome.browserAction.setIcon({path: {'19': 'images/icon19_'+index+'.png'}}); 9 | chrome.browserAction.setIcon({path: {'38': 'images/icon38_'+index+'.png'}}); 10 | setTimeout(function(){chgIcon(index+1)},50); 11 | } 12 | 13 | chgIcon(); -------------------------------------------------------------------------------- /my_clock/js/my_clock.js: -------------------------------------------------------------------------------- 1 | function my_clock(el){ 2 | var today=new Date(); 3 | var h=today.getHours(); 4 | var m=today.getMinutes(); 5 | var s=today.getSeconds(); 6 | m=m>=10?m:('0'+m); 7 | s=s>=10?s:('0'+s); 8 | el.innerHTML = h+":"+m+":"+s; 9 | setTimeout(function(){my_clock(el)}, 1000); 10 | } 11 | 12 | var clock_div = document.getElementById('clock_div'); 13 | my_clock(clock_div); -------------------------------------------------------------------------------- /save_all_images/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Save all images", 4 | "version": "1.0", 5 | "description": "Save all images in current tab", 6 | "background": { 7 | "scripts": ["background.js"], 8 | "persistent": false 9 | }, 10 | "permissions": [ 11 | "activeTab", 12 | "contextMenus", 13 | "downloads" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /my_clock/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /what_is_my_ip/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 |
正在查询……
23 | 24 | 25 | -------------------------------------------------------------------------------- /what_is_my_ip/js/my_ip.js: -------------------------------------------------------------------------------- 1 | function httpRequest(url, callback){ 2 | var xhr = new XMLHttpRequest(); 3 | xhr.open("GET", url, true); 4 | xhr.onreadystatechange = function() { 5 | if (xhr.readyState == 4) { 6 | callback(xhr.responseText); 7 | } 8 | } 9 | xhr.send(); 10 | } 11 | 12 | httpRequest('http://sneezryworks.sinaapp.com/ip.php', function(ip){ 13 | document.getElementById('ip_div').innerText = ip; 14 | }); -------------------------------------------------------------------------------- /media_manager/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "background": { 4 | "scripts": ["background.js"] 5 | } 6 | }, 7 | "manifest_version": 2, 8 | "name": "Media Manager", 9 | "version": "1.0", 10 | "description": "A media manage tool.", 11 | "icons": { 12 | "128": "logo.png" 13 | }, 14 | "permissions": [ 15 | {"mediaGalleries": ["read", "delete", "copyTo", "allAutoDetected"]} 16 | ] 17 | } -------------------------------------------------------------------------------- /usd_price/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "USD Price", 4 | "version": "1.0", 5 | "description": "查询美元当日价格", 6 | "background": { 7 | "scripts": [ 8 | "js/background.js" 9 | ] 10 | }, 11 | "icons": { 12 | "16": "images/icon16.png" 13 | }, 14 | "omnibox": { 15 | "keyword": "usd" 16 | }, 17 | "permissions": [ 18 | "*://query.yahooapis.com/*" 19 | ] 20 | } -------------------------------------------------------------------------------- /bitcoin_price/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Bitcoin Price", 4 | "version": "1.0", 5 | "description": "查询比特币当日价格", 6 | "background": { 7 | "scripts": [ 8 | "js/background.js" 9 | ] 10 | }, 11 | "icons": { 12 | "16": "images/icon16.png" 13 | }, 14 | "omnibox": { 15 | "keyword": "bitcoin" 16 | }, 17 | "permissions": [ 18 | "*://blockchain.info/*" 19 | ] 20 | } -------------------------------------------------------------------------------- /browser_actions_icon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Turtle", 4 | "version": "1.0", 5 | "description": "Turtle", 6 | "browser_action": { 7 | "default_icon": { 8 | "19": "images/icon19_0.png", 9 | "38": "images/icon38_0.png" 10 | }, 11 | "default_title": "Turtle" 12 | }, 13 | "background": { 14 | "scripts": [ 15 | "js/background.js" 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /performance monitor/background.js: -------------------------------------------------------------------------------- 1 | chrome.app.runtime.onLaunched.addListener(function() { 2 | var main_window = chrome.app.window.get('main'); 3 | if(main_window){ 4 | main_window.show(); 5 | } 6 | else{ 7 | chrome.app.window.create('main.html', { 8 | //'id': 'main', 9 | 'bounds': { 10 | 'width': 542, 11 | 'height': 360 12 | }, 13 | 'resizable': false, 14 | 'frame': 'none' 15 | }); 16 | } 17 | }); -------------------------------------------------------------------------------- /http_server/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "background": { 4 | "scripts": ["tcp.js", "tcpServer.js", "background.js"] 5 | } 6 | }, 7 | "manifest_version": 2, 8 | "name": "HTTP Server", 9 | "version": "1.0", 10 | "description": "An HTTP server.", 11 | "icons": { 12 | "128": "http_server.png" 13 | }, 14 | "sockets": { 15 | "tcp": { 16 | "connect": "*" 17 | }, 18 | "tcpServer": { 19 | "listen": ":80" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /my_clock/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "我的时钟", 4 | "version": "1.0", 5 | "description": "我的第一个Chrome扩展", 6 | "icons": { 7 | "16": "images/icon16.png", 8 | "48": "images/icon48.png", 9 | "128": "images/icon128.png" 10 | }, 11 | "browser_action": { 12 | "default_icon": { 13 | "19": "images/icon19.png", 14 | "38": "images/icon38.png" 15 | }, 16 | "default_title": "我的时钟", 17 | "default_popup": "popup.html" 18 | } 19 | } -------------------------------------------------------------------------------- /local_messager/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "background": { 4 | "scripts": ["udp.js", "background.js"] 5 | } 6 | }, 7 | "manifest_version": 2, 8 | "name": "Local Messager", 9 | "version": "1.0", 10 | "description": "A local network chating application.", 11 | "icons": { 12 | "128": "lm.png" 13 | }, 14 | "sockets": { 15 | "udp": { 16 | "send": "224.0.1.100", 17 | "bind": ":*", 18 | "multicastMembership": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /performance monitor/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "background": { 4 | "scripts": ["background.js"] 5 | } 6 | }, 7 | "manifest_version": 2, 8 | "name": "Performance Monitor", 9 | "version": "1.0", 10 | "description": "A performance monitor to show cpu and memory status.", 11 | "icons": { 12 | "16": "images/icon16.png", 13 | "48": "images/icon48.png", 14 | "128": "images/icon128.png" 15 | }, 16 | "permissions": [ 17 | "system.cpu", 18 | "system.memory" 19 | ] 20 | } -------------------------------------------------------------------------------- /google_translate/js/background.js: -------------------------------------------------------------------------------- 1 | chrome.contextMenus.create({ 2 | 'type':'normal', 3 | 'title':'使用Google翻译……', 4 | 'contexts':['selection'], 5 | 'id':'cn', 6 | 'onclick':translate 7 | }); 8 | 9 | function translate(info, tab){ 10 | var url = 'http://translate.google.com.hk/#auto/zh-CN/'+info.selectionText ; 11 | window.open(url, '_blank'); 12 | } 13 | 14 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){ 15 | chrome.contextMenus.update('cn',{ 16 | 'title':'使用Google翻译“'+message+'”' 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /google_translate/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Google Translate", 4 | "version": "1.0", 5 | "description": "Translate what you select with Google", 6 | "background": { 7 | "scripts": [ 8 | "js/background.js" 9 | ] 10 | }, 11 | "icons": { 12 | "16": "images/icon16.png" 13 | }, 14 | "content_scripts": [ 15 | { 16 | "matches": ["*://*/*"], 17 | "js": ["js/content.js"] 18 | } 19 | ], 20 | "permissions": [ 21 | "contextMenus" 22 | ] 23 | } -------------------------------------------------------------------------------- /local_messager/main.js: -------------------------------------------------------------------------------- 1 | document.getElementById('msg').onkeyup = function(e){ 2 | if(e.keyCode==13){ 3 | chrome.runtime.sendMessage({ 4 | action:'send', 5 | msg:encodeURIComponent(this.value) 6 | }); 7 | this.value = ''; 8 | } 9 | } 10 | 11 | chrome.runtime.onMessage.addListener(function(message, sender, callback){ 12 | if(message.action == 'receive'){ 13 | var el = document.createElement('div'); 14 | el.innerText = decodeURIComponent(message.msg); 15 | document.getElementById('history').appendChild(el); 16 | } 17 | }); -------------------------------------------------------------------------------- /what_is_my_ip/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "查看我的IP", 4 | "version": "1.0", 5 | "description": "查看我的电脑当前的公网IP", 6 | "icons": { 7 | "16": "images/icon16.png", 8 | "48": "images/icon48.png", 9 | "128": "images/icon128.png" 10 | }, 11 | "browser_action": { 12 | "default_icon": { 13 | "19": "images/icon19.png", 14 | "38": "images/icon38.png" 15 | }, 16 | "default_title": "查看我的IP", 17 | "default_popup": "popup.html" 18 | }, 19 | "permissions": [ 20 | "http://sneezryworks.sinaapp.com/ip.php" 21 | ] 22 | } -------------------------------------------------------------------------------- /website_status/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Google在线状态", 4 | "version": "1.0", 5 | "description": "监视Google是否在线", 6 | "icons": { 7 | "16": "images/icon16.png", 8 | "48": "images/icon48.png", 9 | "128": "images/icon128.png" 10 | }, 11 | "browser_action": { 12 | "default_icon": { 13 | "19": "images/icon19.png", 14 | "38": "images/icon38.png" 15 | } 16 | }, 17 | "background": { 18 | "scripts": [ 19 | "js/status.js" 20 | ] 21 | }, 22 | "permissions": [ 23 | "http://www.google.cn/" 24 | ] 25 | } -------------------------------------------------------------------------------- /website_status/js/status.js: -------------------------------------------------------------------------------- 1 | function httpRequest(url, callback){ 2 | var xhr = new XMLHttpRequest(); 3 | xhr.open("GET", url, true); 4 | xhr.onreadystatechange = function() { 5 | if (xhr.readyState == 4) { 6 | callback(true); 7 | } 8 | } 9 | xhr.onerror = function(){ 10 | callback(false); 11 | } 12 | xhr.send(); 13 | } 14 | 15 | function checkStatus(){ 16 | httpRequest('http://www.google.cn/', function(status){ 17 | chrome.browserAction.setIcon({path: 'images/'+(status?'online.png':'offline.png')}); 18 | setTimeout(checkStatus, 5000); 19 | }); 20 | } 21 | 22 | checkStatus(); -------------------------------------------------------------------------------- /weather/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "天气预报", 4 | "version": "1.0", 5 | "description": "查看未来两周的天气情况", 6 | "icons": { 7 | "16": "images/icon16.png", 8 | "48": "images/icon48.png", 9 | "128": "images/icon128.png" 10 | }, 11 | "browser_action": { 12 | "default_icon": { 13 | "19": "images/icon19.png", 14 | "38": "images/icon38.png" 15 | }, 16 | "default_title": "天气预报", 17 | "default_popup": "popup.html" 18 | }, 19 | "options_page": "options.html", 20 | "permissions": [ 21 | "http://api.openweathermap.org/data/2.5/forecast?q=*" 22 | ] 23 | } -------------------------------------------------------------------------------- /save_all_images/background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onInstalled.addListener(function(){ 2 | chrome.contextMenus.create({ 3 | 'id':'saveall', 4 | 'type':'normal', 5 | 'title':'保存所有图片', 6 | }); 7 | }); 8 | 9 | chrome.contextMenus.onClicked.addListener(function(info, tab){ 10 | if(info.menuItemId == 'saveall'){ 11 | chrome.tabs.executeScript(tab.id, {file: 'main.js'}, function(results){ 12 | if (results && results[0] && results[0].length){ 13 | results[0].forEach(function(url) { 14 | chrome.downloads.download({ 15 | url: url, 16 | conflictAction: 'uniquify', 17 | saveAs: false 18 | }); 19 | }); 20 | } 21 | }); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /local_messager/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Local Messager 4 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Chrome扩展及应用开发 2 | ==================== 3 | 4 | ![Chrome扩展及应用开发](http://www.ituring.com.cn/download/01g5ecFVoWUi) 5 | 6 | 您可以通过以下渠道获得本书: 7 | 8 | + 免费但未经编辑的首发电子版:,支持推送至Kindle及在线阅读 9 | + 经过编辑精心编辑的,内容更加充实且排版更加精美的电子版:,支持推送至Kindle、下载完整PDF及在线阅读 10 | + 经过编辑精心编辑的,内容更加充实且排版更加精美的纸版: 11 | + 京东: 12 | + 亚马逊: 13 | + 当当: 14 | + 互动出版网: 15 | 16 | 您可以通过以下渠道了解本书: 17 | 18 | + 豆瓣: 19 | + 51CTO: 20 | 21 | 另外,您通过购买的电子版费用中,作者所得的全部收入都将由人民邮电出版社代捐给壹基金,感谢您对慈善事业的支持。 22 | -------------------------------------------------------------------------------- /cannot_touch/js/cannot_touch.js: -------------------------------------------------------------------------------- 1 | function btn_move(el, mouseLeft, mouseTop){ 2 | var leftRnd = (Math.random()-0.5)*20; 3 | var topRnd = (Math.random()-0.5)*20; 4 | var btnLeft = mouseLeft+(leftRnd>0?100:-100)+leftRnd; 5 | var btnTop = mouseTop+(topRnd>0?30:-30)+topRnd; 6 | btnLeft = btnLeft<100?(btnLeft+window.innerWidth-200):(btnLeft>window.innerWidth-100?btnLeft-window.innerWidth+200:btnLeft); 7 | btnTop = btnTop<100?( btnTop+window.innerHeight-200):(btnTop>window.innerHeight-100?btnTop-window.innerHeight+200:btnTop); 8 | el.style.position = 'fixed'; 9 | el.style.left = btnLeft+'px'; 10 | el.style.top = btnTop+'px'; 11 | } 12 | 13 | function over_btn(e){ 14 | if(!e){ 15 | e = window.event; 16 | } 17 | btn_move(this, e.clientX, e.clientY); 18 | } 19 | 20 | document.getElementById('gbqfba').onmouseover = over_btn; -------------------------------------------------------------------------------- /weather/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47 | 48 | 49 |
载入中……
50 | 51 | 52 | -------------------------------------------------------------------------------- /weather/js/weather.js: -------------------------------------------------------------------------------- 1 | function httpRequest(url, callback){ 2 | var xhr = new XMLHttpRequest(); 3 | xhr.open("GET", url, true); 4 | xhr.onreadystatechange = function() { 5 | if (xhr.readyState == 4) { 6 | callback(xhr.responseText); 7 | } 8 | } 9 | xhr.send(); 10 | } 11 | 12 | function showWeather(result){ 13 | result = JSON.parse(result); 14 | var list = result.list; 15 | var table = ''; 16 | for(var i in list){ 17 | var d = new Date(list[i].dt*1000); 18 | table += ''; 19 | table += ''; 20 | table += ''; 21 | table += ''; 22 | table += ''; 23 | table += ''; 24 | } 25 | table += '
日期天气最低温度最高温度
'+d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+''+list[i].weather[0].description+''+Math.round(list[i].temp.min-273.15)+' °C'+Math.round(list[i].temp.max-273.15)+' °C
'; 26 | document.getElementById('weather').innerHTML = table; 27 | } 28 | 29 | var city = localStorage.city; 30 | city = city?city:'beijing'; 31 | var url = 'http://api.openweathermap.org/data/2.5/forecast/daily?q='+city+',china&lang=zh_cn'; 32 | httpRequest(url, showWeather); -------------------------------------------------------------------------------- /local_messager/background.js: -------------------------------------------------------------------------------- 1 | var udpSocket = new udp(); 2 | udpSocket.localPort = 8943; 3 | udpSocket.receive = receiveMsg; 4 | udpSocket.init(function(){ 5 | udpSocket.joinGroup('224.0.1.100', function(){ 6 | chrome.runtime.onMessage.addListener(function(message, sender, callback){ 7 | if(message.action == 'send'){ 8 | var buf = str2ab(message.msg); 9 | udpSocket.send('224.0.1.100', udpSocket.localPort, buf, function(){ 10 | //message is sent 11 | }); 12 | } 13 | }); 14 | chrome.app.runtime.onLaunched.addListener(function(){ 15 | chrome.app.window.create('main.html', { 16 | 'id': 'main', 17 | 'bounds': { 18 | 'width': 400, 19 | 'height': 600 20 | } 21 | }); 22 | }); 23 | }); 24 | }); 25 | 26 | function receiveMsg(info){ 27 | var msg = ab2str(info.data); 28 | chrome.runtime.sendMessage({action:'receive', msg:msg}); 29 | } 30 | 31 | function str2ab(str){ 32 | var buf = new ArrayBuffer(str.length*2); 33 | bufView = new Uint16Array(buf); 34 | for(var i=0; i 2 | 3 | Performance Monitor 4 | 54 | 55 | 56 |
Performance Monitor 57 | 58 | 59 |
60 |
61 |
CPU Usage
62 |
63 | 64 | 65 |
66 |
Memory Usage
67 |
68 | 69 | 70 |
71 |
72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /usd_price/js/background.js: -------------------------------------------------------------------------------- 1 | function httpRequest(url, callback){ 2 | var xhr = new XMLHttpRequest(); 3 | xhr.open("GET", url, true); 4 | xhr.onreadystatechange = function() { 5 | if (xhr.readyState == 4) { 6 | callback(xhr.responseText); 7 | } 8 | } 9 | xhr.send(); 10 | } 11 | 12 | function updateAmount(amount, exchange){ 13 | amount = Number(amount); 14 | if(isNaN(amount) || !amount){ 15 | exchange([{ 16 | 'content': '$1 = ¥'+price, 17 | 'description': '$1 = ¥'+price 18 | },{ 19 | 'content': '¥1 = $'+(1/price).toFixed(6), 20 | 'description': '¥1 = $'+(1/price).toFixed(6) 21 | }]); 22 | } 23 | else{ 24 | exchange([{ 25 | 'content': '$'+amount+' = ¥'+(amount*price).toFixed(2), 26 | 'description': '$'+amount+' = ¥'+(amount*price).toFixed(2) 27 | },{ 28 | 'content': '¥'+amount+' = $'+(amount/price).toFixed(6), 29 | 'description': '¥'+amount+' = $'+(amount/price).toFixed(6) 30 | }]); 31 | } 32 | } 33 | 34 | function gotoYahoo(text, disposition){ 35 | window.open('http://finance.yahoo.com/q?s=USDCNY=X'); 36 | } 37 | 38 | var url = 'http://query.yahooapis.com/v1/public/yql?q=select%20Rate%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22USDCNY%22)&env=store://datatables.org/alltableswithkeys&format=json'; 39 | var price; 40 | 41 | httpRequest(url, function(r){ 42 | price = JSON.parse(r); 43 | price = price.query.results.rate.Rate; 44 | price = Number(price); 45 | }); 46 | 47 | chrome.omnibox.setDefaultSuggestion({'description':'Find current USD price.'}); 48 | 49 | chrome.omnibox.onInputChanged.addListener(updateAmount); 50 | 51 | chrome.omnibox.onInputEntered.addListener(gotoYahoo); -------------------------------------------------------------------------------- /bitcoin_price/js/background.js: -------------------------------------------------------------------------------- 1 | function httpRequest(url, callback){ 2 | var xhr = new XMLHttpRequest(); 3 | xhr.open("GET", url, true); 4 | xhr.onreadystatechange = function() { 5 | if (xhr.readyState == 4) { 6 | callback(xhr.responseText); 7 | } 8 | } 9 | xhr.send(); 10 | } 11 | 12 | function updateAmount(amount, exchange){ 13 | amount = Number(amount); 14 | if(isNaN(amount) || !amount){ 15 | exchange([{ 16 | 'content': '฿1 = $'+price, 17 | 'description': '฿1 = $'+price 18 | },{ 19 | 'content': '$1 = ฿'+(1/price).toFixed(6), 20 | 'description': '$1 = ฿'+(1/price).toFixed(6) 21 | }]); 22 | } 23 | else{ 24 | exchange([{ 25 | 'content': '฿'+amount+' = $'+(amount*price).toFixed(2), 26 | 'description': '฿'+amount+' = $'+(amount*price).toFixed(2) 27 | },{ 28 | 'content': '$'+amount+' = ฿'+(amount/price).toFixed(6), 29 | 'description': '$'+amount+' = ฿'+(amount/price).toFixed(6) 30 | }]); 31 | } 32 | } 33 | 34 | function gotoBlockchain(text, disposition){ 35 | window.open('https://blockchain.info/charts/market-price?timespan=30days&showDataPoints=false&daysAverageString=1&show_header=true&scale=0&address='); 36 | } 37 | 38 | var url = 'https://blockchain.info/charts/market-price?showDataPoints=false×pan=30days&show_header=true&daysAverageString=1&scale=0&format=json&address='; 39 | var price; 40 | 41 | httpRequest(url, function(r){ 42 | price = JSON.parse(r); 43 | price = price.values; 44 | price = price[price.length-1]; 45 | price = price.y; 46 | }); 47 | 48 | chrome.omnibox.setDefaultSuggestion({'description':'Find current Bitcoin price.'}); 49 | 50 | chrome.omnibox.onInputChanged.addListener(updateAmount); 51 | 52 | chrome.omnibox.onInputEntered.addListener(gotoBlockchain); -------------------------------------------------------------------------------- /http_server/tcpServer.js: -------------------------------------------------------------------------------- 1 | function tcpServer(){ 2 | var _tcpServer = chrome.sockets.tcpServer; 3 | this.option = {}, 4 | this.socketId = 0, 5 | 6 | this.create = function(callback){ 7 | _tcpServer.create(this.option, function(socketInfo){ 8 | this.socketId = socketInfo.socketId; 9 | callback(); 10 | }.bind(this)); 11 | }.bind(this), 12 | 13 | this.update = function(){ 14 | _tcpServer.update(this.socketId, newSocketOption, callback); 15 | }.bind(this), 16 | 17 | this.pause = function(isPaused, callback){ 18 | _tcpServer.setPaused(this.socketId, isPaused, callback); 19 | }.bind(this), 20 | 21 | this.disconnect = function(callback){ 22 | _tcpServer.disconnect(this.socketId, callback); 23 | }.bind(this), 24 | 25 | this.close = function(callback){ 26 | _tcpServer.close(this.socketId, callback); 27 | }.bind(this), 28 | 29 | this.listen = function(address, port, callback){ 30 | _tcpServer.listen(this.socketId, address, port, function(code){ 31 | if(code<0){ 32 | this.error(code); 33 | return false; 34 | } 35 | else{ 36 | _tcpServer.onAccept.addListener(function(info){ 37 | if(info.socketId==this.socketId){ 38 | this.accept(info); 39 | } 40 | }.bind(this)); 41 | _tcpServer.onAcceptError.addListener(function(info){ 42 | if(info.socketId==this.socketId){ 43 | this.error(info.resultCode); 44 | } 45 | }.bind(this)); 46 | callback(); 47 | } 48 | }.bind(this)); 49 | }.bind(this), 50 | 51 | this.error = function(code){ 52 | console.log('An error occurred with code '+code); 53 | }, 54 | 55 | this.accept = function(info){ 56 | console.log('Received data.'); 57 | }, 58 | 59 | this.getInfo = function(callback){ 60 | _tcpServer.getInfo(this.socketId, callback); 61 | }.bind(this), 62 | 63 | this.getSockets = function(callback){ 64 | _tcpServer.getSockets (callback); 65 | }.bind(this), 66 | 67 | this.init = function(callback){ 68 | this.create(callback); 69 | }.bind(this) 70 | } -------------------------------------------------------------------------------- /http_server/background.js: -------------------------------------------------------------------------------- 1 | var tcpServerSocket = new tcpServer(); 2 | tcpServerSocket.option = { 3 | persistent: false 4 | }; 5 | tcpServerSocket.accept = handleAccept.bind(tcpServerSocket); 6 | tcpServerSocket.init(function(){ 7 | tcpServerSocket.listen('127.0.0.1', 80, function(){ 8 | console.log('Listening 127.0.0.1:80...'); 9 | }); 10 | }); 11 | 12 | function str2ab(str){ 13 | var buf = new ArrayBuffer(str.length); 14 | bufView = new Uint8Array(buf); 15 | for(var i=0; i'); 52 | var body = "

It Works!

"+ 53 | "
"+ 54 | "Request Header:
"+header; 55 | var respondse = "HTTP/1.1 200 OK\r\n"+ 56 | "Connection: Keep-Alive\r\n"+ 57 | "Content-Length: "+body.length+"\r\n"+ 58 | "Content-Type: text/html\r\n"+ 59 | "Connection: close\r\n\r\n"+body; 60 | respondse = str2ab(respondse); 61 | this.send(respondse, function(){ 62 | console.log('Sent.'); 63 | this.close(function(){ 64 | console.log('Closed.'); 65 | }) 66 | }.bind(this)); 67 | } -------------------------------------------------------------------------------- /http_server/tcp.js: -------------------------------------------------------------------------------- 1 | function tcp(){ 2 | var _tcp = chrome.sockets.tcp; 3 | this.option = {}, 4 | this.socketId = 0, 5 | 6 | this.create = function(callback){ 7 | _tcp.create(this.option, function(socketInfo){ 8 | this.socketId = socketInfo.socketId; 9 | callback(); 10 | }.bind(this)); 11 | }.bind(this), 12 | 13 | this.update = function(){ 14 | _tcp.update(this.socketId, newSocketOption, callback); 15 | }.bind(this), 16 | 17 | this.pause = function(isPaused, callback){ 18 | _tcp.setPaused(this.socketId, isPaused, callback); 19 | }.bind(this), 20 | 21 | this.keepAlive = function(enable, delay, callback){ 22 | _tcp.setKeepAlive(this.socketId, enable, delay, function(code){ 23 | if(code<0){ 24 | this.error(code); 25 | } 26 | else{ 27 | callback(); 28 | } 29 | }.bind(this)); 30 | }.bind(this), 31 | 32 | this.noDelay = function(noDelay, callback){ 33 | _tcp.setNoDelay(this.socketId, noDelay, function(code){ 34 | if(code<0){ 35 | this.error(code); 36 | } 37 | else{ 38 | callback(); 39 | } 40 | }.bind(this)); 41 | }.bind(this), 42 | 43 | this.disconnect = function(callback){ 44 | _tcp.disconnect(this.socketId, callback); 45 | }.bind(this), 46 | 47 | this.close = function(callback){ 48 | _tcp.close(this.socketId, callback); 49 | }.bind(this), 50 | 51 | this.error = function(code){ 52 | console.log('An error occurred with code '+code); 53 | }, 54 | 55 | this.connect = function(address, port, callback){ 56 | _tcp.connect(this.socketId, address, port, function(){ 57 | _tcp.onReceive.addListener(function(info){ 58 | if(info.socketId==this.socketId){ 59 | this.receive(info); 60 | } 61 | }.bind(this)); 62 | _tcp.onReceiveError.addListener(function(info){ 63 | if(info.socketId==this.socketId){ 64 | this.error(info.resultCode); 65 | } 66 | }.bind(this)); 67 | }.bind(this)); 68 | }.bind(this), 69 | 70 | this.send = function(data, callback){ 71 | _tcp.send(this.socketId, data, callback); 72 | }.bind(this), 73 | 74 | this.receive = function(info){ 75 | console.log('Received data .'); 76 | }, 77 | 78 | this.getInfo = function(callback){ 79 | _tcp.getInfo(this.socketId, callback); 80 | }.bind(this), 81 | 82 | this.getSockets = function(callback){ 83 | _tcp.getSockets (callback); 84 | }.bind(this), 85 | 86 | this.init = function(callback){ 87 | this.create(callback); 88 | }.bind(this) 89 | } -------------------------------------------------------------------------------- /media_manager/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 160 | 161 | 162 |
更新失败
163 |
Media Manager󰅜 164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
媒体库»
173 |
174 | 175 | 176 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /local_messager/udp.js: -------------------------------------------------------------------------------- 1 | function udp(){ 2 | var _udp = chrome.sockets.udp; 3 | this.option = {}, 4 | this.socketId = 0, 5 | this.localAddress = '0.0.0.0', 6 | this.localPort = 0, 7 | 8 | this.create = function(callback){ 9 | _udp.create(this.option, function(socketInfo){ 10 | this.socketId = socketInfo.socketId; 11 | callback(); 12 | }.bind(this)); 13 | }.bind(this), 14 | 15 | this.update = function(){ 16 | _udp.update(this.socketId, newSocketOption, callback); 17 | }.bind(this), 18 | 19 | this.pause = function(isPaused, callback){ 20 | _udp.setPaused(this.socketId, isPaused, callback); 21 | }.bind(this), 22 | 23 | this.bind = function(callback){ 24 | _udp.bind(this.socketId, this.localAddress, this.localPort, callback); 25 | }.bind(this), 26 | 27 | this.close = function(callback){ 28 | _udp.close(this.socketId, callback); 29 | }.bind(this), 30 | 31 | this.send = function(address, port, data, callback){ 32 | _udp.send(this.socketId, data, address, port, callback); 33 | }.bind(this), 34 | 35 | this.receive = function(info){ 36 | console.log('Received data from '+info.removeAddress+':'+info.removePort); 37 | }, 38 | 39 | this.error = function(code){ 40 | console.log('An error occurred with code '+code); 41 | }, 42 | 43 | this.joinGroup = function(address, callback){ 44 | _udp.joinGroup(this.socketId, address, function(code){ 45 | if(code<0){ 46 | this.error(code); 47 | return false; 48 | } 49 | else{ 50 | callback(); 51 | } 52 | }.bind(this)); 53 | }.bind(this), 54 | 55 | this.leaveGroup = function(address, callback){ 56 | _udp.leaveGroup(this.socketId, address, function(code){ 57 | if(code<0){ 58 | this.error(code); 59 | return false; 60 | } 61 | else{ 62 | callback(); 63 | } 64 | }.bind(this)); 65 | }.bind(this), 66 | 67 | this.setMilticastTTL = function(ttl, callback){ 68 | _udp.setMulticastTimeToLive(this.socketId, ttl, function(code){ 69 | if(code<0){ 70 | this.error(code); 71 | return false; 72 | } 73 | else{ 74 | callback(); 75 | } 76 | }.bind(this)); 77 | }.bind(this), 78 | 79 | this.setMilticastLoopback = function(enabled, callback){ 80 | _udp.setMulticastLoopbackMode(this.sockedId, enabled, function(code){ 81 | if(code<0){ 82 | this.error(code); 83 | return false; 84 | } 85 | else{ 86 | callback(); 87 | } 88 | }.bind(this)); 89 | }.bind(this), 90 | 91 | this.getInfo = function(callback){ 92 | _udp.getInfo(this.socketId, callback); 93 | }.bind(this), 94 | 95 | this.getSockets = function(callback){ 96 | _udp.getSockets (callback); 97 | }.bind(this), 98 | 99 | this.getGroups = function(callback){ 100 | _udp.getJoinedGroups(this.socketId, callback); 101 | }.bind(this), 102 | 103 | this.init = function(callback){ 104 | this.create(function(){ 105 | this.bind(function(code){ 106 | if(code<0){ 107 | this.error(code); 108 | return false; 109 | } 110 | else{ 111 | callback(); 112 | } 113 | }.bind(this)); 114 | _udp.onReceive.addListener(function(info){ 115 | if(info.socketId==this.socketId){ 116 | this.receive(info); 117 | } 118 | }.bind(this)); 119 | _udp.onReceiveError.addListener(function(info){ 120 | if(info.socketId==this.socketId){ 121 | this.error(info.resultCode); 122 | } 123 | }); 124 | }.bind(this)); 125 | }.bind(this) 126 | } -------------------------------------------------------------------------------- /media_manager/main.js: -------------------------------------------------------------------------------- 1 | var imgFormats = ['png', 'bmp', 'jpeg', 'jpg', 'gif', 'png', 'svg', 'xbm', 'webp']; 2 | var audFormats = ['wav', 'mp3']; 3 | var vidFormats = ['3gp', '3gpp', 'avi', 'flv', 'mov', 'mpeg', 'mpeg4', 'mp4', 'ogg', 'webm', 'wmv']; 4 | var searching = false; 5 | var scanning = false; 6 | 7 | document.getElementById('edit').onclick = function(){ 8 | chrome.mediaGalleries.getMediaFileSystems({ 9 | interactive: 'yes' 10 | }, listMediaGalleries); 11 | } 12 | 13 | document.getElementById('scan').onclick = function(){ 14 | scanning? 15 | chrome.mediaGalleries.startMediaScan&&chrome.mediaGalleries.startMediaScan(): 16 | chrome.mediaGalleries.cancelMediaScan&&chrome.mediaGalleries.cancelMediaScan(); 17 | } 18 | 19 | document.getElementById('error').onclick = function(){ 20 | this.style.display = 'none'; 21 | } 22 | 23 | document.getElementById('home').onclick = function(){ 24 | searching = false; 25 | document.getElementById('subpath').innerHTML = ''; 26 | getMedia(); 27 | } 28 | 29 | chrome.mediaGalleries.onScanProgress&&chrome.mediaGalleries.onScanProgress.addListener(function(details){ 30 | switch(details.type){ 31 | case 'start': 32 | scanning = true; 33 | document.getElementById('loading').style.display = 'block'; 34 | break; 35 | case 'cancel': 36 | scanning = false; 37 | document.getElementById('loading').style.display = 'none'; 38 | break; 39 | case 'finish': 40 | scanning = false; 41 | document.getElementById('loading').style.display = 'none'; 42 | chrome.mediaGalleries.addScanResults(listMediaGalleries); 43 | break; 44 | case 'error': 45 | scanning = false; 46 | document.getElementById('loading').style.display = 'none'; 47 | document.getElementById('error').style.display = 'block'; 48 | break; 49 | } 50 | }); 51 | 52 | function getMedia(){ 53 | chrome.mediaGalleries.getMediaFileSystems({ 54 | interactive: 'if_needed' 55 | }, listMediaGalleries); 56 | } 57 | 58 | function listMediaGalleries(fileSystemArray){ 59 | document.getElementById('container').innerHTML = ''; 60 | for(var i=0; i=0?'image':(vidFormats.indexOf(ext)>=0?'video':(audFormats.indexOf(ext)>=0?'music':null))); 91 | if(!type){ 92 | continue; 93 | } 94 | var item = document.createElement('span'); 95 | item.className = 'item'; 96 | item.title = Entries[i].name; 97 | item.onclick = (function(Entry){ 98 | 99 | })(Entries[i]); 100 | document.getElementById('container').appendChild(item); 101 | var icon = document.createElement('span'); 102 | icon.className = 'icon'; 103 | icon.innerHTML = (type=='image'?'󰄷':(type=='video'?'󰅢':'󰀶')); 104 | item.appendChild(icon); 105 | var text = document.createElement('span'); 106 | text.className = 'text'; 107 | text.innerHTML = Entries[i].name; 108 | item.appendChild(text); 109 | } 110 | else if(Entries[i].isDirectory){ 111 | var dirReader = Entries[i].createReader(); 112 | dirReader.readEntries(listMedia); 113 | } 114 | } 115 | } 116 | 117 | function showMedia(Entry, path){ 118 | document.getElementById('container').innerHTML = ''; 119 | document.getElementById('subpath').innerHTML = ''+path+'»'; 120 | var dirReader = Entry.createReader(); 121 | dirReader.readEntries(listMedia); 122 | } 123 | 124 | getMedia(); -------------------------------------------------------------------------------- /performance monitor/main.js: -------------------------------------------------------------------------------- 1 | function getCpuUsage(callback){ 2 | chrome.system.cpu.getInfo(function(info){ 3 | var total = 0; 4 | var user = 0; 5 | var kernel = 0; 6 | for(var i=0; i=1) return t; 86 | return -1 * (Math.sqrt(1 - (t/=1)*t) - 1); 87 | }, 88 | easeOutCirc: function (t) { 89 | return 1 * Math.sqrt(1 - (t=t/1-1)*t); 90 | }, 91 | easeInOutCirc: function (t) { 92 | if ((t/=1/2) < 1) return -1/2 * (Math.sqrt(1 - t*t) - 1); 93 | return 1/2 * (Math.sqrt(1 - (t-=2)*t) + 1); 94 | }, 95 | easeInElastic: function (t) { 96 | var s=1.70158;var p=0;var a=1; 97 | if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3; 98 | if (a < Math.abs(1)) { a=1; var s=p/4; } 99 | else var s = p/(2*Math.PI) * Math.asin (1/a); 100 | return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )); 101 | }, 102 | easeOutElastic: function (t) { 103 | var s=1.70158;var p=0;var a=1; 104 | if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3; 105 | if (a < Math.abs(1)) { a=1; var s=p/4; } 106 | else var s = p/(2*Math.PI) * Math.asin (1/a); 107 | return a*Math.pow(2,-10*t) * Math.sin( (t*1-s)*(2*Math.PI)/p ) + 1; 108 | }, 109 | easeInOutElastic: function (t) { 110 | var s=1.70158;var p=0;var a=1; 111 | if (t==0) return 0; if ((t/=1/2)==2) return 1; if (!p) p=1*(.3*1.5); 112 | if (a < Math.abs(1)) { a=1; var s=p/4; } 113 | else var s = p/(2*Math.PI) * Math.asin (1/a); 114 | if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )); 115 | return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )*.5 + 1; 116 | }, 117 | easeInBack: function (t) { 118 | var s = 1.70158; 119 | return 1*(t/=1)*t*((s+1)*t - s); 120 | }, 121 | easeOutBack: function (t) { 122 | var s = 1.70158; 123 | return 1*((t=t/1-1)*t*((s+1)*t + s) + 1); 124 | }, 125 | easeInOutBack: function (t) { 126 | var s = 1.70158; 127 | if ((t/=1/2) < 1) return 1/2*(t*t*(((s*=(1.525))+1)*t - s)); 128 | return 1/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2); 129 | }, 130 | easeInBounce: function (t) { 131 | return 1 - animationOptions.easeOutBounce (1-t); 132 | }, 133 | easeOutBounce: function (t) { 134 | if ((t/=1) < (1/2.75)) { 135 | return 1*(7.5625*t*t); 136 | } else if (t < (2/2.75)) { 137 | return 1*(7.5625*(t-=(1.5/2.75))*t + .75); 138 | } else if (t < (2.5/2.75)) { 139 | return 1*(7.5625*(t-=(2.25/2.75))*t + .9375); 140 | } else { 141 | return 1*(7.5625*(t-=(2.625/2.75))*t + .984375); 142 | } 143 | }, 144 | easeInOutBounce: function (t) { 145 | if (t < 1/2) return animationOptions.easeInBounce (t*2) * .5; 146 | return animationOptions.easeOutBounce (t*2-1) * .5 + 1*.5; 147 | } 148 | }; 149 | 150 | //Variables global to the chart 151 | var width = context.canvas.width; 152 | var height = context.canvas.height; 153 | 154 | 155 | //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale. 156 | if (window.devicePixelRatio) { 157 | context.canvas.style.width = width + "px"; 158 | context.canvas.style.height = height + "px"; 159 | context.canvas.height = height * window.devicePixelRatio; 160 | context.canvas.width = width * window.devicePixelRatio; 161 | context.scale(window.devicePixelRatio, window.devicePixelRatio); 162 | } 163 | 164 | this.PolarArea = function(data,options){ 165 | 166 | chart.PolarArea.defaults = { 167 | scaleOverlay : true, 168 | scaleOverride : false, 169 | scaleSteps : null, 170 | scaleStepWidth : null, 171 | scaleStartValue : null, 172 | scaleShowLine : true, 173 | scaleLineColor : "rgba(0,0,0,.1)", 174 | scaleLineWidth : 1, 175 | scaleShowLabels : true, 176 | scaleLabel : "<%=value%>", 177 | scaleFontFamily : "'Arial'", 178 | scaleFontSize : 12, 179 | scaleFontStyle : "normal", 180 | scaleFontColor : "#666", 181 | scaleShowLabelBackdrop : true, 182 | scaleBackdropColor : "rgba(255,255,255,0.75)", 183 | scaleBackdropPaddingY : 2, 184 | scaleBackdropPaddingX : 2, 185 | segmentShowStroke : true, 186 | segmentStrokeColor : "#fff", 187 | segmentStrokeWidth : 2, 188 | animation : true, 189 | animationSteps : 100, 190 | animationEasing : "easeOutBounce", 191 | animateRotate : true, 192 | animateScale : false, 193 | onAnimationComplete : null 194 | }; 195 | 196 | var config = (options)? mergeChartConfig(chart.PolarArea.defaults,options) : chart.PolarArea.defaults; 197 | 198 | return new PolarArea(data,config,context); 199 | }; 200 | 201 | this.Radar = function(data,options){ 202 | 203 | chart.Radar.defaults = { 204 | scaleOverlay : false, 205 | scaleOverride : false, 206 | scaleSteps : null, 207 | scaleStepWidth : null, 208 | scaleStartValue : null, 209 | scaleShowLine : true, 210 | scaleLineColor : "rgba(0,0,0,.1)", 211 | scaleLineWidth : 1, 212 | scaleShowLabels : false, 213 | scaleLabel : "<%=value%>", 214 | scaleFontFamily : "'Arial'", 215 | scaleFontSize : 12, 216 | scaleFontStyle : "normal", 217 | scaleFontColor : "#666", 218 | scaleShowLabelBackdrop : true, 219 | scaleBackdropColor : "rgba(255,255,255,0.75)", 220 | scaleBackdropPaddingY : 2, 221 | scaleBackdropPaddingX : 2, 222 | angleShowLineOut : true, 223 | angleLineColor : "rgba(0,0,0,.1)", 224 | angleLineWidth : 1, 225 | pointLabelFontFamily : "'Arial'", 226 | pointLabelFontStyle : "normal", 227 | pointLabelFontSize : 12, 228 | pointLabelFontColor : "#666", 229 | pointDot : true, 230 | pointDotRadius : 3, 231 | pointDotStrokeWidth : 1, 232 | datasetStroke : true, 233 | datasetStrokeWidth : 2, 234 | datasetFill : true, 235 | animation : true, 236 | animationSteps : 60, 237 | animationEasing : "easeOutQuart", 238 | onAnimationComplete : null 239 | }; 240 | 241 | var config = (options)? mergeChartConfig(chart.Radar.defaults,options) : chart.Radar.defaults; 242 | 243 | return new Radar(data,config,context); 244 | }; 245 | 246 | this.Pie = function(data,options){ 247 | chart.Pie.defaults = { 248 | segmentShowStroke : true, 249 | segmentStrokeColor : "#fff", 250 | segmentStrokeWidth : 2, 251 | animation : true, 252 | animationSteps : 100, 253 | animationEasing : "easeOutBounce", 254 | animateRotate : true, 255 | animateScale : false, 256 | onAnimationComplete : null 257 | }; 258 | 259 | var config = (options)? mergeChartConfig(chart.Pie.defaults,options) : chart.Pie.defaults; 260 | 261 | return new Pie(data,config,context); 262 | }; 263 | 264 | this.Doughnut = function(data,options){ 265 | 266 | chart.Doughnut.defaults = { 267 | segmentShowStroke : true, 268 | segmentStrokeColor : "#fff", 269 | segmentStrokeWidth : 2, 270 | percentageInnerCutout : 50, 271 | animation : true, 272 | animationSteps : 100, 273 | animationEasing : "easeOutBounce", 274 | animateRotate : true, 275 | animateScale : false, 276 | onAnimationComplete : null 277 | }; 278 | 279 | var config = (options)? mergeChartConfig(chart.Doughnut.defaults,options) : chart.Doughnut.defaults; 280 | 281 | return new Doughnut(data,config,context); 282 | 283 | }; 284 | 285 | this.Line = function(data,options){ 286 | 287 | chart.Line.defaults = { 288 | scaleOverlay : false, 289 | scaleOverride : false, 290 | scaleSteps : null, 291 | scaleStepWidth : null, 292 | scaleStartValue : null, 293 | scaleLineColor : "rgba(0,0,0,.1)", 294 | scaleLineWidth : 1, 295 | scaleShowLabels : true, 296 | scaleLabel : "<%=value%>", 297 | scaleFontFamily : "'Arial'", 298 | scaleFontSize : 12, 299 | scaleFontStyle : "normal", 300 | scaleFontColor : "#666", 301 | scaleShowGridLines : true, 302 | scaleGridLineColor : "rgba(0,0,0,.05)", 303 | scaleGridLineWidth : 1, 304 | bezierCurve : true, 305 | pointDot : true, 306 | pointDotRadius : 4, 307 | pointDotStrokeWidth : 2, 308 | datasetStroke : true, 309 | datasetStrokeWidth : 2, 310 | datasetFill : true, 311 | animation : true, 312 | animationSteps : 60, 313 | animationEasing : "easeOutQuart", 314 | onAnimationComplete : null 315 | }; 316 | var config = (options) ? mergeChartConfig(chart.Line.defaults,options) : chart.Line.defaults; 317 | 318 | return new Line(data,config,context); 319 | } 320 | 321 | this.Bar = function(data,options){ 322 | chart.Bar.defaults = { 323 | scaleOverlay : false, 324 | scaleOverride : false, 325 | scaleSteps : null, 326 | scaleStepWidth : null, 327 | scaleStartValue : null, 328 | scaleLineColor : "rgba(0,0,0,.1)", 329 | scaleLineWidth : 1, 330 | scaleShowLabels : true, 331 | scaleLabel : "<%=value%>", 332 | scaleFontFamily : "'Arial'", 333 | scaleFontSize : 12, 334 | scaleFontStyle : "normal", 335 | scaleFontColor : "#666", 336 | scaleShowGridLines : true, 337 | scaleGridLineColor : "rgba(0,0,0,.05)", 338 | scaleGridLineWidth : 1, 339 | barShowStroke : true, 340 | barStrokeWidth : 2, 341 | barValueSpacing : 5, 342 | barDatasetSpacing : 1, 343 | animation : true, 344 | animationSteps : 60, 345 | animationEasing : "easeOutQuart", 346 | onAnimationComplete : null 347 | }; 348 | var config = (options) ? mergeChartConfig(chart.Bar.defaults,options) : chart.Bar.defaults; 349 | 350 | return new Bar(data,config,context); 351 | } 352 | 353 | var clear = function(c){ 354 | c.clearRect(0, 0, width, height); 355 | }; 356 | 357 | var PolarArea = function(data,config,ctx){ 358 | var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString; 359 | 360 | 361 | calculateDrawingSizes(); 362 | 363 | valueBounds = getValueBounds(); 364 | 365 | labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null; 366 | 367 | //Check and set the scale 368 | if (!config.scaleOverride){ 369 | 370 | calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString); 371 | } 372 | else { 373 | calculatedScale = { 374 | steps : config.scaleSteps, 375 | stepValue : config.scaleStepWidth, 376 | graphMin : config.scaleStartValue, 377 | labels : [] 378 | } 379 | populateLabels(labelTemplateString, calculatedScale.labels,calculatedScale.steps,config.scaleStartValue,config.scaleStepWidth); 380 | } 381 | 382 | scaleHop = maxSize/(calculatedScale.steps); 383 | 384 | //Wrap in an animation loop wrapper 385 | animationLoop(config,drawScale,drawAllSegments,ctx); 386 | 387 | function calculateDrawingSizes(){ 388 | maxSize = (Min([width,height])/2); 389 | //Remove whatever is larger - the font size or line width. 390 | 391 | maxSize -= Max([config.scaleFontSize*0.5,config.scaleLineWidth*0.5]); 392 | 393 | labelHeight = config.scaleFontSize*2; 394 | //If we're drawing the backdrop - add the Y padding to the label height and remove from drawing region. 395 | if (config.scaleShowLabelBackdrop){ 396 | labelHeight += (2 * config.scaleBackdropPaddingY); 397 | maxSize -= config.scaleBackdropPaddingY*1.5; 398 | } 399 | 400 | scaleHeight = maxSize; 401 | //If the label height is less than 5, set it to 5 so we don't have lines on top of each other. 402 | labelHeight = Default(labelHeight,5); 403 | } 404 | function drawScale(){ 405 | for (var i=0; i upperValue) {upperValue = data[i].value;} 474 | if (data[i].value < lowerValue) {lowerValue = data[i].value;} 475 | }; 476 | 477 | var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); 478 | var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); 479 | 480 | return { 481 | maxValue : upperValue, 482 | minValue : lowerValue, 483 | maxSteps : maxSteps, 484 | minSteps : minSteps 485 | }; 486 | 487 | 488 | } 489 | } 490 | 491 | var Radar = function (data,config,ctx) { 492 | var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString; 493 | 494 | //If no labels are defined set to an empty array, so referencing length for looping doesn't blow up. 495 | if (!data.labels) data.labels = []; 496 | 497 | calculateDrawingSizes(); 498 | 499 | var valueBounds = getValueBounds(); 500 | 501 | labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null; 502 | 503 | //Check and set the scale 504 | if (!config.scaleOverride){ 505 | 506 | calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString); 507 | } 508 | else { 509 | calculatedScale = { 510 | steps : config.scaleSteps, 511 | stepValue : config.scaleStepWidth, 512 | graphMin : config.scaleStartValue, 513 | labels : [] 514 | } 515 | populateLabels(labelTemplateString, calculatedScale.labels,calculatedScale.steps,config.scaleStartValue,config.scaleStepWidth); 516 | } 517 | 518 | scaleHop = maxSize/(calculatedScale.steps); 519 | 520 | animationLoop(config,drawScale,drawAllDataPoints,ctx); 521 | 522 | //Radar specific functions. 523 | function drawAllDataPoints(animationDecimal){ 524 | var rotationDegree = (2*Math.PI)/data.datasets[0].data.length; 525 | 526 | ctx.save(); 527 | //translate to the centre of the canvas. 528 | ctx.translate(width/2,height/2); 529 | 530 | //We accept multiple data sets for radar charts, so show loop through each set 531 | for (var i=0; i Math.PI){ 636 | ctx.textAlign = "right"; 637 | } 638 | else{ 639 | ctx.textAlign = "left"; 640 | } 641 | 642 | ctx.textBaseline = "middle"; 643 | 644 | ctx.fillText(data.labels[k],opposite,-adjacent); 645 | 646 | } 647 | ctx.restore(); 648 | }; 649 | function calculateDrawingSizes(){ 650 | maxSize = (Min([width,height])/2); 651 | 652 | labelHeight = config.scaleFontSize*2; 653 | 654 | var labelLength = 0; 655 | for (var i=0; ilabelLength) labelLength = textMeasurement; 659 | } 660 | 661 | //Figure out whats the largest - the height of the text or the width of what's there, and minus it from the maximum usable size. 662 | maxSize -= Max([labelLength,((config.pointLabelFontSize/2)*1.5)]); 663 | 664 | maxSize -= config.pointLabelFontSize; 665 | maxSize = CapValue(maxSize, null, 0); 666 | scaleHeight = maxSize; 667 | //If the label height is less than 5, set it to 5 so we don't have lines on top of each other. 668 | labelHeight = Default(labelHeight,5); 669 | }; 670 | function getValueBounds() { 671 | var upperValue = Number.MIN_VALUE; 672 | var lowerValue = Number.MAX_VALUE; 673 | 674 | for (var i=0; i upperValue){upperValue = data.datasets[i].data[j]} 677 | if (data.datasets[i].data[j] < lowerValue){lowerValue = data.datasets[i].data[j]} 678 | } 679 | } 680 | 681 | var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); 682 | var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); 683 | 684 | return { 685 | maxValue : upperValue, 686 | minValue : lowerValue, 687 | maxSteps : maxSteps, 688 | minSteps : minSteps 689 | }; 690 | 691 | 692 | } 693 | } 694 | 695 | var Pie = function(data,config,ctx){ 696 | var segmentTotal = 0; 697 | 698 | //In case we have a canvas that is not a square. Minus 5 pixels as padding round the edge. 699 | var pieRadius = Min([height/2,width/2]) - 5; 700 | 701 | for (var i=0; i 0){ 872 | ctx.save(); 873 | ctx.textAlign = "right"; 874 | } 875 | else{ 876 | ctx.textAlign = "center"; 877 | } 878 | ctx.fillStyle = config.scaleFontColor; 879 | for (var i=0; i 0){ 882 | ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize); 883 | ctx.rotate(-(rotateLabels * (Math.PI/180))); 884 | ctx.fillText(data.labels[i], 0,0); 885 | ctx.restore(); 886 | } 887 | 888 | else{ 889 | ctx.fillText(data.labels[i], yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize+3); 890 | } 891 | 892 | ctx.beginPath(); 893 | ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY+3); 894 | 895 | //Check i isnt 0, so we dont go over the Y axis twice. 896 | if(config.scaleShowGridLines && i>0){ 897 | ctx.lineWidth = config.scaleGridLineWidth; 898 | ctx.strokeStyle = config.scaleGridLineColor; 899 | ctx.lineTo(yAxisPosX + i * valueHop, 5); 900 | } 901 | else{ 902 | ctx.lineTo(yAxisPosX + i * valueHop, xAxisPosY+3); 903 | } 904 | ctx.stroke(); 905 | } 906 | 907 | //Y axis 908 | ctx.lineWidth = config.scaleLineWidth; 909 | ctx.strokeStyle = config.scaleLineColor; 910 | ctx.beginPath(); 911 | ctx.moveTo(yAxisPosX,xAxisPosY+5); 912 | ctx.lineTo(yAxisPosX,5); 913 | ctx.stroke(); 914 | 915 | ctx.textAlign = "right"; 916 | ctx.textBaseline = "middle"; 917 | for (var j=0; j longestText)? measuredText : longestText; 946 | } 947 | //Add a little extra padding from the y axis 948 | longestText +=10; 949 | } 950 | xAxisLength = width - longestText - widestXLabel; 951 | valueHop = Math.floor(xAxisLength/(data.labels.length-1)); 952 | 953 | yAxisPosX = width-widestXLabel/2-xAxisLength; 954 | xAxisPosY = scaleHeight + config.scaleFontSize/2; 955 | } 956 | function calculateDrawingSizes(){ 957 | maxSize = height; 958 | 959 | //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees. 960 | ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily; 961 | widestXLabel = 1; 962 | for (var i=0; i widestXLabel)? textLength : widestXLabel; 966 | } 967 | if (width/data.labels.length < widestXLabel){ 968 | rotateLabels = 45; 969 | if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){ 970 | rotateLabels = 90; 971 | maxSize -= widestXLabel; 972 | } 973 | else{ 974 | maxSize -= Math.sin(rotateLabels) * widestXLabel; 975 | } 976 | } 977 | else{ 978 | maxSize -= config.scaleFontSize; 979 | } 980 | 981 | //Add a little padding between the x line and the text 982 | maxSize -= 5; 983 | 984 | 985 | labelHeight = config.scaleFontSize; 986 | 987 | maxSize -= labelHeight; 988 | //Set 5 pixels greater than the font size to allow for a little padding from the X axis. 989 | 990 | scaleHeight = maxSize; 991 | 992 | //Then get the area above we can safely draw on. 993 | 994 | } 995 | function getValueBounds() { 996 | var upperValue = Number.MIN_VALUE; 997 | var lowerValue = Number.MAX_VALUE; 998 | for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] }; 1001 | if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] }; 1002 | } 1003 | }; 1004 | 1005 | var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); 1006 | var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); 1007 | 1008 | return { 1009 | maxValue : upperValue, 1010 | minValue : lowerValue, 1011 | maxSteps : maxSteps, 1012 | minSteps : minSteps 1013 | }; 1014 | 1015 | 1016 | } 1017 | 1018 | 1019 | } 1020 | 1021 | var Bar = function(data,config,ctx){ 1022 | var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString, valueHop,widestXLabel, xAxisLength,yAxisPosX,xAxisPosY,barWidth, rotateLabels = 0; 1023 | 1024 | calculateDrawingSizes(); 1025 | 1026 | valueBounds = getValueBounds(); 1027 | //Check and set the scale 1028 | labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : ""; 1029 | if (!config.scaleOverride){ 1030 | 1031 | calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString); 1032 | } 1033 | else { 1034 | calculatedScale = { 1035 | steps : config.scaleSteps, 1036 | stepValue : config.scaleStepWidth, 1037 | graphMin : config.scaleStartValue, 1038 | labels : [] 1039 | } 1040 | populateLabels(labelTemplateString, calculatedScale.labels,calculatedScale.steps,config.scaleStartValue,config.scaleStepWidth); 1041 | } 1042 | 1043 | scaleHop = Math.floor(scaleHeight/calculatedScale.steps); 1044 | calculateXAxisSize(); 1045 | animationLoop(config,drawScale,drawBars,ctx); 1046 | 1047 | function drawBars(animPc){ 1048 | ctx.lineWidth = config.barStrokeWidth; 1049 | for (var i=0; i 0){ 1080 | ctx.save(); 1081 | ctx.textAlign = "right"; 1082 | } 1083 | else{ 1084 | ctx.textAlign = "center"; 1085 | } 1086 | ctx.fillStyle = config.scaleFontColor; 1087 | for (var i=0; i 0){ 1090 | ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize); 1091 | ctx.rotate(-(rotateLabels * (Math.PI/180))); 1092 | ctx.fillText(data.labels[i], 0,0); 1093 | ctx.restore(); 1094 | } 1095 | 1096 | else{ 1097 | ctx.fillText(data.labels[i], yAxisPosX + i*valueHop + valueHop/2,xAxisPosY + config.scaleFontSize+3); 1098 | } 1099 | 1100 | ctx.beginPath(); 1101 | ctx.moveTo(yAxisPosX + (i+1) * valueHop, xAxisPosY+3); 1102 | 1103 | //Check i isnt 0, so we dont go over the Y axis twice. 1104 | ctx.lineWidth = config.scaleGridLineWidth; 1105 | ctx.strokeStyle = config.scaleGridLineColor; 1106 | ctx.lineTo(yAxisPosX + (i+1) * valueHop, 5); 1107 | ctx.stroke(); 1108 | } 1109 | 1110 | //Y axis 1111 | ctx.lineWidth = config.scaleLineWidth; 1112 | ctx.strokeStyle = config.scaleLineColor; 1113 | ctx.beginPath(); 1114 | ctx.moveTo(yAxisPosX,xAxisPosY+5); 1115 | ctx.lineTo(yAxisPosX,5); 1116 | ctx.stroke(); 1117 | 1118 | ctx.textAlign = "right"; 1119 | ctx.textBaseline = "middle"; 1120 | for (var j=0; j longestText)? measuredText : longestText; 1148 | } 1149 | //Add a little extra padding from the y axis 1150 | longestText +=10; 1151 | } 1152 | xAxisLength = width - longestText - widestXLabel; 1153 | valueHop = Math.floor(xAxisLength/(data.labels.length)); 1154 | 1155 | barWidth = (valueHop - config.scaleGridLineWidth*2 - (config.barValueSpacing*2) - (config.barDatasetSpacing*data.datasets.length-1) - ((config.barStrokeWidth/2)*data.datasets.length-1))/data.datasets.length; 1156 | 1157 | yAxisPosX = width-widestXLabel/2-xAxisLength; 1158 | xAxisPosY = scaleHeight + config.scaleFontSize/2; 1159 | } 1160 | function calculateDrawingSizes(){ 1161 | maxSize = height; 1162 | 1163 | //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees. 1164 | ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily; 1165 | widestXLabel = 1; 1166 | for (var i=0; i widestXLabel)? textLength : widestXLabel; 1170 | } 1171 | if (width/data.labels.length < widestXLabel){ 1172 | rotateLabels = 45; 1173 | if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){ 1174 | rotateLabels = 90; 1175 | maxSize -= widestXLabel; 1176 | } 1177 | else{ 1178 | maxSize -= Math.sin(rotateLabels) * widestXLabel; 1179 | } 1180 | } 1181 | else{ 1182 | maxSize -= config.scaleFontSize; 1183 | } 1184 | 1185 | //Add a little padding between the x line and the text 1186 | maxSize -= 5; 1187 | 1188 | 1189 | labelHeight = config.scaleFontSize; 1190 | 1191 | maxSize -= labelHeight; 1192 | //Set 5 pixels greater than the font size to allow for a little padding from the X axis. 1193 | 1194 | scaleHeight = maxSize; 1195 | 1196 | //Then get the area above we can safely draw on. 1197 | 1198 | } 1199 | function getValueBounds() { 1200 | var upperValue = Number.MIN_VALUE; 1201 | var lowerValue = Number.MAX_VALUE; 1202 | for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] }; 1205 | if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] }; 1206 | } 1207 | }; 1208 | 1209 | var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); 1210 | var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); 1211 | 1212 | return { 1213 | maxValue : upperValue, 1214 | minValue : lowerValue, 1215 | maxSteps : maxSteps, 1216 | minSteps : minSteps 1217 | }; 1218 | 1219 | 1220 | } 1221 | } 1222 | 1223 | function calculateOffset(val,calculatedScale,scaleHop){ 1224 | var outerValue = calculatedScale.steps * calculatedScale.stepValue; 1225 | var adjustedValue = val - calculatedScale.graphMin; 1226 | var scalingFactor = CapValue(adjustedValue/outerValue,1,0); 1227 | return (scaleHop*calculatedScale.steps) * scalingFactor; 1228 | } 1229 | 1230 | function animationLoop(config,drawScale,drawData,ctx){ 1231 | var animFrameAmount = (config.animation)? 1/CapValue(config.animationSteps,Number.MAX_VALUE,1) : 1, 1232 | easingFunction = animationOptions[config.animationEasing], 1233 | percentAnimComplete =(config.animation)? 0 : 1; 1234 | 1235 | 1236 | 1237 | if (typeof drawScale !== "function") drawScale = function(){}; 1238 | 1239 | requestAnimFrame(animLoop); 1240 | 1241 | function animateFrame(){ 1242 | var easeAdjustedAnimationPercent =(config.animation)? CapValue(easingFunction(percentAnimComplete),null,0) : 1; 1243 | clear(ctx); 1244 | if(config.scaleOverlay){ 1245 | drawData(easeAdjustedAnimationPercent); 1246 | drawScale(); 1247 | } else { 1248 | drawScale(); 1249 | drawData(easeAdjustedAnimationPercent); 1250 | } 1251 | } 1252 | function animLoop(){ 1253 | //We need to check if the animation is incomplete (less than 1), or complete (1). 1254 | percentAnimComplete += animFrameAmount; 1255 | animateFrame(); 1256 | //Stop the loop continuing forever 1257 | if (percentAnimComplete <= 1){ 1258 | requestAnimFrame(animLoop); 1259 | } 1260 | else{ 1261 | if (typeof config.onAnimationComplete == "function") config.onAnimationComplete(); 1262 | } 1263 | 1264 | } 1265 | 1266 | } 1267 | 1268 | //Declare global functions to be called within this namespace here. 1269 | 1270 | 1271 | // shim layer with setTimeout fallback 1272 | var requestAnimFrame = (function(){ 1273 | return window.requestAnimationFrame || 1274 | window.webkitRequestAnimationFrame || 1275 | window.mozRequestAnimationFrame || 1276 | window.oRequestAnimationFrame || 1277 | window.msRequestAnimationFrame || 1278 | function(callback) { 1279 | window.setTimeout(callback, 1000 / 60); 1280 | }; 1281 | })(); 1282 | 1283 | function calculateScale(drawingHeight,maxSteps,minSteps,maxValue,minValue,labelTemplateString){ 1284 | var graphMin,graphMax,graphRange,stepValue,numberOfSteps,valueRange,rangeOrderOfMagnitude,decimalNum; 1285 | 1286 | maxValue = 100, minValue = 0; 1287 | 1288 | valueRange = maxValue - minValue; 1289 | 1290 | rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange); 1291 | 1292 | graphMin = Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); 1293 | 1294 | graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); 1295 | 1296 | graphRange = graphMax - graphMin; 1297 | 1298 | stepValue = Math.pow(10, rangeOrderOfMagnitude); 1299 | 1300 | numberOfSteps = Math.round(graphRange / stepValue); 1301 | 1302 | //Compare number of steps to the max and min for that size graph, and add in half steps if need be. 1303 | while(numberOfSteps < minSteps || numberOfSteps > maxSteps) { 1304 | if (numberOfSteps < minSteps){ 1305 | stepValue /= 2; 1306 | numberOfSteps = Math.round(graphRange/stepValue); 1307 | } 1308 | else{ 1309 | stepValue *=2; 1310 | numberOfSteps = Math.round(graphRange/stepValue); 1311 | } 1312 | }; 1313 | 1314 | var labels = []; 1315 | populateLabels(labelTemplateString, labels, numberOfSteps, graphMin, stepValue); 1316 | 1317 | return { 1318 | steps : numberOfSteps, 1319 | stepValue : stepValue, 1320 | graphMin : graphMin, 1321 | labels : labels 1322 | 1323 | } 1324 | 1325 | function calculateOrderOfMagnitude(val){ 1326 | return Math.floor(Math.log(val) / Math.LN10); 1327 | } 1328 | 1329 | 1330 | } 1331 | 1332 | //Populate an array of all the labels by interpolating the string. 1333 | function populateLabels(labelTemplateString, labels, numberOfSteps, graphMin, stepValue) { 1334 | if (labelTemplateString) { 1335 | //Fix floating point errors by setting to fixed the on the same decimal as the stepValue. 1336 | for (var i = 1; i < numberOfSteps + 1; i++) { 1337 | labels.push(tmpl(labelTemplateString, {value: (graphMin + (stepValue * i)).toFixed(getDecimalPlaces(stepValue))})); 1338 | } 1339 | } 1340 | } 1341 | 1342 | //Max value from array 1343 | function Max( array ){ 1344 | return Math.max.apply( Math, array ); 1345 | }; 1346 | //Min value from array 1347 | function Min( array ){ 1348 | return Math.min.apply( Math, array ); 1349 | }; 1350 | //Default if undefined 1351 | function Default(userDeclared,valueIfFalse){ 1352 | if(!userDeclared){ 1353 | return valueIfFalse; 1354 | } else { 1355 | return userDeclared; 1356 | } 1357 | }; 1358 | //Is a number function 1359 | function isNumber(n) { 1360 | return !isNaN(parseFloat(n)) && isFinite(n); 1361 | } 1362 | //Apply cap a value at a high or low number 1363 | function CapValue(valueToCap, maxValue, minValue){ 1364 | if(isNumber(maxValue)) { 1365 | if( valueToCap > maxValue ) { 1366 | return maxValue; 1367 | } 1368 | } 1369 | if(isNumber(minValue)){ 1370 | if ( valueToCap < minValue ){ 1371 | return minValue; 1372 | } 1373 | } 1374 | return valueToCap; 1375 | } 1376 | function getDecimalPlaces (num){ 1377 | var numberOfDecimalPlaces; 1378 | if (num%1!=0){ 1379 | return num.toString().split(".")[1].length 1380 | } 1381 | else{ 1382 | return 0; 1383 | } 1384 | 1385 | } 1386 | 1387 | function mergeChartConfig(defaults,userDefined){ 1388 | var returnObj = {}; 1389 | for (var attrname in defaults) { returnObj[attrname] = defaults[attrname]; } 1390 | for (var attrname in userDefined) { returnObj[attrname] = userDefined[attrname]; } 1391 | return returnObj; 1392 | } 1393 | 1394 | //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/ 1395 | var cache = {}; 1396 | 1397 | function tmpl(str, data){ 1398 | return ' '; 1399 | // Figure out if we're getting a template, or if we need to 1400 | // load the template - and be sure to cache the result. 1401 | /* 1402 | var fn = !/\W/.test(str) ? 1403 | cache[str] = cache[str] || 1404 | tmpl(document.getElementById(str).innerHTML) : 1405 | 1406 | // Generate a reusable function that will serve as a template 1407 | // generator (and which will be cached). 1408 | new Function("obj", 1409 | "var p=[],print=function(){p.push.apply(p,arguments);};" + 1410 | 1411 | // Introduce the data as local variables using with(){} 1412 | "with(obj){p.push('" + 1413 | 1414 | // Convert the template into pure JavaScript 1415 | str 1416 | .replace(/[\r\t\n]/g, " ") 1417 | .split("<%").join("\t") 1418 | .replace(/((^|%>)[^\t]*)'/g, "$1\r") 1419 | .replace(/\t=(.*?)%>/g, "',$1,'") 1420 | .split("\t").join("');") 1421 | .split("%>").join("p.push('") 1422 | .split("\r").join("\\'") 1423 | + "');}return p.join('');"); 1424 | */ 1425 | 1426 | // Provide some basic currying to the user 1427 | //return data ? fn( data ) : fn; 1428 | }; 1429 | } 1430 | 1431 | 1432 | --------------------------------------------------------------------------------