UNPKG

freeboard-leaflet-realtime

Version:
491 lines (418 loc) 16.7 kB
/** * JustGage - a handy JavaScript plugin for generating and animating nice & clean dashboard gauges. * Copyright (c) 2012 Bojan Djuricic - pindjur(at)gmail(dot)com | http://www.madcog.com * Licensed under MIT. * Date: 31/07/2012 * @author Bojan Djuricic (@Toorshia) * @version 1.0 * * http://www.justgage.com */ JustGage = function(config) { if(!config.id) { alert("Missing id parameter for gauge!"); return false; } if(!document.getElementById(config.id)) { alert("No element with id: \"" + config.id + "\" found!"); return false; } // configurable parameters this.config = { // id : string // this is container element id id : config.id, // value : int // value gauge is showing value : (config.value) ? config.value : 0, // valueFontColor : string // color of label showing current value valueFontColor : (config.valueFontColor) ? config.valueFontColor : "#010101", // min : int // min value min : (config.min) ? config.min : 0, // max : int // max value max : (config.max) ? config.max : 100, // showMinMax : bool // hide or display min and max values showMinMax : (config.showMinMax != null) ? config.showMinMax : true, // gaugeWidthScale : float // width of the gauge element gaugeWidthScale : (config.gaugeWidthScale) ? config.gaugeWidthScale : 1.0, // gaugeColor : string // background color of gauge element gaugeColor : (config.gaugeColor) ? config.gaugeColor : "#edebeb", // label : string // text to show below value label : (config.label) ? config.label : "", // showInnerShadow : bool // give gauge element small amount of inner shadow showInnerShadow : (config.showInnerShadow != null) ? config.showInnerShadow : true, // shadowOpacity : int // 0 ~ 1 shadowOpacity : (config.shadowOpacity) ? config.shadowOpacity : 0.2, // shadowSize: int // inner shadow size shadowSize : (config.shadowSize) ? config.shadowSize : 5, // shadowVerticalOffset : int // how much shadow is offset from top shadowVerticalOffset: (config.shadowVerticalOffset) ? config.shadowVerticalOffset : 3, // levelColors : string[] // colors of indicator, from lower to upper, in RGB format levelColors : (config.levelColors) ? config.levelColors : percentColors, // levelColorsGradient : bool // whether to use gradual color change for value, or sector-based levelColorsGradient : (config.levelColorsGradient != null) ? config.levelColorsGradient : true, // labelFontColor : string // color of label showing label under value labelFontColor : (config.labelFontColor) ? config.labelFontColor : "#b3b3b3", // startAnimationTime : int // length of initial animation startAnimationTime : (config.startAnimationTime) ? config.startAnimationTime : 700, // startAnimationType : string // type of initial animation (linear, >, <, <>, bounce) startAnimationType : (config.startAnimationType) ? config.startAnimationType : ">", // refreshAnimationTime : int // length of refresh animation refreshAnimationTime: (config.refreshAnimationTime) ? config.refreshAnimationTime : 700, // refreshAnimationType : string // type of refresh animation (linear, >, <, <>, bounce) refreshAnimationType: (config.refreshAnimationType) ? config.refreshAnimationType : ">" }; // overflow values if(config.value > this.config.max) this.config.value = this.config.max; if(config.value < this.config.min) this.config.value = this.config.min; this.originalValue = config.value; // canvas this.canvas = Raphael(this.config.id, "100%", "100%"); // canvas dimensions //var canvasW = document.getElementById(this.config.id).clientWidth; //var canvasH = document.getElementById(this.config.id).clientHeight; var canvasW = getStyle(document.getElementById(this.config.id), "width").slice(0, -2) * 1; var canvasH = getStyle(document.getElementById(this.config.id), "height").slice(0, -2) * 1; // widget dimensions var widgetW, widgetH; if((canvasW / canvasH) > 1.25) { widgetW = 1.25 * canvasH; widgetH = canvasH; } else { widgetW = canvasW; widgetH = canvasW / 1.25; } // delta var dx = (canvasW - widgetW) / 2; var dy = (canvasH - widgetH) / 2; // value var valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 6.4) : 16; var valueX = dx + widgetW / 2; var valueY = dy + widgetH / 1.4; // label var labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10; var labelX = dx + widgetW / 2; //var labelY = dy + widgetH / 1.126760563380282; var labelY = valueY + valueFontSize / 2 + 6; // min var minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10; var minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2; var minY = dy + widgetH / 1.126760563380282; // max var maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10; var maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2; var maxY = dy + widgetH / 1.126760563380282; // parameters this.params = { canvasW : canvasW, canvasH : canvasH, widgetW : widgetW, widgetH : widgetH, dx : dx, dy : dy, valueFontSize: valueFontSize, valueX : valueX, valueY : valueY, labelFontSize: labelFontSize, labelX : labelX, labelY : labelY, minFontSize : minFontSize, minX : minX, minY : minY, maxFontSize : maxFontSize, maxX : maxX, maxY : maxY }; // pki - custom attribute for generating gauge paths this.canvas.customAttributes.pki = function(value, min, max, w, h, dx, dy, gws) { var alpha = (1 - (value - min) / (max - min)) * Math.PI , Ro = w / 2 - w / 10, Ri = Ro - w / 6.666666666666667 * gws, Cx = w / 2 + dx, Cy = h / 1.25 + dy, Xo = w / 2 + dx + Ro * Math.cos(alpha), Yo = h - (h - Cy) + dy - Ro * Math.sin(alpha), Xi = w / 2 + dx + Ri * Math.cos(alpha), Yi = h - (h - Cy) + dy - Ri * Math.sin(alpha), path; path += "M" + (Cx - Ri) + "," + Cy + " "; path += "L" + (Cx - Ro) + "," + Cy + " "; path += "A" + Ro + "," + Ro + " 0 0,1 " + Xo + "," + Yo + " "; path += "L" + Xi + "," + Yi + " "; path += "A" + Ri + "," + Ri + " 0 0,0 " + (Cx - Ri) + "," + Cy + " "; path += "z "; return { path: path }; } // gauge this.gauge = this.canvas.path().attr({ "stroke": "none", "fill" : this.config.gaugeColor, pki : [this.config.max, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale] }); this.gauge.id = this.config.id + "-gauge"; // level this.level = this.canvas.path().attr({ "stroke": "none", "fill" : getColorForPercentage((this.config.value - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient), pki : [this.config.min, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale] }); this.level.id = this.config.id + "-level"; // value this.txtValue = this.canvas.text(this.params.valueX, this.params.valueY, this.originalValue); this.txtValue.attr({ "font-size" : this.params.valueFontSize, "font-weight" : "bold", "font-family" : "Arial", "fill" : this.config.valueFontColor, "fill-opacity": "0" }); this.txtValue.id = this.config.id + "-txtvalue"; // label this.txtLabel = this.canvas.text(this.params.labelX, this.params.labelY, this.config.label); this.txtLabel.attr({ "font-size" : this.params.labelFontSize, "font-weight" : "normal", "font-family" : "Arial", "fill" : this.config.labelFontColor, "fill-opacity": "0" }); this.txtLabel.id = this.config.id + "-txtlabel"; // min this.txtMin = this.canvas.text(this.params.minX, this.params.minY, this.config.min); this.txtMin.attr({ "font-size" : this.params.minFontSize, "font-weight" : "normal", "font-family" : "Arial", "fill" : this.config.labelFontColor, "fill-opacity": (this.config.showMinMax == true) ? "1" : "0" }); this.txtMin.id = this.config.id + "-txtmin"; // max this.txtMax = this.canvas.text(this.params.maxX, this.params.maxY, this.config.max); this.txtMax.attr({ "font-size" : this.params.maxFontSize, "font-weight" : "normal", "font-family" : "Arial", "fill" : this.config.labelFontColor, "fill-opacity": (this.config.showMinMax == true) ? "1" : "0" }); this.txtMax.id = this.config.id + "-txtmax"; var defs = this.canvas.canvas.childNodes[1]; var svg = "http://www.w3.org/2000/svg"; if(ie < 9) { onCreateElementNsReady(function() { this.generateShadow(); }); } else { this.generateShadow(svg, defs); } // animate this.level.animate({pki: [this.config.value, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale ]}, this.config.startAnimationTime, this.config.startAnimationType); this.txtValue.animate({"fill-opacity": "1"}, this.config.startAnimationTime, this.config.startAnimationType); this.txtLabel.animate({"fill-opacity": "1"}, this.config.startAnimationTime, this.config.startAnimationType); }; // refresh gauge level JustGage.prototype.refresh = function(val) { // overflow values originalVal = val; if(val > this.config.max) { val = this.config.max; } if(val < this.config.min) { val = this.config.min; } var color = getColorForPercentage((val - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient); this.canvas.getById(this.config.id + "-txtvalue").attr({"text": originalVal}); this.canvas.getById(this.config.id + "-level").animate({pki : [val, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale ], "fill" : color}, this.config.refreshAnimationTime, this.config.refreshAnimationType); }; var percentColors = [ "#a9d70b", "#f9c802", "#ff0000" ] JustGage.prototype.generateShadow = function(svg, defs) { // FILTER var gaussFilter = document.createElementNS(svg, "filter"); gaussFilter.setAttribute("id", this.config.id + "-inner-shadow"); defs.appendChild(gaussFilter); // offset var feOffset = document.createElementNS(svg, "feOffset"); feOffset.setAttribute("dx", 0); feOffset.setAttribute("dy", this.config.shadowVerticalOffset); gaussFilter.appendChild(feOffset); // blur var feGaussianBlur = document.createElementNS(svg, "feGaussianBlur"); feGaussianBlur.setAttribute("result", "offset-blur"); feGaussianBlur.setAttribute("stdDeviation", this.config.shadowSize); gaussFilter.appendChild(feGaussianBlur); // composite 1 var feComposite1 = document.createElementNS(svg, "feComposite"); feComposite1.setAttribute("operator", "out"); feComposite1.setAttribute("in", "SourceGraphic"); feComposite1.setAttribute("in2", "offset-blur"); feComposite1.setAttribute("result", "inverse"); gaussFilter.appendChild(feComposite1); // flood var feFlood = document.createElementNS(svg, "feFlood"); feFlood.setAttribute("flood-color", "black"); feFlood.setAttribute("flood-opacity", this.config.shadowOpacity); feFlood.setAttribute("result", "color"); gaussFilter.appendChild(feFlood); // composite 2 var feComposite2 = document.createElementNS(svg, "feComposite"); feComposite2.setAttribute("operator", "in"); feComposite2.setAttribute("in", "color"); feComposite2.setAttribute("in2", "inverse"); feComposite2.setAttribute("result", "shadow"); gaussFilter.appendChild(feComposite2); // composite 3 var feComposite3 = document.createElementNS(svg, "feComposite"); feComposite3.setAttribute("operator", "over"); feComposite3.setAttribute("in", "shadow"); feComposite3.setAttribute("in2", "SourceGraphic"); gaussFilter.appendChild(feComposite3); // set shadow if(this.config.showInnerShadow == true) { this.canvas.canvas.childNodes[2].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)"); this.canvas.canvas.childNodes[3].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)"); } } var getColorForPercentage = function(pct, col, grad) { var no = col.length; if(no === 1) return col[0]; var inc = (grad) ? (1 / (no - 1)) : (1 / no); var colors = new Array(); for(var i = 0; i < col.length; i++) { var percentage = (grad) ? (inc * i) : (inc * (i + 1)); var rval = parseInt((cutHex(col[i])).substring(0, 2), 16); var gval = parseInt((cutHex(col[i])).substring(2, 4), 16); var bval = parseInt((cutHex(col[i])).substring(4, 6), 16); colors[i] = { pct: percentage, color: { r: rval, g: gval, b: bval } }; } if(pct == 0) return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')'; for(var i = 0; i < colors.length; i++) { if(pct <= colors[i].pct) { if(grad == true) { var lower = colors[i - 1]; var upper = colors[i]; var range = upper.pct - lower.pct; var rangePct = (pct - lower.pct) / range; var pctLower = 1 - rangePct; var pctUpper = rangePct; var color = { r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper), g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper), b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper) }; return 'rgb(' + [color.r, color.g, color.b].join(',') + ')'; } else { return 'rgb(' + [colors[i].color.r, colors[i].color.g, colors[i].color.b].join(',') + ')'; } } } } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function cutHex(str) { return (str.charAt(0) == "#") ? str.substring(1, 7) : str } function getStyle(oElm, strCssRule) { var strValue = ""; if(document.defaultView && document.defaultView.getComputedStyle) { strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule); } else if(oElm.currentStyle) { strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) { return p1.toUpperCase(); }); strValue = oElm.currentStyle[strCssRule]; } return strValue; } function onCreateElementNsReady(func) { if(document.createElementNS != undefined) { func(); } else { setTimeout(function() { onCreateElementNsReady(func); }, 100); } } // ---------------------------------------------------------- // A short snippet for detecting versions of IE in JavaScript // without resorting to user-agent sniffing // ---------------------------------------------------------- // If you're not in IE (or IE version is less than 5) then: // ie === undefined // If you're in IE (>=5) then you can determine which version: // ie === 7; // IE7 // Thus, to detect IE: // if (ie) {} // And to detect the version: // ie === 6 // IE6 // ie > 7 // IE8, IE9 ... // ie < 9 // Anything less than IE9 // ---------------------------------------------------------- // UPDATE: Now using Live NodeList idea from @jdalton var ie = (function() { var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i'); while(div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]); return v > 4 ? v : undef; }());