source: public/vendors/charts/justgage/justgage.js@ 65fafc4

develop
Last change on this file since 65fafc4 was 7304c7f, checked in by beratkjufliju <kufliju@…>, 3 years ago

added user authentication, create & forgot password methods and blades

  • Property mode set to 100644
File size: 37.2 KB
RevLine 
[7304c7f]1/**
2 * JustGage - animated gauges using RaphaelJS
3 * Check http://www.justgage.com for official releases
4 * Licensed under MIT.
5 * @author Bojan Djuricic (@Toorshia)
6 **/
7
8JustGage = function(config) {
9
10 var obj = this;
11
12 // Helps in case developer wants to debug it. unobtrusive
13 if (config === null || config === undefined) {
14 console.log('* justgage: Make sure to pass options to the constructor!');
15 return false;
16 }
17
18 var node;
19
20 if (config.id !== null && config.id !== undefined) {
21 node = document.getElementById(config.id);
22 if (!node) {
23 console.log('* justgage: No element with id : %s found', config.id);
24 return false;
25 }
26 } else if (config.parentNode !== null && config.parentNode !== undefined) {
27 node = config.parentNode;
28 } else {
29 console.log('* justgage: Make sure to pass the existing element id or parentNode to the constructor.');
30 return false;
31 }
32
33 var dataset = node.dataset ? node.dataset : {};
34
35 // check for defaults
36 var defaults = (config.defaults !== null && config.defaults !== undefined) ? config.defaults : false;
37 if (defaults !== false) {
38 config = extend({}, config, defaults);
39 delete config.defaults;
40 }
41
42 // configurable parameters
43 obj.config = {
44 // id : string
45 // this is container element id
46 id: config.id,
47
48 // value : float
49 // value gauge is showing
50 value: kvLookup('value', config, dataset, 0, 'float'),
51
52 // defaults : bool
53 // defaults parameter to use
54 defaults: kvLookup('defaults', config, dataset, 0, false),
55
56 // parentNode : node object
57 // this is container element
58 parentNode: kvLookup('parentNode', config, dataset, null),
59
60 // width : int
61 // gauge width
62 width: kvLookup('width', config, dataset, null),
63
64 // height : int
65 // gauge height
66 height: kvLookup('height', config, dataset, null),
67
68 // title : string
69 // gauge title
70 title: kvLookup('title', config, dataset, ""),
71
72 // titleFontColor : string
73 // color of gauge title
74 titleFontColor: kvLookup('titleFontColor', config, dataset, "#999999"),
75
76 // titleFontFamily : string
77 // color of gauge title
78 titleFontFamily: kvLookup('titleFontFamily', config, dataset, "sans-serif"),
79
80 // titlePosition : string
81 // 'above' or 'below'
82 titlePosition: kvLookup('titlePosition', config, dataset, "above"),
83
84 // valueFontColor : string
85 // color of label showing current value
86 valueFontColor: kvLookup('valueFontColor', config, dataset, "#010101"),
87
88 // valueFontFamily : string
89 // color of label showing current value
90 valueFontFamily: kvLookup('valueFontFamily', config, dataset, "Arial"),
91
92 // symbol : string
93 // special symbol to show next to value
94 symbol: kvLookup('symbol', config, dataset, ''),
95
96 // min : float
97 // min value
98 min: kvLookup('min', config, dataset, 0, 'float'),
99
100 // max : float
101 // max value
102 max: kvLookup('max', config, dataset, 100, 'float'),
103
104 // reverse : bool
105 // reverse min and max
106 reverse: kvLookup('reverse', config, dataset, false),
107
108 // humanFriendlyDecimal : int
109 // number of decimal places for our human friendly number to contain
110 humanFriendlyDecimal: kvLookup('humanFriendlyDecimal', config, dataset, 0),
111
112
113 // textRenderer: func
114 // function applied before rendering text
115 textRenderer: kvLookup('textRenderer', config, dataset, null),
116
117 // gaugeWidthScale : float
118 // width of the gauge element
119 gaugeWidthScale: kvLookup('gaugeWidthScale', config, dataset, 1.0),
120
121 // gaugeColor : string
122 // background color of gauge element
123 gaugeColor: kvLookup('gaugeColor', config, dataset, "#edebeb"),
124
125 // label : string
126 // text to show below value
127 label: kvLookup('label', config, dataset, ''),
128
129 // labelFontColor : string
130 // color of label showing label under value
131 labelFontColor: kvLookup('labelFontColor', config, dataset, "#b3b3b3"),
132
133 // shadowOpacity : int
134 // 0 ~ 1
135 shadowOpacity: kvLookup('shadowOpacity', config, dataset, 0.2),
136
137 // shadowSize: int
138 // inner shadow size
139 shadowSize: kvLookup('shadowSize', config, dataset, 5),
140
141 // shadowVerticalOffset : int
142 // how much shadow is offset from top
143 shadowVerticalOffset: kvLookup('shadowVerticalOffset', config, dataset, 3),
144
145 // levelColors : string[]
146 // colors of indicator, from lower to upper, in RGB format
147 levelColors: kvLookup('levelColors', config, dataset, ["#a9d70b", "#f9c802", "#ff0000"], 'array', ','),
148
149 // startAnimationTime : int
150 // length of initial animation
151 startAnimationTime: kvLookup('startAnimationTime', config, dataset, 700),
152
153 // startAnimationType : string
154 // type of initial animation (linear, >, <, <>, bounce)
155 startAnimationType: kvLookup('startAnimationType', config, dataset, '>'),
156
157 // refreshAnimationTime : int
158 // length of refresh animation
159 refreshAnimationTime: kvLookup('refreshAnimationTime', config, dataset, 700),
160
161 // refreshAnimationType : string
162 // type of refresh animation (linear, >, <, <>, bounce)
163 refreshAnimationType: kvLookup('refreshAnimationType', config, dataset, '>'),
164
165 // donutStartAngle : int
166 // angle to start from when in donut mode
167 donutStartAngle: kvLookup('donutStartAngle', config, dataset, 90),
168
169 // valueMinFontSize : int
170 // absolute minimum font size for the value
171 valueMinFontSize: kvLookup('valueMinFontSize', config, dataset, 16),
172
173 // titleMinFontSize
174 // absolute minimum font size for the title
175 titleMinFontSize: kvLookup('titleMinFontSize', config, dataset, 10),
176
177 // labelMinFontSize
178 // absolute minimum font size for the label
179 labelMinFontSize: kvLookup('labelMinFontSize', config, dataset, 10),
180
181 // minLabelMinFontSize
182 // absolute minimum font size for the minimum label
183 minLabelMinFontSize: kvLookup('minLabelMinFontSize', config, dataset, 10),
184
185 // maxLabelMinFontSize
186 // absolute minimum font size for the maximum label
187 maxLabelMinFontSize: kvLookup('maxLabelMinFontSize', config, dataset, 10),
188
189 // hideValue : bool
190 // hide value text
191 hideValue: kvLookup('hideValue', config, dataset, false),
192
193 // hideMinMax : bool
194 // hide min and max values
195 hideMinMax: kvLookup('hideMinMax', config, dataset, false),
196
197 // hideInnerShadow : bool
198 // hide inner shadow
199 hideInnerShadow: kvLookup('hideInnerShadow', config, dataset, false),
200
201 // humanFriendly : bool
202 // convert large numbers for min, max, value to human friendly (e.g. 1234567 -> 1.23M)
203 humanFriendly: kvLookup('humanFriendly', config, dataset, false),
204
205 // noGradient : bool
206 // whether to use gradual color change for value, or sector-based
207 noGradient: kvLookup('noGradient', config, dataset, false),
208
209 // donut : bool
210 // show full donut gauge
211 donut: kvLookup('donut', config, dataset, false),
212
213 // relativeGaugeSize : bool
214 // whether gauge size should follow changes in container element size
215 relativeGaugeSize: kvLookup('relativeGaugeSize', config, dataset, false),
216
217 // counter : bool
218 // animate level number change
219 counter: kvLookup('counter', config, dataset, false),
220
221 // decimals : int
222 // number of digits after floating point
223 decimals: kvLookup('decimals', config, dataset, 0),
224
225 // customSectors : [] of objects
226 // number of digits after floating point
227 customSectors: kvLookup('customSectors', config, dataset, []),
228
229 // formatNumber: boolean
230 // formats numbers with commas where appropriate
231 formatNumber: kvLookup('formatNumber', config, dataset, false),
232
233 // pointer : bool
234 // show value pointer
235 pointer: kvLookup('pointer', config, dataset, false),
236
237 // pointerOptions : object
238 // define pointer look
239 pointerOptions: kvLookup('pointerOptions', config, dataset, [])
240 };
241
242 // variables
243 var
244 canvasW,
245 canvasH,
246 widgetW,
247 widgetH,
248 aspect,
249 dx,
250 dy,
251 titleFontSize,
252 titleX,
253 titleY,
254 valueFontSize,
255 valueX,
256 valueY,
257 labelFontSize,
258 labelX,
259 labelY,
260 minFontSize,
261 minX,
262 minY,
263 maxFontSize,
264 maxX,
265 maxY;
266
267 // overflow values
268 if (obj.config.value > obj.config.max) obj.config.value = obj.config.max;
269 if (obj.config.value < obj.config.min) obj.config.value = obj.config.min;
270 obj.originalValue = kvLookup('value', config, dataset, -1, 'float');
271
272 // create canvas
273 if (obj.config.id !== null && (document.getElementById(obj.config.id)) !== null) {
274 obj.canvas = Raphael(obj.config.id, "100%", "100%");
275 } else if (obj.config.parentNode !== null) {
276 obj.canvas = Raphael(obj.config.parentNode, "100%", "100%");
277 }
278
279 if (obj.config.relativeGaugeSize === true) {
280 obj.canvas.setViewBox(0, 0, 200, 150, true);
281 }
282
283 // canvas dimensions
284 if (obj.config.relativeGaugeSize === true) {
285 canvasW = 200;
286 canvasH = 150;
287 } else if (obj.config.width !== null && obj.config.height !== null) {
288 canvasW = obj.config.width;
289 canvasH = obj.config.height;
290 } else if (obj.config.parentNode !== null) {
291 obj.canvas.setViewBox(0, 0, 200, 150, true);
292 canvasW = 200;
293 canvasH = 150;
294 } else {
295 canvasW = getStyle(document.getElementById(obj.config.id), "width").slice(0, -2) * 1;
296 canvasH = getStyle(document.getElementById(obj.config.id), "height").slice(0, -2) * 1;
297 }
298
299 // widget dimensions
300 if (obj.config.donut === true) {
301
302 // DONUT *******************************
303
304 // width more than height
305 if (canvasW > canvasH) {
306 widgetH = canvasH;
307 widgetW = widgetH;
308 // width less than height
309 } else if (canvasW < canvasH) {
310 widgetW = canvasW;
311 widgetH = widgetW;
312 // if height don't fit, rescale both
313 if (widgetH > canvasH) {
314 aspect = widgetH / canvasH;
315 widgetH = widgetH / aspect;
316 widgetW = widgetH / aspect;
317 }
318 // equal
319 } else {
320 widgetW = canvasW;
321 widgetH = widgetW;
322 }
323
324 // delta
325 dx = (canvasW - widgetW) / 2;
326 dy = (canvasH - widgetH) / 2;
327
328 // title
329 titleFontSize = ((widgetH / 8) > 10) ? (widgetH / 10) : 10;
330 titleX = dx + widgetW / 2;
331 titleY = dy + widgetH / 11;
332
333 // value
334 valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 5.4) : 18;
335 valueX = dx + widgetW / 2;
336 if (obj.config.label !== '') {
337 valueY = dy + widgetH / 1.85;
338 } else {
339 valueY = dy + widgetH / 1.7;
340 }
341
342 // label
343 labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
344 labelX = dx + widgetW / 2;
345 labelY = valueY + labelFontSize;
346
347 // min
348 minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
349 minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2;
350 minY = labelY;
351
352 // max
353 maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
354 maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2;
355 maxY = labelY;
356
357 } else {
358 // HALF *******************************
359
360 // width more than height
361 if (canvasW > canvasH) {
362 widgetH = canvasH;
363 widgetW = widgetH * 1.25;
364 //if width doesn't fit, rescale both
365 if (widgetW > canvasW) {
366 aspect = widgetW / canvasW;
367 widgetW = widgetW / aspect;
368 widgetH = widgetH / aspect;
369 }
370 // width less than height
371 } else if (canvasW < canvasH) {
372 widgetW = canvasW;
373 widgetH = widgetW / 1.25;
374 // if height don't fit, rescale both
375 if (widgetH > canvasH) {
376 aspect = widgetH / canvasH;
377 widgetH = widgetH / aspect;
378 widgetW = widgetH / aspect;
379 }
380 // equal
381 } else {
382 widgetW = canvasW;
383 widgetH = widgetW * 0.75;
384 }
385
386 // delta
387 dx = (canvasW - widgetW) / 2;
388 dy = (canvasH - widgetH) / 2;
389 if (obj.config.titlePosition === 'below') {
390 // shift whole thing down
391 dy -= (widgetH / 6.4);
392 }
393
394 // title
395 titleFontSize = ((widgetH / 8) > obj.config.titleMinFontSize) ? (widgetH / 10) : obj.config.titleMinFontSize;
396 titleX = dx + widgetW / 2;
397 titleY = dy + (obj.config.titlePosition === 'below' ? (widgetH * 1.07) : (widgetH / 6.4));
398
399 // value
400 valueFontSize = ((widgetH / 6.5) > obj.config.valueMinFontSize) ? (widgetH / 6.5) : obj.config.valueMinFontSize;
401 valueX = dx + widgetW / 2;
402 valueY = dy + widgetH / 1.275;
403
404 // label
405 labelFontSize = ((widgetH / 16) > obj.config.labelMinFontSize) ? (widgetH / 16) : obj.config.labelMinFontSize;
406 labelX = dx + widgetW / 2;
407 labelY = valueY + valueFontSize / 2 + 5;
408
409 // min
410 minFontSize = ((widgetH / 16) > obj.config.minLabelMinFontSize) ? (widgetH / 16) : obj.config.minLabelMinFontSize;
411 minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2;
412 minY = labelY;
413
414 // max
415 maxFontSize = ((widgetH / 16) > obj.config.maxLabelMinFontSize) ? (widgetH / 16) : obj.config.maxLabelMinFontSize;
416 maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2;
417 maxY = labelY;
418 }
419
420 // parameters
421 obj.params = {
422 canvasW: canvasW,
423 canvasH: canvasH,
424 widgetW: widgetW,
425 widgetH: widgetH,
426 dx: dx,
427 dy: dy,
428 titleFontSize: titleFontSize,
429 titleX: titleX,
430 titleY: titleY,
431 valueFontSize: valueFontSize,
432 valueX: valueX,
433 valueY: valueY,
434 labelFontSize: labelFontSize,
435 labelX: labelX,
436 labelY: labelY,
437 minFontSize: minFontSize,
438 minX: minX,
439 minY: minY,
440 maxFontSize: maxFontSize,
441 maxX: maxX,
442 maxY: maxY
443 };
444
445 // var clear
446 canvasW, canvasH, widgetW, widgetH, aspect, dx, dy, titleFontSize, titleX, titleY, valueFontSize, valueX, valueY, labelFontSize, labelX, labelY, minFontSize, minX, minY, maxFontSize, maxX, maxY = null;
447
448 // pki - custom attribute for generating gauge paths
449 obj.canvas.customAttributes.pki = function(value, min, max, w, h, dx, dy, gws, donut, reverse) {
450
451 var alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path;
452
453 if (donut) {
454 alpha = (1 - 2 * (value - min) / (max - min)) * Math.PI;
455 Ro = w / 2 - w / 7;
456 Ri = Ro - w / 6.666666666666667 * gws;
457
458 Cx = w / 2 + dx;
459 Cy = h / 1.95 + dy;
460
461 Xo = w / 2 + dx + Ro * Math.cos(alpha);
462 Yo = h - (h - Cy) - Ro * Math.sin(alpha);
463 Xi = w / 2 + dx + Ri * Math.cos(alpha);
464 Yi = h - (h - Cy) - Ri * Math.sin(alpha);
465
466 path = "M" + (Cx - Ri) + "," + Cy + " ";
467 path += "L" + (Cx - Ro) + "," + Cy + " ";
468 if (value > ((max - min) / 2)) {
469 path += "A" + Ro + "," + Ro + " 0 0 1 " + (Cx + Ro) + "," + Cy + " ";
470 }
471 path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";
472 path += "L" + Xi + "," + Yi + " ";
473 if (value > ((max - min) / 2)) {
474 path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx + Ri) + "," + Cy + " ";
475 }
476 path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";
477 path += "Z ";
478
479 return {
480 path: path
481 };
482
483 } else {
484 alpha = (1 - (value - min) / (max - min)) * Math.PI;
485 Ro = w / 2 - w / 10;
486 Ri = Ro - w / 6.666666666666667 * gws;
487
488 Cx = w / 2 + dx;
489 Cy = h / 1.25 + dy;
490
491 Xo = w / 2 + dx + Ro * Math.cos(alpha);
492 Yo = h - (h - Cy) - Ro * Math.sin(alpha);
493 Xi = w / 2 + dx + Ri * Math.cos(alpha);
494 Yi = h - (h - Cy) - Ri * Math.sin(alpha);
495
496 path = "M" + (Cx - Ri) + "," + Cy + " ";
497 path += "L" + (Cx - Ro) + "," + Cy + " ";
498 path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";
499 path += "L" + Xi + "," + Yi + " ";
500 path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";
501 path += "Z ";
502
503 return {
504 path: path
505 };
506 }
507
508 // var clear
509 alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path = null;
510 };
511
512 // ndl - custom attribute for generating needle path
513 obj.canvas.customAttributes.ndl = function(value, min, max, w, h, dx, dy, gws, donut) {
514
515 var dlt = w * 3.5 / 100;
516 var dlb = w / 15;
517 var dw = w / 100;
518
519 if (obj.config.pointerOptions.toplength != null && obj.config.pointerOptions.toplength != undefined) dlt = obj.config.pointerOptions.toplength;
520 if (obj.config.pointerOptions.bottomlength != null && obj.config.pointerOptions.bottomlength != undefined) dlb = obj.config.pointerOptions.bottomlength;
521 if (obj.config.pointerOptions.bottomwidth != null && obj.config.pointerOptions.bottomwidth != undefined) dw = obj.config.pointerOptions.bottomwidth;
522
523 var alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, Xc, Yc, Xz, Yz, Xa, Ya, Xb, Yb, path;
524
525 if (donut) {
526
527 alpha = (1 - 2 * (value - min) / (max - min)) * Math.PI;
528 Ro = w / 2 - w / 7;
529 Ri = Ro - w / 6.666666666666667 * gws;
530
531 Cx = w / 2 + dx;
532 Cy = h / 1.95 + dy;
533
534 Xo = w / 2 + dx + Ro * Math.cos(alpha);
535 Yo = h - (h - Cy) - Ro * Math.sin(alpha);
536 Xi = w / 2 + dx + Ri * Math.cos(alpha);
537 Yi = h - (h - Cy) - Ri * Math.sin(alpha);
538
539 Xc = Xo + dlt * Math.cos(alpha);
540 Yc = Yo - dlt * Math.sin(alpha);
541 Xz = Xi - dlb * Math.cos(alpha);
542 Yz = Yi + dlb * Math.sin(alpha);
543
544 Xa = Xz + dw * Math.sin(alpha);
545 Ya = Yz + dw * Math.cos(alpha);
546 Xb = Xz - dw * Math.sin(alpha);
547 Yb = Yz - dw * Math.cos(alpha);
548
549 path = 'M' + Xa + ',' + Ya + ' ';
550 path += 'L' + Xb + ',' + Yb + ' ';
551 path += 'L' + Xc + ',' + Yc + ' ';
552 path += 'Z ';
553
554 return {
555 path: path
556 };
557
558 } else {
559 alpha = (1 - (value - min) / (max - min)) * Math.PI;
560 Ro = w / 2 - w / 10;
561 Ri = Ro - w / 6.666666666666667 * gws;
562
563 Cx = w / 2 + dx;
564 Cy = h / 1.25 + dy;
565
566 Xo = w / 2 + dx + Ro * Math.cos(alpha);
567 Yo = h - (h - Cy) - Ro * Math.sin(alpha);
568 Xi = w / 2 + dx + Ri * Math.cos(alpha);
569 Yi = h - (h - Cy) - Ri * Math.sin(alpha);
570
571 Xc = Xo + dlt * Math.cos(alpha);
572 Yc = Yo - dlt * Math.sin(alpha);
573 Xz = Xi - dlb * Math.cos(alpha);
574 Yz = Yi + dlb * Math.sin(alpha);
575
576 Xa = Xz + dw * Math.sin(alpha);
577 Ya = Yz + dw * Math.cos(alpha);
578 Xb = Xz - dw * Math.sin(alpha);
579 Yb = Yz - dw * Math.cos(alpha);
580
581 path = 'M' + Xa + ',' + Ya + ' ';
582 path += 'L' + Xb + ',' + Yb + ' ';
583 path += 'L' + Xc + ',' + Yc + ' ';
584 path += 'Z ';
585
586 return {
587 path: path
588 };
589 }
590
591 // var clear
592 alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, Xc, Yc, Xz, Yz, Xa, Ya, Xb, Yb, path = null;
593 };
594
595 // gauge
596 obj.gauge = obj.canvas.path().attr({
597 "stroke": "none",
598 "fill": obj.config.gaugeColor,
599 pki: [
600 obj.config.max,
601 obj.config.min,
602 obj.config.max,
603 obj.params.widgetW,
604 obj.params.widgetH,
605 obj.params.dx,
606 obj.params.dy,
607 obj.config.gaugeWidthScale,
608 obj.config.donut,
609 obj.config.reverse
610 ]
611 });
612
613 // level
614 obj.level = obj.canvas.path().attr({
615 "stroke": "none",
616 "fill": getColor(obj.config.value, (obj.config.value - obj.config.min) / (obj.config.max - obj.config.min), obj.config.levelColors, obj.config.noGradient, obj.config.customSectors),
617 pki: [
618 obj.config.min,
619 obj.config.min,
620 obj.config.max,
621 obj.params.widgetW,
622 obj.params.widgetH,
623 obj.params.dx,
624 obj.params.dy,
625 obj.config.gaugeWidthScale,
626 obj.config.donut,
627 obj.config.reverse
628 ]
629 });
630 if (obj.config.donut) {
631 obj.level.transform("r" + obj.config.donutStartAngle + ", " + (obj.params.widgetW / 2 + obj.params.dx) + ", " + (obj.params.widgetH / 1.95 + obj.params.dy));
632 }
633
634 if (obj.config.pointer) {
635 // needle
636 obj.needle = obj.canvas.path().attr({
637 "stroke": (obj.config.pointerOptions.stroke !== null && obj.config.pointerOptions.stroke !== undefined) ? obj.config.pointerOptions.stroke : "none",
638 "stroke-width": (obj.config.pointerOptions.stroke_width !== null && obj.config.pointerOptions.stroke_width !== undefined) ? obj.config.pointerOptions.stroke_width : 0,
639 "stroke-linecap": (obj.config.pointerOptions.stroke_linecap !== null && obj.config.pointerOptions.stroke_linecap !== undefined) ? obj.config.pointerOptions.stroke_linecap : "square",
640 "fill": (obj.config.pointerOptions.color !== null && obj.config.pointerOptions.color !== undefined) ? obj.config.pointerOptions.color : "#000000",
641 ndl: [
642 obj.config.min,
643 obj.config.min,
644 obj.config.max,
645 obj.params.widgetW,
646 obj.params.widgetH,
647 obj.params.dx,
648 obj.params.dy,
649 obj.config.gaugeWidthScale,
650 obj.config.donut
651 ]
652 });
653
654 if (obj.config.donut) {
655 obj.needle.transform("r" + obj.config.donutStartAngle + ", " + (obj.params.widgetW / 2 + obj.params.dx) + ", " + (obj.params.widgetH / 1.95 + obj.params.dy));
656 }
657
658 }
659
660 // title
661 obj.txtTitle = obj.canvas.text(obj.params.titleX, obj.params.titleY, obj.config.title);
662 obj.txtTitle.attr({
663 "font-size": obj.params.titleFontSize,
664 "font-weight": "bold",
665 "font-family": obj.config.titleFontFamily,
666 "fill": obj.config.titleFontColor,
667 "fill-opacity": "1"
668 });
669 setDy(obj.txtTitle, obj.params.titleFontSize, obj.params.titleY);
670
671 // value
672 obj.txtValue = obj.canvas.text(obj.params.valueX, obj.params.valueY, 0);
673 obj.txtValue.attr({
674 "font-size": obj.params.valueFontSize,
675 "font-weight": "bold",
676 "font-family": obj.config.valueFontFamily,
677 "fill": obj.config.valueFontColor,
678 "fill-opacity": "0"
679 });
680 setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);
681
682 // label
683 obj.txtLabel = obj.canvas.text(obj.params.labelX, obj.params.labelY, obj.config.label);
684 obj.txtLabel.attr({
685 "font-size": obj.params.labelFontSize,
686 "font-weight": "normal",
687 "font-family": "Arial",
688 "fill": obj.config.labelFontColor,
689 "fill-opacity": "0"
690 });
691 setDy(obj.txtLabel, obj.params.labelFontSize, obj.params.labelY);
692
693 // min
694 var min = obj.config.min;
695 if (obj.config.reverse) {
696 min = obj.config.max;
697 }
698
699 obj.txtMinimum = min;
700 if (obj.config.humanFriendly) {
701 obj.txtMinimum = humanFriendlyNumber(min, obj.config.humanFriendlyDecimal);
702 } else if (obj.config.formatNumber) {
703 obj.txtMinimum = formatNumber(min);
704 }
705 obj.txtMin = obj.canvas.text(obj.params.minX, obj.params.minY, obj.txtMinimum);
706 obj.txtMin.attr({
707 "font-size": obj.params.minFontSize,
708 "font-weight": "normal",
709 "font-family": "Arial",
710 "fill": obj.config.labelFontColor,
711 "fill-opacity": (obj.config.hideMinMax || obj.config.donut) ? "0" : "1"
712 });
713 setDy(obj.txtMin, obj.params.minFontSize, obj.params.minY);
714
715 // max
716 var max = obj.config.max;
717 if (obj.config.reverse) {
718 max = obj.config.min;
719 }
720 obj.txtMaximum = max;
721 if (obj.config.humanFriendly) {
722 obj.txtMaximum = humanFriendlyNumber(max, obj.config.humanFriendlyDecimal);
723 } else if (obj.config.formatNumber) {
724 obj.txtMaximum = formatNumber(max);
725 }
726 obj.txtMax = obj.canvas.text(obj.params.maxX, obj.params.maxY, obj.txtMaximum);
727 obj.txtMax.attr({
728 "font-size": obj.params.maxFontSize,
729 "font-weight": "normal",
730 "font-family": "Arial",
731 "fill": obj.config.labelFontColor,
732 "fill-opacity": (obj.config.hideMinMax || obj.config.donut) ? "0" : "1"
733 });
734 setDy(obj.txtMax, obj.params.maxFontSize, obj.params.maxY);
735
736 var defs = obj.canvas.canvas.childNodes[1];
737 var svg = "http://www.w3.org/2000/svg";
738
739 if (ie !== 'undefined' && ie < 9) {
740 // VML mode - no SVG & SVG filter support
741 } else if (ie !== 'undefined') {
742 onCreateElementNsReady(function() {
743 obj.generateShadow(svg, defs);
744 });
745 } else {
746 obj.generateShadow(svg, defs);
747 }
748
749 // var clear
750 defs, svg = null;
751
752 // set value to display
753 if (obj.config.textRenderer) {
754 obj.originalValue = obj.config.textRenderer(obj.originalValue);
755 } else if (obj.config.humanFriendly) {
756 obj.originalValue = humanFriendlyNumber(obj.originalValue, obj.config.humanFriendlyDecimal) + obj.config.symbol;
757 } else if (obj.config.formatNumber) {
758 obj.originalValue = formatNumber(obj.originalValue) + obj.config.symbol;
759 } else {
760 obj.originalValue = (obj.originalValue * 1).toFixed(obj.config.decimals) + obj.config.symbol;
761 }
762
763 if (obj.config.counter === true) {
764 //on each animation frame
765 eve.on("raphael.anim.frame." + (obj.level.id), function() {
766 var currentValue = obj.level.attr("pki")[0];
767 if (obj.config.reverse) {
768 currentValue = (obj.config.max * 1) + (obj.config.min * 1) - (obj.level.attr("pki")[0] * 1);
769 }
770 if (obj.config.textRenderer) {
771 obj.txtValue.attr("text", obj.config.textRenderer(Math.floor(currentValue)));
772 } else if (obj.config.humanFriendly) {
773 obj.txtValue.attr("text", humanFriendlyNumber(Math.floor(currentValue), obj.config.humanFriendlyDecimal) + obj.config.symbol);
774 } else if (obj.config.formatNumber) {
775 obj.txtValue.attr("text", formatNumber(Math.floor(currentValue)) + obj.config.symbol);
776 } else {
777 obj.txtValue.attr("text", (currentValue * 1).toFixed(obj.config.decimals) + obj.config.symbol);
778 }
779 setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);
780 currentValue = null;
781 });
782 //on animation end
783 eve.on("raphael.anim.finish." + (obj.level.id), function() {
784 obj.txtValue.attr({
785 "text": obj.originalValue
786 });
787 setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);
788 });
789 } else {
790 //on animation start
791 eve.on("raphael.anim.start." + (obj.level.id), function() {
792 obj.txtValue.attr({
793 "text": obj.originalValue
794 });
795 setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);
796 });
797 }
798
799 // animate gauge level, value & label
800 var rvl = obj.config.value;
801 if (obj.config.reverse) {
802 rvl = (obj.config.max * 1) + (obj.config.min * 1) - (obj.config.value * 1);
803 }
804 obj.level.animate({
805 pki: [
806 rvl,
807 obj.config.min,
808 obj.config.max,
809 obj.params.widgetW,
810 obj.params.widgetH,
811 obj.params.dx,
812 obj.params.dy,
813 obj.config.gaugeWidthScale,
814 obj.config.donut,
815 obj.config.reverse
816 ]
817 }, obj.config.startAnimationTime, obj.config.startAnimationType);
818
819 if (obj.config.pointer) {
820 obj.needle.animate({
821 ndl: [
822 rvl,
823 obj.config.min,
824 obj.config.max,
825 obj.params.widgetW,
826 obj.params.widgetH,
827 obj.params.dx,
828 obj.params.dy,
829 obj.config.gaugeWidthScale,
830 obj.config.donut
831 ]
832 }, obj.config.startAnimationTime, obj.config.startAnimationType);
833 }
834
835 obj.txtValue.animate({
836 "fill-opacity": (obj.config.hideValue) ? "0" : "1"
837 }, obj.config.startAnimationTime, obj.config.startAnimationType);
838 obj.txtLabel.animate({
839 "fill-opacity": "1"
840 }, obj.config.startAnimationTime, obj.config.startAnimationType);
841};
842
843/** Refresh gauge level */
844JustGage.prototype.refresh = function(val, max) {
845
846 var obj = this;
847 var displayVal, color, max = max || null;
848
849 // set new max
850 if (max !== null) {
851 obj.config.max = max;
852 // TODO: update customSectors
853
854 obj.txtMaximum = obj.config.max;
855 if (obj.config.humanFriendly) {
856 obj.txtMaximum = humanFriendlyNumber(obj.config.max, obj.config.humanFriendlyDecimal);
857 } else if (obj.config.formatNumber) {
858 obj.txtMaximum = formatNumber(obj.config.max);
859 }
860 if (!obj.config.reverse) {
861 obj.txtMax.attr({
862 "text": obj.txtMaximum
863 });
864 setDy(obj.txtMax, obj.params.maxFontSize, obj.params.maxY);
865 } else {
866 obj.txtMin.attr({
867 "text": obj.txtMaximum
868 });
869 setDy(obj.txtMin, obj.params.minFontSize, obj.params.minY);
870 }
871 }
872
873 // overflow values
874 displayVal = val;
875 if ((val * 1) > (obj.config.max * 1)) {
876 val = (obj.config.max * 1);
877 }
878 if ((val * 1) < (obj.config.min * 1)) {
879 val = (obj.config.min * 1);
880 }
881
882 color = getColor(val, (val - obj.config.min) / (obj.config.max - obj.config.min), obj.config.levelColors, obj.config.noGradient, obj.config.customSectors);
883
884 if (obj.config.textRenderer) {
885 displayVal = obj.config.textRenderer(displayVal);
886 } else if (obj.config.humanFriendly) {
887 displayVal = humanFriendlyNumber(displayVal, obj.config.humanFriendlyDecimal) + obj.config.symbol;
888 } else if (obj.config.formatNumber) {
889 displayVal = formatNumber((displayVal * 1).toFixed(obj.config.decimals)) + obj.config.symbol;
890 } else {
891 displayVal = (displayVal * 1).toFixed(obj.config.decimals) + obj.config.symbol;
892 }
893 obj.originalValue = displayVal;
894 obj.config.value = val * 1;
895
896 if (!obj.config.counter) {
897 obj.txtValue.attr({
898 "text": displayVal
899 });
900 setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);
901 }
902
903 var rvl = obj.config.value;
904 if (obj.config.reverse) {
905 rvl = (obj.config.max * 1) + (obj.config.min * 1) - (obj.config.value * 1);
906 }
907 obj.level.animate({
908 pki: [
909 rvl,
910 obj.config.min,
911 obj.config.max,
912 obj.params.widgetW,
913 obj.params.widgetH,
914 obj.params.dx,
915 obj.params.dy,
916 obj.config.gaugeWidthScale,
917 obj.config.donut,
918 obj.config.reverse
919 ],
920 "fill": color
921 }, obj.config.refreshAnimationTime, obj.config.refreshAnimationType);
922
923 if (obj.config.pointer) {
924 obj.needle.animate({
925 ndl: [
926 rvl,
927 obj.config.min,
928 obj.config.max,
929 obj.params.widgetW,
930 obj.params.widgetH,
931 obj.params.dx,
932 obj.params.dy,
933 obj.config.gaugeWidthScale,
934 obj.config.donut
935 ]
936 }, obj.config.refreshAnimationTime, obj.config.refreshAnimationType);
937 }
938
939 // var clear
940 obj, displayVal, color, max = null;
941};
942
943/** Generate shadow */
944JustGage.prototype.generateShadow = function(svg, defs) {
945
946 var obj = this;
947 var sid = "inner-shadow-" + obj.config.id;
948 var gaussFilter, feOffset, feGaussianBlur, feComposite1, feFlood, feComposite2, feComposite3;
949
950 // FILTER
951 gaussFilter = document.createElementNS(svg, "filter");
952 gaussFilter.setAttribute("id", sid);
953 defs.appendChild(gaussFilter);
954
955 // offset
956 feOffset = document.createElementNS(svg, "feOffset");
957 feOffset.setAttribute("dx", 0);
958 feOffset.setAttribute("dy", obj.config.shadowVerticalOffset);
959 gaussFilter.appendChild(feOffset);
960
961 // blur
962 feGaussianBlur = document.createElementNS(svg, "feGaussianBlur");
963 feGaussianBlur.setAttribute("result", "offset-blur");
964 feGaussianBlur.setAttribute("stdDeviation", obj.config.shadowSize);
965 gaussFilter.appendChild(feGaussianBlur);
966
967 // composite 1
968 feComposite1 = document.createElementNS(svg, "feComposite");
969 feComposite1.setAttribute("operator", "out");
970 feComposite1.setAttribute("in", "SourceGraphic");
971 feComposite1.setAttribute("in2", "offset-blur");
972 feComposite1.setAttribute("result", "inverse");
973 gaussFilter.appendChild(feComposite1);
974
975 // flood
976 feFlood = document.createElementNS(svg, "feFlood");
977 feFlood.setAttribute("flood-color", "black");
978 feFlood.setAttribute("flood-opacity", obj.config.shadowOpacity);
979 feFlood.setAttribute("result", "color");
980 gaussFilter.appendChild(feFlood);
981
982 // composite 2
983 feComposite2 = document.createElementNS(svg, "feComposite");
984 feComposite2.setAttribute("operator", "in");
985 feComposite2.setAttribute("in", "color");
986 feComposite2.setAttribute("in2", "inverse");
987 feComposite2.setAttribute("result", "shadow");
988 gaussFilter.appendChild(feComposite2);
989
990 // composite 3
991 feComposite3 = document.createElementNS(svg, "feComposite");
992 feComposite3.setAttribute("operator", "over");
993 feComposite3.setAttribute("in", "shadow");
994 feComposite3.setAttribute("in2", "SourceGraphic");
995 gaussFilter.appendChild(feComposite3);
996
997 // set shadow
998 if (!obj.config.hideInnerShadow) {
999 obj.canvas.canvas.childNodes[2].setAttribute("filter", "url(#" + sid + ")");
1000 obj.canvas.canvas.childNodes[3].setAttribute("filter", "url(#" + sid + ")");
1001 }
1002
1003 // var clear
1004 gaussFilter, feOffset, feGaussianBlur, feComposite1, feFlood, feComposite2, feComposite3 = null;
1005};
1006
1007//
1008// tiny helper function to lookup value of a key from two hash tables
1009// if none found, return defaultvalue
1010//
1011// key: string
1012// tablea: object
1013// tableb: DOMStringMap|object
1014// defval: string|integer|float|null
1015// datatype: return datatype
1016// delimiter: delimiter to be used in conjunction with datatype formatting
1017//
1018function kvLookup(key, tablea, tableb, defval, datatype, delimiter) {
1019 var val = defval;
1020 var canConvert = false;
1021 if (!(key === null || key === undefined)) {
1022 if (tableb !== null && tableb !== undefined && typeof tableb === "object" && key in tableb) {
1023 val = tableb[key];
1024 canConvert = true;
1025 } else if (tablea !== null && tablea !== undefined && typeof tablea === "object" && key in tablea) {
1026 val = tablea[key];
1027 canConvert = true;
1028 } else {
1029 val = defval;
1030 }
1031 if (canConvert === true) {
1032 if (datatype !== null && datatype !== undefined) {
1033 switch (datatype) {
1034 case 'int':
1035 val = parseInt(val, 10);
1036 break;
1037 case 'float':
1038 val = parseFloat(val);
1039 break;
1040 default:
1041 break;
1042 }
1043 }
1044 }
1045 }
1046 return val;
1047};
1048
1049/** Get color for value */
1050function getColor(val, pct, col, noGradient, custSec) {
1051
1052 var no, inc, colors, percentage, rval, gval, bval, lower, upper, range, rangePct, pctLower, pctUpper, color;
1053 var noGradient = noGradient || custSec.length > 0;
1054
1055 if (custSec.length > 0) {
1056 for (var i = 0; i < custSec.length; i++) {
1057 if (val > custSec[i].lo && val <= custSec[i].hi) {
1058 return custSec[i].color;
1059 }
1060 }
1061 }
1062
1063 no = col.length;
1064 if (no === 1) return col[0];
1065 inc = (noGradient) ? (1 / no) : (1 / (no - 1));
1066 colors = [];
1067 for (i = 0; i < col.length; i++) {
1068 percentage = (noGradient) ? (inc * (i + 1)) : (inc * i);
1069 rval = parseInt((cutHex(col[i])).substring(0, 2), 16);
1070 gval = parseInt((cutHex(col[i])).substring(2, 4), 16);
1071 bval = parseInt((cutHex(col[i])).substring(4, 6), 16);
1072 colors[i] = {
1073 pct: percentage,
1074 color: {
1075 r: rval,
1076 g: gval,
1077 b: bval
1078 }
1079 };
1080 }
1081
1082 if (pct === 0) {
1083 return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')';
1084 }
1085
1086 for (var j = 0; j < colors.length; j++) {
1087 if (pct <= colors[j].pct) {
1088 if (noGradient) {
1089 return 'rgb(' + [colors[j].color.r, colors[j].color.g, colors[j].color.b].join(',') + ')';
1090 } else {
1091 lower = colors[j - 1];
1092 upper = colors[j];
1093 range = upper.pct - lower.pct;
1094 rangePct = (pct - lower.pct) / range;
1095 pctLower = 1 - rangePct;
1096 pctUpper = rangePct;
1097 color = {
1098 r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),
1099 g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),
1100 b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)
1101 };
1102 return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';
1103 }
1104 }
1105 }
1106
1107}
1108
1109/** Fix Raphael display:none tspan dy attribute bug */
1110function setDy(elem, fontSize, txtYpos) {
1111 if ((!ie || ie > 9) && elem.node.firstChild.attributes.dy) {
1112 elem.node.firstChild.attributes.dy.value = 0;
1113 }
1114}
1115
1116/** Random integer */
1117function getRandomInt(min, max) {
1118 return Math.floor(Math.random() * (max - min + 1)) + min;
1119}
1120
1121/** Cut hex */
1122function cutHex(str) {
1123 return (str.charAt(0) == "#") ? str.substring(1, 7) : str;
1124}
1125
1126/** Human friendly number suffix - From: http://stackoverflow.com/questions/2692323/code-golf-friendly-number-abbreviator */
1127function humanFriendlyNumber(n, d) {
1128 var p, d2, i, s;
1129
1130 p = Math.pow;
1131 d2 = p(10, d);
1132 i = 7;
1133 while (i) {
1134 s = p(10, i-- * 3);
1135 if (s <= n) {
1136 n = Math.round(n * d2 / s) / d2 + "KMGTPE" [i];
1137 }
1138 }
1139 return n;
1140}
1141
1142/** Format numbers with commas - From: http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript */
1143function formatNumber(x) {
1144 var parts = x.toString().split(".");
1145 parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1146 return parts.join(".");
1147}
1148
1149/** Get style */
1150function getStyle(oElm, strCssRule) {
1151 var strValue = "";
1152 if (document.defaultView && document.defaultView.getComputedStyle) {
1153 strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
1154 } else if (oElm.currentStyle) {
1155 strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) {
1156 return p1.toUpperCase();
1157 });
1158 strValue = oElm.currentStyle[strCssRule];
1159 }
1160 return strValue;
1161}
1162
1163/** Create Element NS Ready */
1164function onCreateElementNsReady(func) {
1165 if (document.createElementNS !== undefined) {
1166 func();
1167 } else {
1168 setTimeout(function() {
1169 onCreateElementNsReady(func);
1170 }, 100);
1171 }
1172}
1173
1174/** Get IE version */
1175// ----------------------------------------------------------
1176// A short snippet for detecting versions of IE in JavaScript
1177// without resorting to user-agent sniffing
1178// ----------------------------------------------------------
1179// If you're not in IE (or IE version is less than 5) then:
1180// ie === undefined
1181// If you're in IE (>=5) then you can determine which version:
1182// ie === 7; // IE7
1183// Thus, to detect IE:
1184// if (ie) {}
1185// And to detect the version:
1186// ie === 6 // IE6
1187// ie > 7 // IE8, IE9 ...
1188// ie < 9 // Anything less than IE9
1189// ----------------------------------------------------------
1190// UPDATE: Now using Live NodeList idea from @jdalton
1191var ie = (function() {
1192
1193 var undef,
1194 v = 3,
1195 div = document.createElement('div'),
1196 all = div.getElementsByTagName('i');
1197
1198 while (
1199 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
1200 all[0]
1201 );
1202 return v > 4 ? v : undef;
1203}());
1204
1205// extend target object with second object
1206function extend(out) {
1207 out = out || {};
1208
1209 for (var i = 1; i < arguments.length; i++) {
1210 if (!arguments[i])
1211 continue;
1212
1213 for (var key in arguments[i]) {
1214 if (arguments[i].hasOwnProperty(key))
1215 out[key] = arguments[i][key];
1216 }
1217 }
1218
1219 return out;
1220};
Note: See TracBrowser for help on using the repository browser.