justgage-rails 1.0.1.2 → 1.0.2.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }());