justgage-rails 1.0.1.2 → 1.0.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module JustGage
2
2
  module Rails
3
- VERSION = "1.0.1.2"
3
+ VERSION = "1.0.2.rc1"
4
4
  end
5
5
  end
@@ -1,474 +1,706 @@
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
-
12
- JustGage = 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
305
- JustGage.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
-
316
- var percentColors = [
317
- "#a9d70b",
318
- "#f9c802",
319
- "#ff0000"
320
- ]
321
-
322
- JustGage.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
-
377
- var 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
-
414
- function getRandomInt (min, max) {
415
- return Math.floor(Math.random() * (max - min + 1)) + min;
416
- }
417
-
418
- function cutHex(str) {return (str.charAt(0)=="#") ? str.substring(1,7):str}
419
-
420
- function 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
-
460
- var 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
- }());
1
+ /**
2
+ * JustGage - this is work-in-progress, unreleased, unofficial code, so it might not work top-notch :)
3
+ * Check http://www.justgage.com for official releases
4
+ * Licensed under MIT.
5
+ * @author Bojan Djuricic (@Toorshia)
6
+ *
7
+ * LATEST UPDATES
8
+ * -----------------------------
9
+ * November 25, 2012.
10
+ * -----------------------------
11
+ * Option to define custom rendering function for displayed value
12
+ * -----------------------------
13
+ * November 19, 2012.
14
+ * -----------------------------
15
+ * Config.value is now updated after gauge refresh
16
+ * -----------------------------
17
+ * November 13, 2012.
18
+ * -----------------------------
19
+ * Donut display mode added
20
+ * Option to hide value label
21
+ * Option to enable responsive gauge size
22
+ * Removed default title attribute
23
+ * Option to accept min and max defined as string values
24
+ * Option to configure value symbol
25
+ * Fixed bad aspect ratio calculations
26
+ * Option to configure minimum font size for all texts
27
+ * Option to show shorthand big numbers (human friendly)
28
+ */
29
+
30
+ JustGage = function(config) {
31
+
32
+ if (!config.id) {alert("Missing id parameter for gauge!"); return false;}
33
+ if (!document.getElementById(config.id)) {alert("No element with id: \""+config.id+"\" found!"); return false;}
34
+
35
+ // configurable parameters
36
+ this.config =
37
+ {
38
+ // id : string
39
+ // this is container element id
40
+ id : config.id,
41
+
42
+ // title : string
43
+ // gauge title
44
+ title : (config.title) ? config.title : "",
45
+
46
+ // titleFontColor : string
47
+ // color of gauge title
48
+ titleFontColor : (config.titleFontColor) ? config.titleFontColor : "#999999",
49
+
50
+ // value : int
51
+ // value gauge is showing
52
+ value : (config.value) ? config.value : 0,
53
+
54
+ // symbol : string
55
+ // special symbol to show next to value
56
+ symbol : (config.symbol) ? config.symbol : "",
57
+
58
+ // valueFontColor : string
59
+ // color of label showing current value
60
+ valueFontColor : (config.valueFontColor) ? config.valueFontColor : "#010101",
61
+
62
+ // showValue : bool
63
+ // hide or display value text
64
+ showValue : (config.showValue != null) ? config.showValue : true,
65
+
66
+ // min : int
67
+ // min value
68
+ min : (config.min) ? parseFloat(config.min) : 0,
69
+
70
+ // max : int
71
+ // max value
72
+ max : (config.max) ? parseFloat(config.max) : 100,
73
+
74
+ // showMinMax : bool
75
+ // hide or display min and max values
76
+ showMinMax : (config.showMinMax != null) ? config.showMinMax : true,
77
+
78
+ // humanFriendly : bool
79
+ // convert large numbers for min, max, value to human friendly (e.g. 1234567 -> 1.23M)
80
+ humanFriendly : (config.humanFriendly) ? config.humanFriendly : false,
81
+
82
+ // humanFriendlyDecimal : int
83
+ // number of decimal places for our human friendly number to contain
84
+ humanFriendlyDecimal : (config.humanFriendlyDecimal) ? config.humanFriendlyDecimal : 0,
85
+
86
+ // textRenderer: func
87
+ // function applied before rendering text
88
+ textRenderer : (config.textRenderer) ? config.textRenderer : null,
89
+
90
+ // gaugeWidthScale : float
91
+ // width of the gauge element
92
+ gaugeWidthScale : (config.gaugeWidthScale) ? config.gaugeWidthScale : 1.0,
93
+
94
+ // gaugeColor : string
95
+ // background color of gauge element
96
+ gaugeColor : (config.gaugeColor) ? config.gaugeColor : "#edebeb",
97
+
98
+ // label : string
99
+ // text to show below value
100
+ label : (config.label) ? config.label : "",
101
+
102
+ // showInnerShadow : bool
103
+ // give gauge element small amount of inner shadow
104
+ showInnerShadow : (config.showInnerShadow != null) ? config.showInnerShadow : true,
105
+
106
+ // shadowOpacity : int
107
+ // 0 ~ 1
108
+ shadowOpacity : (config.shadowOpacity) ? config.shadowOpacity : 0.2,
109
+
110
+ // shadowSize: int
111
+ // inner shadow size
112
+ shadowSize : (config.shadowSize) ? config.shadowSize : 5,
113
+
114
+ // shadowVerticalOffset : int
115
+ // how much shadow is offset from top
116
+ shadowVerticalOffset : (config.shadowVerticalOffset) ? config.shadowVerticalOffset : 3,
117
+
118
+ // levelColors : string[]
119
+ // colors of indicator, from lower to upper, in RGB format
120
+ levelColors : (config.levelColors) ? config.levelColors : [
121
+ "#a9d70b",
122
+ "#f9c802",
123
+ "#ff0000"
124
+ ],
125
+
126
+ // levelColorsGradient : bool
127
+ // whether to use gradual color change for value, or sector-based
128
+ levelColorsGradient : (config.levelColorsGradient != null) ? config.levelColorsGradient : true,
129
+
130
+ // labelFontColor : string
131
+ // color of label showing label under value
132
+ labelFontColor : (config.labelFontColor) ? config.labelFontColor : "#b3b3b3",
133
+
134
+ // startAnimationTime : int
135
+ // length of initial animation
136
+ startAnimationTime : (config.startAnimationTime) ? config.startAnimationTime : 700,
137
+
138
+ // startAnimationType : string
139
+ // type of initial animation (linear, >, <, <>, bounce)
140
+ startAnimationType : (config.startAnimationType) ? config.startAnimationType : ">",
141
+
142
+ // refreshAnimationTime : int
143
+ // length of refresh animation
144
+ refreshAnimationTime : (config.refreshAnimationTime) ? config.refreshAnimationTime : 700,
145
+
146
+ // refreshAnimationType : string
147
+ // type of refresh animation (linear, >, <, <>, bounce)
148
+ refreshAnimationType : (config.refreshAnimationType) ? config.refreshAnimationType : ">",
149
+
150
+ // donut : bool
151
+ // show full donut gauge
152
+ donut : (config.donut != null) ? config.donut : false,
153
+
154
+ // valueMinFontSize : int
155
+ // absolute minimum font size for the value
156
+ valueMinFontSize : config.valueMinFontSize || 16,
157
+
158
+ // titleMinFontSize
159
+ // absolute minimum font size for the title
160
+ titleMinFontSize : config.titleMinFontSize || 10,
161
+
162
+ // labelMinFontSize
163
+ // absolute minimum font size for the label
164
+ labelMinFontSize : config.labelMinFontSize || 10,
165
+
166
+ // minLabelMinFontSize
167
+ // absolute minimum font size for the minimum label
168
+ minLabelMinFontSize : config.minLabelMinFontSize || 10,
169
+
170
+ // maxLabelMinFontSize
171
+ // absolute minimum font size for the maximum label
172
+ maxLabelMinFontSize : config.maxLabelMinFontSize || 10,
173
+
174
+ // relativeGaugeSize : bool
175
+ // whether gauge size should follow changes in container element size
176
+ relativeGaugeSize : (config.relativeGaugeSize != null) ? config.relativeGaugeSize : false,
177
+ };
178
+
179
+ // overflow values
180
+ if (config.value > this.config.max) this.config.value = this.config.max;
181
+ if (config.value < this.config.min) this.config.value = this.config.min;
182
+ this.originalValue = config.value;
183
+
184
+ // canvas
185
+ this.canvas = Raphael(this.config.id, "100%", "100%");
186
+ if (this.config.relativeGaugeSize) {
187
+ this.canvas.setViewBox(0, 0, 200, 150, true);
188
+ }
189
+
190
+ // canvas dimensions
191
+ var canvasW, canvasH;
192
+ if (this.config.relativeGaugeSize) {
193
+ canvasW = 200;
194
+ canvasH = 150;
195
+ } else {
196
+ canvasW = getStyle(document.getElementById(this.config.id), "width").slice(0, -2) * 1;
197
+ canvasH = getStyle(document.getElementById(this.config.id), "height").slice(0, -2) * 1;
198
+ }
199
+
200
+ // widget dimensions
201
+ var widgetW, widgetH, aspect;
202
+
203
+ if (this.config.donut) {
204
+
205
+ // DONUT *******************************
206
+
207
+ // width more than height
208
+ if(canvasW > canvasH) {
209
+ widgetH = canvasH;
210
+ widgetW = widgetH;
211
+ // width less than height
212
+ } else if (canvasW < canvasH) {
213
+ widgetW = canvasW;
214
+ widgetH = widgetW;
215
+ // if height don't fit, rescale both
216
+ if(widgetH > canvasH) {
217
+ aspect = widgetH / canvasH;
218
+ widgetH = widgetH / aspect;
219
+ widgetW = widgetH / aspect;
220
+ }
221
+ // equal
222
+ } else {
223
+ widgetW = canvasW;
224
+ widgetH = widgetW;
225
+ }
226
+
227
+ // delta
228
+ var dx = (canvasW - widgetW)/2;
229
+ var dy = (canvasH - widgetH)/2;
230
+
231
+ // title
232
+ var titleFontSize = ((widgetH / 8) > 10) ? (widgetH / 10) : 10;
233
+ var titleX = dx + widgetW / 2;
234
+ var titleY = dy + widgetH / 15;
235
+
236
+ // value
237
+ var valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 5.4) : 18;
238
+ var valueX = dx + widgetW / 2;
239
+ var valueY = dy + widgetH / 1.95;
240
+
241
+ // label
242
+ var labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
243
+ var labelX = dx + widgetW / 2;
244
+ var labelY = valueY + valueFontSize / 2 + 6;
245
+
246
+ // min
247
+ var minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
248
+ var minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2 ;
249
+ var minY = dy + widgetH / 2;
250
+
251
+ // max
252
+ var maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
253
+ var maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2 ;
254
+ var maxY = dy + widgetH / 2;
255
+
256
+ } else {
257
+ // HALF *******************************
258
+
259
+ // width more than height
260
+ if(canvasW > canvasH) {
261
+ widgetH = canvasH;
262
+ widgetW = widgetH * 1.25;
263
+ //if width doesn't fit, rescale both
264
+ if(widgetW > canvasW) {
265
+ aspect = widgetW / canvasW;
266
+ widgetW = widgetW / aspect;
267
+ widgetH = widgetH / aspect;
268
+ }
269
+ // width less than height
270
+ } else if (canvasW < canvasH) {
271
+ widgetW = canvasW;
272
+ widgetH = widgetW / 1.25;
273
+ // if height don't fit, rescale both
274
+ if(widgetH > canvasH) {
275
+ aspect = widgetH / canvasH;
276
+ widgetH = widgetH / aspect;
277
+ widgetW = widgetH / aspect;
278
+ }
279
+ // equal
280
+ } else {
281
+ widgetW = canvasW;
282
+ widgetH = widgetW * 0.75;
283
+ }
284
+
285
+ // delta
286
+ var dx = (canvasW - widgetW)/2;
287
+ var dy = (canvasH - widgetH)/2;
288
+
289
+ // title
290
+ var titleFontSize = ((widgetH / 8) > this.config.titleMinFontSize) ? (widgetH / 10) : this.config.titleMinFontSize;
291
+ var titleX = dx + widgetW / 2;
292
+ var titleY = dy + widgetH / 6.5;
293
+
294
+ // value
295
+ var valueFontSize = ((widgetH / 6.4) > this.config.valueMinFontSize) ? (widgetH / 6.4) : this.config.valueMinFontSize;
296
+ var valueX = dx + widgetW / 2;
297
+ var valueY = dy + widgetH / 1.4;
298
+
299
+ // label
300
+ var labelFontSize = ((widgetH / 16) > this.config.labelMinFontSize) ? (widgetH / 16) : this.config.labelMinFontSize;
301
+ var labelX = dx + widgetW / 2;
302
+ //var labelY = dy + widgetH / 1.126760563380282;
303
+ var labelY = valueY + valueFontSize / 2 + 6;
304
+
305
+ // min
306
+ var minFontSize = ((widgetH / 16) > this.config.minLabelMinFontSize) ? (widgetH / 16) : this.config.minLabelMinFontSize;
307
+ var minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2 ;
308
+ var minY = dy + widgetH / 1.126760563380282;
309
+
310
+ // max
311
+ var maxFontSize = ((widgetH / 16) > this.config.maxLabelMinFontSize) ? (widgetH / 16) : this.config.maxLabelMinFontSize;
312
+ var maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2 ;
313
+ var maxY = dy + widgetH / 1.126760563380282;
314
+ }
315
+ // parameters
316
+ this.params = {
317
+ canvasW : canvasW,
318
+ canvasH : canvasH,
319
+ widgetW : widgetW,
320
+ widgetH : widgetH,
321
+ dx : dx,
322
+ dy : dy,
323
+ titleFontSize : titleFontSize,
324
+ titleX : titleX,
325
+ titleY : titleY,
326
+ valueFontSize : valueFontSize,
327
+ valueX : valueX,
328
+ valueY : valueY,
329
+ labelFontSize : labelFontSize,
330
+ labelX : labelX,
331
+ labelY : labelY,
332
+ minFontSize : minFontSize,
333
+ minX : minX,
334
+ minY : minY,
335
+ maxFontSize : maxFontSize,
336
+ maxX : maxX,
337
+ maxY : maxY
338
+ };
339
+
340
+ // pki - custom attribute for generating gauge paths
341
+ this.canvas.customAttributes.pki = function (value, min, max, w, h, dx, dy, gws, donut) {
342
+
343
+ if (donut) {
344
+ var
345
+ alpha = (1 - 2 * (value - min) / (max - min)) * Math.PI,
346
+ Ro = w / 2 - w / 7,
347
+ Ri = Ro - w / 6.666666666666667 * gws,
348
+
349
+ Cx = w / 2 + dx,
350
+ Cy = h / 1.95 + dy,
351
+
352
+ Xo = w / 2 + dx + Ro * Math.cos(alpha),
353
+ Yo = h - (h - Cy) + 0 - Ro * Math.sin(alpha),
354
+ Xi = w / 2 + dx + Ri * Math.cos(alpha),
355
+ Yi = h - (h - Cy) + 0 - Ri * Math.sin(alpha),
356
+ path = "";
357
+
358
+ path += "M" + (Cx - Ri) + "," + Cy + " ";
359
+ path += "L" + (Cx - Ro) + "," + Cy + " ";
360
+ if (value > ((max - min) / 2)) {
361
+ path += "A" + Ro + "," + Ro + " 0 0 1 " + (Cx + Ro) + "," + Cy + " ";
362
+ }
363
+ path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";
364
+ path += "L" + Xi + "," + Yi + " ";
365
+ if (value > ((max - min) / 2)) {
366
+ path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx + Ri) + "," + Cy + " ";
367
+ }
368
+ path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";
369
+ path += "Z ";
370
+ return { path: path };
371
+
372
+ } else {
373
+ var
374
+ alpha = (1 - (value - min) / (max - min)) * Math.PI,
375
+
376
+ Ro = w / 2 - w / 10,
377
+ Ri = Ro - w / 6.666666666666667 * gws,
378
+
379
+ Cx = w / 2 + dx,
380
+ Cy = h / 1.25 + dy,
381
+
382
+ Xo = w / 2 + dx + Ro * Math.cos(alpha),
383
+ Yo = h - (h - Cy) + 0 - Ro * Math.sin(alpha),
384
+ Xi = w / 2 + dx + Ri * Math.cos(alpha),
385
+ Yi = h - (h - Cy) + 0 - Ri * Math.sin(alpha),
386
+ path = "";
387
+
388
+ path += "M" + (Cx - Ri) + "," + Cy + " ";
389
+ path += "L" + (Cx - Ro) + "," + Cy + " ";
390
+ path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";
391
+ path += "L" + Xi + "," + Yi + " ";
392
+ path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";
393
+ path += "Z ";
394
+ return { path: path };
395
+ }
396
+ }
397
+
398
+ // gauge
399
+ this.gauge = this.canvas.path().attr({
400
+ "stroke": "none",
401
+ "fill": this.config.gaugeColor,
402
+ 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, this.config.donut]
403
+ });
404
+ this.gauge.id = this.config.id+"-gauge";
405
+
406
+ // level
407
+ this.level = this.canvas.path().attr({
408
+ "stroke": "none",
409
+ "fill": getColorForPercentage((this.config.value - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient),
410
+ 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, this.config.donut]
411
+ });
412
+ this.level.id = this.config.id+"-level";
413
+
414
+ // title
415
+ this.txtTitle = this.canvas.text(this.params.titleX, this.params.titleY, this.config.title);
416
+ this.txtTitle. attr({
417
+ "font-size":this.params.titleFontSize,
418
+ "font-weight":"bold",
419
+ "font-family":"Arial",
420
+ "fill":this.config.titleFontColor,
421
+ "fill-opacity":"1"
422
+ });
423
+ this.txtTitle.id = this.config.id+"-txttitle";
424
+
425
+ // value
426
+ if(this.config.textRenderer)
427
+ this.originalValue = this.config.textRenderer(this.originalValue);
428
+ else if( this.config.humanFriendly )
429
+ this.originalValue = humanFriendlyNumber( this.originalValue, this.config.humanFriendlyDecimal ) + this.config.symbol;
430
+
431
+ this.txtValue = this.canvas.text(this.params.valueX, this.params.valueY, this.originalValue);
432
+ this.txtValue. attr({
433
+ "font-size":this.params.valueFontSize,
434
+ "font-weight":"bold",
435
+ "font-family":"Arial",
436
+ "fill":this.config.valueFontColor,
437
+ "fill-opacity":"0"
438
+ });
439
+ this.txtValue.id = this.config.id+"-txtvalue";
440
+
441
+ // label
442
+ this.txtLabel = this.canvas.text(this.params.labelX, this.params.labelY, this.config.label);
443
+ this.txtLabel. attr({
444
+ "font-size":this.params.labelFontSize,
445
+ "font-weight":"normal",
446
+ "font-family":"Arial",
447
+ "fill":this.config.labelFontColor,
448
+ "fill-opacity":"0"
449
+ });
450
+ this.txtLabel.id = this.config.id+"-txtlabel";
451
+
452
+ // min
453
+ this.txtMinimum = this.config.min;
454
+ if( this.config.humanFriendly ) this.txtMinimum = humanFriendlyNumber( this.config.min, this.config.humanFriendlyDecimal );
455
+ this.txtMin = this.canvas.text(this.params.minX, this.params.minY, this.txtMinimum);
456
+ this.txtMin. attr({
457
+ "font-size":this.params.minFontSize,
458
+ "font-weight":"normal",
459
+ "font-family":"Arial",
460
+ "fill":this.config.labelFontColor,
461
+ "fill-opacity": (this.config.showMinMax == true)? "1" : "0"
462
+ });
463
+ this.txtMin.id = this.config.id+"-txtmin";
464
+
465
+ // max
466
+ this.txtMaximum = this.config.max;
467
+ if( this.config.humanFriendly ) this.txtMaximum = humanFriendlyNumber( this.config.max, this.config.humanFriendlyDecimal );
468
+ this.txtMax = this.canvas.text(this.params.maxX, this.params.maxY, this.txtMaximum);
469
+ this.txtMax. attr({
470
+ "font-size":this.params.maxFontSize,
471
+ "font-weight":"normal",
472
+ "font-family":"Arial",
473
+ "fill":this.config.labelFontColor,
474
+ "fill-opacity": (this.config.showMinMax == true)? "1" : "0"
475
+ });
476
+ this.txtMax.id = this.config.id+"-txtmax";
477
+
478
+ var defs = this.canvas.canvas.childNodes[1];
479
+ var svg = "http://www.w3.org/2000/svg";
480
+
481
+ if (ie < 9) {
482
+ onCreateElementNsReady(function() {
483
+ this.generateShadow();
484
+ });
485
+ } else {
486
+ this.generateShadow(svg, defs);
487
+ defs = null;
488
+ svg = null;
489
+ }
490
+
491
+ // animate
492
+ 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.donut]}, this.config.startAnimationTime, this.config.startAnimationType);
493
+
494
+ if (this.config.showValue) {
495
+ this.txtValue.animate({"fill-opacity":"1"}, this.config.startAnimationTime, this.config.startAnimationType);
496
+ }
497
+ this.txtLabel.animate({"fill-opacity":"1"}, this.config.startAnimationTime, this.config.startAnimationType);
498
+ };
499
+
500
+ /** Refresh gauge level */
501
+ JustGage.prototype.refresh = function(val) {
502
+ // overflow values
503
+ var originalVal = val;
504
+ var displayVal = val;
505
+ if (val > this.config.max) {val = this.config.max;}
506
+ if (val < this.config.min) {val = this.config.min;}
507
+
508
+ var color = getColorForPercentage((val - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient);
509
+
510
+ if(this.config.textRenderer)
511
+ displayVal = this.config.textRenderer(displayVal);
512
+ else if( this.config.humanFriendly )
513
+ displayVal = humanFriendlyNumber( displayVal, this.config.humanFriendlyDecimal ) + this.config.symbol;
514
+
515
+ this.canvas.getById(this.config.id+"-txtvalue").attr({"text":displayVal});
516
+ 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, this.config.donut], "fill":color}, this.config.refreshAnimationTime, this.config.refreshAnimationType);
517
+ this.config.value = val;
518
+ originalVal = null;
519
+ displayVal = null;
520
+ };
521
+
522
+ /** Generate shadow */
523
+ JustGage.prototype.generateShadow = function(svg, defs) {
524
+ // FILTER
525
+ var gaussFilter=document.createElementNS(svg,"filter");
526
+ gaussFilter.setAttribute("id", this.config.id + "-inner-shadow");
527
+ defs.appendChild(gaussFilter);
528
+
529
+ // offset
530
+ var feOffset = document.createElementNS(svg,"feOffset");
531
+ feOffset.setAttribute("dx", 0);
532
+ feOffset.setAttribute("dy", this.config.shadowVerticalOffset);
533
+ gaussFilter.appendChild(feOffset);
534
+ feOffset = null;
535
+
536
+ // blur
537
+ var feGaussianBlur = document.createElementNS(svg,"feGaussianBlur");
538
+ feGaussianBlur.setAttribute("result","offset-blur");
539
+ feGaussianBlur.setAttribute("stdDeviation", this.config.shadowSize);
540
+ gaussFilter.appendChild(feGaussianBlur);
541
+ feGaussianBlur = null;
542
+
543
+ // composite 1
544
+ var feComposite1 = document.createElementNS(svg,"feComposite");
545
+ feComposite1.setAttribute("operator","out");
546
+ feComposite1.setAttribute("in", "SourceGraphic");
547
+ feComposite1.setAttribute("in2","offset-blur");
548
+ feComposite1.setAttribute("result","inverse");
549
+ gaussFilter.appendChild(feComposite1);
550
+ feComposite1 = null;
551
+
552
+ // flood
553
+ var feFlood = document.createElementNS(svg,"feFlood");
554
+ feFlood.setAttribute("flood-color","black");
555
+ feFlood.setAttribute("flood-opacity", this.config.shadowOpacity);
556
+ feFlood.setAttribute("result","color");
557
+ gaussFilter.appendChild(feFlood);
558
+ feFlood = null;
559
+
560
+ // composite 2
561
+ var feComposite2 = document.createElementNS(svg,"feComposite");
562
+ feComposite2.setAttribute("operator","in");
563
+ feComposite2.setAttribute("in", "color");
564
+ feComposite2.setAttribute("in2","inverse");
565
+ feComposite2.setAttribute("result","shadow");
566
+ gaussFilter.appendChild(feComposite2);
567
+ feComposite2 = null;
568
+
569
+ // composite 3
570
+ var feComposite3 = document.createElementNS(svg,"feComposite");
571
+ feComposite3.setAttribute("operator","over");
572
+ feComposite3.setAttribute("in", "shadow");
573
+ feComposite3.setAttribute("in2","SourceGraphic");
574
+ gaussFilter.appendChild(feComposite3);
575
+ feComposite3 = null;
576
+
577
+ // set shadow
578
+ if (this.config.showInnerShadow == true) {
579
+ this.canvas.canvas.childNodes[2].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)");
580
+ this.canvas.canvas.childNodes[3].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)");
581
+ }
582
+
583
+ // clear vars
584
+ gaussFilter = null;
585
+
586
+ }
587
+
588
+ /** Get color for value percentage */
589
+ function getColorForPercentage(pct, col, grad) {
590
+
591
+ var no = col.length;
592
+ if (no === 1) return col[0];
593
+ var inc = (grad) ? (1 / (no - 1)) : (1 / no);
594
+ var colors = new Array();
595
+ for (var i = 0; i < col.length; i++) {
596
+ var percentage = (grad) ? (inc * i) : (inc * (i + 1));
597
+ var rval = parseInt((cutHex(col[i])).substring(0,2),16);
598
+ var gval = parseInt((cutHex(col[i])).substring(2,4),16);
599
+ var bval = parseInt((cutHex(col[i])).substring(4,6),16);
600
+ colors[i] = { pct: percentage, color: { r: rval, g: gval, b: bval } };
601
+ }
602
+
603
+ if(pct == 0) return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')';
604
+
605
+ for (var i = 0; i < colors.length; i++) {
606
+ if (pct <= colors[i].pct) {
607
+ if (grad == true) {
608
+ var lower = colors[i - 1];
609
+ var upper = colors[i];
610
+ var range = upper.pct - lower.pct;
611
+ var rangePct = (pct - lower.pct) / range;
612
+ var pctLower = 1 - rangePct;
613
+ var pctUpper = rangePct;
614
+ var color = {
615
+ r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),
616
+ g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),
617
+ b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)
618
+ };
619
+ return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';
620
+ } else {
621
+ return 'rgb(' + [colors[i].color.r, colors[i].color.g, colors[i].color.b].join(',') + ')';
622
+ }
623
+ }
624
+ }
625
+
626
+ }
627
+
628
+ /** Random integer */
629
+ function getRandomInt (min, max) {
630
+ return Math.floor(Math.random() * (max - min + 1)) + min;
631
+ }
632
+
633
+ /** Cut hex */
634
+ function cutHex(str) {return (str.charAt(0)=="#") ? str.substring(1,7):str}
635
+
636
+ /** Human friendly number suffix */
637
+ // From: http://stackoverflow.com/questions/2692323/code-golf-friendly-number-abbreviator
638
+ function humanFriendlyNumber( n, d ) {
639
+ var p = Math.pow;
640
+ var d = p(10,d);
641
+ var i = 7
642
+ while( i ) {
643
+ s = p(10,i--*3)
644
+ if( s <= n ) {
645
+ n = Math.round(n*d/s)/d+"kMGTPE"[i];
646
+ }
647
+ }
648
+ return n;
649
+ }
650
+
651
+ /** Get style */
652
+ function getStyle(oElm, strCssRule){
653
+ var strValue = "";
654
+ if(document.defaultView && document.defaultView.getComputedStyle){
655
+ strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
656
+ }
657
+ else if(oElm.currentStyle){
658
+ strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
659
+ return p1.toUpperCase();
660
+ });
661
+ strValue = oElm.currentStyle[strCssRule];
662
+ }
663
+ return strValue;
664
+ }
665
+
666
+ /** Create Element NS Ready */
667
+ function onCreateElementNsReady(func) {
668
+ if (document.createElementNS != undefined) {
669
+ func();
670
+ } else {
671
+ setTimeout(function() { onCreateElementNsReady(func); }, 100);
672
+ }
673
+ }
674
+
675
+ /** Get IE version */
676
+ // ----------------------------------------------------------
677
+ // A short snippet for detecting versions of IE in JavaScript
678
+ // without resorting to user-agent sniffing
679
+ // ----------------------------------------------------------
680
+ // If you're not in IE (or IE version is less than 5) then:
681
+ // ie === undefined
682
+ // If you're in IE (>=5) then you can determine which version:
683
+ // ie === 7; // IE7
684
+ // Thus, to detect IE:
685
+ // if (ie) {}
686
+ // And to detect the version:
687
+ // ie === 6 // IE6
688
+ // ie > 7 // IE8, IE9 ...
689
+ // ie < 9 // Anything less than IE9
690
+ // ----------------------------------------------------------
691
+ // UPDATE: Now using Live NodeList idea from @jdalton
692
+ var ie = (function(){
693
+
694
+ var undef,
695
+ v = 3,
696
+ div = document.createElement('div'),
697
+ all = div.getElementsByTagName('i');
698
+
699
+ while (
700
+ div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
701
+ all[0]
702
+ );
703
+
704
+ return v > 4 ? v : undef;
705
+
706
+ }());