1/** 2 * JustGage - a handy JavaScript plugin for generating and animating nice & clean dashboard gauges. 3 * Copyright (c) 2012 Bojan Djuricic - pindjur(at)gmail(dot)com | http://www.madcog.com 4 * Licensed under MIT. 5 * Date: 31/07/2012 6 * @author Bojan Djuricic (@Toorshia) 7 * @version 1.0 8 * 9 * http://www.justgage.com 10 */ 11 12JustGage = function(config) { 13 14 if (!config.id) {alert("Missing id parameter for gauge!"); return false;} 15 if (!document.getElementById(config.id)) {alert("No element with id: \""+config.id+"\" found!"); return false;} 16 17 // configurable parameters 18 this.config = 19 { 20 // id : string 21 // this is container element id 22 id : config.id, 23 24 // title : string 25 // gauge title 26 title : (config.title) ? config.title : "Title", 27 28 // titleFontColor : string 29 // color of gauge title 30 titleFontColor : (config.titleFontColor) ? config.titleFontColor : "#999999", 31 32 // value : int 33 // value gauge is showing 34 value : (config.value) ? config.value : 0, 35 36 // valueFontColor : string 37 // color of label showing current value 38 valueFontColor : (config.valueFontColor) ? config.valueFontColor : "#010101", 39 40 // min : int 41 // min value 42 min : (config.min) ? config.min : 0, 43 44 // max : int 45 // max value 46 max : (config.max) ? config.max : 100, 47 48 // showMinMax : bool 49 // hide or display min and max values 50 showMinMax : (config.showMinMax != null) ? config.showMinMax : true, 51 52 // gaugeWidthScale : float 53 // width of the gauge element 54 gaugeWidthScale : (config.gaugeWidthScale) ? config.gaugeWidthScale : 1.0, 55 56 // gaugeColor : string 57 // background color of gauge element 58 gaugeColor : (config.gaugeColor) ? config.gaugeColor : "#edebeb", 59 60 // label : string 61 // text to show below value 62 label : (config.label) ? config.label : "", 63 64 // showInnerShadow : bool 65 // give gauge element small amount of inner shadow 66 showInnerShadow : (config.showInnerShadow != null) ? config.showInnerShadow : true, 67 68 // shadowOpacity : int 69 // 0 ~ 1 70 shadowOpacity : (config.shadowOpacity) ? config.shadowOpacity : 0.2, 71 72 // shadowSize: int 73 // inner shadow size 74 shadowSize : (config.shadowSize) ? config.shadowSize : 5, 75 76 // shadowVerticalOffset : int 77 // how much shadow is offset from top 78 shadowVerticalOffset : (config.shadowVerticalOffset) ? config.shadowVerticalOffset : 3, 79 80 // levelColors : string[] 81 // colors of indicator, from lower to upper, in RGB format 82 levelColors : (config.levelColors) ? config.levelColors : percentColors, 83 84 // levelColorsGradient : bool 85 // whether to use gradual color change for value, or sector-based 86 levelColorsGradient : (config.levelColorsGradient != null) ? config.levelColorsGradient : true, 87 88 // labelFontColor : string 89 // color of label showing label under value 90 labelFontColor : (config.labelFontColor) ? config.labelFontColor : "#b3b3b3", 91 92 // startAnimationTime : int 93 // length of initial animation 94 startAnimationTime : (config.startAnimationTime) ? config.startAnimationTime : 700, 95 96 // startAnimationType : string 97 // type of initial animation (linear, >, <, <>, bounce) 98 startAnimationType : (config.startAnimationType) ? config.startAnimationType : ">", 99 100 // refreshAnimationTime : int 101 // length of refresh animation 102 refreshAnimationTime : (config.refreshAnimationTime) ? config.refreshAnimationTime : 700, 103 104 // refreshAnimationType : string 105 // type of refresh animation (linear, >, <, <>, bounce) 106 refreshAnimationType : (config.refreshAnimationType) ? config.refreshAnimationType : ">" 107 }; 108 109 // overflow values 110 if (config.value > this.config.max) this.config.value = this.config.max; 111 if (config.value < this.config.min) this.config.value = this.config.min; 112 this.originalValue = config.value; 113 114 // canvas 115 this.canvas = Raphael(this.config.id, "100%", "100%"); 116 117 // canvas dimensions 118 //var canvasW = document.getElementById(this.config.id).clientWidth; 119 //var canvasH = document.getElementById(this.config.id).clientHeight; 120 var canvasW = getStyle(document.getElementById(this.config.id), "width").slice(0, -2) * 1; 121 var canvasH = getStyle(document.getElementById(this.config.id), "height").slice(0, -2) * 1; 122 123 // widget dimensions 124 var widgetW, widgetH; 125 if ((canvasW / canvasH) > 1.25) { 126 widgetW = 1.25 * canvasH; 127 widgetH = canvasH; 128 } else { 129 widgetW = canvasW; 130 widgetH = canvasW / 1.25; 131 } 132 133 // delta 134 var dx = (canvasW - widgetW)/2; 135 var dy = (canvasH - widgetH)/2; 136 137 // title 138 var titleFontSize = ((widgetH / 8) > 10) ? (widgetH / 10) : 10; 139 var titleX = dx + widgetW / 2; 140 var titleY = dy + widgetH / 6.5; 141 142 // value 143 var valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 6.4) : 16; 144 var valueX = dx + widgetW / 2; 145 var valueY = dy + widgetH / 1.4; 146
147 // label 148 var labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10; 149 var labelX = dx + widgetW / 2; 150 //var labelY = dy + widgetH / 1.126760563380282; 151 var labelY = valueY + valueFontSize / 2 + 6; 152 153 // min 154 var minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10; 155 var minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2 ; 156 var minY = dy + widgetH / 1.126760563380282; 157 158 // max 159 var maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10; 160 var maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2 ; 161 var maxY = dy + widgetH / 1.126760563380282; 162 163 // parameters 164 this.params = { 165 canvasW : canvasW, 166 canvasH : canvasH, 167 widgetW : widgetW, 168 widgetH : widgetH, 169 dx : dx, 170 dy : dy, 171 titleFontSize : titleFontSize, 172 titleX : titleX, 173 titleY : titleY, 174 valueFontSize : valueFontSize, 175 valueX : valueX, 176 valueY : valueY, 177 labelFontSize : labelFontSize, 178 labelX : labelX, 179 labelY : labelY, 180 minFontSize : minFontSize, 181 minX : minX, 182 minY : minY, 183 maxFontSize : maxFontSize, 184 maxX : maxX, 185 maxY : maxY 186 }; 187 188 // pki - custom attribute for generating gauge paths 189 this.canvas.customAttributes.pki = function (value, min, max, w, h, dx, dy, gws) { 190 191 var alpha = (1 - (value - min) / (max - min)) * Math.PI , 192 Ro = w / 2 - w / 10, 193 Ri = Ro - w / 6.666666666666667 * gws, 194 195 Cx = w / 2 + dx, 196 Cy = h / 1.25 + dy, 197 198 Xo = w / 2 + dx + Ro * Math.cos(alpha), 199 Yo = h - (h - Cy) + dy - Ro * Math.sin(alpha), 200 Xi = w / 2 + dx + Ri * Math.cos(alpha), 201 Yi = h - (h - Cy) + dy - Ri * Math.sin(alpha), 202 path; 203 204 path += "M" + (Cx - Ri) + "," + Cy + " "; 205 path += "L" + (Cx - Ro) + "," + Cy + " "; 206 path += "A" + Ro + "," + Ro + " 0 0,1 " + Xo + "," + Yo + " "; 207 path += "L" + Xi + "," + Yi + " "; 208 path += "A" + Ri + "," + Ri + " 0 0,0 " + (Cx - Ri) + "," + Cy + " "; 209 path += "z "; 210 return { path: path }; 211 } 212 213 // gauge 214 this.gauge = this.canvas.path().attr({ 215 "stroke": "none", 216 "fill": this.config.gaugeColor, 217 pki: [this.config.max, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale] 218 }); 219 this.gauge.id = this.config.id+"-gauge"; 220 221 // level 222 this.level = this.canvas.path().attr({ 223 "stroke": "none", 224 "fill": getColorForPercentage((this.config.value - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient), 225 pki: [this.config.min, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale] 226 }); 227 this.level.id = this.config.id+"-level"; 228 229 // title 230 this.txtTitle = this.canvas.text(this.params.titleX, this.params.titleY, this.config.title); 231 this.txtTitle. attr({ 232 "font-size":this.params.titleFontSize, 233 "font-weight":"bold", 234 "font-family":"Arial", 235 "fill":this.config.titleFontColor, 236 "fill-opacity":"1" 237 }); 238 this.txtTitle.id = this.config.id+"-txttitle"; 239 240 // value 241 this.txtValue = this.canvas.text(this.params.valueX, this.params.valueY, this.originalValue); 242 this.txtValue. attr({ 243 "font-size":this.params.valueFontSize, 244 "font-weight":"bold", 245 "font-family":"Arial", 246 "fill":this.config.valueFontColor, 247 "fill-opacity":"0" 248 }); 249 this.txtValue.id = this.config.id+"-txtvalue"; 250 251 // label 252 this.txtLabel = this.canvas.text(this.params.labelX, this.params.labelY, this.config.label); 253 this.txtLabel. attr({ 254 "font-size":this.params.labelFontSize, 255 "font-weight":"normal", 256 "font-family":"Arial", 257 "fill":this.config.labelFontColor, 258 "fill-opacity":"0" 259 }); 260 this.txtLabel.id = this.config.id+"-txtlabel"; 261 262 // min 263 this.txtMin = this.canvas.text(this.params.minX, this.params.minY, this.config.min); 264 this.txtMin. attr({ 265 "font-size":this.params.minFontSize, 266 "font-weight":"normal", 267 "font-family":"Arial", 268 "fill":this.config.labelFontColor, 269 "fill-opacity": (this.config.showMinMax == true)? "1" : "0" 270 }); 271 this.txtMin.id = this.config.id+"-txtmin"; 272 273 // max 274 this.txtMax = this.canvas.text(this.params.maxX, this.params.maxY, this.config.max); 275 this.txtMax. attr({ 276 "font-size":this.params.maxFontSize, 277 "font-weight":"normal", 278 "font-family":"Arial", 279 "fill":this.config.labelFontColor, 280 "fill-opacity": (this.config.showMinMax == true)? "1" : "0" 281 }); 282 this.txtMax.id = this.config.id+"-txtmax"; 283 284 var defs = this.canvas.canvas.childNodes[1]; 285 var svg = "http://www.w3.org/2000/svg"; 286 287 288 289 if (ie < 9) { 290 onCreateElementNsReady(function() { 291 this.generateShadow(); 292 }); 293 } else { 294 this.generateShadow(svg, defs); 295 } 296 297 // animate 298 this.level.animate({pki: [this.config.value, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale]}, this.config.startAnimationTime, this.config.startAnimationType); 299 300 this.txtValue.animate({"fill-opacity":"1"}, this.config.startAnimationTime, this.config.startAnimationType); 301 this.txtLabel.animate({"fill-opacity":"1"}, this.config.startAnimationTime, this.config.startAnimationType); 302}; 303 304// refresh gauge level 305JustGage.prototype.refresh = function(val) { 306 // overflow values 307 originalVal = val; 308 if (val > this.config.max) {val = this.config.max;} 309 if (val < this.config.min) {val = this.config.min;} 310 311 var color = getColorForPercentage((val - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient); 312 this.canvas.getById(this.config.id+"-txtvalue").attr({"text":originalVal}); 313 this.canvas.getById(this.config.id+"-level").animate({pki: [val, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale], "fill":color}, this.config.refreshAnimationTime, this.config.refreshAnimationType); 314}; 315 316var percentColors = [ 317 "#a9d70b", 318 "#f9c802", 319 "#ff0000" 320] 321 322JustGage.prototype.generateShadow = function(svg, defs) { 323 // FILTER 324 var gaussFilter=document.createElementNS(svg,"filter"); 325 gaussFilter.setAttribute("id", this.config.id + "-inner-shadow"); 326 defs.appendChild(gaussFilter); 327 328 // offset 329 var feOffset = document.createElementNS(svg,"feOffset"); 330 feOffset.setAttribute("dx", 0); 331 feOffset.setAttribute("dy", this.config.shadowVerticalOffset); 332 gaussFilter.appendChild(feOffset); 333 334 // blur 335 var feGaussianBlur = document.createElementNS(svg,"feGaussianBlur"); 336 feGaussianBlur.setAttribute("result","offset-blur"); 337 feGaussianBlur.setAttribute("stdDeviation", this.config.shadowSize); 338 gaussFilter.appendChild(feGaussianBlur); 339 340 // composite 1 341 var feComposite1 = document.createElementNS(svg,"feComposite"); 342 feComposite1.setAttribute("operator","out"); 343 feComposite1.setAttribute("in", "SourceGraphic"); 344 feComposite1.setAttribute("in2","offset-blur"); 345 feComposite1.setAttribute("result","inverse"); 346 gaussFilter.appendChild(feComposite1); 347 348 // flood 349 var feFlood = document.createElementNS(svg,"feFlood"); 350 feFlood.setAttribute("flood-color","black"); 351 feFlood.setAttribute("flood-opacity", this.config.shadowOpacity); 352 feFlood.setAttribute("result","color"); 353 gaussFilter.appendChild(feFlood); 354 355 // composite 2 356 var feComposite2 = document.createElementNS(svg,"feComposite"); 357 feComposite2.setAttribute("operator","in"); 358 feComposite2.setAttribute("in", "color"); 359 feComposite2.setAttribute("in2","inverse"); 360 feComposite2.setAttribute("result","shadow"); 361 gaussFilter.appendChild(feComposite2); 362 363 // composite 3 364 var feComposite3 = document.createElementNS(svg,"feComposite"); 365 feComposite3.setAttribute("operator","over"); 366 feComposite3.setAttribute("in", "shadow"); 367 feComposite3.setAttribute("in2","SourceGraphic"); 368 gaussFilter.appendChild(feComposite3); 369 370 // set shadow 371 if (this.config.showInnerShadow == true) { 372 this.canvas.canvas.childNodes[2].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)"); 373 this.canvas.canvas.childNodes[3].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)"); 374 } 375} 376 377var getColorForPercentage = function(pct, col, grad) { 378 379 var no = col.length; 380 if (no === 1) return col[0]; 381 var inc = (grad) ? (1 / (no - 1)) : (1 / no); 382 var colors = new Array(); 383 for (var i = 0; i < col.length; i++) { 384 var percentage = (grad) ? (inc * i) : (inc * (i + 1)); 385 var rval = parseInt((cutHex(col[i])).substring(0,2),16); 386 var gval = parseInt((cutHex(col[i])).substring(2,4),16); 387 var bval = parseInt((cutHex(col[i])).substring(4,6),16); 388 colors[i] = { pct: percentage, color: { r: rval, g: gval, b: bval } }; 389 } 390 391 if(pct == 0) return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')'; 392 for (var i = 0; i < colors.length; i++) { 393 if (pct <= colors[i].pct) { 394 if (grad == true) { 395 var lower = colors[i - 1]; 396 var upper = colors[i]; 397 var range = upper.pct - lower.pct; 398 var rangePct = (pct - lower.pct) / range; 399 var pctLower = 1 - rangePct; 400 var pctUpper = rangePct; 401 var color = { 402 r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper), 403 g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper), 404 b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper) 405 }; 406 return 'rgb(' + [color.r, color.g, color.b].join(',') + ')'; 407 } else { 408 return 'rgb(' + [colors[i].color.r, colors[i].color.g, colors[i].color.b].join(',') + ')'; 409 } 410 } 411 } 412} 413 414function getRandomInt (min, max) { 415 return Math.floor(Math.random() * (max - min + 1)) + min; 416} 417 418function cutHex(str) {return (str.charAt(0)=="#") ? str.substring(1,7):str} 419 420function getStyle(oElm, strCssRule){ 421 var strValue = ""; 422 if(document.defaultView && document.defaultView.getComputedStyle){ 423 strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule); 424 } 425 else if(oElm.currentStyle){ 426 strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){ 427 return p1.toUpperCase(); 428 }); 429 strValue = oElm.currentStyle[strCssRule]; 430 } 431 return strValue; 432} 433 434 function onCreateElementNsReady(func) { 435 if (document.createElementNS != undefined) { 436 func(); 437 } else { 438 setTimeout(function() { onCreateElementNsReady(func); }, 100); 439 } 440} 441 442// ---------------------------------------------------------- 443// A short snippet for detecting versions of IE in JavaScript 444// without resorting to user-agent sniffing 445// ---------------------------------------------------------- 446// If you're not in IE (or IE version is less than 5) then: 447// ie === undefined 448// If you're in IE (>=5) then you can determine which version: 449// ie === 7; // IE7 450// Thus, to detect IE: 451// if (ie) {} 452// And to detect the version: 453// ie === 6 // IE6 454// ie > 7 // IE8, IE9 ... 455// ie < 9 // Anything less than IE9 456// ---------------------------------------------------------- 457 458// UPDATE: Now using Live NodeList idea from @jdalton 459 460var ie = (function(){ 461 462 var undef, 463 v = 3, 464 div = document.createElement('div'), 465 all = div.getElementsByTagName('i'); 466 467 while ( 468 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', 469 all[0] 470 ); 471 472 return v > 4 ? v : undef; 473 474}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.