[IMP] [FIX] kanban: updated justgage and sparklin libraries; fixed gauge widget showi...
authorThibault Delavallée <tde@openerp.com>
Fri, 6 Sep 2013 09:32:21 +0000 (11:32 +0200)
committerThibault Delavallée <tde@openerp.com>
Fri, 6 Sep 2013 09:32:21 +0000 (11:32 +0200)
bzr revid: tde@openerp.com-20130906093221-n94whqrrj2meknwf

addons/web/__openerp__.py
addons/web/static/lib/jquery.sparkline/jquery.sparkline.js
addons/web/static/lib/justgage/justgage.1.0.1.js [deleted file]
addons/web/static/lib/justgage/justgage.js [new file with mode: 0644]
addons/web_kanban/static/src/js/kanban.js

index 32a108c..9b13fd4 100644 (file)
@@ -36,7 +36,7 @@ This module provides the core of the OpenERP Web Client.
         "static/lib/jquery.tipsy/jquery.tipsy.js",
         "static/lib/jquery.textext/jquery.textext.js",
         "static/lib/jquery.timeago/jquery.timeago.js",
-        "static/lib/justgage/justgage.1.0.1.js",
+        "static/lib/justgage/justgage.js",
         "static/lib/qweb/qweb2.js",
         "static/lib/underscore/underscore.js",
         "static/lib/underscore.string/lib/underscore.string.js",
index 8069db4..43b24c0 100644 (file)
@@ -2,7 +2,7 @@
 *
 * jquery.sparkline.js
 *
-* v2.1.1
+* v2.1.2
 * (c) Splunk, Inc
 * Contact: Gareth Watts (gareth@splunk.com)
 * http://omnipotent.net/jquery.sparkline/
 
 /*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
 
+(function(document, Math, undefined) { // performance/minified-size optimization
 (function(factory) {
     if(typeof define === 'function' && define.amd) {
         define(['jquery'], factory);
-    }
-    else {
+    } else if (jQuery && !jQuery.fn.sparkline) {
         factory(jQuery);
     }
 }
         if (useExisting && (target = this.data('_jqs_vcanvas'))) {
             return target;
         }
+
+        if ($.fn.sparkline.canvas === false) {
+            // We've already determined that neither Canvas nor VML are available
+            return false;
+
+        } else if ($.fn.sparkline.canvas === undefined) {
+            // No function defined yet -- need to see if we support Canvas or VML
+            var el = document.createElement('canvas');
+            if (!!(el.getContext && el.getContext('2d'))) {
+                // Canvas is available
+                $.fn.sparkline.canvas = function(width, height, target, interact) {
+                    return new VCanvas_canvas(width, height, target, interact);
+                };
+            } else if (document.namespaces && !document.namespaces.v) {
+                // VML is available
+                document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
+                $.fn.sparkline.canvas = function(width, height, target, interact) {
+                    return new VCanvas_vml(width, height, target);
+                };
+            } else {
+                // Neither Canvas nor VML are available
+                $.fn.sparkline.canvas = false;
+                return false;
+            }
+        }
+
         if (width === undefined) {
             width = $(this).innerWidth();
         }
         if (height === undefined) {
             height = $(this).innerHeight();
         }
-        if ($.fn.sparkline.hasCanvas) {
-            target = new VCanvas_canvas(width, height, this, interact);
-        } else if ($.fn.sparkline.hasVML) {
-            target = new VCanvas_vml(width, height, this);
-        } else {
-            return false;
-        }
+
+        target = $.fn.sparkline.canvas(width, height, this, interact);
+
         mhandler = $(this).data('_jqs_mhandler');
         if (mhandler) {
             mhandler.registerCanvas(target);
                     mhandler.registerSparkline(sp);
                 }
             };
-            // jQuery 1.3.0 completely changed the meaning of :hidden :-/
-            if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || ($.fn.jquery < '1.3.0' && $(this).parents().is(':hidden')) || !$(this).parents('body').length) {
+            if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {
                 if (!options.get('composite') && $.data(this, '_jqs_pending')) {
                     // remove any existing references to the element
                     for (i = pending.length; i; i--) {
     // Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
     // This is accessible as $(foo).simpledraw()
 
-    // Detect browser renderer support
-    (function() {
-        if (document.namespaces && !document.namespaces.v) {
-            $.fn.sparkline.hasVML = true;
-            document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
-        } else {
-            $.fn.sparkline.hasVML = false;
-        }
-
-        var el = document.createElement('canvas');
-        $.fn.sparkline.hasCanvas = !!(el.getContext && el.getContext('2d'));
-
-    })()
-
     VShape = createClass({
         init: function (target, id, type, args) {
             this.target = target;
         }
     });
 
-}));
+}))}(document, Math));
\ No newline at end of file
diff --git a/addons/web/static/lib/justgage/justgage.1.0.1.js b/addons/web/static/lib/justgage/justgage.1.0.1.js
deleted file mode 100644 (file)
index 24540be..0000000
+++ /dev/null
@@ -1,946 +0,0 @@
-/**\r
- * JustGage - this is work-in-progress, unreleased, unofficial code, so it might not work top-notch :)\r
- * Check http://www.justgage.com for official releases\r
- * Licensed under MIT.\r
- * @author Bojan Djuricic  (@Toorshia)\r
- *\r
- * LATEST UPDATES\r
-\r
- * -----------------------------\r
- * April 18, 2013.\r
- * -----------------------------\r
-     * parentNode - use this instead of id, to attach gauge to node which is outside of DOM tree - https://github.com/toorshia/justgage/issues/48\r
-     * width - force gauge width\r
-     * height - force gauge height\r
-\r
- * -----------------------------\r
- * April 17, 2013.\r
- * -----------------------------\r
-     * fix - https://github.com/toorshia/justgage/issues/49\r
-\r
- * -----------------------------\r
- * April 01, 2013.\r
- * -----------------------------\r
-     * fix - https://github.com/toorshia/justgage/issues/46\r
-\r
- * -----------------------------\r
- * March 26, 2013.\r
- * -----------------------------\r
-     * customSectors - define specific color for value range (0-10 : red, 10-30 : blue etc.)\r
-\r
- * -----------------------------\r
- * March 23, 2013.\r
- * -----------------------------\r
-     * counter - option to animate value  in counting fashion\r
-     * fix - https://github.com/toorshia/justgage/issues/45\r
-\r
- * -----------------------------\r
- * March 13, 2013.\r
- * -----------------------------\r
-     * refresh method - added optional 'max' parameter to use when you need to update max value\r
-\r
- * -----------------------------\r
- * February 26, 2013.\r
- * -----------------------------\r
-     * decimals - option to define/limit number of decimals when not using humanFriendly or customRenderer to display value\r
-     * fixed a missing parameters bug when calling generateShadow()  for IE < 9\r
-\r
- * -----------------------------\r
- * December 31, 2012.\r
- * -----------------------------\r
-     * fixed text y-position for hidden divs - workaround for Raphael <tspan> 'dy' bug - https://github.com/DmitryBaranovskiy/raphael/issues/491\r
-     * 'show' parameters, like showMinMax are now 'hide' because I am lame developer - please update these in your setups\r
-     * Min and Max labels are now auto-off when in donut mode\r
-     * Start angle in donut mode is now 90\r
-     * donutStartAngle - option to define start angle for donut\r
-\r
- * -----------------------------\r
- * November 25, 2012.\r
- * -----------------------------\r
-     * Option to define custom rendering function for displayed value\r
-\r
- * -----------------------------\r
- * November 19, 2012.\r
- * -----------------------------\r
-     * Config.value is now updated after gauge refresh\r
-\r
- * -----------------------------\r
- * November 13, 2012.\r
- * -----------------------------\r
-     * Donut display mode added\r
-     * Option to hide value label\r
-     * Option to enable responsive gauge size\r
-     * Removed default title attribute\r
-     * Option to accept min and max defined as string values\r
-     * Option to configure value symbol\r
-     * Fixed bad aspect ratio calculations\r
-     * Option to configure minimum font size for all texts\r
-     * Option to show shorthand big numbers (human friendly)\r
-     */\r
-\r
- JustGage = function(config) {\r
-\r
-  // if (!config.id) {alert("Missing id parameter for gauge!"); return false;}\r
-  // if (!document.getElementById(config.id)) {alert("No element with id: \""+config.id+"\" found!"); return false;}\r
-\r
-  var obj = this;\r
-\r
-  // configurable parameters\r
-  obj.config =\r
-  {\r
-    // id : string\r
-    // this is container element id\r
-    id : config.id,\r
-\r
-    // parentNode : node object\r
-    // this is container element\r
-    parentNode : (config.parentNode) ? config.parentNode : null,\r
-\r
-    // width : int\r
-    // gauge width\r
-    width : (config.width) ? config.width : null,\r
-\r
-    // height : int\r
-    // gauge height\r
-    height : (config.height) ? config.height : null,\r
-\r
-    // title : string\r
-    // gauge title\r
-    title : (config.title) ? config.title : "",\r
-\r
-    // titleFontColor : string\r
-    // color of gauge title\r
-    titleFontColor : (config.titleFontColor) ? config.titleFontColor : "#999999",\r
-\r
-    // value : int\r
-    // value gauge is showing\r
-    value : (config.value) ? config.value : 0,\r
-\r
-    // valueFontColor : string\r
-    // color of label showing current value\r
-    valueFontColor : (config.valueFontColor) ? config.valueFontColor : "#010101",\r
-\r
-    // symbol : string\r
-    // special symbol to show next to value\r
-    symbol : (config.symbol) ? config.symbol : "",\r
-\r
-    // min : int\r
-    // min value\r
-    min : (config.min !== undefined) ? parseFloat(config.min) : 0,\r
-\r
-    // max : int\r
-    // max value\r
-    max : (config.max !== undefined) ? parseFloat(config.max) : 100,\r
-\r
-    // humanFriendlyDecimal : int\r
-    // number of decimal places for our human friendly number to contain\r
-    humanFriendlyDecimal : (config.humanFriendlyDecimal) ? config.humanFriendlyDecimal : 0,\r
-\r
-    // textRenderer: func\r
-    // function applied before rendering text\r
-    textRenderer  : (config.textRenderer) ? config.textRenderer : null,\r
-\r
-    // gaugeWidthScale : float\r
-    // width of the gauge element\r
-    gaugeWidthScale : (config.gaugeWidthScale) ? config.gaugeWidthScale : 1.0,\r
-\r
-    // gaugeColor : string\r
-    // background color of gauge element\r
-    gaugeColor : (config.gaugeColor) ? config.gaugeColor : "#edebeb",\r
-\r
-    // label : string\r
-    // text to show below value\r
-    label : (config.label) ? config.label : "",\r
-\r
-    // labelFontColor : string\r
-    // color of label showing label under value\r
-    labelFontColor : (config.labelFontColor) ? config.labelFontColor : "#b3b3b3",\r
-\r
-    // shadowOpacity : int\r
-    // 0 ~ 1\r
-    shadowOpacity : (config.shadowOpacity) ? config.shadowOpacity : 0.2,\r
-\r
-    // shadowSize: int\r
-    // inner shadow size\r
-    shadowSize : (config.shadowSize) ? config.shadowSize : 5,\r
-\r
-    // shadowVerticalOffset : int\r
-    // how much shadow is offset from top\r
-    shadowVerticalOffset : (config.shadowVerticalOffset) ? config.shadowVerticalOffset : 3,\r
-\r
-    // levelColors : string[]\r
-    // colors of indicator, from lower to upper, in RGB format\r
-    levelColors : (config.levelColors) ? config.levelColors : [\r
-    "#a9d70b",\r
-    "#f9c802",\r
-    "#ff0000"\r
-    ],\r
-\r
-    // startAnimationTime : int\r
-    // length of initial animation\r
-    startAnimationTime : (config.startAnimationTime) ? config.startAnimationTime : 700,\r
-\r
-    // startAnimationType : string\r
-    // type of initial animation (linear, >, <,  <>, bounce)\r
-    startAnimationType : (config.startAnimationType) ? config.startAnimationType : ">",\r
-\r
-    // refreshAnimationTime : int\r
-    // length of refresh animation\r
-    refreshAnimationTime : (config.refreshAnimationTime) ? config.refreshAnimationTime : 700,\r
-\r
-    // refreshAnimationType : string\r
-    // type of refresh animation (linear, >, <,  <>, bounce)\r
-    refreshAnimationType : (config.refreshAnimationType) ? config.refreshAnimationType : ">",\r
-\r
-    // donutStartAngle : int\r
-    // angle to start from when in donut mode\r
-    donutStartAngle : (config.donutStartAngle) ? config.donutStartAngle : 90,\r
-\r
-    // valueMinFontSize : int\r
-    // absolute minimum font size for the value\r
-    valueMinFontSize : config.valueMinFontSize || 16,\r
-\r
-    // titleMinFontSize\r
-    // absolute minimum font size for the title\r
-    titleMinFontSize : config.titleMinFontSize || 10,\r
-\r
-    // labelMinFontSize\r
-    // absolute minimum font size for the label\r
-    labelMinFontSize : config.labelMinFontSize || 10,\r
-\r
-    // minLabelMinFontSize\r
-    // absolute minimum font size for the minimum label\r
-    minLabelMinFontSize : config.minLabelMinFontSize || 10,\r
-\r
-    // maxLabelMinFontSize\r
-    // absolute minimum font size for the maximum label\r
-    maxLabelMinFontSize : config.maxLabelMinFontSize || 10,\r
-\r
-    // hideValue : bool\r
-    // hide value text\r
-    hideValue : (config.hideValue) ? config.hideValue : false,\r
-\r
-    // hideMinMax : bool\r
-    // hide min and max values\r
-    hideMinMax : (config.hideMinMax) ? config.hideMinMax : false,\r
-\r
-    // hideInnerShadow : bool\r
-    // hide inner shadow\r
-    hideInnerShadow : (config.hideInnerShadow) ? config.hideInnerShadow : false,\r
-\r
-    // humanFriendly : bool\r
-    // convert large numbers for min, max, value to human friendly (e.g. 1234567 -> 1.23M)\r
-    humanFriendly : (config.humanFriendly) ? config.humanFriendly : false,\r
-\r
-    // noGradient : bool\r
-    // whether to use gradual color change for value, or sector-based\r
-    noGradient : (config.noGradient) ? config.noGradient : false,\r
-\r
-    // donut : bool\r
-    // show full donut gauge\r
-    donut : (config.donut) ? config.donut : false,\r
-\r
-    // relativeGaugeSize : bool\r
-    // whether gauge size should follow changes in container element size\r
-    relativeGaugeSize : (config.relativeGaugeSize) ? config.relativeGaugeSize : false,\r
-\r
-    // counter : bool\r
-    // animate level number change\r
-    counter : (config.counter) ? config.counter : false,\r
-\r
-    // decimals : int\r
-    // number of digits after floating point\r
-    decimals : (config.decimals) ? config.decimals : 0,\r
-\r
-    // customSectors : [] of objects\r
-    // number of digits after floating point\r
-    customSectors : (config.customSectors) ? config.customSectors : []\r
-  };\r
-\r
-  // variables\r
-  var\r
-  canvasW,\r
-  canvasH,\r
-  widgetW,\r
-  widgetH,\r
-  aspect,\r
-  dx,\r
-  dy,\r
-  titleFontSize,\r
-  titleX,\r
-  titleY,\r
-  valueFontSize,\r
-  valueX,\r
-  valueY,\r
-  labelFontSize,\r
-  labelX,\r
-  labelY,\r
-  minFontSize,\r
-  minX,\r
-  minY,\r
-  maxFontSize,\r
-  maxX,\r
-  maxY;\r
-\r
-  // overflow values\r
-  if (obj.config.value > obj.config.max) obj.config.value = obj.config.max;\r
-  if (obj.config.value < obj.config.min) obj.config.value = obj.config.min;\r
-  obj.originalValue = config.value;\r
-\r
-  // create canvas\r
-  if (obj.config.id !== null && (document.getElementById(obj.config.id)) !== null) {\r
-    obj.canvas = Raphael(obj.config.id, "100%", "100%");\r
-  } else if (obj.config.parentNode !== null) {\r
-    obj.canvas = Raphael(obj.config.parentNode, "100%", "100%");\r
-  }\r
-\r
-  if (obj.config.relativeGaugeSize === true) {\r
-    obj.canvas.setViewBox(0, 0, 200, 150, true);\r
-  }\r
-\r
-  // canvas dimensions\r
-  if (obj.config.relativeGaugeSize === true) {\r
-    canvasW = 200;\r
-    canvasH = 150;\r
-  } else if (obj.config.width !== null && obj.config.height !== null) {\r
-    canvasW = obj.config.width;\r
-    canvasH = obj.config.height;\r
-  } else if (obj.config.parentNode !== null) {\r
-    obj.canvas.setViewBox(0, 0, 200, 150, true);\r
-    canvasW = 200;\r
-    canvasH = 150;\r
-  } else {\r
-    canvasW = getStyle(document.getElementById(obj.config.id), "width").slice(0, -2) * 1;\r
-    canvasH = getStyle(document.getElementById(obj.config.id), "height").slice(0, -2) * 1;\r
-  }\r
-\r
-  // widget dimensions\r
-  if (obj.config.donut === true) {\r
-\r
-    // DONUT *******************************\r
-\r
-    // width more than height\r
-    if(canvasW > canvasH) {\r
-      widgetH = canvasH;\r
-      widgetW = widgetH;\r
-    // width less than height\r
-  } else if (canvasW < canvasH) {\r
-    widgetW = canvasW;\r
-    widgetH = widgetW;\r
-      // if height don't fit, rescale both\r
-      if(widgetH > canvasH) {\r
-        aspect = widgetH / canvasH;\r
-        widgetH = widgetH / aspect;\r
-        widgetW = widgetH / aspect;\r
-      }\r
-    // equal\r
-  } else {\r
-    widgetW = canvasW;\r
-    widgetH = widgetW;\r
-  }\r
-\r
-    // delta\r
-    dx = (canvasW - widgetW)/2;\r
-    dy = (canvasH - widgetH)/2;\r
-\r
-    // title\r
-    titleFontSize = ((widgetH / 8) > 10) ? (widgetH / 10) : 10;\r
-    titleX = dx + widgetW / 2;\r
-    titleY = dy + widgetH / 11;\r
-\r
-    // value\r
-    valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 5.4) : 18;\r
-    valueX = dx + widgetW / 2;\r
-    if(obj.config.label !== '') {\r
-      valueY = dy + widgetH / 1.85;\r
-    } else {\r
-      valueY = dy + widgetH / 1.7;\r
-    }\r
-\r
-    // label\r
-    labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;\r
-    labelX = dx + widgetW / 2;\r
-    labelY = valueY + labelFontSize;\r
-\r
-    // min\r
-    minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;\r
-    minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
-    minY = labelY;\r
-\r
-    // max\r
-    maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;\r
-    maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
-    maxY = labelY;\r
-\r
-  } else {\r
-    // HALF *******************************\r
-\r
-    // width more than height\r
-    if(canvasW > canvasH) {\r
-      widgetH = canvasH;\r
-      widgetW = widgetH * 1.25;\r
-      //if width doesn't fit, rescale both\r
-      if(widgetW > canvasW) {\r
-        aspect = widgetW / canvasW;\r
-        widgetW = widgetW / aspect;\r
-        widgetH = widgetH / aspect;\r
-      }\r
-    // width less than height\r
-  } else if (canvasW < canvasH) {\r
-    widgetW = canvasW;\r
-    widgetH = widgetW / 1.25;\r
-      // if height don't fit, rescale both\r
-      if(widgetH > canvasH) {\r
-        aspect = widgetH / canvasH;\r
-        widgetH = widgetH / aspect;\r
-        widgetW = widgetH / aspect;\r
-      }\r
-    // equal\r
-  } else {\r
-    widgetW = canvasW;\r
-    widgetH = widgetW * 0.75;\r
-  }\r
-\r
-    // delta\r
-    dx = (canvasW - widgetW)/2;\r
-    dy = (canvasH - widgetH)/2;\r
-\r
-    // title\r
-    titleFontSize = ((widgetH / 8) > obj.config.titleMinFontSize) ? (widgetH / 10) : obj.config.titleMinFontSize;\r
-    titleX = dx + widgetW / 2;\r
-    titleY = dy + widgetH / 6.4;\r
-\r
-    // value\r
-    valueFontSize = ((widgetH / 6.5) > obj.config.valueMinFontSize) ? (widgetH / 6.5) : obj.config.valueMinFontSize;\r
-    valueX = dx + widgetW / 2;\r
-    valueY = dy + widgetH / 1.275;\r
-\r
-    // label\r
-    labelFontSize = ((widgetH / 16) > obj.config.labelMinFontSize) ? (widgetH / 16) : obj.config.labelMinFontSize;\r
-    labelX = dx + widgetW / 2;\r
-    labelY = valueY + valueFontSize / 2 + 5;\r
-\r
-    // min\r
-    minFontSize = ((widgetH / 16) > obj.config.minLabelMinFontSize) ? (widgetH / 16) : obj.config.minLabelMinFontSize;\r
-    minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
-    minY = labelY;\r
-\r
-    // max\r
-    maxFontSize = ((widgetH / 16) > obj.config.maxLabelMinFontSize) ? (widgetH / 16) : obj.config.maxLabelMinFontSize;\r
-    maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
-    maxY = labelY;\r
-  }\r
-\r
-  // parameters\r
-  obj.params  = {\r
-    canvasW : canvasW,\r
-    canvasH : canvasH,\r
-    widgetW : widgetW,\r
-    widgetH : widgetH,\r
-    dx : dx,\r
-    dy : dy,\r
-    titleFontSize : titleFontSize,\r
-    titleX : titleX,\r
-    titleY : titleY,\r
-    valueFontSize : valueFontSize,\r
-    valueX : valueX,\r
-    valueY : valueY,\r
-    labelFontSize : labelFontSize,\r
-    labelX : labelX,\r
-    labelY : labelY,\r
-    minFontSize : minFontSize,\r
-    minX : minX,\r
-    minY : minY,\r
-    maxFontSize : maxFontSize,\r
-    maxX : maxX,\r
-    maxY : maxY\r
-  };\r
-\r
-  // var clear\r
-  canvasW, canvasH, widgetW, widgetH, aspect, dx, dy, titleFontSize, titleX, titleY, valueFontSize, valueX, valueY, labelFontSize, labelX, labelY, minFontSize, minX, minY, maxFontSize, maxX, maxY = null\r
-\r
-  // pki - custom attribute for generating gauge paths\r
-  obj.canvas.customAttributes.pki = function (value, min, max, w, h, dx, dy, gws, donut) {\r
-\r
-    var alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path;\r
-\r
-    if (donut) {\r
-      alpha = (1 - 2 * (value - min) / (max - min)) * Math.PI;\r
-      Ro = w / 2 - w / 7;\r
-      Ri = Ro - w / 6.666666666666667 * gws;\r
-\r
-      Cx = w / 2 + dx;\r
-      Cy = h / 1.95 + dy;\r
-\r
-      Xo = w / 2 + dx + Ro * Math.cos(alpha);\r
-      Yo = h - (h - Cy) + 0 - Ro * Math.sin(alpha);\r
-      Xi = w / 2 + dx + Ri * Math.cos(alpha);\r
-      Yi = h - (h - Cy) + 0 - Ri * Math.sin(alpha);\r
-\r
-      path += "M" + (Cx - Ri) + "," + Cy + " ";\r
-      path += "L" + (Cx - Ro) + "," + Cy + " ";\r
-      if (value > ((max - min) / 2)) {\r
-        path += "A" + Ro + "," + Ro + " 0 0 1 " + (Cx + Ro) + "," + Cy + " ";\r
-      }\r
-      path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";\r
-      path += "L" + Xi + "," + Yi + " ";\r
-      if (value > ((max - min) / 2)) {\r
-        path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx + Ri) + "," + Cy + " ";\r
-      }\r
-      path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";\r
-      path += "Z ";\r
-\r
-      return { path: path };\r
-\r
-    } else {\r
-      alpha = (1 - (value - min) / (max - min)) * Math.PI;\r
-      Ro = w / 2 - w / 10;\r
-      Ri = Ro - w / 6.666666666666667 * gws;\r
-\r
-      Cx = w / 2 + dx;\r
-      Cy = h / 1.25 + dy;\r
-\r
-      Xo = w / 2 + dx + Ro * Math.cos(alpha);\r
-      Yo = h - (h - Cy) + 0 - Ro * Math.sin(alpha);\r
-      Xi = w / 2 + dx + Ri * Math.cos(alpha);\r
-      Yi = h - (h - Cy) + 0 - Ri * Math.sin(alpha);\r
-\r
-      path += "M" + (Cx - Ri) + "," + Cy + " ";\r
-      path += "L" + (Cx - Ro) + "," + Cy + " ";\r
-      path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";\r
-      path += "L" + Xi + "," + Yi + " ";\r
-      path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";\r
-      path += "Z ";\r
-\r
-      return { path: path };\r
-    }\r
-\r
-    // var clear\r
-    alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path = null;\r
-  };\r
-\r
-  // gauge\r
-  obj.gauge = obj.canvas.path().attr({\r
-      "stroke": "none",\r
-      "fill": obj.config.gaugeColor,\r
-      pki: [\r
-        obj.config.max,\r
-        obj.config.min,\r
-        obj.config.max,\r
-        obj.params.widgetW,\r
-        obj.params.widgetH,\r
-        obj.params.dx,\r
-        obj.params.dy,\r
-        obj.config.gaugeWidthScale,\r
-        obj.config.donut\r
-      ]\r
-  });\r
-\r
-  // level\r
-  obj.level = obj.canvas.path().attr({\r
-    "stroke": "none",\r
-    "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),\r
-    pki: [\r
-      obj.config.min,\r
-      obj.config.min,\r
-      obj.config.max,\r
-      obj.params.widgetW,\r
-      obj.params.widgetH,\r
-      obj.params.dx,\r
-      obj.params.dy,\r
-      obj.config.gaugeWidthScale,\r
-      obj.config.donut\r
-    ]\r
-  });\r
-  if(obj.config.donut) {\r
-    obj.level.transform("r" + obj.config.donutStartAngle + ", " + (obj.params.widgetW/2 + obj.params.dx) + ", " + (obj.params.widgetH/1.95 + obj.params.dy));\r
-  }\r
-\r
-  // title\r
-  obj.txtTitle = obj.canvas.text(obj.params.titleX, obj.params.titleY, obj.config.title);\r
-  obj.txtTitle.attr({\r
-    "font-size":obj.params.titleFontSize,\r
-    "font-weight":"bold",\r
-    "font-family":"Arial",\r
-    "fill":obj.config.titleFontColor,\r
-    "fill-opacity":"1"\r
-  });\r
-  setDy(obj.txtTitle, obj.params.titleFontSize, obj.params.titleY);\r
-\r
-  // value\r
-  obj.txtValue = obj.canvas.text(obj.params.valueX, obj.params.valueY, 0);\r
-  obj.txtValue.attr({\r
-    "font-size":obj.params.valueFontSize,\r
-    "font-weight":"bold",\r
-    "font-family":"Arial",\r
-    "fill":obj.config.valueFontColor,\r
-    "fill-opacity":"0"\r
-  });\r
-  setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
-\r
-  // label\r
-  obj.txtLabel = obj.canvas.text(obj.params.labelX, obj.params.labelY, obj.config.label);\r
-  obj.txtLabel.attr({\r
-    "font-size":obj.params.labelFontSize,\r
-    "font-weight":"normal",\r
-    "font-family":"Arial",\r
-    "fill":obj.config.labelFontColor,\r
-    "fill-opacity":"0"\r
-  });\r
-  setDy(obj.txtLabel, obj.params.labelFontSize, obj.params.labelY);\r
-\r
-  // min\r
-  obj.txtMinimum = obj.config.min;\r
-  if( obj.config.humanFriendly ) obj.txtMinimum = humanFriendlyNumber( obj.config.min, obj.config.humanFriendlyDecimal );\r
-  obj.txtMin = obj.canvas.text(obj.params.minX, obj.params.minY, obj.txtMinimum);\r
-  obj.txtMin.attr({\r
-    "font-size":obj.params.minFontSize,\r
-    "font-weight":"normal",\r
-    "font-family":"Arial",\r
-    "fill":obj.config.labelFontColor,\r
-    "fill-opacity": (obj.config.hideMinMax || obj.config.donut)? "0" : "1"\r
-  });\r
-  setDy(obj.txtMin, obj.params.minFontSize, obj.params.minY);\r
-\r
-  // max\r
-  obj.txtMaximum = obj.config.max;\r
-  if( obj.config.humanFriendly ) obj.txtMaximum = humanFriendlyNumber( obj.config.max, obj.config.humanFriendlyDecimal );\r
-  obj.txtMax = obj.canvas.text(obj.params.maxX, obj.params.maxY, obj.txtMaximum);\r
-  obj.txtMax.attr({\r
-    "font-size":obj.params.maxFontSize,\r
-    "font-weight":"normal",\r
-    "font-family":"Arial",\r
-    "fill":obj.config.labelFontColor,\r
-    "fill-opacity": (obj.config.hideMinMax || obj.config.donut)? "0" : "1"\r
-  });\r
-  setDy(obj.txtMax, obj.params.maxFontSize, obj.params.maxY);\r
-\r
-  var defs = obj.canvas.canvas.childNodes[1];\r
-  var svg = "http://www.w3.org/2000/svg";\r
-\r
-  if (ie < 9) {\r
-    onCreateElementNsReady(function() {\r
-      obj.generateShadow(svg, defs);\r
-    });\r
-  } else {\r
-    obj.generateShadow(svg, defs);\r
-  }\r
-\r
-  // var clear\r
-  defs, svg = null;\r
-\r
-  // set value to display\r
-  if(obj.config.textRenderer) {\r
-    obj.originalValue = obj.config.textRenderer(obj.originalValue);\r
-  } else if(obj.config.humanFriendly) {\r
-    obj.originalValue = humanFriendlyNumber( obj.originalValue, obj.config.humanFriendlyDecimal ) + obj.config.symbol;\r
-  } else {\r
-    obj.originalValue = (obj.originalValue * 1).toFixed(obj.config.decimals) + obj.config.symbol;\r
-  }\r
-\r
-  if(obj.config.counter === true) {\r
-    //on each animation frame\r
-    eve.on("raphael.anim.frame." + (obj.level.id), function() {\r
-      var currentValue = obj.level.attr("pki");\r
-      if(obj.config.textRenderer) {\r
-        obj.txtValue.attr("text", obj.config.textRenderer(Math.floor(currentValue[0])));\r
-      } else if(obj.config.humanFriendly) {\r
-        obj.txtValue.attr("text", humanFriendlyNumber( Math.floor(currentValue[0]), obj.config.humanFriendlyDecimal ) + obj.config.symbol);\r
-      } else {\r
-        obj.txtValue.attr("text", (currentValue[0] * 1).toFixed(obj.config.decimals) + obj.config.symbol);\r
-      }\r
-      setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
-      currentValue = null;\r
-    });\r
-    //on animation end\r
-    eve.on("raphael.anim.finish." + (obj.level.id), function() {\r
-      obj.txtValue.attr({"text" : obj.originalValue});\r
-      setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
-    });\r
-  } else {\r
-    //on animation start\r
-    eve.on("raphael.anim.start." + (obj.level.id), function() {\r
-      obj.txtValue.attr({"text" : obj.originalValue});\r
-      setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
-    });\r
-  }\r
-\r
-  // animate gauge level, value & label\r
-  obj.level.animate({\r
-    pki: [\r
-      obj.config.value,\r
-      obj.config.min,\r
-      obj.config.max,\r
-      obj.params.widgetW,\r
-      obj.params.widgetH,\r
-      obj.params.dx,\r
-      obj.params.dy,\r
-      obj.config.gaugeWidthScale,\r
-      obj.config.donut\r
-    ]\r
-  }, obj.config.startAnimationTime, obj.config.startAnimationType);\r
-  obj.txtValue.animate({"fill-opacity":(obj.config.hideValue)?"0":"1"}, obj.config.startAnimationTime, obj.config.startAnimationType);\r
-  obj.txtLabel.animate({"fill-opacity":"1"}, obj.config.startAnimationTime, obj.config.startAnimationType);\r
-};\r
-\r
-/** Refresh gauge level */\r
-JustGage.prototype.refresh = function(val, max) {\r
-\r
-  var obj = this;\r
-  var displayVal, color, max = max || null;\r
-\r
-  // set new max\r
-  if(max !== null) {\r
-    obj.config.max = max;\r
-\r
-    obj.txtMaximum = obj.config.max;\r
-    if( obj.config.humanFriendly ) obj.txtMaximum = humanFriendlyNumber( obj.config.max, obj.config.humanFriendlyDecimal );\r
-    obj.txtMax.attr({"text" : obj.txtMaximum});\r
-    setDy(obj.txtMax, obj.params.maxFontSize, obj.params.maxY);\r
-  }\r
-\r
-  // overflow values\r
-  displayVal = val;\r
-  if ((val * 1) > (obj.config.max * 1)) {val = (obj.config.max * 1);}\r
-  if ((val * 1) < (obj.config.min * 1)) {val = (obj.config.min * 1);}\r
-\r
-  color = getColor(val, (val - obj.config.min) / (obj.config.max - obj.config.min), obj.config.levelColors, obj.config.noGradient, obj.config.customSectors);\r
-\r
-  if(obj.config.textRenderer) {\r
-    displayVal = obj.config.textRenderer(displayVal);\r
-  } else if( obj.config.humanFriendly ) {\r
-    displayVal = humanFriendlyNumber( displayVal, obj.config.humanFriendlyDecimal ) + obj.config.symbol;\r
-  } else {\r
-    displayVal = (displayVal * 1).toFixed(obj.config.decimals) + obj.config.symbol;\r
-  }\r
-  obj.originalValue = displayVal;\r
-  obj.config.value = val * 1;\r
-\r
-  if(!obj.config.counter) {\r
-    obj.txtValue.attr({"text":displayVal});\r
-    setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
-  }\r
-\r
-  obj.level.animate({\r
-    pki: [\r
-      obj.config.value,\r
-      obj.config.min,\r
-      obj.config.max,\r
-      obj.params.widgetW,\r
-      obj.params.widgetH,\r
-      obj.params.dx,\r
-      obj.params.dy,\r
-      obj.config.gaugeWidthScale,\r
-      obj.config.donut\r
-    ],\r
-    "fill":color\r
-  },  obj.config.refreshAnimationTime, obj.config.refreshAnimationType);\r
-\r
-  // var clear\r
-  obj, displayVal, color, max = null;\r
-};\r
-\r
-/** Generate shadow */\r
-JustGage.prototype.generateShadow = function(svg, defs) {\r
-\r
-  var obj = this;\r
-  var gaussFilter, feOffset, feGaussianBlur, feComposite1, feFlood, feComposite2, feComposite3;\r
-\r
-  // FILTER\r
-  gaussFilter = document.createElementNS(svg,"filter");\r
-  gaussFilter.setAttribute("id","inner-shadow");\r
-  defs.appendChild(gaussFilter);\r
-\r
-  // offset\r
-  feOffset = document.createElementNS(svg,"feOffset");\r
-  feOffset.setAttribute("dx", 0);\r
-  feOffset.setAttribute("dy", obj.config.shadowVerticalOffset);\r
-  gaussFilter.appendChild(feOffset);\r
-\r
-  // blur\r
-  feGaussianBlur = document.createElementNS(svg,"feGaussianBlur");\r
-  feGaussianBlur.setAttribute("result","offset-blur");\r
-  feGaussianBlur.setAttribute("stdDeviation", obj.config.shadowSize);\r
-  gaussFilter.appendChild(feGaussianBlur);\r
-\r
-  // composite 1\r
-  feComposite1 = document.createElementNS(svg,"feComposite");\r
-  feComposite1.setAttribute("operator","out");\r
-  feComposite1.setAttribute("in", "SourceGraphic");\r
-  feComposite1.setAttribute("in2","offset-blur");\r
-  feComposite1.setAttribute("result","inverse");\r
-  gaussFilter.appendChild(feComposite1);\r
-\r
-  // flood\r
-  feFlood = document.createElementNS(svg,"feFlood");\r
-  feFlood.setAttribute("flood-color","black");\r
-  feFlood.setAttribute("flood-opacity", obj.config.shadowOpacity);\r
-  feFlood.setAttribute("result","color");\r
-  gaussFilter.appendChild(feFlood);\r
-\r
-  // composite 2\r
-  feComposite2 = document.createElementNS(svg,"feComposite");\r
-  feComposite2.setAttribute("operator","in");\r
-  feComposite2.setAttribute("in", "color");\r
-  feComposite2.setAttribute("in2","inverse");\r
-  feComposite2.setAttribute("result","shadow");\r
-  gaussFilter.appendChild(feComposite2);\r
-\r
-  // composite 3\r
-  feComposite3 = document.createElementNS(svg,"feComposite");\r
-  feComposite3.setAttribute("operator","over");\r
-  feComposite3.setAttribute("in", "shadow");\r
-  feComposite3.setAttribute("in2","SourceGraphic");\r
-  gaussFilter.appendChild(feComposite3);\r
-\r
-  // set shadow\r
-  if (!obj.config.hideInnerShadow) {\r
-    obj.canvas.canvas.childNodes[2].setAttribute("filter", "url(#inner-shadow)");\r
-    obj.canvas.canvas.childNodes[3].setAttribute("filter", "url(#inner-shadow)");\r
-  }\r
-\r
-  // var clear\r
-  gaussFilter, feOffset, feGaussianBlur, feComposite1, feFlood, feComposite2, feComposite3 = null;\r
-\r
-};\r
-\r
-/** Get color for value */\r
-function getColor(val, pct, col, noGradient, custSec) {\r
-\r
-  var no, inc, colors, percentage, rval, gval, bval, lower, upper, range, rangePct, pctLower, pctUpper, color;\r
-  var noGradient = noGradient || custSec.length > 0;\r
-\r
-  if(custSec.length > 0) {\r
-    for(var i = 0; i < custSec.length; i++) {\r
-      if(val > custSec[i].lo && val <= custSec[i].hi) {\r
-        return custSec[i].color;\r
-      }\r
-    }\r
-  }\r
-\r
-  no = col.length;\r
-  if (no === 1) return col[0];\r
-  inc = (noGradient) ? (1 / no) : (1 / (no - 1));\r
-  colors = [];\r
-  for (var i = 0; i < col.length; i++) {\r
-    percentage = (noGradient) ? (inc * (i + 1)) : (inc * i);\r
-    rval = parseInt((cutHex(col[i])).substring(0,2),16);\r
-    gval = parseInt((cutHex(col[i])).substring(2,4),16);\r
-    bval = parseInt((cutHex(col[i])).substring(4,6),16);\r
-    colors[i] = { pct: percentage, color: { r: rval, g: gval, b: bval  } };\r
-  }\r
-\r
-  if(pct === 0) {\r
-    return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')';\r
-  }\r
-\r
-  for (var j = 0; j < colors.length; j++) {\r
-    if (pct <= colors[j].pct) {\r
-      if (noGradient) {\r
-        return 'rgb(' + [colors[j].color.r, colors[j].color.g, colors[j].color.b].join(',') + ')';\r
-      } else {\r
-        lower = colors[j - 1];\r
-        upper = colors[j];\r
-        range = upper.pct - lower.pct;\r
-        rangePct = (pct - lower.pct) / range;\r
-        pctLower = 1 - rangePct;\r
-        pctUpper = rangePct;\r
-        color = {\r
-          r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),\r
-          g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),\r
-          b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)\r
-        };\r
-        return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';\r
-      }\r
-    }\r
-  }\r
-\r
-}\r
-\r
-/** Fix Raphael display:none tspan dy attribute bug */\r
-function setDy(elem, fontSize, txtYpos) {\r
-  if (!ie || ie > 9) {\r
-    elem.node.firstChild.attributes.dy.value = 0;\r
-  }\r
-}\r
-\r
-/** Random integer  */\r
-function getRandomInt (min, max) {\r
-  return Math.floor(Math.random() * (max - min + 1)) + min;\r
-}\r
-\r
-/**  Cut hex  */\r
-function cutHex(str) {\r
-  return (str.charAt(0)=="#") ? str.substring(1,7):str;\r
-}\r
-\r
-/**  Human friendly number suffix - From: http://stackoverflow.com/questions/2692323/code-golf-friendly-number-abbreviator */\r
-function humanFriendlyNumber( n, d ) {\r
-  var p, d2, i, s;\r
-\r
-  p = Math.pow;\r
-  d2 = p(10, d);\r
-  i = 7;\r
-  while( i ) {\r
-    s = p(10,i--*3);\r
-    if( s <= n ) {\r
-     n = Math.round(n*d2/s)/d2+"KMGTPE"[i];\r
-   }\r
- }\r
- return n;\r
-}\r
-\r
-/**  Get style  */\r
-function getStyle(oElm, strCssRule){\r
-  var strValue = "";\r
-  if(document.defaultView && document.defaultView.getComputedStyle){\r
-    strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);\r
-  }\r
-  else if(oElm.currentStyle){\r
-    strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){\r
-      return p1.toUpperCase();\r
-    });\r
-    strValue = oElm.currentStyle[strCssRule];\r
-  }\r
-  return strValue;\r
-}\r
-\r
-/**  Create Element NS Ready  */\r
-function onCreateElementNsReady(func) {\r
-  if (document.createElementNS !== undefined) {\r
-    func();\r
-  } else {\r
-    setTimeout(function() { onCreateElementNsReady(func); }, 100);\r
-  }\r
-}\r
-\r
-/**  Get IE version  */\r
-// ----------------------------------------------------------\r
-// A short snippet for detecting versions of IE in JavaScript\r
-// without resorting to user-agent sniffing\r
-// ----------------------------------------------------------\r
-// If you're not in IE (or IE version is less than 5) then:\r
-// ie === undefined\r
-// If you're in IE (>=5) then you can determine which version:\r
-// ie === 7; // IE7\r
-// Thus, to detect IE:\r
-// if (ie) {}\r
-// And to detect the version:\r
-// ie === 6 // IE6\r
-// ie > 7 // IE8, IE9 ...\r
-// ie < 9 // Anything less than IE9\r
-// ----------------------------------------------------------\r
-// UPDATE: Now using Live NodeList idea from @jdalton\r
-var ie = (function(){\r
-\r
-  var undef,\r
-  v = 3,\r
-  div = document.createElement('div'),\r
-  all = div.getElementsByTagName('i');\r
-\r
-  while (\r
-    div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',\r
-    all[0]\r
-    );\r
-    return v > 4 ? v : undef;\r
-}());
\ No newline at end of file
diff --git a/addons/web/static/lib/justgage/justgage.js b/addons/web/static/lib/justgage/justgage.js
new file mode 100644 (file)
index 0000000..24540be
--- /dev/null
@@ -0,0 +1,946 @@
+/**\r
+ * JustGage - this is work-in-progress, unreleased, unofficial code, so it might not work top-notch :)\r
+ * Check http://www.justgage.com for official releases\r
+ * Licensed under MIT.\r
+ * @author Bojan Djuricic  (@Toorshia)\r
+ *\r
+ * LATEST UPDATES\r
+\r
+ * -----------------------------\r
+ * April 18, 2013.\r
+ * -----------------------------\r
+     * parentNode - use this instead of id, to attach gauge to node which is outside of DOM tree - https://github.com/toorshia/justgage/issues/48\r
+     * width - force gauge width\r
+     * height - force gauge height\r
+\r
+ * -----------------------------\r
+ * April 17, 2013.\r
+ * -----------------------------\r
+     * fix - https://github.com/toorshia/justgage/issues/49\r
+\r
+ * -----------------------------\r
+ * April 01, 2013.\r
+ * -----------------------------\r
+     * fix - https://github.com/toorshia/justgage/issues/46\r
+\r
+ * -----------------------------\r
+ * March 26, 2013.\r
+ * -----------------------------\r
+     * customSectors - define specific color for value range (0-10 : red, 10-30 : blue etc.)\r
+\r
+ * -----------------------------\r
+ * March 23, 2013.\r
+ * -----------------------------\r
+     * counter - option to animate value  in counting fashion\r
+     * fix - https://github.com/toorshia/justgage/issues/45\r
+\r
+ * -----------------------------\r
+ * March 13, 2013.\r
+ * -----------------------------\r
+     * refresh method - added optional 'max' parameter to use when you need to update max value\r
+\r
+ * -----------------------------\r
+ * February 26, 2013.\r
+ * -----------------------------\r
+     * decimals - option to define/limit number of decimals when not using humanFriendly or customRenderer to display value\r
+     * fixed a missing parameters bug when calling generateShadow()  for IE < 9\r
+\r
+ * -----------------------------\r
+ * December 31, 2012.\r
+ * -----------------------------\r
+     * fixed text y-position for hidden divs - workaround for Raphael <tspan> 'dy' bug - https://github.com/DmitryBaranovskiy/raphael/issues/491\r
+     * 'show' parameters, like showMinMax are now 'hide' because I am lame developer - please update these in your setups\r
+     * Min and Max labels are now auto-off when in donut mode\r
+     * Start angle in donut mode is now 90\r
+     * donutStartAngle - option to define start angle for donut\r
+\r
+ * -----------------------------\r
+ * November 25, 2012.\r
+ * -----------------------------\r
+     * Option to define custom rendering function for displayed value\r
+\r
+ * -----------------------------\r
+ * November 19, 2012.\r
+ * -----------------------------\r
+     * Config.value is now updated after gauge refresh\r
+\r
+ * -----------------------------\r
+ * November 13, 2012.\r
+ * -----------------------------\r
+     * Donut display mode added\r
+     * Option to hide value label\r
+     * Option to enable responsive gauge size\r
+     * Removed default title attribute\r
+     * Option to accept min and max defined as string values\r
+     * Option to configure value symbol\r
+     * Fixed bad aspect ratio calculations\r
+     * Option to configure minimum font size for all texts\r
+     * Option to show shorthand big numbers (human friendly)\r
+     */\r
+\r
+ JustGage = function(config) {\r
+\r
+  // if (!config.id) {alert("Missing id parameter for gauge!"); return false;}\r
+  // if (!document.getElementById(config.id)) {alert("No element with id: \""+config.id+"\" found!"); return false;}\r
+\r
+  var obj = this;\r
+\r
+  // configurable parameters\r
+  obj.config =\r
+  {\r
+    // id : string\r
+    // this is container element id\r
+    id : config.id,\r
+\r
+    // parentNode : node object\r
+    // this is container element\r
+    parentNode : (config.parentNode) ? config.parentNode : null,\r
+\r
+    // width : int\r
+    // gauge width\r
+    width : (config.width) ? config.width : null,\r
+\r
+    // height : int\r
+    // gauge height\r
+    height : (config.height) ? config.height : null,\r
+\r
+    // title : string\r
+    // gauge title\r
+    title : (config.title) ? config.title : "",\r
+\r
+    // titleFontColor : string\r
+    // color of gauge title\r
+    titleFontColor : (config.titleFontColor) ? config.titleFontColor : "#999999",\r
+\r
+    // value : int\r
+    // value gauge is showing\r
+    value : (config.value) ? config.value : 0,\r
+\r
+    // valueFontColor : string\r
+    // color of label showing current value\r
+    valueFontColor : (config.valueFontColor) ? config.valueFontColor : "#010101",\r
+\r
+    // symbol : string\r
+    // special symbol to show next to value\r
+    symbol : (config.symbol) ? config.symbol : "",\r
+\r
+    // min : int\r
+    // min value\r
+    min : (config.min !== undefined) ? parseFloat(config.min) : 0,\r
+\r
+    // max : int\r
+    // max value\r
+    max : (config.max !== undefined) ? parseFloat(config.max) : 100,\r
+\r
+    // humanFriendlyDecimal : int\r
+    // number of decimal places for our human friendly number to contain\r
+    humanFriendlyDecimal : (config.humanFriendlyDecimal) ? config.humanFriendlyDecimal : 0,\r
+\r
+    // textRenderer: func\r
+    // function applied before rendering text\r
+    textRenderer  : (config.textRenderer) ? config.textRenderer : null,\r
+\r
+    // gaugeWidthScale : float\r
+    // width of the gauge element\r
+    gaugeWidthScale : (config.gaugeWidthScale) ? config.gaugeWidthScale : 1.0,\r
+\r
+    // gaugeColor : string\r
+    // background color of gauge element\r
+    gaugeColor : (config.gaugeColor) ? config.gaugeColor : "#edebeb",\r
+\r
+    // label : string\r
+    // text to show below value\r
+    label : (config.label) ? config.label : "",\r
+\r
+    // labelFontColor : string\r
+    // color of label showing label under value\r
+    labelFontColor : (config.labelFontColor) ? config.labelFontColor : "#b3b3b3",\r
+\r
+    // shadowOpacity : int\r
+    // 0 ~ 1\r
+    shadowOpacity : (config.shadowOpacity) ? config.shadowOpacity : 0.2,\r
+\r
+    // shadowSize: int\r
+    // inner shadow size\r
+    shadowSize : (config.shadowSize) ? config.shadowSize : 5,\r
+\r
+    // shadowVerticalOffset : int\r
+    // how much shadow is offset from top\r
+    shadowVerticalOffset : (config.shadowVerticalOffset) ? config.shadowVerticalOffset : 3,\r
+\r
+    // levelColors : string[]\r
+    // colors of indicator, from lower to upper, in RGB format\r
+    levelColors : (config.levelColors) ? config.levelColors : [\r
+    "#a9d70b",\r
+    "#f9c802",\r
+    "#ff0000"\r
+    ],\r
+\r
+    // startAnimationTime : int\r
+    // length of initial animation\r
+    startAnimationTime : (config.startAnimationTime) ? config.startAnimationTime : 700,\r
+\r
+    // startAnimationType : string\r
+    // type of initial animation (linear, >, <,  <>, bounce)\r
+    startAnimationType : (config.startAnimationType) ? config.startAnimationType : ">",\r
+\r
+    // refreshAnimationTime : int\r
+    // length of refresh animation\r
+    refreshAnimationTime : (config.refreshAnimationTime) ? config.refreshAnimationTime : 700,\r
+\r
+    // refreshAnimationType : string\r
+    // type of refresh animation (linear, >, <,  <>, bounce)\r
+    refreshAnimationType : (config.refreshAnimationType) ? config.refreshAnimationType : ">",\r
+\r
+    // donutStartAngle : int\r
+    // angle to start from when in donut mode\r
+    donutStartAngle : (config.donutStartAngle) ? config.donutStartAngle : 90,\r
+\r
+    // valueMinFontSize : int\r
+    // absolute minimum font size for the value\r
+    valueMinFontSize : config.valueMinFontSize || 16,\r
+\r
+    // titleMinFontSize\r
+    // absolute minimum font size for the title\r
+    titleMinFontSize : config.titleMinFontSize || 10,\r
+\r
+    // labelMinFontSize\r
+    // absolute minimum font size for the label\r
+    labelMinFontSize : config.labelMinFontSize || 10,\r
+\r
+    // minLabelMinFontSize\r
+    // absolute minimum font size for the minimum label\r
+    minLabelMinFontSize : config.minLabelMinFontSize || 10,\r
+\r
+    // maxLabelMinFontSize\r
+    // absolute minimum font size for the maximum label\r
+    maxLabelMinFontSize : config.maxLabelMinFontSize || 10,\r
+\r
+    // hideValue : bool\r
+    // hide value text\r
+    hideValue : (config.hideValue) ? config.hideValue : false,\r
+\r
+    // hideMinMax : bool\r
+    // hide min and max values\r
+    hideMinMax : (config.hideMinMax) ? config.hideMinMax : false,\r
+\r
+    // hideInnerShadow : bool\r
+    // hide inner shadow\r
+    hideInnerShadow : (config.hideInnerShadow) ? config.hideInnerShadow : false,\r
+\r
+    // humanFriendly : bool\r
+    // convert large numbers for min, max, value to human friendly (e.g. 1234567 -> 1.23M)\r
+    humanFriendly : (config.humanFriendly) ? config.humanFriendly : false,\r
+\r
+    // noGradient : bool\r
+    // whether to use gradual color change for value, or sector-based\r
+    noGradient : (config.noGradient) ? config.noGradient : false,\r
+\r
+    // donut : bool\r
+    // show full donut gauge\r
+    donut : (config.donut) ? config.donut : false,\r
+\r
+    // relativeGaugeSize : bool\r
+    // whether gauge size should follow changes in container element size\r
+    relativeGaugeSize : (config.relativeGaugeSize) ? config.relativeGaugeSize : false,\r
+\r
+    // counter : bool\r
+    // animate level number change\r
+    counter : (config.counter) ? config.counter : false,\r
+\r
+    // decimals : int\r
+    // number of digits after floating point\r
+    decimals : (config.decimals) ? config.decimals : 0,\r
+\r
+    // customSectors : [] of objects\r
+    // number of digits after floating point\r
+    customSectors : (config.customSectors) ? config.customSectors : []\r
+  };\r
+\r
+  // variables\r
+  var\r
+  canvasW,\r
+  canvasH,\r
+  widgetW,\r
+  widgetH,\r
+  aspect,\r
+  dx,\r
+  dy,\r
+  titleFontSize,\r
+  titleX,\r
+  titleY,\r
+  valueFontSize,\r
+  valueX,\r
+  valueY,\r
+  labelFontSize,\r
+  labelX,\r
+  labelY,\r
+  minFontSize,\r
+  minX,\r
+  minY,\r
+  maxFontSize,\r
+  maxX,\r
+  maxY;\r
+\r
+  // overflow values\r
+  if (obj.config.value > obj.config.max) obj.config.value = obj.config.max;\r
+  if (obj.config.value < obj.config.min) obj.config.value = obj.config.min;\r
+  obj.originalValue = config.value;\r
+\r
+  // create canvas\r
+  if (obj.config.id !== null && (document.getElementById(obj.config.id)) !== null) {\r
+    obj.canvas = Raphael(obj.config.id, "100%", "100%");\r
+  } else if (obj.config.parentNode !== null) {\r
+    obj.canvas = Raphael(obj.config.parentNode, "100%", "100%");\r
+  }\r
+\r
+  if (obj.config.relativeGaugeSize === true) {\r
+    obj.canvas.setViewBox(0, 0, 200, 150, true);\r
+  }\r
+\r
+  // canvas dimensions\r
+  if (obj.config.relativeGaugeSize === true) {\r
+    canvasW = 200;\r
+    canvasH = 150;\r
+  } else if (obj.config.width !== null && obj.config.height !== null) {\r
+    canvasW = obj.config.width;\r
+    canvasH = obj.config.height;\r
+  } else if (obj.config.parentNode !== null) {\r
+    obj.canvas.setViewBox(0, 0, 200, 150, true);\r
+    canvasW = 200;\r
+    canvasH = 150;\r
+  } else {\r
+    canvasW = getStyle(document.getElementById(obj.config.id), "width").slice(0, -2) * 1;\r
+    canvasH = getStyle(document.getElementById(obj.config.id), "height").slice(0, -2) * 1;\r
+  }\r
+\r
+  // widget dimensions\r
+  if (obj.config.donut === true) {\r
+\r
+    // DONUT *******************************\r
+\r
+    // width more than height\r
+    if(canvasW > canvasH) {\r
+      widgetH = canvasH;\r
+      widgetW = widgetH;\r
+    // width less than height\r
+  } else if (canvasW < canvasH) {\r
+    widgetW = canvasW;\r
+    widgetH = widgetW;\r
+      // if height don't fit, rescale both\r
+      if(widgetH > canvasH) {\r
+        aspect = widgetH / canvasH;\r
+        widgetH = widgetH / aspect;\r
+        widgetW = widgetH / aspect;\r
+      }\r
+    // equal\r
+  } else {\r
+    widgetW = canvasW;\r
+    widgetH = widgetW;\r
+  }\r
+\r
+    // delta\r
+    dx = (canvasW - widgetW)/2;\r
+    dy = (canvasH - widgetH)/2;\r
+\r
+    // title\r
+    titleFontSize = ((widgetH / 8) > 10) ? (widgetH / 10) : 10;\r
+    titleX = dx + widgetW / 2;\r
+    titleY = dy + widgetH / 11;\r
+\r
+    // value\r
+    valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 5.4) : 18;\r
+    valueX = dx + widgetW / 2;\r
+    if(obj.config.label !== '') {\r
+      valueY = dy + widgetH / 1.85;\r
+    } else {\r
+      valueY = dy + widgetH / 1.7;\r
+    }\r
+\r
+    // label\r
+    labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;\r
+    labelX = dx + widgetW / 2;\r
+    labelY = valueY + labelFontSize;\r
+\r
+    // min\r
+    minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;\r
+    minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
+    minY = labelY;\r
+\r
+    // max\r
+    maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;\r
+    maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
+    maxY = labelY;\r
+\r
+  } else {\r
+    // HALF *******************************\r
+\r
+    // width more than height\r
+    if(canvasW > canvasH) {\r
+      widgetH = canvasH;\r
+      widgetW = widgetH * 1.25;\r
+      //if width doesn't fit, rescale both\r
+      if(widgetW > canvasW) {\r
+        aspect = widgetW / canvasW;\r
+        widgetW = widgetW / aspect;\r
+        widgetH = widgetH / aspect;\r
+      }\r
+    // width less than height\r
+  } else if (canvasW < canvasH) {\r
+    widgetW = canvasW;\r
+    widgetH = widgetW / 1.25;\r
+      // if height don't fit, rescale both\r
+      if(widgetH > canvasH) {\r
+        aspect = widgetH / canvasH;\r
+        widgetH = widgetH / aspect;\r
+        widgetW = widgetH / aspect;\r
+      }\r
+    // equal\r
+  } else {\r
+    widgetW = canvasW;\r
+    widgetH = widgetW * 0.75;\r
+  }\r
+\r
+    // delta\r
+    dx = (canvasW - widgetW)/2;\r
+    dy = (canvasH - widgetH)/2;\r
+\r
+    // title\r
+    titleFontSize = ((widgetH / 8) > obj.config.titleMinFontSize) ? (widgetH / 10) : obj.config.titleMinFontSize;\r
+    titleX = dx + widgetW / 2;\r
+    titleY = dy + widgetH / 6.4;\r
+\r
+    // value\r
+    valueFontSize = ((widgetH / 6.5) > obj.config.valueMinFontSize) ? (widgetH / 6.5) : obj.config.valueMinFontSize;\r
+    valueX = dx + widgetW / 2;\r
+    valueY = dy + widgetH / 1.275;\r
+\r
+    // label\r
+    labelFontSize = ((widgetH / 16) > obj.config.labelMinFontSize) ? (widgetH / 16) : obj.config.labelMinFontSize;\r
+    labelX = dx + widgetW / 2;\r
+    labelY = valueY + valueFontSize / 2 + 5;\r
+\r
+    // min\r
+    minFontSize = ((widgetH / 16) > obj.config.minLabelMinFontSize) ? (widgetH / 16) : obj.config.minLabelMinFontSize;\r
+    minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
+    minY = labelY;\r
+\r
+    // max\r
+    maxFontSize = ((widgetH / 16) > obj.config.maxLabelMinFontSize) ? (widgetH / 16) : obj.config.maxLabelMinFontSize;\r
+    maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * obj.config.gaugeWidthScale) / 2 ;\r
+    maxY = labelY;\r
+  }\r
+\r
+  // parameters\r
+  obj.params  = {\r
+    canvasW : canvasW,\r
+    canvasH : canvasH,\r
+    widgetW : widgetW,\r
+    widgetH : widgetH,\r
+    dx : dx,\r
+    dy : dy,\r
+    titleFontSize : titleFontSize,\r
+    titleX : titleX,\r
+    titleY : titleY,\r
+    valueFontSize : valueFontSize,\r
+    valueX : valueX,\r
+    valueY : valueY,\r
+    labelFontSize : labelFontSize,\r
+    labelX : labelX,\r
+    labelY : labelY,\r
+    minFontSize : minFontSize,\r
+    minX : minX,\r
+    minY : minY,\r
+    maxFontSize : maxFontSize,\r
+    maxX : maxX,\r
+    maxY : maxY\r
+  };\r
+\r
+  // var clear\r
+  canvasW, canvasH, widgetW, widgetH, aspect, dx, dy, titleFontSize, titleX, titleY, valueFontSize, valueX, valueY, labelFontSize, labelX, labelY, minFontSize, minX, minY, maxFontSize, maxX, maxY = null\r
+\r
+  // pki - custom attribute for generating gauge paths\r
+  obj.canvas.customAttributes.pki = function (value, min, max, w, h, dx, dy, gws, donut) {\r
+\r
+    var alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path;\r
+\r
+    if (donut) {\r
+      alpha = (1 - 2 * (value - min) / (max - min)) * Math.PI;\r
+      Ro = w / 2 - w / 7;\r
+      Ri = Ro - w / 6.666666666666667 * gws;\r
+\r
+      Cx = w / 2 + dx;\r
+      Cy = h / 1.95 + dy;\r
+\r
+      Xo = w / 2 + dx + Ro * Math.cos(alpha);\r
+      Yo = h - (h - Cy) + 0 - Ro * Math.sin(alpha);\r
+      Xi = w / 2 + dx + Ri * Math.cos(alpha);\r
+      Yi = h - (h - Cy) + 0 - Ri * Math.sin(alpha);\r
+\r
+      path += "M" + (Cx - Ri) + "," + Cy + " ";\r
+      path += "L" + (Cx - Ro) + "," + Cy + " ";\r
+      if (value > ((max - min) / 2)) {\r
+        path += "A" + Ro + "," + Ro + " 0 0 1 " + (Cx + Ro) + "," + Cy + " ";\r
+      }\r
+      path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";\r
+      path += "L" + Xi + "," + Yi + " ";\r
+      if (value > ((max - min) / 2)) {\r
+        path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx + Ri) + "," + Cy + " ";\r
+      }\r
+      path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";\r
+      path += "Z ";\r
+\r
+      return { path: path };\r
+\r
+    } else {\r
+      alpha = (1 - (value - min) / (max - min)) * Math.PI;\r
+      Ro = w / 2 - w / 10;\r
+      Ri = Ro - w / 6.666666666666667 * gws;\r
+\r
+      Cx = w / 2 + dx;\r
+      Cy = h / 1.25 + dy;\r
+\r
+      Xo = w / 2 + dx + Ro * Math.cos(alpha);\r
+      Yo = h - (h - Cy) + 0 - Ro * Math.sin(alpha);\r
+      Xi = w / 2 + dx + Ri * Math.cos(alpha);\r
+      Yi = h - (h - Cy) + 0 - Ri * Math.sin(alpha);\r
+\r
+      path += "M" + (Cx - Ri) + "," + Cy + " ";\r
+      path += "L" + (Cx - Ro) + "," + Cy + " ";\r
+      path += "A" + Ro + "," + Ro + " 0 0 1 " + Xo + "," + Yo + " ";\r
+      path += "L" + Xi + "," + Yi + " ";\r
+      path += "A" + Ri + "," + Ri + " 0 0 0 " + (Cx - Ri) + "," + Cy + " ";\r
+      path += "Z ";\r
+\r
+      return { path: path };\r
+    }\r
+\r
+    // var clear\r
+    alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path = null;\r
+  };\r
+\r
+  // gauge\r
+  obj.gauge = obj.canvas.path().attr({\r
+      "stroke": "none",\r
+      "fill": obj.config.gaugeColor,\r
+      pki: [\r
+        obj.config.max,\r
+        obj.config.min,\r
+        obj.config.max,\r
+        obj.params.widgetW,\r
+        obj.params.widgetH,\r
+        obj.params.dx,\r
+        obj.params.dy,\r
+        obj.config.gaugeWidthScale,\r
+        obj.config.donut\r
+      ]\r
+  });\r
+\r
+  // level\r
+  obj.level = obj.canvas.path().attr({\r
+    "stroke": "none",\r
+    "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),\r
+    pki: [\r
+      obj.config.min,\r
+      obj.config.min,\r
+      obj.config.max,\r
+      obj.params.widgetW,\r
+      obj.params.widgetH,\r
+      obj.params.dx,\r
+      obj.params.dy,\r
+      obj.config.gaugeWidthScale,\r
+      obj.config.donut\r
+    ]\r
+  });\r
+  if(obj.config.donut) {\r
+    obj.level.transform("r" + obj.config.donutStartAngle + ", " + (obj.params.widgetW/2 + obj.params.dx) + ", " + (obj.params.widgetH/1.95 + obj.params.dy));\r
+  }\r
+\r
+  // title\r
+  obj.txtTitle = obj.canvas.text(obj.params.titleX, obj.params.titleY, obj.config.title);\r
+  obj.txtTitle.attr({\r
+    "font-size":obj.params.titleFontSize,\r
+    "font-weight":"bold",\r
+    "font-family":"Arial",\r
+    "fill":obj.config.titleFontColor,\r
+    "fill-opacity":"1"\r
+  });\r
+  setDy(obj.txtTitle, obj.params.titleFontSize, obj.params.titleY);\r
+\r
+  // value\r
+  obj.txtValue = obj.canvas.text(obj.params.valueX, obj.params.valueY, 0);\r
+  obj.txtValue.attr({\r
+    "font-size":obj.params.valueFontSize,\r
+    "font-weight":"bold",\r
+    "font-family":"Arial",\r
+    "fill":obj.config.valueFontColor,\r
+    "fill-opacity":"0"\r
+  });\r
+  setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
+\r
+  // label\r
+  obj.txtLabel = obj.canvas.text(obj.params.labelX, obj.params.labelY, obj.config.label);\r
+  obj.txtLabel.attr({\r
+    "font-size":obj.params.labelFontSize,\r
+    "font-weight":"normal",\r
+    "font-family":"Arial",\r
+    "fill":obj.config.labelFontColor,\r
+    "fill-opacity":"0"\r
+  });\r
+  setDy(obj.txtLabel, obj.params.labelFontSize, obj.params.labelY);\r
+\r
+  // min\r
+  obj.txtMinimum = obj.config.min;\r
+  if( obj.config.humanFriendly ) obj.txtMinimum = humanFriendlyNumber( obj.config.min, obj.config.humanFriendlyDecimal );\r
+  obj.txtMin = obj.canvas.text(obj.params.minX, obj.params.minY, obj.txtMinimum);\r
+  obj.txtMin.attr({\r
+    "font-size":obj.params.minFontSize,\r
+    "font-weight":"normal",\r
+    "font-family":"Arial",\r
+    "fill":obj.config.labelFontColor,\r
+    "fill-opacity": (obj.config.hideMinMax || obj.config.donut)? "0" : "1"\r
+  });\r
+  setDy(obj.txtMin, obj.params.minFontSize, obj.params.minY);\r
+\r
+  // max\r
+  obj.txtMaximum = obj.config.max;\r
+  if( obj.config.humanFriendly ) obj.txtMaximum = humanFriendlyNumber( obj.config.max, obj.config.humanFriendlyDecimal );\r
+  obj.txtMax = obj.canvas.text(obj.params.maxX, obj.params.maxY, obj.txtMaximum);\r
+  obj.txtMax.attr({\r
+    "font-size":obj.params.maxFontSize,\r
+    "font-weight":"normal",\r
+    "font-family":"Arial",\r
+    "fill":obj.config.labelFontColor,\r
+    "fill-opacity": (obj.config.hideMinMax || obj.config.donut)? "0" : "1"\r
+  });\r
+  setDy(obj.txtMax, obj.params.maxFontSize, obj.params.maxY);\r
+\r
+  var defs = obj.canvas.canvas.childNodes[1];\r
+  var svg = "http://www.w3.org/2000/svg";\r
+\r
+  if (ie < 9) {\r
+    onCreateElementNsReady(function() {\r
+      obj.generateShadow(svg, defs);\r
+    });\r
+  } else {\r
+    obj.generateShadow(svg, defs);\r
+  }\r
+\r
+  // var clear\r
+  defs, svg = null;\r
+\r
+  // set value to display\r
+  if(obj.config.textRenderer) {\r
+    obj.originalValue = obj.config.textRenderer(obj.originalValue);\r
+  } else if(obj.config.humanFriendly) {\r
+    obj.originalValue = humanFriendlyNumber( obj.originalValue, obj.config.humanFriendlyDecimal ) + obj.config.symbol;\r
+  } else {\r
+    obj.originalValue = (obj.originalValue * 1).toFixed(obj.config.decimals) + obj.config.symbol;\r
+  }\r
+\r
+  if(obj.config.counter === true) {\r
+    //on each animation frame\r
+    eve.on("raphael.anim.frame." + (obj.level.id), function() {\r
+      var currentValue = obj.level.attr("pki");\r
+      if(obj.config.textRenderer) {\r
+        obj.txtValue.attr("text", obj.config.textRenderer(Math.floor(currentValue[0])));\r
+      } else if(obj.config.humanFriendly) {\r
+        obj.txtValue.attr("text", humanFriendlyNumber( Math.floor(currentValue[0]), obj.config.humanFriendlyDecimal ) + obj.config.symbol);\r
+      } else {\r
+        obj.txtValue.attr("text", (currentValue[0] * 1).toFixed(obj.config.decimals) + obj.config.symbol);\r
+      }\r
+      setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
+      currentValue = null;\r
+    });\r
+    //on animation end\r
+    eve.on("raphael.anim.finish." + (obj.level.id), function() {\r
+      obj.txtValue.attr({"text" : obj.originalValue});\r
+      setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
+    });\r
+  } else {\r
+    //on animation start\r
+    eve.on("raphael.anim.start." + (obj.level.id), function() {\r
+      obj.txtValue.attr({"text" : obj.originalValue});\r
+      setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
+    });\r
+  }\r
+\r
+  // animate gauge level, value & label\r
+  obj.level.animate({\r
+    pki: [\r
+      obj.config.value,\r
+      obj.config.min,\r
+      obj.config.max,\r
+      obj.params.widgetW,\r
+      obj.params.widgetH,\r
+      obj.params.dx,\r
+      obj.params.dy,\r
+      obj.config.gaugeWidthScale,\r
+      obj.config.donut\r
+    ]\r
+  }, obj.config.startAnimationTime, obj.config.startAnimationType);\r
+  obj.txtValue.animate({"fill-opacity":(obj.config.hideValue)?"0":"1"}, obj.config.startAnimationTime, obj.config.startAnimationType);\r
+  obj.txtLabel.animate({"fill-opacity":"1"}, obj.config.startAnimationTime, obj.config.startAnimationType);\r
+};\r
+\r
+/** Refresh gauge level */\r
+JustGage.prototype.refresh = function(val, max) {\r
+\r
+  var obj = this;\r
+  var displayVal, color, max = max || null;\r
+\r
+  // set new max\r
+  if(max !== null) {\r
+    obj.config.max = max;\r
+\r
+    obj.txtMaximum = obj.config.max;\r
+    if( obj.config.humanFriendly ) obj.txtMaximum = humanFriendlyNumber( obj.config.max, obj.config.humanFriendlyDecimal );\r
+    obj.txtMax.attr({"text" : obj.txtMaximum});\r
+    setDy(obj.txtMax, obj.params.maxFontSize, obj.params.maxY);\r
+  }\r
+\r
+  // overflow values\r
+  displayVal = val;\r
+  if ((val * 1) > (obj.config.max * 1)) {val = (obj.config.max * 1);}\r
+  if ((val * 1) < (obj.config.min * 1)) {val = (obj.config.min * 1);}\r
+\r
+  color = getColor(val, (val - obj.config.min) / (obj.config.max - obj.config.min), obj.config.levelColors, obj.config.noGradient, obj.config.customSectors);\r
+\r
+  if(obj.config.textRenderer) {\r
+    displayVal = obj.config.textRenderer(displayVal);\r
+  } else if( obj.config.humanFriendly ) {\r
+    displayVal = humanFriendlyNumber( displayVal, obj.config.humanFriendlyDecimal ) + obj.config.symbol;\r
+  } else {\r
+    displayVal = (displayVal * 1).toFixed(obj.config.decimals) + obj.config.symbol;\r
+  }\r
+  obj.originalValue = displayVal;\r
+  obj.config.value = val * 1;\r
+\r
+  if(!obj.config.counter) {\r
+    obj.txtValue.attr({"text":displayVal});\r
+    setDy(obj.txtValue, obj.params.valueFontSize, obj.params.valueY);\r
+  }\r
+\r
+  obj.level.animate({\r
+    pki: [\r
+      obj.config.value,\r
+      obj.config.min,\r
+      obj.config.max,\r
+      obj.params.widgetW,\r
+      obj.params.widgetH,\r
+      obj.params.dx,\r
+      obj.params.dy,\r
+      obj.config.gaugeWidthScale,\r
+      obj.config.donut\r
+    ],\r
+    "fill":color\r
+  },  obj.config.refreshAnimationTime, obj.config.refreshAnimationType);\r
+\r
+  // var clear\r
+  obj, displayVal, color, max = null;\r
+};\r
+\r
+/** Generate shadow */\r
+JustGage.prototype.generateShadow = function(svg, defs) {\r
+\r
+  var obj = this;\r
+  var gaussFilter, feOffset, feGaussianBlur, feComposite1, feFlood, feComposite2, feComposite3;\r
+\r
+  // FILTER\r
+  gaussFilter = document.createElementNS(svg,"filter");\r
+  gaussFilter.setAttribute("id","inner-shadow");\r
+  defs.appendChild(gaussFilter);\r
+\r
+  // offset\r
+  feOffset = document.createElementNS(svg,"feOffset");\r
+  feOffset.setAttribute("dx", 0);\r
+  feOffset.setAttribute("dy", obj.config.shadowVerticalOffset);\r
+  gaussFilter.appendChild(feOffset);\r
+\r
+  // blur\r
+  feGaussianBlur = document.createElementNS(svg,"feGaussianBlur");\r
+  feGaussianBlur.setAttribute("result","offset-blur");\r
+  feGaussianBlur.setAttribute("stdDeviation", obj.config.shadowSize);\r
+  gaussFilter.appendChild(feGaussianBlur);\r
+\r
+  // composite 1\r
+  feComposite1 = document.createElementNS(svg,"feComposite");\r
+  feComposite1.setAttribute("operator","out");\r
+  feComposite1.setAttribute("in", "SourceGraphic");\r
+  feComposite1.setAttribute("in2","offset-blur");\r
+  feComposite1.setAttribute("result","inverse");\r
+  gaussFilter.appendChild(feComposite1);\r
+\r
+  // flood\r
+  feFlood = document.createElementNS(svg,"feFlood");\r
+  feFlood.setAttribute("flood-color","black");\r
+  feFlood.setAttribute("flood-opacity", obj.config.shadowOpacity);\r
+  feFlood.setAttribute("result","color");\r
+  gaussFilter.appendChild(feFlood);\r
+\r
+  // composite 2\r
+  feComposite2 = document.createElementNS(svg,"feComposite");\r
+  feComposite2.setAttribute("operator","in");\r
+  feComposite2.setAttribute("in", "color");\r
+  feComposite2.setAttribute("in2","inverse");\r
+  feComposite2.setAttribute("result","shadow");\r
+  gaussFilter.appendChild(feComposite2);\r
+\r
+  // composite 3\r
+  feComposite3 = document.createElementNS(svg,"feComposite");\r
+  feComposite3.setAttribute("operator","over");\r
+  feComposite3.setAttribute("in", "shadow");\r
+  feComposite3.setAttribute("in2","SourceGraphic");\r
+  gaussFilter.appendChild(feComposite3);\r
+\r
+  // set shadow\r
+  if (!obj.config.hideInnerShadow) {\r
+    obj.canvas.canvas.childNodes[2].setAttribute("filter", "url(#inner-shadow)");\r
+    obj.canvas.canvas.childNodes[3].setAttribute("filter", "url(#inner-shadow)");\r
+  }\r
+\r
+  // var clear\r
+  gaussFilter, feOffset, feGaussianBlur, feComposite1, feFlood, feComposite2, feComposite3 = null;\r
+\r
+};\r
+\r
+/** Get color for value */\r
+function getColor(val, pct, col, noGradient, custSec) {\r
+\r
+  var no, inc, colors, percentage, rval, gval, bval, lower, upper, range, rangePct, pctLower, pctUpper, color;\r
+  var noGradient = noGradient || custSec.length > 0;\r
+\r
+  if(custSec.length > 0) {\r
+    for(var i = 0; i < custSec.length; i++) {\r
+      if(val > custSec[i].lo && val <= custSec[i].hi) {\r
+        return custSec[i].color;\r
+      }\r
+    }\r
+  }\r
+\r
+  no = col.length;\r
+  if (no === 1) return col[0];\r
+  inc = (noGradient) ? (1 / no) : (1 / (no - 1));\r
+  colors = [];\r
+  for (var i = 0; i < col.length; i++) {\r
+    percentage = (noGradient) ? (inc * (i + 1)) : (inc * i);\r
+    rval = parseInt((cutHex(col[i])).substring(0,2),16);\r
+    gval = parseInt((cutHex(col[i])).substring(2,4),16);\r
+    bval = parseInt((cutHex(col[i])).substring(4,6),16);\r
+    colors[i] = { pct: percentage, color: { r: rval, g: gval, b: bval  } };\r
+  }\r
+\r
+  if(pct === 0) {\r
+    return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')';\r
+  }\r
+\r
+  for (var j = 0; j < colors.length; j++) {\r
+    if (pct <= colors[j].pct) {\r
+      if (noGradient) {\r
+        return 'rgb(' + [colors[j].color.r, colors[j].color.g, colors[j].color.b].join(',') + ')';\r
+      } else {\r
+        lower = colors[j - 1];\r
+        upper = colors[j];\r
+        range = upper.pct - lower.pct;\r
+        rangePct = (pct - lower.pct) / range;\r
+        pctLower = 1 - rangePct;\r
+        pctUpper = rangePct;\r
+        color = {\r
+          r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),\r
+          g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),\r
+          b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)\r
+        };\r
+        return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';\r
+      }\r
+    }\r
+  }\r
+\r
+}\r
+\r
+/** Fix Raphael display:none tspan dy attribute bug */\r
+function setDy(elem, fontSize, txtYpos) {\r
+  if (!ie || ie > 9) {\r
+    elem.node.firstChild.attributes.dy.value = 0;\r
+  }\r
+}\r
+\r
+/** Random integer  */\r
+function getRandomInt (min, max) {\r
+  return Math.floor(Math.random() * (max - min + 1)) + min;\r
+}\r
+\r
+/**  Cut hex  */\r
+function cutHex(str) {\r
+  return (str.charAt(0)=="#") ? str.substring(1,7):str;\r
+}\r
+\r
+/**  Human friendly number suffix - From: http://stackoverflow.com/questions/2692323/code-golf-friendly-number-abbreviator */\r
+function humanFriendlyNumber( n, d ) {\r
+  var p, d2, i, s;\r
+\r
+  p = Math.pow;\r
+  d2 = p(10, d);\r
+  i = 7;\r
+  while( i ) {\r
+    s = p(10,i--*3);\r
+    if( s <= n ) {\r
+     n = Math.round(n*d2/s)/d2+"KMGTPE"[i];\r
+   }\r
+ }\r
+ return n;\r
+}\r
+\r
+/**  Get style  */\r
+function getStyle(oElm, strCssRule){\r
+  var strValue = "";\r
+  if(document.defaultView && document.defaultView.getComputedStyle){\r
+    strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);\r
+  }\r
+  else if(oElm.currentStyle){\r
+    strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){\r
+      return p1.toUpperCase();\r
+    });\r
+    strValue = oElm.currentStyle[strCssRule];\r
+  }\r
+  return strValue;\r
+}\r
+\r
+/**  Create Element NS Ready  */\r
+function onCreateElementNsReady(func) {\r
+  if (document.createElementNS !== undefined) {\r
+    func();\r
+  } else {\r
+    setTimeout(function() { onCreateElementNsReady(func); }, 100);\r
+  }\r
+}\r
+\r
+/**  Get IE version  */\r
+// ----------------------------------------------------------\r
+// A short snippet for detecting versions of IE in JavaScript\r
+// without resorting to user-agent sniffing\r
+// ----------------------------------------------------------\r
+// If you're not in IE (or IE version is less than 5) then:\r
+// ie === undefined\r
+// If you're in IE (>=5) then you can determine which version:\r
+// ie === 7; // IE7\r
+// Thus, to detect IE:\r
+// if (ie) {}\r
+// And to detect the version:\r
+// ie === 6 // IE6\r
+// ie > 7 // IE8, IE9 ...\r
+// ie < 9 // Anything less than IE9\r
+// ----------------------------------------------------------\r
+// UPDATE: Now using Live NodeList idea from @jdalton\r
+var ie = (function(){\r
+\r
+  var undef,\r
+  v = 3,\r
+  div = document.createElement('div'),\r
+  all = div.getElementsByTagName('i');\r
+\r
+  while (\r
+    div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',\r
+    all[0]\r
+    );\r
+    return v > 4 ? v : undef;\r
+}());
\ No newline at end of file
index bd1c116..9bc8e3b 100644 (file)
@@ -1276,6 +1276,7 @@ instance.web_kanban.GaugeWidget = instance.web_kanban.AbstractField.extend({
     className: "oe_gauge",
     start: function() {
         var self = this;
+        var parent = this.getParent();
         var max = 100;
         if (this.options.max_field) {
             max = this.getParent().record[this.options.max_field].raw_value;
@@ -1287,33 +1288,43 @@ instance.web_kanban.GaugeWidget = instance.web_kanban.AbstractField.extend({
         var val = this.field.value;
         var value = _.isArray(val) && val.length ? val[val.length-1]['value'] : val;
         var title = this.$node.html() || this.field.string;
+        // var unique_id = _.uniqueId("JustGage");
+
+        this.$el.empty()
+            .attr('style', this.$node.attr('style') + ';position:relative; display:inline-block;');
+
         this.gage = new JustGage({
             parentNode: this.$el[0],
+            // id: unique_id,
             value: value,
             title: title,
             min: 0,
             max: max,
             relativeGaugeSize: true,
             humanFriendly: true,
+            titleFontColor: '#333333',
+            valueFontColor: '#333333',
+            labelFontColor: '#000',
             label: label,
             levelColors: [
                 "#ff0000",
                 "#f9c802",
                 "#a9d70b"
-            ]
+            ],
         });
+        this.gage.refresh(value, max);
 
         var flag_open = false;
-        if (self.options.action_change) {
-            var $svg = self.$el.find('svg');
+        if (this.options.action_change) {
+            var $svg = this.$el.find('svg');
             var css = {
                 'text-align': 'center',
                 'position': 'absolute',
-                'width': self.$el.outerWidth() + 'px',
-                'top': (self.$el.outerHeight()/2-5) + 'px'
+                'width': this.$el.outerWidth() + 'px',
+                'top': (this.$el.outerHeight()/2-5) + 'px'
             };
 
-            self.$el.click(function (event) {
+            this.$el.click(function (event) {
                 event.stopPropagation();
                 flag_open = false;
                 if (!parent.view.is_action_enabled('edit')) {
@@ -1364,7 +1375,7 @@ instance.web_kanban.GaugeWidget = instance.web_kanban.AbstractField.extend({
                 $svg.fadeTo(0, 0.3);
                 $div = $('<div/>').text(_t("Click to change value"));
                 $div.css(css);
-                self.$el.append($div);
+                this.$el.append($div);
             }
         }
     },