From b4c8862774da78bd4165047d2ed94cf921c76325 Mon Sep 17 00:00:00 2001 From: Alastair Hewitt Date: Sun, 20 Mar 2016 20:33:35 -0400 Subject: [PATCH] remove chart-flot to investigate Heroku asset pipeline issue --- app/assets/components/flot-spline/.bower.json | 32 - app/assets/components/flot-spline/bower.json | 23 - .../flot-spline/js/jquery.flot.spline.js | 212 -- .../flot-spline/js/jquery.flot.spline.min.js | 1 - .../components/flot.tooltip/.bower.json | 24 - app/assets/components/flot.tooltip/bower.json | 14 - .../flot.tooltip/js/excanvas.min.js | 1 - .../components/flot.tooltip/js/jquery.flot.js | 3168 ----------------- .../flot.tooltip/js/jquery.flot.tooltip.js | 517 --- .../js/jquery.flot.tooltip.min.js | 12 - .../js/jquery.flot.tooltip.source.js | 506 --- .../radius-theme/modules/demo/demo-flot.js | 660 ---- app/assets/stylesheets/radius-theme/app.scss | 6 +- 13 files changed, 3 insertions(+), 5173 deletions(-) delete mode 100644 app/assets/components/flot-spline/.bower.json delete mode 100644 app/assets/components/flot-spline/bower.json delete mode 100644 app/assets/components/flot-spline/js/jquery.flot.spline.js delete mode 100644 app/assets/components/flot-spline/js/jquery.flot.spline.min.js delete mode 100644 app/assets/components/flot.tooltip/.bower.json delete mode 100644 app/assets/components/flot.tooltip/bower.json delete mode 100644 app/assets/components/flot.tooltip/js/excanvas.min.js delete mode 100644 app/assets/components/flot.tooltip/js/jquery.flot.js delete mode 100644 app/assets/components/flot.tooltip/js/jquery.flot.tooltip.js delete mode 100644 app/assets/components/flot.tooltip/js/jquery.flot.tooltip.min.js delete mode 100644 app/assets/components/flot.tooltip/js/jquery.flot.tooltip.source.js delete mode 100644 app/assets/javascripts/radius-theme/modules/demo/demo-flot.js diff --git a/app/assets/components/flot-spline/.bower.json b/app/assets/components/flot-spline/.bower.json deleted file mode 100644 index 3809e99..0000000 --- a/app/assets/components/flot-spline/.bower.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "flot-spline", - "version": "0.0.1", - "homepage": "https://github.com/JohnPozy/flot-spline", - "authors": [ - "Alex Bardas < alex.bardas@gmail.com >" - ], - "description": "Flot plugin that provides spline interpolation for line graphs", - "keywords": [ - "jquery", - "flot", - "spline" - ], - "license": "MIT", - "main": "js/jquery.flot.spline.js", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], - "_release": "0.0.1", - "_resolution": { - "type": "version", - "tag": "0.0.1", - "commit": "e2261a31a3d6042969e23a1d12e6daae13e5f798" - }, - "_source": "git://github.com/JohnPozy/flot-spline.git", - "_target": "*", - "_originalSource": "flot-spline" -} \ No newline at end of file diff --git a/app/assets/components/flot-spline/bower.json b/app/assets/components/flot-spline/bower.json deleted file mode 100644 index 8a80929..0000000 --- a/app/assets/components/flot-spline/bower.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "flot-spline", - "version": "0.0.1", - "homepage": "https://github.com/JohnPozy/flot-spline", - "authors": [ - "Alex Bardas < alex.bardas@gmail.com >" - ], - "description": "Flot plugin that provides spline interpolation for line graphs", - "keywords": [ - "jquery", - "flot", - "spline" - ], - "license": "MIT", - "main": "js/jquery.flot.spline.js", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/app/assets/components/flot-spline/js/jquery.flot.spline.js b/app/assets/components/flot-spline/js/jquery.flot.spline.js deleted file mode 100644 index 71f1c41..0000000 --- a/app/assets/components/flot-spline/js/jquery.flot.spline.js +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Flot plugin that provides spline interpolation for line graphs - * author: Alex Bardas < alex.bardas@gmail.com > - * modified by: Avi Kohn https://github.com/AMKohn - * based on the spline interpolation described at: - * http://scaledinnovation.com/analytics/splines/aboutSplines.html - * - * Example usage: (add in plot options series object) - * for linespline: - * series: { - * ... - * lines: { - * show: false - * }, - * splines: { - * show: true, - * tension: x, (float between 0 and 1, defaults to 0.5), - * lineWidth: y (number, defaults to 2), - * fill: z (float between 0 .. 1 or false, as in flot documentation) - * }, - * ... - * } - * areaspline: - * series: { - * ... - * lines: { - * show: true, - * lineWidth: 0, (line drawing will not execute) - * fill: x, (float between 0 .. 1, as in flot documentation) - * ... - * }, - * splines: { - * show: true, - * tension: 0.5 (float between 0 and 1) - * }, - * ... - * } - * - */ - -(function($) { - 'use strict' - - /** - * @param {Number} x0, y0, x1, y1: coordinates of the end (knot) points of the segment - * @param {Number} x2, y2: the next knot (not connected, but needed to calculate p2) - * @param {Number} tension: control how far the control points spread - * @return {Array}: p1 -> control point, from x1 back toward x0 - * p2 -> the next control point, returned to become the next segment's p1 - * - * @api private - */ - function getControlPoints(x0, y0, x1, y1, x2, y2, tension) { - - var pow = Math.pow, - sqrt = Math.sqrt, - d01, d12, fa, fb, p1x, p1y, p2x, p2y; - - // Scaling factors: distances from this knot to the previous and following knots. - d01 = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2)); - d12 = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); - - fa = tension * d01 / (d01 + d12); - fb = tension - fa; - - p1x = x1 + fa * (x0 - x2); - p1y = y1 + fa * (y0 - y2); - - p2x = x1 - fb * (x0 - x2); - p2y = y1 - fb * (y0 - y2); - - return [p1x, p1y, p2x, p2y]; - } - - var line = []; - - function drawLine(points, ctx, height, fill, seriesColor) { - var c = $.color.parse(seriesColor); - - c.a = typeof fill == "number" ? fill : .3; - c.normalize(); - c = c.toString(); - - ctx.beginPath(); - ctx.moveTo(points[0][0], points[0][1]); - - var plength = points.length; - - for (var i = 0; i < plength; i++) { - ctx[points[i][3]].apply(ctx, points[i][2]); - } - - ctx.stroke(); - - ctx.lineWidth = 0; - ctx.lineTo(points[plength - 1][0], height); - ctx.lineTo(points[0][0], height); - - ctx.closePath(); - - if (fill !== false) { - ctx.fillStyle = c; - ctx.fill(); - } - } - - /** - * @param {Object} ctx: canvas context - * @param {String} type: accepted strings: 'bezier' or 'quadratic' (defaults to quadratic) - * @param {Array} points: 2 points for which to draw the interpolation - * @param {Array} cpoints: control points for those segment points - * - * @api private - */ - function queue(ctx, type, points, cpoints) { - if (type === void 0 || (type !== 'bezier' && type !== 'quadratic')) { - type = 'quadratic'; - } - type = type + 'CurveTo'; - - if (line.length == 0) line.push([points[0], points[1], cpoints.concat(points.slice(2)), type]); - else if (type == "quadraticCurveTo" && points.length == 2) { - cpoints = cpoints.slice(0, 2).concat(points); - - line.push([points[0], points[1], cpoints, type]); - } - else line.push([points[2], points[3], cpoints.concat(points.slice(2)), type]); - } - - /** - * @param {Object} plot - * @param {Object} ctx: canvas context - * @param {Object} series - * - * @api private - */ - - function drawSpline(plot, ctx, series) { - // Not interested if spline is not requested - if (series.splines.show !== true) { - return; - } - - var cp = [], - // array of control points - tension = series.splines.tension || 0.5, - idx, x, y, points = series.datapoints.points, - ps = series.datapoints.pointsize, - plotOffset = plot.getPlotOffset(), - len = points.length, - pts = []; - - line = []; - - // Cannot display a linespline/areaspline if there are less than 3 points - if (len / ps < 4) { - $.extend(series.lines, series.splines); - return; - } - - for (idx = 0; idx < len; idx += ps) { - x = points[idx]; - y = points[idx + 1]; - if (x == null || x < series.xaxis.min || x > series.xaxis.max || y < series.yaxis.min || y > series.yaxis.max) { - continue; - } - - pts.push(series.xaxis.p2c(x) + plotOffset.left, series.yaxis.p2c(y) + plotOffset.top); - } - - len = pts.length; - - // Draw an open curve, not connected at the ends - for (idx = 0; idx < len - 2; idx += 2) { - cp = cp.concat(getControlPoints.apply(this, pts.slice(idx, idx + 6).concat([tension]))); - } - - ctx.save(); - ctx.strokeStyle = series.color; - ctx.lineWidth = series.splines.lineWidth; - - queue(ctx, 'quadratic', pts.slice(0, 4), cp.slice(0, 2)); - - for (idx = 2; idx < len - 3; idx += 2) { - queue(ctx, 'bezier', pts.slice(idx, idx + 4), cp.slice(2 * idx - 2, 2 * idx + 2)); - } - - queue(ctx, 'quadratic', pts.slice(len - 2, len), [cp[2 * len - 10], cp[2 * len - 9], pts[len - 4], pts[len - 3]]); - - drawLine(line, ctx, plot.height() + 10, series.splines.fill, series.color); - - ctx.restore(); - } - - $.plot.plugins.push({ - init: function(plot) { - plot.hooks.drawSeries.push(drawSpline); - }, - options: { - series: { - splines: { - show: false, - lineWidth: 2, - tension: 0.5, - fill: false - } - } - }, - name: 'spline', - version: '0.8.2' - }); -})(jQuery); diff --git a/app/assets/components/flot-spline/js/jquery.flot.spline.min.js b/app/assets/components/flot-spline/js/jquery.flot.spline.min.js deleted file mode 100644 index 65c8a13..0000000 --- a/app/assets/components/flot-spline/js/jquery.flot.spline.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(a){"use strict";function b(a,b,c,d,e,f,g){var j,k,l,m,n,o,p,q,h=Math.pow,i=Math.sqrt;return j=i(h(c-a,2)+h(d-b,2)),k=i(h(e-c,2)+h(f-d,2)),l=g*j/(j+k),m=g-l,n=c+l*(a-e),o=d+l*(b-f),p=c-m*(a-e),q=d-m*(b-f),[n,o,p,q]}function d(b,c,d,e,f){var g=a.color.parse(f);g.a="number"==typeof e?e:.3,g.normalize(),g=g.toString(),c.beginPath(),c.moveTo(b[0][0],b[0][1]);for(var h=b.length,i=0;h>i;i++)c[b[i][3]].apply(c,b[i][2]);c.stroke(),c.lineWidth=0,c.lineTo(b[h-1][0],d),c.lineTo(b[0][0],d),c.closePath(),e!==!1&&(c.fillStyle=g,c.fill())}function e(a,b,d,e){(void 0===b||"bezier"!==b&&"quadratic"!==b)&&(b="quadratic"),b+="CurveTo",0==c.length?c.push([d[0],d[1],e.concat(d.slice(2)),b]):"quadraticCurveTo"==b&&2==d.length?(e=e.slice(0,2).concat(d),c.push([d[0],d[1],e,b])):c.push([d[2],d[3],e.concat(d.slice(2)),b])}function f(f,g,h){if(h.splines.show===!0){var k,l,m,i=[],j=h.splines.tension||.5,n=h.datapoints.points,o=h.datapoints.pointsize,p=f.getPlotOffset(),q=n.length,r=[];if(c=[],4>q/o)return a.extend(h.lines,h.splines),void 0;for(k=0;q>k;k+=o)l=n[k],m=n[k+1],null==l||lh.xaxis.max||mh.yaxis.max||r.push(h.xaxis.p2c(l)+p.left,h.yaxis.p2c(m)+p.top);for(q=r.length,k=0;q-2>k;k+=2)i=i.concat(b.apply(this,r.slice(k,k+6).concat([j])));for(g.save(),g.strokeStyle=h.color,g.lineWidth=h.splines.lineWidth,e(g,"quadratic",r.slice(0,4),i.slice(0,2)),k=2;q-3>k;k+=2)e(g,"bezier",r.slice(k,k+4),i.slice(2*k-2,2*k+2));e(g,"quadratic",r.slice(q-2,q),[i[2*q-10],i[2*q-9],r[q-4],r[q-3]]),d(c,g,f.height()+10,h.splines.fill,h.color),g.restore()}}var c=[];a.plot.plugins.push({init:function(a){a.hooks.drawSeries.push(f)},options:{series:{splines:{show:!1,lineWidth:2,tension:.5,fill:!1}}},name:"spline",version:"0.8.2"})}(jQuery); \ No newline at end of file diff --git a/app/assets/components/flot.tooltip/.bower.json b/app/assets/components/flot.tooltip/.bower.json deleted file mode 100644 index e2d75dd..0000000 --- a/app/assets/components/flot.tooltip/.bower.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "flot.tooltip", - "version": "0.8.5", - "license": "MIT", - "main": "js/jquery.flot.tooltip.js", - "ignore": [ - ".gitignore", - "Gruntfile.js", - "README.md", - "package.json", - "examples", - "js/old" - ], - "homepage": "https://github.com/krzysu/flot.tooltip", - "_release": "0.8.5", - "_resolution": { - "type": "version", - "tag": "0.8.5", - "commit": "e2dbb407ffcf5ece0f2e6ab922b0192b8a6d168e" - }, - "_source": "git://github.com/krzysu/flot.tooltip.git", - "_target": "0.8.5", - "_originalSource": "flot.tooltip" -} \ No newline at end of file diff --git a/app/assets/components/flot.tooltip/bower.json b/app/assets/components/flot.tooltip/bower.json deleted file mode 100644 index f1670a5..0000000 --- a/app/assets/components/flot.tooltip/bower.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "flot.tooltip", - "version": "0.8.5", - "license": "MIT", - "main": "js/jquery.flot.tooltip.js", - "ignore": [ - ".gitignore", - "Gruntfile.js", - "README.md", - "package.json", - "examples", - "js/old" - ] -} diff --git a/app/assets/components/flot.tooltip/js/excanvas.min.js b/app/assets/components/flot.tooltip/js/excanvas.min.js deleted file mode 100644 index 12c74f7..0000000 --- a/app/assets/components/flot.tooltip/js/excanvas.min.js +++ /dev/null @@ -1 +0,0 @@ -if(!document.createElement("canvas").getContext){(function(){var z=Math;var K=z.round;var J=z.sin;var U=z.cos;var b=z.abs;var k=z.sqrt;var D=10;var F=D/2;function T(){return this.context_||(this.context_=new W(this))}var O=Array.prototype.slice;function G(i,j,m){var Z=O.call(arguments,2);return function(){return i.apply(j,Z.concat(O.call(arguments)))}}function AD(Z){return String(Z).replace(/&/g,"&").replace(/"/g,""")}function r(i){if(!i.namespaces.g_vml_){i.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML")}if(!i.namespaces.g_o_){i.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML")}if(!i.styleSheets.ex_canvas_){var Z=i.createStyleSheet();Z.owningElement.id="ex_canvas_";Z.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}r(document);var E={init:function(Z){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var i=Z||document;i.createElement("canvas");i.attachEvent("onreadystatechange",G(this.init_,this,i))}},init_:function(m){var j=m.getElementsByTagName("canvas");for(var Z=0;Z1){j--}if(6*j<1){return i+(Z-i)*6*j}else{if(2*j<1){return Z}else{if(3*j<2){return i+(Z-i)*(2/3-j)*6}else{return i}}}}function Y(Z){var AE,p=1;Z=String(Z);if(Z.charAt(0)=="#"){AE=Z}else{if(/^rgb/.test(Z)){var m=g(Z);var AE="#",AF;for(var j=0;j<3;j++){if(m[j].indexOf("%")!=-1){AF=Math.floor(C(m[j])*255)}else{AF=Number(m[j])}AE+=I[N(AF,0,255)]}p=m[3]}else{if(/^hsl/.test(Z)){var m=g(Z);AE=c(m);p=m[3]}else{AE=B[Z]||Z}}}return{color:AE,alpha:p}}var L={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var f={};function X(Z){if(f[Z]){return f[Z]}var m=document.createElement("div");var j=m.style;try{j.font=Z}catch(i){}return f[Z]={style:j.fontStyle||L.style,variant:j.fontVariant||L.variant,weight:j.fontWeight||L.weight,size:j.fontSize||L.size,family:j.fontFamily||L.family}}function P(j,i){var Z={};for(var AF in j){Z[AF]=j[AF]}var AE=parseFloat(i.currentStyle.fontSize),m=parseFloat(j.size);if(typeof j.size=="number"){Z.size=j.size}else{if(j.size.indexOf("px")!=-1){Z.size=m}else{if(j.size.indexOf("em")!=-1){Z.size=AE*m}else{if(j.size.indexOf("%")!=-1){Z.size=(AE/100)*m}else{if(j.size.indexOf("pt")!=-1){Z.size=m/0.75}else{Z.size=AE}}}}}Z.size*=0.981;return Z}function AA(Z){return Z.style+" "+Z.variant+" "+Z.weight+" "+Z.size+"px "+Z.family}function t(Z){switch(Z){case"butt":return"flat";case"round":return"round";case"square":default:return"square"}}function W(i){this.m_=V();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=D*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var Z=i.ownerDocument.createElement("div");Z.style.width=i.clientWidth+"px";Z.style.height=i.clientHeight+"px";Z.style.overflow="hidden";Z.style.position="absolute";i.appendChild(Z);this.element_=Z;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var M=W.prototype;M.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};M.beginPath=function(){this.currentPath_=[]};M.moveTo=function(i,Z){var j=this.getCoords_(i,Z);this.currentPath_.push({type:"moveTo",x:j.x,y:j.y});this.currentX_=j.x;this.currentY_=j.y};M.lineTo=function(i,Z){var j=this.getCoords_(i,Z);this.currentPath_.push({type:"lineTo",x:j.x,y:j.y});this.currentX_=j.x;this.currentY_=j.y};M.bezierCurveTo=function(j,i,AI,AH,AG,AE){var Z=this.getCoords_(AG,AE);var AF=this.getCoords_(j,i);var m=this.getCoords_(AI,AH);e(this,AF,m,Z)};function e(Z,m,j,i){Z.currentPath_.push({type:"bezierCurveTo",cp1x:m.x,cp1y:m.y,cp2x:j.x,cp2y:j.y,x:i.x,y:i.y});Z.currentX_=i.x;Z.currentY_=i.y}M.quadraticCurveTo=function(AG,j,i,Z){var AF=this.getCoords_(AG,j);var AE=this.getCoords_(i,Z);var AH={x:this.currentX_+2/3*(AF.x-this.currentX_),y:this.currentY_+2/3*(AF.y-this.currentY_)};var m={x:AH.x+(AE.x-this.currentX_)/3,y:AH.y+(AE.y-this.currentY_)/3};e(this,AH,m,AE)};M.arc=function(AJ,AH,AI,AE,i,j){AI*=D;var AN=j?"at":"wa";var AK=AJ+U(AE)*AI-F;var AM=AH+J(AE)*AI-F;var Z=AJ+U(i)*AI-F;var AL=AH+J(i)*AI-F;if(AK==Z&&!j){AK+=0.125}var m=this.getCoords_(AJ,AH);var AG=this.getCoords_(AK,AM);var AF=this.getCoords_(Z,AL);this.currentPath_.push({type:AN,x:m.x,y:m.y,radius:AI,xStart:AG.x,yStart:AG.y,xEnd:AF.x,yEnd:AF.y})};M.rect=function(j,i,Z,m){this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath()};M.strokeRect=function(j,i,Z,m){var p=this.currentPath_;this.beginPath();this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath();this.stroke();this.currentPath_=p};M.fillRect=function(j,i,Z,m){var p=this.currentPath_;this.beginPath();this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath();this.fill();this.currentPath_=p};M.createLinearGradient=function(i,m,Z,j){var p=new v("gradient");p.x0_=i;p.y0_=m;p.x1_=Z;p.y1_=j;return p};M.createRadialGradient=function(m,AE,j,i,p,Z){var AF=new v("gradientradial");AF.x0_=m;AF.y0_=AE;AF.r0_=j;AF.x1_=i;AF.y1_=p;AF.r1_=Z;return AF};M.drawImage=function(AO,j){var AH,AF,AJ,AV,AM,AK,AQ,AX;var AI=AO.runtimeStyle.width;var AN=AO.runtimeStyle.height;AO.runtimeStyle.width="auto";AO.runtimeStyle.height="auto";var AG=AO.width;var AT=AO.height;AO.runtimeStyle.width=AI;AO.runtimeStyle.height=AN;if(arguments.length==3){AH=arguments[1];AF=arguments[2];AM=AK=0;AQ=AJ=AG;AX=AV=AT}else{if(arguments.length==5){AH=arguments[1];AF=arguments[2];AJ=arguments[3];AV=arguments[4];AM=AK=0;AQ=AG;AX=AT}else{if(arguments.length==9){AM=arguments[1];AK=arguments[2];AQ=arguments[3];AX=arguments[4];AH=arguments[5];AF=arguments[6];AJ=arguments[7];AV=arguments[8]}else{throw Error("Invalid number of arguments")}}}var AW=this.getCoords_(AH,AF);var m=AQ/2;var i=AX/2;var AU=[];var Z=10;var AE=10;AU.push(" ','","");this.element_.insertAdjacentHTML("BeforeEnd",AU.join(""))};M.stroke=function(AM){var m=10;var AN=10;var AE=5000;var AG={x:null,y:null};var AL={x:null,y:null};for(var AH=0;AHAL.x){AL.x=Z.x}if(AG.y==null||Z.yAL.y){AL.y=Z.y}}}AK.push(' ">');if(!AM){R(this,AK)}else{a(this,AK,AG,AL)}AK.push("");this.element_.insertAdjacentHTML("beforeEnd",AK.join(""))}};function R(j,AE){var i=Y(j.strokeStyle);var m=i.color;var p=i.alpha*j.globalAlpha;var Z=j.lineScale_*j.lineWidth;if(Z<1){p*=Z}AE.push("')}function a(AO,AG,Ah,AP){var AH=AO.fillStyle;var AY=AO.arcScaleX_;var AX=AO.arcScaleY_;var Z=AP.x-Ah.x;var m=AP.y-Ah.y;if(AH instanceof v){var AL=0;var Ac={x:0,y:0};var AU=0;var AK=1;if(AH.type_=="gradient"){var AJ=AH.x0_/AY;var j=AH.y0_/AX;var AI=AH.x1_/AY;var Aj=AH.y1_/AX;var Ag=AO.getCoords_(AJ,j);var Af=AO.getCoords_(AI,Aj);var AE=Af.x-Ag.x;var p=Af.y-Ag.y;AL=Math.atan2(AE,p)*180/Math.PI;if(AL<0){AL+=360}if(AL<0.000001){AL=0}}else{var Ag=AO.getCoords_(AH.x0_,AH.y0_);Ac={x:(Ag.x-Ah.x)/Z,y:(Ag.y-Ah.y)/m};Z/=AY*D;m/=AX*D;var Aa=z.max(Z,m);AU=2*AH.r0_/Aa;AK=2*AH.r1_/Aa-AU}var AS=AH.colors_;AS.sort(function(Ak,i){return Ak.offset-i.offset});var AN=AS.length;var AR=AS[0].color;var AQ=AS[AN-1].color;var AW=AS[0].alpha*AO.globalAlpha;var AV=AS[AN-1].alpha*AO.globalAlpha;var Ab=[];for(var Ae=0;Ae')}else{if(AH instanceof u){if(Z&&m){var AF=-Ah.x;var AZ=-Ah.y;AG.push("')}}else{var Ai=Y(AO.fillStyle);var AT=Ai.color;var Ad=Ai.alpha*AO.globalAlpha;AG.push('')}}}M.fill=function(){this.stroke(true)};M.closePath=function(){this.currentPath_.push({type:"close"})};M.getCoords_=function(j,i){var Z=this.m_;return{x:D*(j*Z[0][0]+i*Z[1][0]+Z[2][0])-F,y:D*(j*Z[0][1]+i*Z[1][1]+Z[2][1])-F}};M.save=function(){var Z={};Q(this,Z);this.aStack_.push(Z);this.mStack_.push(this.m_);this.m_=d(V(),this.m_)};M.restore=function(){if(this.aStack_.length){Q(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function H(Z){return isFinite(Z[0][0])&&isFinite(Z[0][1])&&isFinite(Z[1][0])&&isFinite(Z[1][1])&&isFinite(Z[2][0])&&isFinite(Z[2][1])}function y(i,Z,j){if(!H(Z)){return }i.m_=Z;if(j){var p=Z[0][0]*Z[1][1]-Z[0][1]*Z[1][0];i.lineScale_=k(b(p))}}M.translate=function(j,i){var Z=[[1,0,0],[0,1,0],[j,i,1]];y(this,d(Z,this.m_),false)};M.rotate=function(i){var m=U(i);var j=J(i);var Z=[[m,j,0],[-j,m,0],[0,0,1]];y(this,d(Z,this.m_),false)};M.scale=function(j,i){this.arcScaleX_*=j;this.arcScaleY_*=i;var Z=[[j,0,0],[0,i,0],[0,0,1]];y(this,d(Z,this.m_),true)};M.transform=function(p,m,AF,AE,i,Z){var j=[[p,m,0],[AF,AE,0],[i,Z,1]];y(this,d(j,this.m_),true)};M.setTransform=function(AE,p,AG,AF,j,i){var Z=[[AE,p,0],[AG,AF,0],[j,i,1]];y(this,Z,true)};M.drawText_=function(AK,AI,AH,AN,AG){var AM=this.m_,AQ=1000,i=0,AP=AQ,AF={x:0,y:0},AE=[];var Z=P(X(this.font),this.element_);var j=AA(Z);var AR=this.element_.currentStyle;var p=this.textAlign.toLowerCase();switch(p){case"left":case"center":case"right":break;case"end":p=AR.direction=="ltr"?"right":"left";break;case"start":p=AR.direction=="rtl"?"right":"left";break;default:p="left"}switch(this.textBaseline){case"hanging":case"top":AF.y=Z.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":AF.y=-Z.size/2.25;break}switch(p){case"right":i=AQ;AP=0.05;break;case"center":i=AP=AQ/2;break}var AO=this.getCoords_(AI+AF.x,AH+AF.y);AE.push('');if(AG){R(this,AE)}else{a(this,AE,{x:-i,y:0},{x:AP,y:Z.size})}var AL=AM[0][0].toFixed(3)+","+AM[1][0].toFixed(3)+","+AM[0][1].toFixed(3)+","+AM[1][1].toFixed(3)+",0,0";var AJ=K(AO.x/D)+","+K(AO.y/D);AE.push('','','');this.element_.insertAdjacentHTML("beforeEnd",AE.join(""))};M.fillText=function(j,Z,m,i){this.drawText_(j,Z,m,i,false)};M.strokeText=function(j,Z,m,i){this.drawText_(j,Z,m,i,true)};M.measureText=function(j){if(!this.textMeasureEl_){var Z='';this.element_.insertAdjacentHTML("beforeEnd",Z);this.textMeasureEl_=this.element_.lastChild}var i=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(i.createTextNode(j));return{width:this.textMeasureEl_.offsetWidth}};M.clip=function(){};M.arcTo=function(){};M.createPattern=function(i,Z){return new u(i,Z)};function v(Z){this.type_=Z;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}v.prototype.addColorStop=function(i,Z){Z=Y(Z);this.colors_.push({offset:i,color:Z.color,alpha:Z.alpha})};function u(i,Z){q(i);switch(Z){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=Z;break;default:n("SYNTAX_ERR")}this.src_=i.src;this.width_=i.width;this.height_=i.height}function n(Z){throw new o(Z)}function q(Z){if(!Z||Z.nodeType!=1||Z.tagName!="IMG"){n("TYPE_MISMATCH_ERR")}if(Z.readyState!="complete"){n("INVALID_STATE_ERR")}}function o(Z){this.code=this[Z];this.message=Z+": DOM Exception "+this.code}var x=o.prototype=new Error;x.INDEX_SIZE_ERR=1;x.DOMSTRING_SIZE_ERR=2;x.HIERARCHY_REQUEST_ERR=3;x.WRONG_DOCUMENT_ERR=4;x.INVALID_CHARACTER_ERR=5;x.NO_DATA_ALLOWED_ERR=6;x.NO_MODIFICATION_ALLOWED_ERR=7;x.NOT_FOUND_ERR=8;x.NOT_SUPPORTED_ERR=9;x.INUSE_ATTRIBUTE_ERR=10;x.INVALID_STATE_ERR=11;x.SYNTAX_ERR=12;x.INVALID_MODIFICATION_ERR=13;x.NAMESPACE_ERR=14;x.INVALID_ACCESS_ERR=15;x.VALIDATION_ERR=16;x.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=E;CanvasRenderingContext2D=W;CanvasGradient=v;CanvasPattern=u;DOMException=o})()}; \ No newline at end of file diff --git a/app/assets/components/flot.tooltip/js/jquery.flot.js b/app/assets/components/flot.tooltip/js/jquery.flot.js deleted file mode 100644 index 39f3e4c..0000000 --- a/app/assets/components/flot.tooltip/js/jquery.flot.js +++ /dev/null @@ -1,3168 +0,0 @@ -/* Javascript plotting library for jQuery, version 0.8.3. - -Copyright (c) 2007-2014 IOLA and Ole Laursen. -Licensed under the MIT license. - -*/ - -// first an inline dependency, jquery.colorhelpers.js, we inline it here -// for convenience - -/* Plugin for jQuery for working with colors. - * - * Version 1.1. - * - * Inspiration from jQuery color animation plugin by John Resig. - * - * Released under the MIT license by Ole Laursen, October 2009. - * - * Examples: - * - * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() - * var c = $.color.extract($("#mydiv"), 'background-color'); - * console.log(c.r, c.g, c.b, c.a); - * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" - * - * Note that .scale() and .add() return the same modified object - * instead of making a new one. - * - * V. 1.1: Fix error handling so e.g. parsing an empty string does - * produce a color rather than just crashing. - */ -(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return valuemax?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); - -// the actual Flot code -(function($) { - - // Cache the prototype hasOwnProperty for faster access - - var hasOwnProperty = Object.prototype.hasOwnProperty; - - // A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM - // operation produces the same effect as detach, i.e. removing the element - // without touching its jQuery data. - - // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+. - - if (!$.fn.detach) { - $.fn.detach = function() { - return this.each(function() { - if (this.parentNode) { - this.parentNode.removeChild( this ); - } - }); - }; - } - - /////////////////////////////////////////////////////////////////////////// - // The Canvas object is a wrapper around an HTML5 tag. - // - // @constructor - // @param {string} cls List of classes to apply to the canvas. - // @param {element} container Element onto which to append the canvas. - // - // Requiring a container is a little iffy, but unfortunately canvas - // operations don't work unless the canvas is attached to the DOM. - - function Canvas(cls, container) { - - var element = container.children("." + cls)[0]; - - if (element == null) { - - element = document.createElement("canvas"); - element.className = cls; - - $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) - .appendTo(container); - - // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas - - if (!element.getContext) { - if (window.G_vmlCanvasManager) { - element = window.G_vmlCanvasManager.initElement(element); - } else { - throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); - } - } - } - - this.element = element; - - var context = this.context = element.getContext("2d"); - - // Determine the screen's ratio of physical to device-independent - // pixels. This is the ratio between the canvas width that the browser - // advertises and the number of pixels actually present in that space. - - // The iPhone 4, for example, has a device-independent width of 320px, - // but its screen is actually 640px wide. It therefore has a pixel - // ratio of 2, while most normal devices have a ratio of 1. - - var devicePixelRatio = window.devicePixelRatio || 1, - backingStoreRatio = - context.webkitBackingStorePixelRatio || - context.mozBackingStorePixelRatio || - context.msBackingStorePixelRatio || - context.oBackingStorePixelRatio || - context.backingStorePixelRatio || 1; - - this.pixelRatio = devicePixelRatio / backingStoreRatio; - - // Size the canvas to match the internal dimensions of its container - - this.resize(container.width(), container.height()); - - // Collection of HTML div layers for text overlaid onto the canvas - - this.textContainer = null; - this.text = {}; - - // Cache of text fragments and metrics, so we can avoid expensively - // re-calculating them when the plot is re-rendered in a loop. - - this._textCache = {}; - } - - // Resizes the canvas to the given dimensions. - // - // @param {number} width New width of the canvas, in pixels. - // @param {number} width New height of the canvas, in pixels. - - Canvas.prototype.resize = function(width, height) { - - if (width <= 0 || height <= 0) { - throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); - } - - var element = this.element, - context = this.context, - pixelRatio = this.pixelRatio; - - // Resize the canvas, increasing its density based on the display's - // pixel ratio; basically giving it more pixels without increasing the - // size of its element, to take advantage of the fact that retina - // displays have that many more pixels in the same advertised space. - - // Resizing should reset the state (excanvas seems to be buggy though) - - if (this.width != width) { - element.width = width * pixelRatio; - element.style.width = width + "px"; - this.width = width; - } - - if (this.height != height) { - element.height = height * pixelRatio; - element.style.height = height + "px"; - this.height = height; - } - - // Save the context, so we can reset in case we get replotted. The - // restore ensure that we're really back at the initial state, and - // should be safe even if we haven't saved the initial state yet. - - context.restore(); - context.save(); - - // Scale the coordinate space to match the display density; so even though we - // may have twice as many pixels, we still want lines and other drawing to - // appear at the same size; the extra pixels will just make them crisper. - - context.scale(pixelRatio, pixelRatio); - }; - - // Clears the entire canvas area, not including any overlaid HTML text - - Canvas.prototype.clear = function() { - this.context.clearRect(0, 0, this.width, this.height); - }; - - // Finishes rendering the canvas, including managing the text overlay. - - Canvas.prototype.render = function() { - - var cache = this._textCache; - - // For each text layer, add elements marked as active that haven't - // already been rendered, and remove those that are no longer active. - - for (var layerKey in cache) { - if (hasOwnProperty.call(cache, layerKey)) { - - var layer = this.getTextLayer(layerKey), - layerCache = cache[layerKey]; - - layer.hide(); - - for (var styleKey in layerCache) { - if (hasOwnProperty.call(layerCache, styleKey)) { - var styleCache = layerCache[styleKey]; - for (var key in styleCache) { - if (hasOwnProperty.call(styleCache, key)) { - - var positions = styleCache[key].positions; - - for (var i = 0, position; position = positions[i]; i++) { - if (position.active) { - if (!position.rendered) { - layer.append(position.element); - position.rendered = true; - } - } else { - positions.splice(i--, 1); - if (position.rendered) { - position.element.detach(); - } - } - } - - if (positions.length == 0) { - delete styleCache[key]; - } - } - } - } - } - - layer.show(); - } - } - }; - - // Creates (if necessary) and returns the text overlay container. - // - // @param {string} classes String of space-separated CSS classes used to - // uniquely identify the text layer. - // @return {object} The jQuery-wrapped text-layer div. - - Canvas.prototype.getTextLayer = function(classes) { - - var layer = this.text[classes]; - - // Create the text layer if it doesn't exist - - if (layer == null) { - - // Create the text layer container, if it doesn't exist - - if (this.textContainer == null) { - this.textContainer = $("
") - .css({ - position: "absolute", - top: 0, - left: 0, - bottom: 0, - right: 0, - 'font-size': "smaller", - color: "#545454" - }) - .insertAfter(this.element); - } - - layer = this.text[classes] = $("
") - .addClass(classes) - .css({ - position: "absolute", - top: 0, - left: 0, - bottom: 0, - right: 0 - }) - .appendTo(this.textContainer); - } - - return layer; - }; - - // Creates (if necessary) and returns a text info object. - // - // The object looks like this: - // - // { - // width: Width of the text's wrapper div. - // height: Height of the text's wrapper div. - // element: The jQuery-wrapped HTML div containing the text. - // positions: Array of positions at which this text is drawn. - // } - // - // The positions array contains objects that look like this: - // - // { - // active: Flag indicating whether the text should be visible. - // rendered: Flag indicating whether the text is currently visible. - // element: The jQuery-wrapped HTML div containing the text. - // x: X coordinate at which to draw the text. - // y: Y coordinate at which to draw the text. - // } - // - // Each position after the first receives a clone of the original element. - // - // The idea is that that the width, height, and general 'identity' of the - // text is constant no matter where it is placed; the placements are a - // secondary property. - // - // Canvas maintains a cache of recently-used text info objects; getTextInfo - // either returns the cached element or creates a new entry. - // - // @param {string} layer A string of space-separated CSS classes uniquely - // identifying the layer containing this text. - // @param {string} text Text string to retrieve info for. - // @param {(string|object)=} font Either a string of space-separated CSS - // classes or a font-spec object, defining the text's font and style. - // @param {number=} angle Angle at which to rotate the text, in degrees. - // Angle is currently unused, it will be implemented in the future. - // @param {number=} width Maximum width of the text before it wraps. - // @return {object} a text info object. - - Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { - - var textStyle, layerCache, styleCache, info; - - // Cast the value to a string, in case we were given a number or such - - text = "" + text; - - // If the font is a font-spec object, generate a CSS font definition - - if (typeof font === "object") { - textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; - } else { - textStyle = font; - } - - // Retrieve (or create) the cache for the text's layer and styles - - layerCache = this._textCache[layer]; - - if (layerCache == null) { - layerCache = this._textCache[layer] = {}; - } - - styleCache = layerCache[textStyle]; - - if (styleCache == null) { - styleCache = layerCache[textStyle] = {}; - } - - info = styleCache[text]; - - // If we can't find a matching element in our cache, create a new one - - if (info == null) { - - var element = $("
").html(text) - .css({ - position: "absolute", - 'max-width': width, - top: -9999 - }) - .appendTo(this.getTextLayer(layer)); - - if (typeof font === "object") { - element.css({ - font: textStyle, - color: font.color - }); - } else if (typeof font === "string") { - element.addClass(font); - } - - info = styleCache[text] = { - width: element.outerWidth(true), - height: element.outerHeight(true), - element: element, - positions: [] - }; - - element.detach(); - } - - return info; - }; - - // Adds a text string to the canvas text overlay. - // - // The text isn't drawn immediately; it is marked as rendering, which will - // result in its addition to the canvas on the next render pass. - // - // @param {string} layer A string of space-separated CSS classes uniquely - // identifying the layer containing this text. - // @param {number} x X coordinate at which to draw the text. - // @param {number} y Y coordinate at which to draw the text. - // @param {string} text Text string to draw. - // @param {(string|object)=} font Either a string of space-separated CSS - // classes or a font-spec object, defining the text's font and style. - // @param {number=} angle Angle at which to rotate the text, in degrees. - // Angle is currently unused, it will be implemented in the future. - // @param {number=} width Maximum width of the text before it wraps. - // @param {string=} halign Horizontal alignment of the text; either "left", - // "center" or "right". - // @param {string=} valign Vertical alignment of the text; either "top", - // "middle" or "bottom". - - Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { - - var info = this.getTextInfo(layer, text, font, angle, width), - positions = info.positions; - - // Tweak the div's position to match the text's alignment - - if (halign == "center") { - x -= info.width / 2; - } else if (halign == "right") { - x -= info.width; - } - - if (valign == "middle") { - y -= info.height / 2; - } else if (valign == "bottom") { - y -= info.height; - } - - // Determine whether this text already exists at this position. - // If so, mark it for inclusion in the next render pass. - - for (var i = 0, position; position = positions[i]; i++) { - if (position.x == x && position.y == y) { - position.active = true; - return; - } - } - - // If the text doesn't exist at this position, create a new entry - - // For the very first position we'll re-use the original element, - // while for subsequent ones we'll clone it. - - position = { - active: true, - rendered: false, - element: positions.length ? info.element.clone() : info.element, - x: x, - y: y - }; - - positions.push(position); - - // Move the element to its final position within the container - - position.element.css({ - top: Math.round(y), - left: Math.round(x), - 'text-align': halign // In case the text wraps - }); - }; - - // Removes one or more text strings from the canvas text overlay. - // - // If no parameters are given, all text within the layer is removed. - // - // Note that the text is not immediately removed; it is simply marked as - // inactive, which will result in its removal on the next render pass. - // This avoids the performance penalty for 'clear and redraw' behavior, - // where we potentially get rid of all text on a layer, but will likely - // add back most or all of it later, as when redrawing axes, for example. - // - // @param {string} layer A string of space-separated CSS classes uniquely - // identifying the layer containing this text. - // @param {number=} x X coordinate of the text. - // @param {number=} y Y coordinate of the text. - // @param {string=} text Text string to remove. - // @param {(string|object)=} font Either a string of space-separated CSS - // classes or a font-spec object, defining the text's font and style. - // @param {number=} angle Angle at which the text is rotated, in degrees. - // Angle is currently unused, it will be implemented in the future. - - Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { - if (text == null) { - var layerCache = this._textCache[layer]; - if (layerCache != null) { - for (var styleKey in layerCache) { - if (hasOwnProperty.call(layerCache, styleKey)) { - var styleCache = layerCache[styleKey]; - for (var key in styleCache) { - if (hasOwnProperty.call(styleCache, key)) { - var positions = styleCache[key].positions; - for (var i = 0, position; position = positions[i]; i++) { - position.active = false; - } - } - } - } - } - } - } else { - var positions = this.getTextInfo(layer, text, font, angle).positions; - for (var i = 0, position; position = positions[i]; i++) { - if (position.x == x && position.y == y) { - position.active = false; - } - } - } - }; - - /////////////////////////////////////////////////////////////////////////// - // The top-level container for the entire plot. - - function Plot(placeholder, data_, options_, plugins) { - // data is on the form: - // [ series1, series2 ... ] - // where series is either just the data as [ [x1, y1], [x2, y2], ... ] - // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... } - - var series = [], - options = { - // the color theme used for graphs - colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], - legend: { - show: true, - noColumns: 1, // number of colums in legend table - labelFormatter: null, // fn: string -> string - labelBoxBorderColor: "#ccc", // border color for the little label boxes - container: null, // container (as jQuery object) to put legend in, null means default on top of graph - position: "ne", // position of default legend container within plot - margin: 5, // distance from grid edge to default legend container within plot - backgroundColor: null, // null means auto-detect - backgroundOpacity: 0.85, // set to 0 to avoid background - sorted: null // default to no legend sorting - }, - xaxis: { - show: null, // null = auto-detect, true = always, false = never - position: "bottom", // or "top" - mode: null, // null or "time" - font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } - color: null, // base color, labels, ticks - tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" - transform: null, // null or f: number -> number to transform axis - inverseTransform: null, // if transform is set, this should be the inverse function - min: null, // min. value to show, null means set automatically - max: null, // max. value to show, null means set automatically - autoscaleMargin: null, // margin in % to add if auto-setting min/max - ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks - tickFormatter: null, // fn: number -> string - labelWidth: null, // size of tick labels in pixels - labelHeight: null, - reserveSpace: null, // whether to reserve space even if axis isn't shown - tickLength: null, // size in pixels of ticks, or "full" for whole line - alignTicksWithAxis: null, // axis number or null for no sync - tickDecimals: null, // no. of decimals, null means auto - tickSize: null, // number or [number, "unit"] - minTickSize: null // number or [number, "unit"] - }, - yaxis: { - autoscaleMargin: 0.02, - position: "left" // or "right" - }, - xaxes: [], - yaxes: [], - series: { - points: { - show: false, - radius: 3, - lineWidth: 2, // in pixels - fill: true, - fillColor: "#ffffff", - symbol: "circle" // or callback - }, - lines: { - // we don't put in show: false so we can see - // whether lines were actively disabled - lineWidth: 2, // in pixels - fill: false, - fillColor: null, - steps: false - // Omit 'zero', so we can later default its value to - // match that of the 'fill' option. - }, - bars: { - show: false, - lineWidth: 2, // in pixels - barWidth: 1, // in units of the x axis - fill: true, - fillColor: null, - align: "left", // "left", "right", or "center" - horizontal: false, - zero: true - }, - shadowSize: 3, - highlightColor: null - }, - grid: { - show: true, - aboveData: false, - color: "#545454", // primary color used for outline and labels - backgroundColor: null, // null for transparent, else color - borderColor: null, // set if different from the grid color - tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)" - margin: 0, // distance from the canvas edge to the grid - labelMargin: 5, // in pixels - axisMargin: 8, // in pixels - borderWidth: 2, // in pixels - minBorderMargin: null, // in pixels, null means taken from points radius - markings: null, // array of ranges or fn: axes -> array of ranges - markingsColor: "#f4f4f4", - markingsLineWidth: 2, - // interactive stuff - clickable: false, - hoverable: false, - autoHighlight: true, // highlight in case mouse is near - mouseActiveRadius: 10 // how far the mouse can be away to activate an item - }, - interaction: { - redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow - }, - hooks: {} - }, - surface = null, // the canvas for the plot itself - overlay = null, // canvas for interactive stuff on top of plot - eventHolder = null, // jQuery object that events should be bound to - ctx = null, octx = null, - xaxes = [], yaxes = [], - plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, - plotWidth = 0, plotHeight = 0, - hooks = { - processOptions: [], - processRawData: [], - processDatapoints: [], - processOffset: [], - drawBackground: [], - drawSeries: [], - draw: [], - bindEvents: [], - drawOverlay: [], - shutdown: [] - }, - plot = this; - - // public functions - plot.setData = setData; - plot.setupGrid = setupGrid; - plot.draw = draw; - plot.getPlaceholder = function() { return placeholder; }; - plot.getCanvas = function() { return surface.element; }; - plot.getPlotOffset = function() { return plotOffset; }; - plot.width = function () { return plotWidth; }; - plot.height = function () { return plotHeight; }; - plot.offset = function () { - var o = eventHolder.offset(); - o.left += plotOffset.left; - o.top += plotOffset.top; - return o; - }; - plot.getData = function () { return series; }; - plot.getAxes = function () { - var res = {}, i; - $.each(xaxes.concat(yaxes), function (_, axis) { - if (axis) - res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis; - }); - return res; - }; - plot.getXAxes = function () { return xaxes; }; - plot.getYAxes = function () { return yaxes; }; - plot.c2p = canvasToAxisCoords; - plot.p2c = axisToCanvasCoords; - plot.getOptions = function () { return options; }; - plot.highlight = highlight; - plot.unhighlight = unhighlight; - plot.triggerRedrawOverlay = triggerRedrawOverlay; - plot.pointOffset = function(point) { - return { - left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10), - top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10) - }; - }; - plot.shutdown = shutdown; - plot.destroy = function () { - shutdown(); - placeholder.removeData("plot").empty(); - - series = []; - options = null; - surface = null; - overlay = null; - eventHolder = null; - ctx = null; - octx = null; - xaxes = []; - yaxes = []; - hooks = null; - highlights = []; - plot = null; - }; - plot.resize = function () { - var width = placeholder.width(), - height = placeholder.height(); - surface.resize(width, height); - overlay.resize(width, height); - }; - - // public attributes - plot.hooks = hooks; - - // initialize - initPlugins(plot); - parseOptions(options_); - setupCanvases(); - setData(data_); - setupGrid(); - draw(); - bindEvents(); - - - function executeHooks(hook, args) { - args = [plot].concat(args); - for (var i = 0; i < hook.length; ++i) - hook[i].apply(this, args); - } - - function initPlugins() { - - // References to key classes, allowing plugins to modify them - - var classes = { - Canvas: Canvas - }; - - for (var i = 0; i < plugins.length; ++i) { - var p = plugins[i]; - p.init(plot, classes); - if (p.options) - $.extend(true, options, p.options); - } - } - - function parseOptions(opts) { - - $.extend(true, options, opts); - - // $.extend merges arrays, rather than replacing them. When less - // colors are provided than the size of the default palette, we - // end up with those colors plus the remaining defaults, which is - // not expected behavior; avoid it by replacing them here. - - if (opts && opts.colors) { - options.colors = opts.colors; - } - - if (options.xaxis.color == null) - options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); - if (options.yaxis.color == null) - options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); - - if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility - options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; - if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility - options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; - - if (options.grid.borderColor == null) - options.grid.borderColor = options.grid.color; - if (options.grid.tickColor == null) - options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); - - // Fill in defaults for axis options, including any unspecified - // font-spec fields, if a font-spec was provided. - - // If no x/y axis options were provided, create one of each anyway, - // since the rest of the code assumes that they exist. - - var i, axisOptions, axisCount, - fontSize = placeholder.css("font-size"), - fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13, - fontDefaults = { - style: placeholder.css("font-style"), - size: Math.round(0.8 * fontSizeDefault), - variant: placeholder.css("font-variant"), - weight: placeholder.css("font-weight"), - family: placeholder.css("font-family") - }; - - axisCount = options.xaxes.length || 1; - for (i = 0; i < axisCount; ++i) { - - axisOptions = options.xaxes[i]; - if (axisOptions && !axisOptions.tickColor) { - axisOptions.tickColor = axisOptions.color; - } - - axisOptions = $.extend(true, {}, options.xaxis, axisOptions); - options.xaxes[i] = axisOptions; - - if (axisOptions.font) { - axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); - if (!axisOptions.font.color) { - axisOptions.font.color = axisOptions.color; - } - if (!axisOptions.font.lineHeight) { - axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); - } - } - } - - axisCount = options.yaxes.length || 1; - for (i = 0; i < axisCount; ++i) { - - axisOptions = options.yaxes[i]; - if (axisOptions && !axisOptions.tickColor) { - axisOptions.tickColor = axisOptions.color; - } - - axisOptions = $.extend(true, {}, options.yaxis, axisOptions); - options.yaxes[i] = axisOptions; - - if (axisOptions.font) { - axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); - if (!axisOptions.font.color) { - axisOptions.font.color = axisOptions.color; - } - if (!axisOptions.font.lineHeight) { - axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); - } - } - } - - // backwards compatibility, to be removed in future - if (options.xaxis.noTicks && options.xaxis.ticks == null) - options.xaxis.ticks = options.xaxis.noTicks; - if (options.yaxis.noTicks && options.yaxis.ticks == null) - options.yaxis.ticks = options.yaxis.noTicks; - if (options.x2axis) { - options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis); - options.xaxes[1].position = "top"; - // Override the inherit to allow the axis to auto-scale - if (options.x2axis.min == null) { - options.xaxes[1].min = null; - } - if (options.x2axis.max == null) { - options.xaxes[1].max = null; - } - } - if (options.y2axis) { - options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis); - options.yaxes[1].position = "right"; - // Override the inherit to allow the axis to auto-scale - if (options.y2axis.min == null) { - options.yaxes[1].min = null; - } - if (options.y2axis.max == null) { - options.yaxes[1].max = null; - } - } - if (options.grid.coloredAreas) - options.grid.markings = options.grid.coloredAreas; - if (options.grid.coloredAreasColor) - options.grid.markingsColor = options.grid.coloredAreasColor; - if (options.lines) - $.extend(true, options.series.lines, options.lines); - if (options.points) - $.extend(true, options.series.points, options.points); - if (options.bars) - $.extend(true, options.series.bars, options.bars); - if (options.shadowSize != null) - options.series.shadowSize = options.shadowSize; - if (options.highlightColor != null) - options.series.highlightColor = options.highlightColor; - - // save options on axes for future reference - for (i = 0; i < options.xaxes.length; ++i) - getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; - for (i = 0; i < options.yaxes.length; ++i) - getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; - - // add hooks from options - for (var n in hooks) - if (options.hooks[n] && options.hooks[n].length) - hooks[n] = hooks[n].concat(options.hooks[n]); - - executeHooks(hooks.processOptions, [options]); - } - - function setData(d) { - series = parseData(d); - fillInSeriesOptions(); - processData(); - } - - function parseData(d) { - var res = []; - for (var i = 0; i < d.length; ++i) { - var s = $.extend(true, {}, options.series); - - if (d[i].data != null) { - s.data = d[i].data; // move the data instead of deep-copy - delete d[i].data; - - $.extend(true, s, d[i]); - - d[i].data = s.data; - } - else - s.data = d[i]; - res.push(s); - } - - return res; - } - - function axisNumber(obj, coord) { - var a = obj[coord + "axis"]; - if (typeof a == "object") // if we got a real axis, extract number - a = a.n; - if (typeof a != "number") - a = 1; // default to first axis - return a; - } - - function allAxes() { - // return flat array without annoying null entries - return $.grep(xaxes.concat(yaxes), function (a) { return a; }); - } - - function canvasToAxisCoords(pos) { - // return an object with x/y corresponding to all used axes - var res = {}, i, axis; - for (i = 0; i < xaxes.length; ++i) { - axis = xaxes[i]; - if (axis && axis.used) - res["x" + axis.n] = axis.c2p(pos.left); - } - - for (i = 0; i < yaxes.length; ++i) { - axis = yaxes[i]; - if (axis && axis.used) - res["y" + axis.n] = axis.c2p(pos.top); - } - - if (res.x1 !== undefined) - res.x = res.x1; - if (res.y1 !== undefined) - res.y = res.y1; - - return res; - } - - function axisToCanvasCoords(pos) { - // get canvas coords from the first pair of x/y found in pos - var res = {}, i, axis, key; - - for (i = 0; i < xaxes.length; ++i) { - axis = xaxes[i]; - if (axis && axis.used) { - key = "x" + axis.n; - if (pos[key] == null && axis.n == 1) - key = "x"; - - if (pos[key] != null) { - res.left = axis.p2c(pos[key]); - break; - } - } - } - - for (i = 0; i < yaxes.length; ++i) { - axis = yaxes[i]; - if (axis && axis.used) { - key = "y" + axis.n; - if (pos[key] == null && axis.n == 1) - key = "y"; - - if (pos[key] != null) { - res.top = axis.p2c(pos[key]); - break; - } - } - } - - return res; - } - - function getOrCreateAxis(axes, number) { - if (!axes[number - 1]) - axes[number - 1] = { - n: number, // save the number for future reference - direction: axes == xaxes ? "x" : "y", - options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis) - }; - - return axes[number - 1]; - } - - function fillInSeriesOptions() { - - var neededColors = series.length, maxIndex = -1, i; - - // Subtract the number of series that already have fixed colors or - // color indexes from the number that we still need to generate. - - for (i = 0; i < series.length; ++i) { - var sc = series[i].color; - if (sc != null) { - neededColors--; - if (typeof sc == "number" && sc > maxIndex) { - maxIndex = sc; - } - } - } - - // If any of the series have fixed color indexes, then we need to - // generate at least as many colors as the highest index. - - if (neededColors <= maxIndex) { - neededColors = maxIndex + 1; - } - - // Generate all the colors, using first the option colors and then - // variations on those colors once they're exhausted. - - var c, colors = [], colorPool = options.colors, - colorPoolSize = colorPool.length, variation = 0; - - for (i = 0; i < neededColors; i++) { - - c = $.color.parse(colorPool[i % colorPoolSize] || "#666"); - - // Each time we exhaust the colors in the pool we adjust - // a scaling factor used to produce more variations on - // those colors. The factor alternates negative/positive - // to produce lighter/darker colors. - - // Reset the variation after every few cycles, or else - // it will end up producing only white or black colors. - - if (i % colorPoolSize == 0 && i) { - if (variation >= 0) { - if (variation < 0.5) { - variation = -variation - 0.2; - } else variation = 0; - } else variation = -variation; - } - - colors[i] = c.scale('rgb', 1 + variation); - } - - // Finalize the series options, filling in their colors - - var colori = 0, s; - for (i = 0; i < series.length; ++i) { - s = series[i]; - - // assign colors - if (s.color == null) { - s.color = colors[colori].toString(); - ++colori; - } - else if (typeof s.color == "number") - s.color = colors[s.color].toString(); - - // turn on lines automatically in case nothing is set - if (s.lines.show == null) { - var v, show = true; - for (v in s) - if (s[v] && s[v].show) { - show = false; - break; - } - if (show) - s.lines.show = true; - } - - // If nothing was provided for lines.zero, default it to match - // lines.fill, since areas by default should extend to zero. - - if (s.lines.zero == null) { - s.lines.zero = !!s.lines.fill; - } - - // setup axes - s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x")); - s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y")); - } - } - - function processData() { - var topSentry = Number.POSITIVE_INFINITY, - bottomSentry = Number.NEGATIVE_INFINITY, - fakeInfinity = Number.MAX_VALUE, - i, j, k, m, length, - s, points, ps, x, y, axis, val, f, p, - data, format; - - function updateAxis(axis, min, max) { - if (min < axis.datamin && min != -fakeInfinity) - axis.datamin = min; - if (max > axis.datamax && max != fakeInfinity) - axis.datamax = max; - } - - $.each(allAxes(), function (_, axis) { - // init axis - axis.datamin = topSentry; - axis.datamax = bottomSentry; - axis.used = false; - }); - - for (i = 0; i < series.length; ++i) { - s = series[i]; - s.datapoints = { points: [] }; - - executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]); - } - - // first pass: clean and copy data - for (i = 0; i < series.length; ++i) { - s = series[i]; - - data = s.data; - format = s.datapoints.format; - - if (!format) { - format = []; - // find out how to copy - format.push({ x: true, number: true, required: true }); - format.push({ y: true, number: true, required: true }); - - if (s.bars.show || (s.lines.show && s.lines.fill)) { - var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); - format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); - if (s.bars.horizontal) { - delete format[format.length - 1].y; - format[format.length - 1].x = true; - } - } - - s.datapoints.format = format; - } - - if (s.datapoints.pointsize != null) - continue; // already filled in - - s.datapoints.pointsize = format.length; - - ps = s.datapoints.pointsize; - points = s.datapoints.points; - - var insertSteps = s.lines.show && s.lines.steps; - s.xaxis.used = s.yaxis.used = true; - - for (j = k = 0; j < data.length; ++j, k += ps) { - p = data[j]; - - var nullify = p == null; - if (!nullify) { - for (m = 0; m < ps; ++m) { - val = p[m]; - f = format[m]; - - if (f) { - if (f.number && val != null) { - val = +val; // convert to number - if (isNaN(val)) - val = null; - else if (val == Infinity) - val = fakeInfinity; - else if (val == -Infinity) - val = -fakeInfinity; - } - - if (val == null) { - if (f.required) - nullify = true; - - if (f.defaultValue != null) - val = f.defaultValue; - } - } - - points[k + m] = val; - } - } - - if (nullify) { - for (m = 0; m < ps; ++m) { - val = points[k + m]; - if (val != null) { - f = format[m]; - // extract min/max info - if (f.autoscale !== false) { - if (f.x) { - updateAxis(s.xaxis, val, val); - } - if (f.y) { - updateAxis(s.yaxis, val, val); - } - } - } - points[k + m] = null; - } - } - else { - // a little bit of line specific stuff that - // perhaps shouldn't be here, but lacking - // better means... - if (insertSteps && k > 0 - && points[k - ps] != null - && points[k - ps] != points[k] - && points[k - ps + 1] != points[k + 1]) { - // copy the point to make room for a middle point - for (m = 0; m < ps; ++m) - points[k + ps + m] = points[k + m]; - - // middle point has same y - points[k + 1] = points[k - ps + 1]; - - // we've added a point, better reflect that - k += ps; - } - } - } - } - - // give the hooks a chance to run - for (i = 0; i < series.length; ++i) { - s = series[i]; - - executeHooks(hooks.processDatapoints, [ s, s.datapoints]); - } - - // second pass: find datamax/datamin for auto-scaling - for (i = 0; i < series.length; ++i) { - s = series[i]; - points = s.datapoints.points; - ps = s.datapoints.pointsize; - format = s.datapoints.format; - - var xmin = topSentry, ymin = topSentry, - xmax = bottomSentry, ymax = bottomSentry; - - for (j = 0; j < points.length; j += ps) { - if (points[j] == null) - continue; - - for (m = 0; m < ps; ++m) { - val = points[j + m]; - f = format[m]; - if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity) - continue; - - if (f.x) { - if (val < xmin) - xmin = val; - if (val > xmax) - xmax = val; - } - if (f.y) { - if (val < ymin) - ymin = val; - if (val > ymax) - ymax = val; - } - } - } - - if (s.bars.show) { - // make sure we got room for the bar on the dancing floor - var delta; - - switch (s.bars.align) { - case "left": - delta = 0; - break; - case "right": - delta = -s.bars.barWidth; - break; - default: - delta = -s.bars.barWidth / 2; - } - - if (s.bars.horizontal) { - ymin += delta; - ymax += delta + s.bars.barWidth; - } - else { - xmin += delta; - xmax += delta + s.bars.barWidth; - } - } - - updateAxis(s.xaxis, xmin, xmax); - updateAxis(s.yaxis, ymin, ymax); - } - - $.each(allAxes(), function (_, axis) { - if (axis.datamin == topSentry) - axis.datamin = null; - if (axis.datamax == bottomSentry) - axis.datamax = null; - }); - } - - function setupCanvases() { - - // Make sure the placeholder is clear of everything except canvases - // from a previous plot in this container that we'll try to re-use. - - placeholder.css("padding", 0) // padding messes up the positioning - .children().filter(function(){ - return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); - }).remove(); - - if (placeholder.css("position") == 'static') - placeholder.css("position", "relative"); // for positioning labels and overlay - - surface = new Canvas("flot-base", placeholder); - overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features - - ctx = surface.context; - octx = overlay.context; - - // define which element we're listening for events on - eventHolder = $(overlay.element).unbind(); - - // If we're re-using a plot object, shut down the old one - - var existing = placeholder.data("plot"); - - if (existing) { - existing.shutdown(); - overlay.clear(); - } - - // save in case we get replotted - placeholder.data("plot", plot); - } - - function bindEvents() { - // bind events - if (options.grid.hoverable) { - eventHolder.mousemove(onMouseMove); - - // Use bind, rather than .mouseleave, because we officially - // still support jQuery 1.2.6, which doesn't define a shortcut - // for mouseenter or mouseleave. This was a bug/oversight that - // was fixed somewhere around 1.3.x. We can return to using - // .mouseleave when we drop support for 1.2.6. - - eventHolder.bind("mouseleave", onMouseLeave); - } - - if (options.grid.clickable) - eventHolder.click(onClick); - - executeHooks(hooks.bindEvents, [eventHolder]); - } - - function shutdown() { - if (redrawTimeout) - clearTimeout(redrawTimeout); - - eventHolder.unbind("mousemove", onMouseMove); - eventHolder.unbind("mouseleave", onMouseLeave); - eventHolder.unbind("click", onClick); - - executeHooks(hooks.shutdown, [eventHolder]); - } - - function setTransformationHelpers(axis) { - // set helper functions on the axis, assumes plot area - // has been computed already - - function identity(x) { return x; } - - var s, m, t = axis.options.transform || identity, - it = axis.options.inverseTransform; - - // precompute how much the axis is scaling a point - // in canvas space - if (axis.direction == "x") { - s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); - m = Math.min(t(axis.max), t(axis.min)); - } - else { - s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); - s = -s; - m = Math.max(t(axis.max), t(axis.min)); - } - - // data point to canvas coordinate - if (t == identity) // slight optimization - axis.p2c = function (p) { return (p - m) * s; }; - else - axis.p2c = function (p) { return (t(p) - m) * s; }; - // canvas coordinate to data point - if (!it) - axis.c2p = function (c) { return m + c / s; }; - else - axis.c2p = function (c) { return it(m + c / s); }; - } - - function measureTickLabels(axis) { - - var opts = axis.options, - ticks = axis.ticks || [], - labelWidth = opts.labelWidth || 0, - labelHeight = opts.labelHeight || 0, - maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null), - legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", - layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, - font = opts.font || "flot-tick-label tickLabel"; - - for (var i = 0; i < ticks.length; ++i) { - - var t = ticks[i]; - - if (!t.label) - continue; - - var info = surface.getTextInfo(layer, t.label, font, null, maxWidth); - - labelWidth = Math.max(labelWidth, info.width); - labelHeight = Math.max(labelHeight, info.height); - } - - axis.labelWidth = opts.labelWidth || labelWidth; - axis.labelHeight = opts.labelHeight || labelHeight; - } - - function allocateAxisBoxFirstPhase(axis) { - // find the bounding box of the axis by looking at label - // widths/heights and ticks, make room by diminishing the - // plotOffset; this first phase only looks at one - // dimension per axis, the other dimension depends on the - // other axes so will have to wait - - var lw = axis.labelWidth, - lh = axis.labelHeight, - pos = axis.options.position, - isXAxis = axis.direction === "x", - tickLength = axis.options.tickLength, - axisMargin = options.grid.axisMargin, - padding = options.grid.labelMargin, - innermost = true, - outermost = true, - first = true, - found = false; - - // Determine the axis's position in its direction and on its side - - $.each(isXAxis ? xaxes : yaxes, function(i, a) { - if (a && (a.show || a.reserveSpace)) { - if (a === axis) { - found = true; - } else if (a.options.position === pos) { - if (found) { - outermost = false; - } else { - innermost = false; - } - } - if (!found) { - first = false; - } - } - }); - - // The outermost axis on each side has no margin - - if (outermost) { - axisMargin = 0; - } - - // The ticks for the first axis in each direction stretch across - - if (tickLength == null) { - tickLength = first ? "full" : 5; - } - - if (!isNaN(+tickLength)) - padding += +tickLength; - - if (isXAxis) { - lh += padding; - - if (pos == "bottom") { - plotOffset.bottom += lh + axisMargin; - axis.box = { top: surface.height - plotOffset.bottom, height: lh }; - } - else { - axis.box = { top: plotOffset.top + axisMargin, height: lh }; - plotOffset.top += lh + axisMargin; - } - } - else { - lw += padding; - - if (pos == "left") { - axis.box = { left: plotOffset.left + axisMargin, width: lw }; - plotOffset.left += lw + axisMargin; - } - else { - plotOffset.right += lw + axisMargin; - axis.box = { left: surface.width - plotOffset.right, width: lw }; - } - } - - // save for future reference - axis.position = pos; - axis.tickLength = tickLength; - axis.box.padding = padding; - axis.innermost = innermost; - } - - function allocateAxisBoxSecondPhase(axis) { - // now that all axis boxes have been placed in one - // dimension, we can set the remaining dimension coordinates - if (axis.direction == "x") { - axis.box.left = plotOffset.left - axis.labelWidth / 2; - axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; - } - else { - axis.box.top = plotOffset.top - axis.labelHeight / 2; - axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; - } - } - - function adjustLayoutForThingsStickingOut() { - // possibly adjust plot offset to ensure everything stays - // inside the canvas and isn't clipped off - - var minMargin = options.grid.minBorderMargin, - axis, i; - - // check stuff from the plot (FIXME: this should just read - // a value from the series, otherwise it's impossible to - // customize) - if (minMargin == null) { - minMargin = 0; - for (i = 0; i < series.length; ++i) - minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2)); - } - - var margins = { - left: minMargin, - right: minMargin, - top: minMargin, - bottom: minMargin - }; - - // check axis labels, note we don't check the actual - // labels but instead use the overall width/height to not - // jump as much around with replots - $.each(allAxes(), function (_, axis) { - if (axis.reserveSpace && axis.ticks && axis.ticks.length) { - if (axis.direction === "x") { - margins.left = Math.max(margins.left, axis.labelWidth / 2); - margins.right = Math.max(margins.right, axis.labelWidth / 2); - } else { - margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); - margins.top = Math.max(margins.top, axis.labelHeight / 2); - } - } - }); - - plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); - plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); - plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); - plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); - } - - function setupGrid() { - var i, axes = allAxes(), showGrid = options.grid.show; - - // Initialize the plot's offset from the edge of the canvas - - for (var a in plotOffset) { - var margin = options.grid.margin || 0; - plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0; - } - - executeHooks(hooks.processOffset, [plotOffset]); - - // If the grid is visible, add its border width to the offset - - for (var a in plotOffset) { - if(typeof(options.grid.borderWidth) == "object") { - plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; - } - else { - plotOffset[a] += showGrid ? options.grid.borderWidth : 0; - } - } - - $.each(axes, function (_, axis) { - var axisOpts = axis.options; - axis.show = axisOpts.show == null ? axis.used : axisOpts.show; - axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; - setRange(axis); - }); - - if (showGrid) { - - var allocatedAxes = $.grep(axes, function (axis) { - return axis.show || axis.reserveSpace; - }); - - $.each(allocatedAxes, function (_, axis) { - // make the ticks - setupTickGeneration(axis); - setTicks(axis); - snapRangeToTicks(axis, axis.ticks); - // find labelWidth/Height for axis - measureTickLabels(axis); - }); - - // with all dimensions calculated, we can compute the - // axis bounding boxes, start from the outside - // (reverse order) - for (i = allocatedAxes.length - 1; i >= 0; --i) - allocateAxisBoxFirstPhase(allocatedAxes[i]); - - // make sure we've got enough space for things that - // might stick out - adjustLayoutForThingsStickingOut(); - - $.each(allocatedAxes, function (_, axis) { - allocateAxisBoxSecondPhase(axis); - }); - } - - plotWidth = surface.width - plotOffset.left - plotOffset.right; - plotHeight = surface.height - plotOffset.bottom - plotOffset.top; - - // now we got the proper plot dimensions, we can compute the scaling - $.each(axes, function (_, axis) { - setTransformationHelpers(axis); - }); - - if (showGrid) { - drawAxisLabels(); - } - - insertLegend(); - } - - function setRange(axis) { - var opts = axis.options, - min = +(opts.min != null ? opts.min : axis.datamin), - max = +(opts.max != null ? opts.max : axis.datamax), - delta = max - min; - - if (delta == 0.0) { - // degenerate case - var widen = max == 0 ? 1 : 0.01; - - if (opts.min == null) - min -= widen; - // always widen max if we couldn't widen min to ensure we - // don't fall into min == max which doesn't work - if (opts.max == null || opts.min != null) - max += widen; - } - else { - // consider autoscaling - var margin = opts.autoscaleMargin; - if (margin != null) { - if (opts.min == null) { - min -= delta * margin; - // make sure we don't go below zero if all values - // are positive - if (min < 0 && axis.datamin != null && axis.datamin >= 0) - min = 0; - } - if (opts.max == null) { - max += delta * margin; - if (max > 0 && axis.datamax != null && axis.datamax <= 0) - max = 0; - } - } - } - axis.min = min; - axis.max = max; - } - - function setupTickGeneration(axis) { - var opts = axis.options; - - // estimate number of ticks - var noTicks; - if (typeof opts.ticks == "number" && opts.ticks > 0) - noTicks = opts.ticks; - else - // heuristic based on the model a*sqrt(x) fitted to - // some data points that seemed reasonable - noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height); - - var delta = (axis.max - axis.min) / noTicks, - dec = -Math.floor(Math.log(delta) / Math.LN10), - maxDec = opts.tickDecimals; - - if (maxDec != null && dec > maxDec) { - dec = maxDec; - } - - var magn = Math.pow(10, -dec), - norm = delta / magn, // norm is between 1.0 and 10.0 - size; - - if (norm < 1.5) { - size = 1; - } else if (norm < 3) { - size = 2; - // special case for 2.5, requires an extra decimal - if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) { - size = 2.5; - ++dec; - } - } else if (norm < 7.5) { - size = 5; - } else { - size = 10; - } - - size *= magn; - - if (opts.minTickSize != null && size < opts.minTickSize) { - size = opts.minTickSize; - } - - axis.delta = delta; - axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); - axis.tickSize = opts.tickSize || size; - - // Time mode was moved to a plug-in in 0.8, and since so many people use it - // we'll add an especially friendly reminder to make sure they included it. - - if (opts.mode == "time" && !axis.tickGenerator) { - throw new Error("Time mode requires the flot.time plugin."); - } - - // Flot supports base-10 axes; any other mode else is handled by a plug-in, - // like flot.time.js. - - if (!axis.tickGenerator) { - - axis.tickGenerator = function (axis) { - - var ticks = [], - start = floorInBase(axis.min, axis.tickSize), - i = 0, - v = Number.NaN, - prev; - - do { - prev = v; - v = start + i * axis.tickSize; - ticks.push(v); - ++i; - } while (v < axis.max && v != prev); - return ticks; - }; - - axis.tickFormatter = function (value, axis) { - - var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; - var formatted = "" + Math.round(value * factor) / factor; - - // If tickDecimals was specified, ensure that we have exactly that - // much precision; otherwise default to the value's own precision. - - if (axis.tickDecimals != null) { - var decimal = formatted.indexOf("."); - var precision = decimal == -1 ? 0 : formatted.length - decimal - 1; - if (precision < axis.tickDecimals) { - return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); - } - } - - return formatted; - }; - } - - if ($.isFunction(opts.tickFormatter)) - axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); }; - - if (opts.alignTicksWithAxis != null) { - var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; - if (otherAxis && otherAxis.used && otherAxis != axis) { - // consider snapping min/max to outermost nice ticks - var niceTicks = axis.tickGenerator(axis); - if (niceTicks.length > 0) { - if (opts.min == null) - axis.min = Math.min(axis.min, niceTicks[0]); - if (opts.max == null && niceTicks.length > 1) - axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); - } - - axis.tickGenerator = function (axis) { - // copy ticks, scaled to this axis - var ticks = [], v, i; - for (i = 0; i < otherAxis.ticks.length; ++i) { - v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min); - v = axis.min + v * (axis.max - axis.min); - ticks.push(v); - } - return ticks; - }; - - // we might need an extra decimal since forced - // ticks don't necessarily fit naturally - if (!axis.mode && opts.tickDecimals == null) { - var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1), - ts = axis.tickGenerator(axis); - - // only proceed if the tick interval rounded - // with an extra decimal doesn't give us a - // zero at end - if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) - axis.tickDecimals = extraDec; - } - } - } - } - - function setTicks(axis) { - var oticks = axis.options.ticks, ticks = []; - if (oticks == null || (typeof oticks == "number" && oticks > 0)) - ticks = axis.tickGenerator(axis); - else if (oticks) { - if ($.isFunction(oticks)) - // generate the ticks - ticks = oticks(axis); - else - ticks = oticks; - } - - // clean up/labelify the supplied ticks, copy them over - var i, v; - axis.ticks = []; - for (i = 0; i < ticks.length; ++i) { - var label = null; - var t = ticks[i]; - if (typeof t == "object") { - v = +t[0]; - if (t.length > 1) - label = t[1]; - } - else - v = +t; - if (label == null) - label = axis.tickFormatter(v, axis); - if (!isNaN(v)) - axis.ticks.push({ v: v, label: label }); - } - } - - function snapRangeToTicks(axis, ticks) { - if (axis.options.autoscaleMargin && ticks.length > 0) { - // snap to ticks - if (axis.options.min == null) - axis.min = Math.min(axis.min, ticks[0].v); - if (axis.options.max == null && ticks.length > 1) - axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); - } - } - - function draw() { - - surface.clear(); - - executeHooks(hooks.drawBackground, [ctx]); - - var grid = options.grid; - - // draw background, if any - if (grid.show && grid.backgroundColor) - drawBackground(); - - if (grid.show && !grid.aboveData) { - drawGrid(); - } - - for (var i = 0; i < series.length; ++i) { - executeHooks(hooks.drawSeries, [ctx, series[i]]); - drawSeries(series[i]); - } - - executeHooks(hooks.draw, [ctx]); - - if (grid.show && grid.aboveData) { - drawGrid(); - } - - surface.render(); - - // A draw implies that either the axes or data have changed, so we - // should probably update the overlay highlights as well. - - triggerRedrawOverlay(); - } - - function extractRange(ranges, coord) { - var axis, from, to, key, axes = allAxes(); - - for (var i = 0; i < axes.length; ++i) { - axis = axes[i]; - if (axis.direction == coord) { - key = coord + axis.n + "axis"; - if (!ranges[key] && axis.n == 1) - key = coord + "axis"; // support x1axis as xaxis - if (ranges[key]) { - from = ranges[key].from; - to = ranges[key].to; - break; - } - } - } - - // backwards-compat stuff - to be removed in future - if (!ranges[key]) { - axis = coord == "x" ? xaxes[0] : yaxes[0]; - from = ranges[coord + "1"]; - to = ranges[coord + "2"]; - } - - // auto-reverse as an added bonus - if (from != null && to != null && from > to) { - var tmp = from; - from = to; - to = tmp; - } - - return { from: from, to: to, axis: axis }; - } - - function drawBackground() { - ctx.save(); - ctx.translate(plotOffset.left, plotOffset.top); - - ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)"); - ctx.fillRect(0, 0, plotWidth, plotHeight); - ctx.restore(); - } - - function drawGrid() { - var i, axes, bw, bc; - - ctx.save(); - ctx.translate(plotOffset.left, plotOffset.top); - - // draw markings - var markings = options.grid.markings; - if (markings) { - if ($.isFunction(markings)) { - axes = plot.getAxes(); - // xmin etc. is backwards compatibility, to be - // removed in the future - axes.xmin = axes.xaxis.min; - axes.xmax = axes.xaxis.max; - axes.ymin = axes.yaxis.min; - axes.ymax = axes.yaxis.max; - - markings = markings(axes); - } - - for (i = 0; i < markings.length; ++i) { - var m = markings[i], - xrange = extractRange(m, "x"), - yrange = extractRange(m, "y"); - - // fill in missing - if (xrange.from == null) - xrange.from = xrange.axis.min; - if (xrange.to == null) - xrange.to = xrange.axis.max; - if (yrange.from == null) - yrange.from = yrange.axis.min; - if (yrange.to == null) - yrange.to = yrange.axis.max; - - // clip - if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || - yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) - continue; - - xrange.from = Math.max(xrange.from, xrange.axis.min); - xrange.to = Math.min(xrange.to, xrange.axis.max); - yrange.from = Math.max(yrange.from, yrange.axis.min); - yrange.to = Math.min(yrange.to, yrange.axis.max); - - var xequal = xrange.from === xrange.to, - yequal = yrange.from === yrange.to; - - if (xequal && yequal) { - continue; - } - - // then draw - xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); - xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); - yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); - yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); - - if (xequal || yequal) { - var lineWidth = m.lineWidth || options.grid.markingsLineWidth, - subPixel = lineWidth % 2 ? 0.5 : 0; - ctx.beginPath(); - ctx.strokeStyle = m.color || options.grid.markingsColor; - ctx.lineWidth = lineWidth; - if (xequal) { - ctx.moveTo(xrange.to + subPixel, yrange.from); - ctx.lineTo(xrange.to + subPixel, yrange.to); - } else { - ctx.moveTo(xrange.from, yrange.to + subPixel); - ctx.lineTo(xrange.to, yrange.to + subPixel); - } - ctx.stroke(); - } else { - ctx.fillStyle = m.color || options.grid.markingsColor; - ctx.fillRect(xrange.from, yrange.to, - xrange.to - xrange.from, - yrange.from - yrange.to); - } - } - } - - // draw the ticks - axes = allAxes(); - bw = options.grid.borderWidth; - - for (var j = 0; j < axes.length; ++j) { - var axis = axes[j], box = axis.box, - t = axis.tickLength, x, y, xoff, yoff; - if (!axis.show || axis.ticks.length == 0) - continue; - - ctx.lineWidth = 1; - - // find the edges - if (axis.direction == "x") { - x = 0; - if (t == "full") - y = (axis.position == "top" ? 0 : plotHeight); - else - y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0); - } - else { - y = 0; - if (t == "full") - x = (axis.position == "left" ? 0 : plotWidth); - else - x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0); - } - - // draw tick bar - if (!axis.innermost) { - ctx.strokeStyle = axis.options.color; - ctx.beginPath(); - xoff = yoff = 0; - if (axis.direction == "x") - xoff = plotWidth + 1; - else - yoff = plotHeight + 1; - - if (ctx.lineWidth == 1) { - if (axis.direction == "x") { - y = Math.floor(y) + 0.5; - } else { - x = Math.floor(x) + 0.5; - } - } - - ctx.moveTo(x, y); - ctx.lineTo(x + xoff, y + yoff); - ctx.stroke(); - } - - // draw ticks - - ctx.strokeStyle = axis.options.tickColor; - - ctx.beginPath(); - for (i = 0; i < axis.ticks.length; ++i) { - var v = axis.ticks[i].v; - - xoff = yoff = 0; - - if (isNaN(v) || v < axis.min || v > axis.max - // skip those lying on the axes if we got a border - || (t == "full" - && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0) - && (v == axis.min || v == axis.max))) - continue; - - if (axis.direction == "x") { - x = axis.p2c(v); - yoff = t == "full" ? -plotHeight : t; - - if (axis.position == "top") - yoff = -yoff; - } - else { - y = axis.p2c(v); - xoff = t == "full" ? -plotWidth : t; - - if (axis.position == "left") - xoff = -xoff; - } - - if (ctx.lineWidth == 1) { - if (axis.direction == "x") - x = Math.floor(x) + 0.5; - else - y = Math.floor(y) + 0.5; - } - - ctx.moveTo(x, y); - ctx.lineTo(x + xoff, y + yoff); - } - - ctx.stroke(); - } - - - // draw border - if (bw) { - // If either borderWidth or borderColor is an object, then draw the border - // line by line instead of as one rectangle - bc = options.grid.borderColor; - if(typeof bw == "object" || typeof bc == "object") { - if (typeof bw !== "object") { - bw = {top: bw, right: bw, bottom: bw, left: bw}; - } - if (typeof bc !== "object") { - bc = {top: bc, right: bc, bottom: bc, left: bc}; - } - - if (bw.top > 0) { - ctx.strokeStyle = bc.top; - ctx.lineWidth = bw.top; - ctx.beginPath(); - ctx.moveTo(0 - bw.left, 0 - bw.top/2); - ctx.lineTo(plotWidth, 0 - bw.top/2); - ctx.stroke(); - } - - if (bw.right > 0) { - ctx.strokeStyle = bc.right; - ctx.lineWidth = bw.right; - ctx.beginPath(); - ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); - ctx.lineTo(plotWidth + bw.right / 2, plotHeight); - ctx.stroke(); - } - - if (bw.bottom > 0) { - ctx.strokeStyle = bc.bottom; - ctx.lineWidth = bw.bottom; - ctx.beginPath(); - ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); - ctx.lineTo(0, plotHeight + bw.bottom / 2); - ctx.stroke(); - } - - if (bw.left > 0) { - ctx.strokeStyle = bc.left; - ctx.lineWidth = bw.left; - ctx.beginPath(); - ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom); - ctx.lineTo(0- bw.left/2, 0); - ctx.stroke(); - } - } - else { - ctx.lineWidth = bw; - ctx.strokeStyle = options.grid.borderColor; - ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw); - } - } - - ctx.restore(); - } - - function drawAxisLabels() { - - $.each(allAxes(), function (_, axis) { - var box = axis.box, - legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", - layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, - font = axis.options.font || "flot-tick-label tickLabel", - tick, x, y, halign, valign; - - // Remove text before checking for axis.show and ticks.length; - // otherwise plugins, like flot-tickrotor, that draw their own - // tick labels will end up with both theirs and the defaults. - - surface.removeText(layer); - - if (!axis.show || axis.ticks.length == 0) - return; - - for (var i = 0; i < axis.ticks.length; ++i) { - - tick = axis.ticks[i]; - if (!tick.label || tick.v < axis.min || tick.v > axis.max) - continue; - - if (axis.direction == "x") { - halign = "center"; - x = plotOffset.left + axis.p2c(tick.v); - if (axis.position == "bottom") { - y = box.top + box.padding; - } else { - y = box.top + box.height - box.padding; - valign = "bottom"; - } - } else { - valign = "middle"; - y = plotOffset.top + axis.p2c(tick.v); - if (axis.position == "left") { - x = box.left + box.width - box.padding; - halign = "right"; - } else { - x = box.left + box.padding; - } - } - - surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); - } - }); - } - - function drawSeries(series) { - if (series.lines.show) - drawSeriesLines(series); - if (series.bars.show) - drawSeriesBars(series); - if (series.points.show) - drawSeriesPoints(series); - } - - function drawSeriesLines(series) { - function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { - var points = datapoints.points, - ps = datapoints.pointsize, - prevx = null, prevy = null; - - ctx.beginPath(); - for (var i = ps; i < points.length; i += ps) { - var x1 = points[i - ps], y1 = points[i - ps + 1], - x2 = points[i], y2 = points[i + 1]; - - if (x1 == null || x2 == null) - continue; - - // clip with ymin - if (y1 <= y2 && y1 < axisy.min) { - if (y2 < axisy.min) - continue; // line segment is outside - // compute new intersection point - x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = axisy.min; - } - else if (y2 <= y1 && y2 < axisy.min) { - if (y1 < axisy.min) - continue; - x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = axisy.min; - } - - // clip with ymax - if (y1 >= y2 && y1 > axisy.max) { - if (y2 > axisy.max) - continue; - x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = axisy.max; - } - else if (y2 >= y1 && y2 > axisy.max) { - if (y1 > axisy.max) - continue; - x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = axisy.max; - } - - // clip with xmin - if (x1 <= x2 && x1 < axisx.min) { - if (x2 < axisx.min) - continue; - y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = axisx.min; - } - else if (x2 <= x1 && x2 < axisx.min) { - if (x1 < axisx.min) - continue; - y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = axisx.min; - } - - // clip with xmax - if (x1 >= x2 && x1 > axisx.max) { - if (x2 > axisx.max) - continue; - y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = axisx.max; - } - else if (x2 >= x1 && x2 > axisx.max) { - if (x1 > axisx.max) - continue; - y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = axisx.max; - } - - if (x1 != prevx || y1 != prevy) - ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); - - prevx = x2; - prevy = y2; - ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset); - } - ctx.stroke(); - } - - function plotLineArea(datapoints, axisx, axisy) { - var points = datapoints.points, - ps = datapoints.pointsize, - bottom = Math.min(Math.max(0, axisy.min), axisy.max), - i = 0, top, areaOpen = false, - ypos = 1, segmentStart = 0, segmentEnd = 0; - - // we process each segment in two turns, first forward - // direction to sketch out top, then once we hit the - // end we go backwards to sketch the bottom - while (true) { - if (ps > 0 && i > points.length + ps) - break; - - i += ps; // ps is negative if going backwards - - var x1 = points[i - ps], - y1 = points[i - ps + ypos], - x2 = points[i], y2 = points[i + ypos]; - - if (areaOpen) { - if (ps > 0 && x1 != null && x2 == null) { - // at turning point - segmentEnd = i; - ps = -ps; - ypos = 2; - continue; - } - - if (ps < 0 && i == segmentStart + ps) { - // done with the reverse sweep - ctx.fill(); - areaOpen = false; - ps = -ps; - ypos = 1; - i = segmentStart = segmentEnd + ps; - continue; - } - } - - if (x1 == null || x2 == null) - continue; - - // clip x values - - // clip with xmin - if (x1 <= x2 && x1 < axisx.min) { - if (x2 < axisx.min) - continue; - y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = axisx.min; - } - else if (x2 <= x1 && x2 < axisx.min) { - if (x1 < axisx.min) - continue; - y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = axisx.min; - } - - // clip with xmax - if (x1 >= x2 && x1 > axisx.max) { - if (x2 > axisx.max) - continue; - y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = axisx.max; - } - else if (x2 >= x1 && x2 > axisx.max) { - if (x1 > axisx.max) - continue; - y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = axisx.max; - } - - if (!areaOpen) { - // open area - ctx.beginPath(); - ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); - areaOpen = true; - } - - // now first check the case where both is outside - if (y1 >= axisy.max && y2 >= axisy.max) { - ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); - ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); - continue; - } - else if (y1 <= axisy.min && y2 <= axisy.min) { - ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); - ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); - continue; - } - - // else it's a bit more complicated, there might - // be a flat maxed out rectangle first, then a - // triangular cutout or reverse; to find these - // keep track of the current x values - var x1old = x1, x2old = x2; - - // clip the y values, without shortcutting, we - // go through all cases in turn - - // clip with ymin - if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { - x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = axisy.min; - } - else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { - x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = axisy.min; - } - - // clip with ymax - if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { - x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = axisy.max; - } - else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { - x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = axisy.max; - } - - // if the x value was changed we got a rectangle - // to fill - if (x1 != x1old) { - ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); - // it goes to (x1, y1), but we fill that below - } - - // fill triangular section, this sometimes result - // in redundant points if (x1, y1) hasn't changed - // from previous line to, but we just ignore that - ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); - ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); - - // fill the other rectangle if it's there - if (x2 != x2old) { - ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); - ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); - } - } - } - - ctx.save(); - ctx.translate(plotOffset.left, plotOffset.top); - ctx.lineJoin = "round"; - - var lw = series.lines.lineWidth, - sw = series.shadowSize; - // FIXME: consider another form of shadow when filling is turned on - if (lw > 0 && sw > 0) { - // draw shadow as a thick and thin line with transparency - ctx.lineWidth = sw; - ctx.strokeStyle = "rgba(0,0,0,0.1)"; - // position shadow at angle from the mid of line - var angle = Math.PI/18; - plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis); - ctx.lineWidth = sw/2; - plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis); - } - - ctx.lineWidth = lw; - ctx.strokeStyle = series.color; - var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); - if (fillStyle) { - ctx.fillStyle = fillStyle; - plotLineArea(series.datapoints, series.xaxis, series.yaxis); - } - - if (lw > 0) - plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); - ctx.restore(); - } - - function drawSeriesPoints(series) { - function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { - var points = datapoints.points, ps = datapoints.pointsize; - - for (var i = 0; i < points.length; i += ps) { - var x = points[i], y = points[i + 1]; - if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) - continue; - - ctx.beginPath(); - x = axisx.p2c(x); - y = axisy.p2c(y) + offset; - if (symbol == "circle") - ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); - else - symbol(ctx, x, y, radius, shadow); - ctx.closePath(); - - if (fillStyle) { - ctx.fillStyle = fillStyle; - ctx.fill(); - } - ctx.stroke(); - } - } - - ctx.save(); - ctx.translate(plotOffset.left, plotOffset.top); - - var lw = series.points.lineWidth, - sw = series.shadowSize, - radius = series.points.radius, - symbol = series.points.symbol; - - // If the user sets the line width to 0, we change it to a very - // small value. A line width of 0 seems to force the default of 1. - // Doing the conditional here allows the shadow setting to still be - // optional even with a lineWidth of 0. - - if( lw == 0 ) - lw = 0.0001; - - if (lw > 0 && sw > 0) { - // draw shadow in two steps - var w = sw / 2; - ctx.lineWidth = w; - ctx.strokeStyle = "rgba(0,0,0,0.1)"; - plotPoints(series.datapoints, radius, null, w + w/2, true, - series.xaxis, series.yaxis, symbol); - - ctx.strokeStyle = "rgba(0,0,0,0.2)"; - plotPoints(series.datapoints, radius, null, w/2, true, - series.xaxis, series.yaxis, symbol); - } - - ctx.lineWidth = lw; - ctx.strokeStyle = series.color; - plotPoints(series.datapoints, radius, - getFillStyle(series.points, series.color), 0, false, - series.xaxis, series.yaxis, symbol); - ctx.restore(); - } - - function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { - var left, right, bottom, top, - drawLeft, drawRight, drawTop, drawBottom, - tmp; - - // in horizontal mode, we start the bar from the left - // instead of from the bottom so it appears to be - // horizontal rather than vertical - if (horizontal) { - drawBottom = drawRight = drawTop = true; - drawLeft = false; - left = b; - right = x; - top = y + barLeft; - bottom = y + barRight; - - // account for negative bars - if (right < left) { - tmp = right; - right = left; - left = tmp; - drawLeft = true; - drawRight = false; - } - } - else { - drawLeft = drawRight = drawTop = true; - drawBottom = false; - left = x + barLeft; - right = x + barRight; - bottom = b; - top = y; - - // account for negative bars - if (top < bottom) { - tmp = top; - top = bottom; - bottom = tmp; - drawBottom = true; - drawTop = false; - } - } - - // clip - if (right < axisx.min || left > axisx.max || - top < axisy.min || bottom > axisy.max) - return; - - if (left < axisx.min) { - left = axisx.min; - drawLeft = false; - } - - if (right > axisx.max) { - right = axisx.max; - drawRight = false; - } - - if (bottom < axisy.min) { - bottom = axisy.min; - drawBottom = false; - } - - if (top > axisy.max) { - top = axisy.max; - drawTop = false; - } - - left = axisx.p2c(left); - bottom = axisy.p2c(bottom); - right = axisx.p2c(right); - top = axisy.p2c(top); - - // fill the bar - if (fillStyleCallback) { - c.fillStyle = fillStyleCallback(bottom, top); - c.fillRect(left, top, right - left, bottom - top) - } - - // draw outline - if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { - c.beginPath(); - - // FIXME: inline moveTo is buggy with excanvas - c.moveTo(left, bottom); - if (drawLeft) - c.lineTo(left, top); - else - c.moveTo(left, top); - if (drawTop) - c.lineTo(right, top); - else - c.moveTo(right, top); - if (drawRight) - c.lineTo(right, bottom); - else - c.moveTo(right, bottom); - if (drawBottom) - c.lineTo(left, bottom); - else - c.moveTo(left, bottom); - c.stroke(); - } - } - - function drawSeriesBars(series) { - function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { - var points = datapoints.points, ps = datapoints.pointsize; - - for (var i = 0; i < points.length; i += ps) { - if (points[i] == null) - continue; - drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); - } - } - - ctx.save(); - ctx.translate(plotOffset.left, plotOffset.top); - - // FIXME: figure out a way to add shadows (for instance along the right edge) - ctx.lineWidth = series.bars.lineWidth; - ctx.strokeStyle = series.color; - - var barLeft; - - switch (series.bars.align) { - case "left": - barLeft = 0; - break; - case "right": - barLeft = -series.bars.barWidth; - break; - default: - barLeft = -series.bars.barWidth / 2; - } - - var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null; - plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); - ctx.restore(); - } - - function getFillStyle(filloptions, seriesColor, bottom, top) { - var fill = filloptions.fill; - if (!fill) - return null; - - if (filloptions.fillColor) - return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); - - var c = $.color.parse(seriesColor); - c.a = typeof fill == "number" ? fill : 0.4; - c.normalize(); - return c.toString(); - } - - function insertLegend() { - - if (options.legend.container != null) { - $(options.legend.container).html(""); - } else { - placeholder.find(".legend").remove(); - } - - if (!options.legend.show) { - return; - } - - var fragments = [], entries = [], rowStarted = false, - lf = options.legend.labelFormatter, s, label; - - // Build a list of legend entries, with each having a label and a color - - for (var i = 0; i < series.length; ++i) { - s = series[i]; - if (s.label) { - label = lf ? lf(s.label, s) : s.label; - if (label) { - entries.push({ - label: label, - color: s.color - }); - } - } - } - - // Sort the legend using either the default or a custom comparator - - if (options.legend.sorted) { - if ($.isFunction(options.legend.sorted)) { - entries.sort(options.legend.sorted); - } else if (options.legend.sorted == "reverse") { - entries.reverse(); - } else { - var ascending = options.legend.sorted != "descending"; - entries.sort(function(a, b) { - return a.label == b.label ? 0 : ( - (a.label < b.label) != ascending ? 1 : -1 // Logical XOR - ); - }); - } - } - - // Generate markup for the list of entries, in their final order - - for (var i = 0; i < entries.length; ++i) { - - var entry = entries[i]; - - if (i % options.legend.noColumns == 0) { - if (rowStarted) - fragments.push(''); - fragments.push(''); - rowStarted = true; - } - - fragments.push( - '
' + - '' + entry.label + '' - ); - } - - if (rowStarted) - fragments.push(''); - - if (fragments.length == 0) - return; - - var table = '' + fragments.join("") + '
'; - if (options.legend.container != null) - $(options.legend.container).html(table); - else { - var pos = "", - p = options.legend.position, - m = options.legend.margin; - if (m[0] == null) - m = [m, m]; - if (p.charAt(0) == "n") - pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; - else if (p.charAt(0) == "s") - pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; - if (p.charAt(1) == "e") - pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; - else if (p.charAt(1) == "w") - pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; - var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos +';') + '
').appendTo(placeholder); - if (options.legend.backgroundOpacity != 0.0) { - // put in the transparent background - // separately to avoid blended labels and - // label boxes - var c = options.legend.backgroundColor; - if (c == null) { - c = options.grid.backgroundColor; - if (c && typeof c == "string") - c = $.color.parse(c); - else - c = $.color.extract(legend, 'background-color'); - c.a = 1; - c = c.toString(); - } - var div = legend.children(); - $('
').prependTo(legend).css('opacity', options.legend.backgroundOpacity); - } - } - } - - - // interactive features - - var highlights = [], - redrawTimeout = null; - - // returns the data item the mouse is over, or null if none is found - function findNearbyItem(mouseX, mouseY, seriesFilter) { - var maxDistance = options.grid.mouseActiveRadius, - smallestDistance = maxDistance * maxDistance + 1, - item = null, foundPoint = false, i, j, ps; - - for (i = series.length - 1; i >= 0; --i) { - if (!seriesFilter(series[i])) - continue; - - var s = series[i], - axisx = s.xaxis, - axisy = s.yaxis, - points = s.datapoints.points, - mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster - my = axisy.c2p(mouseY), - maxx = maxDistance / axisx.scale, - maxy = maxDistance / axisy.scale; - - ps = s.datapoints.pointsize; - // with inverse transforms, we can't use the maxx/maxy - // optimization, sadly - if (axisx.options.inverseTransform) - maxx = Number.MAX_VALUE; - if (axisy.options.inverseTransform) - maxy = Number.MAX_VALUE; - - if (s.lines.show || s.points.show) { - for (j = 0; j < points.length; j += ps) { - var x = points[j], y = points[j + 1]; - if (x == null) - continue; - - // For points and lines, the cursor must be within a - // certain distance to the data point - if (x - mx > maxx || x - mx < -maxx || - y - my > maxy || y - my < -maxy) - continue; - - // We have to calculate distances in pixels, not in - // data units, because the scales of the axes may be different - var dx = Math.abs(axisx.p2c(x) - mouseX), - dy = Math.abs(axisy.p2c(y) - mouseY), - dist = dx * dx + dy * dy; // we save the sqrt - - // use <= to ensure last point takes precedence - // (last generally means on top of) - if (dist < smallestDistance) { - smallestDistance = dist; - item = [i, j / ps]; - } - } - } - - if (s.bars.show && !item) { // no other point can be nearby - - var barLeft, barRight; - - switch (s.bars.align) { - case "left": - barLeft = 0; - break; - case "right": - barLeft = -s.bars.barWidth; - break; - default: - barLeft = -s.bars.barWidth / 2; - } - - barRight = barLeft + s.bars.barWidth; - - for (j = 0; j < points.length; j += ps) { - var x = points[j], y = points[j + 1], b = points[j + 2]; - if (x == null) - continue; - - // for a bar graph, the cursor must be inside the bar - if (series[i].bars.horizontal ? - (mx <= Math.max(b, x) && mx >= Math.min(b, x) && - my >= y + barLeft && my <= y + barRight) : - (mx >= x + barLeft && mx <= x + barRight && - my >= Math.min(b, y) && my <= Math.max(b, y))) - item = [i, j / ps]; - } - } - } - - if (item) { - i = item[0]; - j = item[1]; - ps = series[i].datapoints.pointsize; - - return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), - dataIndex: j, - series: series[i], - seriesIndex: i }; - } - - return null; - } - - function onMouseMove(e) { - if (options.grid.hoverable) - triggerClickHoverEvent("plothover", e, - function (s) { return s["hoverable"] != false; }); - } - - function onMouseLeave(e) { - if (options.grid.hoverable) - triggerClickHoverEvent("plothover", e, - function (s) { return false; }); - } - - function onClick(e) { - triggerClickHoverEvent("plotclick", e, - function (s) { return s["clickable"] != false; }); - } - - // trigger click or hover event (they send the same parameters - // so we share their code) - function triggerClickHoverEvent(eventname, event, seriesFilter) { - var offset = eventHolder.offset(), - canvasX = event.pageX - offset.left - plotOffset.left, - canvasY = event.pageY - offset.top - plotOffset.top, - pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); - - pos.pageX = event.pageX; - pos.pageY = event.pageY; - - var item = findNearbyItem(canvasX, canvasY, seriesFilter); - - if (item) { - // fill in mouse pos for any listeners out there - item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); - item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10); - } - - if (options.grid.autoHighlight) { - // clear auto-highlights - for (var i = 0; i < highlights.length; ++i) { - var h = highlights[i]; - if (h.auto == eventname && - !(item && h.series == item.series && - h.point[0] == item.datapoint[0] && - h.point[1] == item.datapoint[1])) - unhighlight(h.series, h.point); - } - - if (item) - highlight(item.series, item.datapoint, eventname); - } - - placeholder.trigger(eventname, [ pos, item ]); - } - - function triggerRedrawOverlay() { - var t = options.interaction.redrawOverlayInterval; - if (t == -1) { // skip event queue - drawOverlay(); - return; - } - - if (!redrawTimeout) - redrawTimeout = setTimeout(drawOverlay, t); - } - - function drawOverlay() { - redrawTimeout = null; - - // draw highlights - octx.save(); - overlay.clear(); - octx.translate(plotOffset.left, plotOffset.top); - - var i, hi; - for (i = 0; i < highlights.length; ++i) { - hi = highlights[i]; - - if (hi.series.bars.show) - drawBarHighlight(hi.series, hi.point); - else - drawPointHighlight(hi.series, hi.point); - } - octx.restore(); - - executeHooks(hooks.drawOverlay, [octx]); - } - - function highlight(s, point, auto) { - if (typeof s == "number") - s = series[s]; - - if (typeof point == "number") { - var ps = s.datapoints.pointsize; - point = s.datapoints.points.slice(ps * point, ps * (point + 1)); - } - - var i = indexOfHighlight(s, point); - if (i == -1) { - highlights.push({ series: s, point: point, auto: auto }); - - triggerRedrawOverlay(); - } - else if (!auto) - highlights[i].auto = false; - } - - function unhighlight(s, point) { - if (s == null && point == null) { - highlights = []; - triggerRedrawOverlay(); - return; - } - - if (typeof s == "number") - s = series[s]; - - if (typeof point == "number") { - var ps = s.datapoints.pointsize; - point = s.datapoints.points.slice(ps * point, ps * (point + 1)); - } - - var i = indexOfHighlight(s, point); - if (i != -1) { - highlights.splice(i, 1); - - triggerRedrawOverlay(); - } - } - - function indexOfHighlight(s, p) { - for (var i = 0; i < highlights.length; ++i) { - var h = highlights[i]; - if (h.series == s && h.point[0] == p[0] - && h.point[1] == p[1]) - return i; - } - return -1; - } - - function drawPointHighlight(series, point) { - var x = point[0], y = point[1], - axisx = series.xaxis, axisy = series.yaxis, - highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); - - if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) - return; - - var pointRadius = series.points.radius + series.points.lineWidth / 2; - octx.lineWidth = pointRadius; - octx.strokeStyle = highlightColor; - var radius = 1.5 * pointRadius; - x = axisx.p2c(x); - y = axisy.p2c(y); - - octx.beginPath(); - if (series.points.symbol == "circle") - octx.arc(x, y, radius, 0, 2 * Math.PI, false); - else - series.points.symbol(octx, x, y, radius, false); - octx.closePath(); - octx.stroke(); - } - - function drawBarHighlight(series, point) { - var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), - fillStyle = highlightColor, - barLeft; - - switch (series.bars.align) { - case "left": - barLeft = 0; - break; - case "right": - barLeft = -series.bars.barWidth; - break; - default: - barLeft = -series.bars.barWidth / 2; - } - - octx.lineWidth = series.bars.lineWidth; - octx.strokeStyle = highlightColor; - - drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, - function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); - } - - function getColorOrGradient(spec, bottom, top, defaultColor) { - if (typeof spec == "string") - return spec; - else { - // assume this is a gradient spec; IE currently only - // supports a simple vertical gradient properly, so that's - // what we support too - var gradient = ctx.createLinearGradient(0, top, 0, bottom); - - for (var i = 0, l = spec.colors.length; i < l; ++i) { - var c = spec.colors[i]; - if (typeof c != "string") { - var co = $.color.parse(defaultColor); - if (c.brightness != null) - co = co.scale('rgb', c.brightness); - if (c.opacity != null) - co.a *= c.opacity; - c = co.toString(); - } - gradient.addColorStop(i / (l - 1), c); - } - - return gradient; - } - } - } - - // Add the plot function to the top level of the jQuery object - - $.plot = function(placeholder, data, options) { - //var t0 = new Date(); - var plot = new Plot($(placeholder), data, options, $.plot.plugins); - //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime())); - return plot; - }; - - $.plot.version = "0.8.3"; - - $.plot.plugins = []; - - // Also add the plot function as a chainable property - - $.fn.plot = function(data, options) { - return this.each(function() { - $.plot(this, data, options); - }); - }; - - // round to nearby lower multiple of base - function floorInBase(n, base) { - return base * Math.floor(n / base); - } - -})(jQuery); diff --git a/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.js b/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.js deleted file mode 100644 index 5bb1964..0000000 --- a/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.js +++ /dev/null @@ -1,517 +0,0 @@ -/* - * jquery.flot.tooltip - * - * description: easy-to-use tooltips for Flot charts - * version: 0.8.5 - * authors: Krzysztof Urbas @krzysu [myviews.pl],Evan Steinkerchner @Roundaround - * website: https://github.com/krzysu/flot.tooltip - * - * build on 2015-05-11 - * released under MIT License, 2012 -*/ -(function ($) { - // plugin options, default values - var defaultOptions = { - tooltip: { - show: false, - cssClass: "flotTip", - content: "%s | X: %x | Y: %y", - // allowed templates are: - // %s -> series label, - // %c -> series color, - // %lx -> x axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels), - // %ly -> y axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels), - // %x -> X value, - // %y -> Y value, - // %x.2 -> precision of X value, - // %p -> percent - xDateFormat: null, - yDateFormat: null, - monthNames: null, - dayNames: null, - shifts: { - x: 10, - y: 20 - }, - defaultTheme: true, - lines: false, - - // callbacks - onHover: function (flotItem, $tooltipEl) {}, - - $compat: false - } - }; - - // dummy default options object for legacy code (<0.8.5) - is deleted later - defaultOptions.tooltipOpts = defaultOptions.tooltip; - - // object - var FlotTooltip = function (plot) { - // variables - this.tipPosition = {x: 0, y: 0}; - - this.init(plot); - }; - - // main plugin function - FlotTooltip.prototype.init = function (plot) { - var that = this; - - // detect other flot plugins - var plotPluginsLength = $.plot.plugins.length; - this.plotPlugins = []; - - if (plotPluginsLength) { - for (var p = 0; p < plotPluginsLength; p++) { - this.plotPlugins.push($.plot.plugins[p].name); - } - } - - plot.hooks.bindEvents.push(function (plot, eventHolder) { - - // get plot options - that.plotOptions = plot.getOptions(); - - // for legacy (<0.8.5) implementations - if (typeof(that.plotOptions.tooltip) === 'boolean') { - that.plotOptions.tooltipOpts.show = that.plotOptions.tooltip; - that.plotOptions.tooltip = that.plotOptions.tooltipOpts; - delete that.plotOptions.tooltipOpts; - } - - // if not enabled return - if (that.plotOptions.tooltip.show === false || typeof that.plotOptions.tooltip.show === 'undefined') return; - - // shortcut to access tooltip options - that.tooltipOptions = that.plotOptions.tooltip; - - if (that.tooltipOptions.$compat) { - that.wfunc = 'width'; - that.hfunc = 'height'; - } else { - that.wfunc = 'innerWidth'; - that.hfunc = 'innerHeight'; - } - - // create tooltip DOM element - var $tip = that.getDomElement(); - - // bind event - $( plot.getPlaceholder() ).bind("plothover", plothover); - - $(eventHolder).bind('mousemove', mouseMove); - }); - - plot.hooks.shutdown.push(function (plot, eventHolder){ - $(plot.getPlaceholder()).unbind("plothover", plothover); - $(eventHolder).unbind("mousemove", mouseMove); - }); - - function mouseMove(e){ - var pos = {}; - pos.x = e.pageX; - pos.y = e.pageY; - plot.setTooltipPosition(pos); - } - - function plothover(event, pos, item) { - // Simple distance formula. - var lineDistance = function (p1x, p1y, p2x, p2y) { - return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y)); - }; - - // Here is some voodoo magic for determining the distance to a line form a given point {x, y}. - var dotLineLength = function (x, y, x0, y0, x1, y1, o) { - if (o && !(o = - function (x, y, x0, y0, x1, y1) { - if (typeof x0 !== 'undefined') return { x: x0, y: y }; - else if (typeof y0 !== 'undefined') return { x: x, y: y0 }; - - var left, - tg = -1 / ((y1 - y0) / (x1 - x0)); - - return { - x: left = (x1 * (x * tg - y + y0) + x0 * (x * -tg + y - y1)) / (tg * (x1 - x0) + y0 - y1), - y: tg * left - tg * x + y - }; - } (x, y, x0, y0, x1, y1), - o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1)) - ) { - var l1 = lineDistance(x, y, x0, y0), l2 = lineDistance(x, y, x1, y1); - return l1 > l2 ? l2 : l1; - } else { - var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1; - return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b); - } - }; - - if (item) { - plot.showTooltip(item, pos); - } else if (that.plotOptions.series.lines.show && that.tooltipOptions.lines === true) { - var maxDistance = that.plotOptions.grid.mouseActiveRadius; - - var closestTrace = { - distance: maxDistance + 1 - }; - - $.each(plot.getData(), function (i, series) { - var xBeforeIndex = 0, - xAfterIndex = -1; - - // Our search here assumes our data is sorted via the x-axis. - // TODO: Improve efficiency somehow - search smaller sets of data. - for (var j = 1; j < series.data.length; j++) { - if (series.data[j - 1][0] <= pos.x && series.data[j][0] >= pos.x) { - xBeforeIndex = j - 1; - xAfterIndex = j; - } - } - - if (xAfterIndex === -1) { - plot.hideTooltip(); - return; - } - - var pointPrev = { x: series.data[xBeforeIndex][0], y: series.data[xBeforeIndex][1] }, - pointNext = { x: series.data[xAfterIndex][0], y: series.data[xAfterIndex][1] }; - - var distToLine = dotLineLength(series.xaxis.p2c(pos.x), series.yaxis.p2c(pos.y), series.xaxis.p2c(pointPrev.x), - series.yaxis.p2c(pointPrev.y), series.xaxis.p2c(pointNext.x), series.yaxis.p2c(pointNext.y), false); - - if (distToLine < closestTrace.distance) { - - var closestIndex = lineDistance(pointPrev.x, pointPrev.y, pos.x, pos.y) < - lineDistance(pos.x, pos.y, pointNext.x, pointNext.y) ? xBeforeIndex : xAfterIndex; - - var pointSize = series.datapoints.pointsize; - - // Calculate the point on the line vertically closest to our cursor. - var pointOnLine = [ - pos.x, - pointPrev.y + ((pointNext.y - pointPrev.y) * ((pos.x - pointPrev.x) / (pointNext.x - pointPrev.x))) - ]; - - var item = { - datapoint: pointOnLine, - dataIndex: closestIndex, - series: series, - seriesIndex: i - }; - - closestTrace = { - distance: distToLine, - item: item - }; - } - }); - - if (closestTrace.distance < maxDistance + 1) - plot.showTooltip(closestTrace.item, pos); - else - plot.hideTooltip(); - } else { - plot.hideTooltip(); - } - } - - // Quick little function for setting the tooltip position. - plot.setTooltipPosition = function (pos) { - var $tip = that.getDomElement(); - - var totalTipWidth = $tip.outerWidth() + that.tooltipOptions.shifts.x; - var totalTipHeight = $tip.outerHeight() + that.tooltipOptions.shifts.y; - if ((pos.x - $(window).scrollLeft()) > ($(window)[that.wfunc]() - totalTipWidth)) { - pos.x -= totalTipWidth; - } - if ((pos.y - $(window).scrollTop()) > ($(window)[that.hfunc]() - totalTipHeight)) { - pos.y -= totalTipHeight; - } - that.tipPosition.x = pos.x; - that.tipPosition.y = pos.y; - }; - - // Quick little function for showing the tooltip. - plot.showTooltip = function (target, position) { - var $tip = that.getDomElement(); - - // convert tooltip content template to real tipText - var tipText = that.stringFormat(that.tooltipOptions.content, target); - if (tipText === '') - return; - - $tip.html(tipText); - plot.setTooltipPosition({ x: position.pageX, y: position.pageY }); - $tip.css({ - left: that.tipPosition.x + that.tooltipOptions.shifts.x, - top: that.tipPosition.y + that.tooltipOptions.shifts.y - }).show(); - - // run callback - if (typeof that.tooltipOptions.onHover === 'function') { - that.tooltipOptions.onHover(target, $tip); - } - }; - - // Quick little function for hiding the tooltip. - plot.hideTooltip = function () { - that.getDomElement().hide().html(''); - }; - }; - - /** - * get or create tooltip DOM element - * @return jQuery object - */ - FlotTooltip.prototype.getDomElement = function () { - var $tip = $('.' + this.tooltipOptions.cssClass); - - if( $tip.length === 0 ){ - $tip = $('
').addClass(this.tooltipOptions.cssClass); - $tip.appendTo('body').hide().css({position: 'absolute'}); - - if(this.tooltipOptions.defaultTheme) { - $tip.css({ - 'background': '#fff', - 'z-index': '1040', - 'padding': '0.4em 0.6em', - 'border-radius': '0.5em', - 'font-size': '0.8em', - 'border': '1px solid #111', - 'display': 'none', - 'white-space': 'nowrap' - }); - } - } - - return $tip; - }; - - /** - * core function, create tooltip content - * @param {string} content - template with tooltip content - * @param {object} item - Flot item - * @return {string} real tooltip content for current item - */ - FlotTooltip.prototype.stringFormat = function (content, item) { - - var percentPattern = /%p\.{0,1}(\d{0,})/; - var seriesPattern = /%s/; - var colorPattern = /%c/; - var xLabelPattern = /%lx/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded - var yLabelPattern = /%ly/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded - var xPattern = /%x\.{0,1}(\d{0,})/; - var yPattern = /%y\.{0,1}(\d{0,})/; - var xPatternWithoutPrecision = "%x"; - var yPatternWithoutPrecision = "%y"; - var customTextPattern = "%ct"; - - var x, y, customText, p; - - // for threshold plugin we need to read data from different place - if (typeof item.series.threshold !== "undefined") { - x = item.datapoint[0]; - y = item.datapoint[1]; - customText = item.datapoint[2]; - } else if (typeof item.series.lines !== "undefined" && item.series.lines.steps) { - x = item.series.datapoints.points[item.dataIndex * 2]; - y = item.series.datapoints.points[item.dataIndex * 2 + 1]; - // TODO: where to find custom text in this variant? - customText = ""; - } else { - x = item.series.data[item.dataIndex][0]; - y = item.series.data[item.dataIndex][1]; - customText = item.series.data[item.dataIndex][2]; - } - - // I think this is only in case of threshold plugin - if (item.series.label === null && item.series.originSeries) { - item.series.label = item.series.originSeries.label; - } - - // if it is a function callback get the content string - if (typeof(content) === 'function') { - content = content(item.series.label, x, y, item); - } - - // the case where the passed content is equal to false - if (typeof(content) === 'boolean' && !content) { - return ''; - } - - // percent match for pie charts and stacked percent - if (typeof (item.series.percent) !== 'undefined') { - p = item.series.percent; - } else if (typeof (item.series.percents) !== 'undefined') { - p = item.series.percents[item.dataIndex]; - } - if (typeof p === 'number') { - content = this.adjustValPrecision(percentPattern, content, p); - } - - // series match - if (typeof(item.series.label) !== 'undefined') { - content = content.replace(seriesPattern, item.series.label); - } else { - //remove %s if label is undefined - content = content.replace(seriesPattern, ""); - } - - // color match - if (typeof(item.series.color) !== 'undefined') { - content = content.replace(colorPattern, item.series.color); - } else { - //remove %s if color is undefined - content = content.replace(colorPattern, ""); - } - - // x axis label match - if (this.hasAxisLabel('xaxis', item)) { - content = content.replace(xLabelPattern, item.series.xaxis.options.axisLabel); - } else { - //remove %lx if axis label is undefined or axislabels plugin not present - content = content.replace(xLabelPattern, ""); - } - - // y axis label match - if (this.hasAxisLabel('yaxis', item)) { - content = content.replace(yLabelPattern, item.series.yaxis.options.axisLabel); - } else { - //remove %ly if axis label is undefined or axislabels plugin not present - content = content.replace(yLabelPattern, ""); - } - - // time mode axes with custom dateFormat - if (this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) { - content = content.replace(xPattern, this.timestampToDate(x, this.tooltipOptions.xDateFormat, item.series.xaxis.options)); - } - if (this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) { - content = content.replace(yPattern, this.timestampToDate(y, this.tooltipOptions.yDateFormat, item.series.yaxis.options)); - } - - // set precision if defined - if (typeof x === 'number') { - content = this.adjustValPrecision(xPattern, content, x); - } - if (typeof y === 'number') { - content = this.adjustValPrecision(yPattern, content, y); - } - - // change x from number to given label, if given - if (typeof item.series.xaxis.ticks !== 'undefined') { - - var ticks; - if (this.hasRotatedXAxisTicks(item)) { - // xaxis.ticks will be an empty array if tickRotor is being used, but the values are available in rotatedTicks - ticks = 'rotatedTicks'; - } else { - ticks = 'ticks'; - } - - // see https://github.com/krzysu/flot.tooltip/issues/65 - var tickIndex = item.dataIndex + item.seriesIndex; - - for (var index in item.series.xaxis[ticks]) { - if (item.series.xaxis[ticks].hasOwnProperty(tickIndex) && !this.isTimeMode('xaxis', item)) { - var valueX = (this.isCategoriesMode('xaxis', item)) ? item.series.xaxis[ticks][tickIndex].label : item.series.xaxis[ticks][tickIndex].v; - if (valueX === x) { - content = content.replace(xPattern, item.series.xaxis[ticks][tickIndex].label); - } - } - } - } - - // change y from number to given label, if given - if (typeof item.series.yaxis.ticks !== 'undefined') { - for (var index in item.series.yaxis.ticks) { - if (item.series.yaxis.ticks.hasOwnProperty(index)) { - var valueY = (this.isCategoriesMode('yaxis', item)) ? item.series.yaxis.ticks[index].label : item.series.yaxis.ticks[index].v; - if (valueY === y) { - content = content.replace(yPattern, item.series.yaxis.ticks[index].label); - } - } - } - } - - // if no value customization, use tickFormatter by default - if (typeof item.series.xaxis.tickFormatter !== 'undefined') { - //escape dollar - content = content.replace(xPatternWithoutPrecision, item.series.xaxis.tickFormatter(x, item.series.xaxis).replace(/\$/g, '$$')); - } - if (typeof item.series.yaxis.tickFormatter !== 'undefined') { - //escape dollar - content = content.replace(yPatternWithoutPrecision, item.series.yaxis.tickFormatter(y, item.series.yaxis).replace(/\$/g, '$$')); - } - - if (customText) - content = content.replace(customTextPattern, customText); - - return content; - }; - - // helpers just for readability - FlotTooltip.prototype.isTimeMode = function (axisName, item) { - return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time'); - }; - - FlotTooltip.prototype.isXDateFormat = function (item) { - return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null); - }; - - FlotTooltip.prototype.isYDateFormat = function (item) { - return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null); - }; - - FlotTooltip.prototype.isCategoriesMode = function (axisName, item) { - return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'categories'); - }; - - // - FlotTooltip.prototype.timestampToDate = function (tmst, dateFormat, options) { - var theDate = $.plot.dateGenerator(tmst, options); - return $.plot.formatDate(theDate, dateFormat, this.tooltipOptions.monthNames, this.tooltipOptions.dayNames); - }; - - // - FlotTooltip.prototype.adjustValPrecision = function (pattern, content, value) { - - var precision; - var matchResult = content.match(pattern); - if( matchResult !== null ) { - if(RegExp.$1 !== '') { - precision = RegExp.$1; - value = value.toFixed(precision); - - // only replace content if precision exists, in other case use thickformater - content = content.replace(pattern, value); - } - } - return content; - }; - - // other plugins detection below - - // check if flot-axislabels plugin (https://github.com/markrcote/flot-axislabels) is used and that an axis label is given - FlotTooltip.prototype.hasAxisLabel = function (axisName, item) { - return ($.inArray(this.plotPlugins, 'axisLabels') !== -1 && typeof item.series[axisName].options.axisLabel !== 'undefined' && item.series[axisName].options.axisLabel.length > 0); - }; - - // check whether flot-tickRotor, a plugin which allows rotation of X-axis ticks, is being used - FlotTooltip.prototype.hasRotatedXAxisTicks = function (item) { - return ($.inArray(this.plotPlugins, 'tickRotor') !== -1 && typeof item.series.xaxis.rotatedTicks !== 'undefined'); - }; - - // - var init = function (plot) { - new FlotTooltip(plot); - }; - - // define Flot plugin - $.plot.plugins.push({ - init: init, - options: defaultOptions, - name: 'tooltip', - version: '0.8.5' - }); - -})(jQuery); diff --git a/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.min.js b/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.min.js deleted file mode 100644 index 3fb7569..0000000 --- a/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.min.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * jquery.flot.tooltip - * - * description: easy-to-use tooltips for Flot charts - * version: 0.8.5 - * authors: Krzysztof Urbas @krzysu [myviews.pl],Evan Steinkerchner @Roundaround - * website: https://github.com/krzysu/flot.tooltip - * - * build on 2015-05-11 - * released under MIT License, 2012 -*/ -!function(a){var b={tooltip:{show:!1,cssClass:"flotTip",content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,lines:!1,onHover:function(a,b){},$compat:!1}};b.tooltipOpts=b.tooltip;var c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){function c(a){var c={};c.x=a.pageX,c.y=a.pageY,b.setTooltipPosition(c)}function d(c,d,f){var g=function(a,b,c,d){return Math.sqrt((c-a)*(c-a)+(d-b)*(d-b))},h=function(a,b,c,d,e,f,h){if(!h||(h=function(a,b,c,d,e,f){if("undefined"!=typeof c)return{x:c,y:b};if("undefined"!=typeof d)return{x:a,y:d};var g,h=-1/((f-d)/(e-c));return{x:g=(e*(a*h-b+d)+c*(a*-h+b-f))/(h*(e-c)+d-f),y:h*g-h*a+b}}(a,b,c,d,e,f),h.x>=Math.min(c,e)&&h.x<=Math.max(c,e)&&h.y>=Math.min(d,f)&&h.y<=Math.max(d,f))){var i=d-f,j=e-c,k=c*f-d*e;return Math.abs(i*a+j*b+k)/Math.sqrt(i*i+j*j)}var l=g(a,b,c,d),m=g(a,b,e,f);return l>m?m:l};if(f)b.showTooltip(f,d);else if(e.plotOptions.series.lines.show&&e.tooltipOptions.lines===!0){var i=e.plotOptions.grid.mouseActiveRadius,j={distance:i+1};a.each(b.getData(),function(a,c){for(var e=0,f=-1,i=1;i=d.x&&(e=i-1,f=i);if(-1===f)return void b.hideTooltip();var k={x:c.data[e][0],y:c.data[e][1]},l={x:c.data[f][0],y:c.data[f][1]},m=h(c.xaxis.p2c(d.x),c.yaxis.p2c(d.y),c.xaxis.p2c(k.x),c.yaxis.p2c(k.y),c.xaxis.p2c(l.x),c.yaxis.p2c(l.y),!1);if(mg;g++)this.plotPlugins.push(a.plot.plugins[g].name);b.hooks.bindEvents.push(function(b,f){if(e.plotOptions=b.getOptions(),"boolean"==typeof e.plotOptions.tooltip&&(e.plotOptions.tooltipOpts.show=e.plotOptions.tooltip,e.plotOptions.tooltip=e.plotOptions.tooltipOpts,delete e.plotOptions.tooltipOpts),e.plotOptions.tooltip.show!==!1&&"undefined"!=typeof e.plotOptions.tooltip.show){e.tooltipOptions=e.plotOptions.tooltip,e.tooltipOptions.$compat?(e.wfunc="width",e.hfunc="height"):(e.wfunc="innerWidth",e.hfunc="innerHeight");e.getDomElement();a(b.getPlaceholder()).bind("plothover",d),a(f).bind("mousemove",c)}}),b.hooks.shutdown.push(function(b,e){a(b.getPlaceholder()).unbind("plothover",d),a(e).unbind("mousemove",c)}),b.setTooltipPosition=function(b){var c=e.getDomElement(),d=c.outerWidth()+e.tooltipOptions.shifts.x,f=c.outerHeight()+e.tooltipOptions.shifts.y;b.x-a(window).scrollLeft()>a(window)[e.wfunc]()-d&&(b.x-=d),b.y-a(window).scrollTop()>a(window)[e.hfunc]()-f&&(b.y-=f),e.tipPosition.x=b.x,e.tipPosition.y=b.y},b.showTooltip=function(a,c){var d=e.getDomElement(),f=e.stringFormat(e.tooltipOptions.content,a);""!==f&&(d.html(f),b.setTooltipPosition({x:c.pageX,y:c.pageY}),d.css({left:e.tipPosition.x+e.tooltipOptions.shifts.x,top:e.tipPosition.y+e.tooltipOptions.shifts.y}).show(),"function"==typeof e.tooltipOptions.onHover&&e.tooltipOptions.onHover(a,d))},b.hideTooltip=function(){e.getDomElement().hide().html("")}},c.prototype.getDomElement=function(){var b=a("."+this.tooltipOptions.cssClass);return 0===b.length&&(b=a("
").addClass(this.tooltipOptions.cssClass),b.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&b.css({background:"#fff","z-index":"1040",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),b},c.prototype.stringFormat=function(a,b){var c,d,e,f,g=/%p\.{0,1}(\d{0,})/,h=/%s/,i=/%c/,j=/%lx/,k=/%ly/,l=/%x\.{0,1}(\d{0,})/,m=/%y\.{0,1}(\d{0,})/,n="%x",o="%y",p="%ct";if("undefined"!=typeof b.series.threshold?(c=b.datapoint[0],d=b.datapoint[1],e=b.datapoint[2]):"undefined"!=typeof b.series.lines&&b.series.lines.steps?(c=b.series.datapoints.points[2*b.dataIndex],d=b.series.datapoints.points[2*b.dataIndex+1],e=""):(c=b.series.data[b.dataIndex][0],d=b.series.data[b.dataIndex][1],e=b.series.data[b.dataIndex][2]),null===b.series.label&&b.series.originSeries&&(b.series.label=b.series.originSeries.label),"function"==typeof a&&(a=a(b.series.label,c,d,b)),"boolean"==typeof a&&!a)return"";if("undefined"!=typeof b.series.percent?f=b.series.percent:"undefined"!=typeof b.series.percents&&(f=b.series.percents[b.dataIndex]),"number"==typeof f&&(a=this.adjustValPrecision(g,a,f)),a="undefined"!=typeof b.series.label?a.replace(h,b.series.label):a.replace(h,""),a="undefined"!=typeof b.series.color?a.replace(i,b.series.color):a.replace(i,""),a=this.hasAxisLabel("xaxis",b)?a.replace(j,b.series.xaxis.options.axisLabel):a.replace(j,""),a=this.hasAxisLabel("yaxis",b)?a.replace(k,b.series.yaxis.options.axisLabel):a.replace(k,""),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(l,this.timestampToDate(c,this.tooltipOptions.xDateFormat,b.series.xaxis.options))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(m,this.timestampToDate(d,this.tooltipOptions.yDateFormat,b.series.yaxis.options))),"number"==typeof c&&(a=this.adjustValPrecision(l,a,c)),"number"==typeof d&&(a=this.adjustValPrecision(m,a,d)),"undefined"!=typeof b.series.xaxis.ticks){var q;q=this.hasRotatedXAxisTicks(b)?"rotatedTicks":"ticks";var r=b.dataIndex+b.seriesIndex;for(var s in b.series.xaxis[q])if(b.series.xaxis[q].hasOwnProperty(r)&&!this.isTimeMode("xaxis",b)){var t=this.isCategoriesMode("xaxis",b)?b.series.xaxis[q][r].label:b.series.xaxis[q][r].v;t===c&&(a=a.replace(l,b.series.xaxis[q][r].label))}}if("undefined"!=typeof b.series.yaxis.ticks)for(var s in b.series.yaxis.ticks)if(b.series.yaxis.ticks.hasOwnProperty(s)){var u=this.isCategoriesMode("yaxis",b)?b.series.yaxis.ticks[s].label:b.series.yaxis.ticks[s].v;u===d&&(a=a.replace(m,b.series.yaxis.ticks[s].label))}return"undefined"!=typeof b.series.xaxis.tickFormatter&&(a=a.replace(n,b.series.xaxis.tickFormatter(c,b.series.xaxis).replace(/\$/g,"$$"))),"undefined"!=typeof b.series.yaxis.tickFormatter&&(a=a.replace(o,b.series.yaxis.tickFormatter(d,b.series.yaxis).replace(/\$/g,"$$"))),e&&(a=a.replace(p,e)),a},c.prototype.isTimeMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"time"===b.series[a].options.mode},c.prototype.isXDateFormat=function(a){return"undefined"!=typeof this.tooltipOptions.xDateFormat&&null!==this.tooltipOptions.xDateFormat},c.prototype.isYDateFormat=function(a){return"undefined"!=typeof this.tooltipOptions.yDateFormat&&null!==this.tooltipOptions.yDateFormat},c.prototype.isCategoriesMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"categories"===b.series[a].options.mode},c.prototype.timestampToDate=function(b,c,d){var e=a.plot.dateGenerator(b,d);return a.plot.formatDate(e,c,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},c.prototype.adjustValPrecision=function(a,b,c){var d,e=b.match(a);return null!==e&&""!==RegExp.$1&&(d=RegExp.$1,c=c.toFixed(d),b=b.replace(a,c)),b},c.prototype.hasAxisLabel=function(b,c){return-1!==a.inArray(this.plotPlugins,"axisLabels")&&"undefined"!=typeof c.series[b].options.axisLabel&&c.series[b].options.axisLabel.length>0},c.prototype.hasRotatedXAxisTicks=function(b){return-1!==a.inArray(this.plotPlugins,"tickRotor")&&"undefined"!=typeof b.series.xaxis.rotatedTicks};var d=function(a){new c(a)};a.plot.plugins.push({init:d,options:b,name:"tooltip",version:"0.8.5"})}(jQuery); \ No newline at end of file diff --git a/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.source.js b/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.source.js deleted file mode 100644 index 265af61..0000000 --- a/app/assets/components/flot.tooltip/js/jquery.flot.tooltip.source.js +++ /dev/null @@ -1,506 +0,0 @@ -(function ($) { - // plugin options, default values - var defaultOptions = { - tooltip: { - show: false, - cssClass: "flotTip", - content: "%s | X: %x | Y: %y", - // allowed templates are: - // %s -> series label, - // %c -> series color, - // %lx -> x axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels), - // %ly -> y axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels), - // %x -> X value, - // %y -> Y value, - // %x.2 -> precision of X value, - // %p -> percent - xDateFormat: null, - yDateFormat: null, - monthNames: null, - dayNames: null, - shifts: { - x: 10, - y: 20 - }, - defaultTheme: true, - lines: false, - - // callbacks - onHover: function (flotItem, $tooltipEl) {}, - - $compat: false - } - }; - - // dummy default options object for legacy code (<0.8.5) - is deleted later - defaultOptions.tooltipOpts = defaultOptions.tooltip; - - // object - var FlotTooltip = function (plot) { - // variables - this.tipPosition = {x: 0, y: 0}; - - this.init(plot); - }; - - // main plugin function - FlotTooltip.prototype.init = function (plot) { - var that = this; - - // detect other flot plugins - var plotPluginsLength = $.plot.plugins.length; - this.plotPlugins = []; - - if (plotPluginsLength) { - for (var p = 0; p < plotPluginsLength; p++) { - this.plotPlugins.push($.plot.plugins[p].name); - } - } - - plot.hooks.bindEvents.push(function (plot, eventHolder) { - - // get plot options - that.plotOptions = plot.getOptions(); - - // for legacy (<0.8.5) implementations - if (typeof(that.plotOptions.tooltip) === 'boolean') { - that.plotOptions.tooltipOpts.show = that.plotOptions.tooltip; - that.plotOptions.tooltip = that.plotOptions.tooltipOpts; - delete that.plotOptions.tooltipOpts; - } - - // if not enabled return - if (that.plotOptions.tooltip.show === false || typeof that.plotOptions.tooltip.show === 'undefined') return; - - // shortcut to access tooltip options - that.tooltipOptions = that.plotOptions.tooltip; - - if (that.tooltipOptions.$compat) { - that.wfunc = 'width'; - that.hfunc = 'height'; - } else { - that.wfunc = 'innerWidth'; - that.hfunc = 'innerHeight'; - } - - // create tooltip DOM element - var $tip = that.getDomElement(); - - // bind event - $( plot.getPlaceholder() ).bind("plothover", plothover); - - $(eventHolder).bind('mousemove', mouseMove); - }); - - plot.hooks.shutdown.push(function (plot, eventHolder){ - $(plot.getPlaceholder()).unbind("plothover", plothover); - $(eventHolder).unbind("mousemove", mouseMove); - }); - - function mouseMove(e){ - var pos = {}; - pos.x = e.pageX; - pos.y = e.pageY; - plot.setTooltipPosition(pos); - } - - function plothover(event, pos, item) { - // Simple distance formula. - var lineDistance = function (p1x, p1y, p2x, p2y) { - return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y)); - }; - - // Here is some voodoo magic for determining the distance to a line form a given point {x, y}. - var dotLineLength = function (x, y, x0, y0, x1, y1, o) { - if (o && !(o = - function (x, y, x0, y0, x1, y1) { - if (typeof x0 !== 'undefined') return { x: x0, y: y }; - else if (typeof y0 !== 'undefined') return { x: x, y: y0 }; - - var left, - tg = -1 / ((y1 - y0) / (x1 - x0)); - - return { - x: left = (x1 * (x * tg - y + y0) + x0 * (x * -tg + y - y1)) / (tg * (x1 - x0) + y0 - y1), - y: tg * left - tg * x + y - }; - } (x, y, x0, y0, x1, y1), - o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1)) - ) { - var l1 = lineDistance(x, y, x0, y0), l2 = lineDistance(x, y, x1, y1); - return l1 > l2 ? l2 : l1; - } else { - var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1; - return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b); - } - }; - - if (item) { - plot.showTooltip(item, pos); - } else if (that.plotOptions.series.lines.show && that.tooltipOptions.lines === true) { - var maxDistance = that.plotOptions.grid.mouseActiveRadius; - - var closestTrace = { - distance: maxDistance + 1 - }; - - $.each(plot.getData(), function (i, series) { - var xBeforeIndex = 0, - xAfterIndex = -1; - - // Our search here assumes our data is sorted via the x-axis. - // TODO: Improve efficiency somehow - search smaller sets of data. - for (var j = 1; j < series.data.length; j++) { - if (series.data[j - 1][0] <= pos.x && series.data[j][0] >= pos.x) { - xBeforeIndex = j - 1; - xAfterIndex = j; - } - } - - if (xAfterIndex === -1) { - plot.hideTooltip(); - return; - } - - var pointPrev = { x: series.data[xBeforeIndex][0], y: series.data[xBeforeIndex][1] }, - pointNext = { x: series.data[xAfterIndex][0], y: series.data[xAfterIndex][1] }; - - var distToLine = dotLineLength(series.xaxis.p2c(pos.x), series.yaxis.p2c(pos.y), series.xaxis.p2c(pointPrev.x), - series.yaxis.p2c(pointPrev.y), series.xaxis.p2c(pointNext.x), series.yaxis.p2c(pointNext.y), false); - - if (distToLine < closestTrace.distance) { - - var closestIndex = lineDistance(pointPrev.x, pointPrev.y, pos.x, pos.y) < - lineDistance(pos.x, pos.y, pointNext.x, pointNext.y) ? xBeforeIndex : xAfterIndex; - - var pointSize = series.datapoints.pointsize; - - // Calculate the point on the line vertically closest to our cursor. - var pointOnLine = [ - pos.x, - pointPrev.y + ((pointNext.y - pointPrev.y) * ((pos.x - pointPrev.x) / (pointNext.x - pointPrev.x))) - ]; - - var item = { - datapoint: pointOnLine, - dataIndex: closestIndex, - series: series, - seriesIndex: i - }; - - closestTrace = { - distance: distToLine, - item: item - }; - } - }); - - if (closestTrace.distance < maxDistance + 1) - plot.showTooltip(closestTrace.item, pos); - else - plot.hideTooltip(); - } else { - plot.hideTooltip(); - } - } - - // Quick little function for setting the tooltip position. - plot.setTooltipPosition = function (pos) { - var $tip = that.getDomElement(); - - var totalTipWidth = $tip.outerWidth() + that.tooltipOptions.shifts.x; - var totalTipHeight = $tip.outerHeight() + that.tooltipOptions.shifts.y; - if ((pos.x - $(window).scrollLeft()) > ($(window)[that.wfunc]() - totalTipWidth)) { - pos.x -= totalTipWidth; - } - if ((pos.y - $(window).scrollTop()) > ($(window)[that.hfunc]() - totalTipHeight)) { - pos.y -= totalTipHeight; - } - that.tipPosition.x = pos.x; - that.tipPosition.y = pos.y; - }; - - // Quick little function for showing the tooltip. - plot.showTooltip = function (target, position) { - var $tip = that.getDomElement(); - - // convert tooltip content template to real tipText - var tipText = that.stringFormat(that.tooltipOptions.content, target); - if (tipText === '') - return; - - $tip.html(tipText); - plot.setTooltipPosition({ x: position.pageX, y: position.pageY }); - $tip.css({ - left: that.tipPosition.x + that.tooltipOptions.shifts.x, - top: that.tipPosition.y + that.tooltipOptions.shifts.y - }).show(); - - // run callback - if (typeof that.tooltipOptions.onHover === 'function') { - that.tooltipOptions.onHover(target, $tip); - } - }; - - // Quick little function for hiding the tooltip. - plot.hideTooltip = function () { - that.getDomElement().hide().html(''); - }; - }; - - /** - * get or create tooltip DOM element - * @return jQuery object - */ - FlotTooltip.prototype.getDomElement = function () { - var $tip = $('.' + this.tooltipOptions.cssClass); - - if( $tip.length === 0 ){ - $tip = $('
').addClass(this.tooltipOptions.cssClass); - $tip.appendTo('body').hide().css({position: 'absolute'}); - - if(this.tooltipOptions.defaultTheme) { - $tip.css({ - 'background': '#fff', - 'z-index': '1040', - 'padding': '0.4em 0.6em', - 'border-radius': '0.5em', - 'font-size': '0.8em', - 'border': '1px solid #111', - 'display': 'none', - 'white-space': 'nowrap' - }); - } - } - - return $tip; - }; - - /** - * core function, create tooltip content - * @param {string} content - template with tooltip content - * @param {object} item - Flot item - * @return {string} real tooltip content for current item - */ - FlotTooltip.prototype.stringFormat = function (content, item) { - - var percentPattern = /%p\.{0,1}(\d{0,})/; - var seriesPattern = /%s/; - var colorPattern = /%c/; - var xLabelPattern = /%lx/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded - var yLabelPattern = /%ly/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded - var xPattern = /%x\.{0,1}(\d{0,})/; - var yPattern = /%y\.{0,1}(\d{0,})/; - var xPatternWithoutPrecision = "%x"; - var yPatternWithoutPrecision = "%y"; - var customTextPattern = "%ct"; - - var x, y, customText, p; - - // for threshold plugin we need to read data from different place - if (typeof item.series.threshold !== "undefined") { - x = item.datapoint[0]; - y = item.datapoint[1]; - customText = item.datapoint[2]; - } else if (typeof item.series.lines !== "undefined" && item.series.lines.steps) { - x = item.series.datapoints.points[item.dataIndex * 2]; - y = item.series.datapoints.points[item.dataIndex * 2 + 1]; - // TODO: where to find custom text in this variant? - customText = ""; - } else { - x = item.series.data[item.dataIndex][0]; - y = item.series.data[item.dataIndex][1]; - customText = item.series.data[item.dataIndex][2]; - } - - // I think this is only in case of threshold plugin - if (item.series.label === null && item.series.originSeries) { - item.series.label = item.series.originSeries.label; - } - - // if it is a function callback get the content string - if (typeof(content) === 'function') { - content = content(item.series.label, x, y, item); - } - - // the case where the passed content is equal to false - if (typeof(content) === 'boolean' && !content) { - return ''; - } - - // percent match for pie charts and stacked percent - if (typeof (item.series.percent) !== 'undefined') { - p = item.series.percent; - } else if (typeof (item.series.percents) !== 'undefined') { - p = item.series.percents[item.dataIndex]; - } - if (typeof p === 'number') { - content = this.adjustValPrecision(percentPattern, content, p); - } - - // series match - if (typeof(item.series.label) !== 'undefined') { - content = content.replace(seriesPattern, item.series.label); - } else { - //remove %s if label is undefined - content = content.replace(seriesPattern, ""); - } - - // color match - if (typeof(item.series.color) !== 'undefined') { - content = content.replace(colorPattern, item.series.color); - } else { - //remove %s if color is undefined - content = content.replace(colorPattern, ""); - } - - // x axis label match - if (this.hasAxisLabel('xaxis', item)) { - content = content.replace(xLabelPattern, item.series.xaxis.options.axisLabel); - } else { - //remove %lx if axis label is undefined or axislabels plugin not present - content = content.replace(xLabelPattern, ""); - } - - // y axis label match - if (this.hasAxisLabel('yaxis', item)) { - content = content.replace(yLabelPattern, item.series.yaxis.options.axisLabel); - } else { - //remove %ly if axis label is undefined or axislabels plugin not present - content = content.replace(yLabelPattern, ""); - } - - // time mode axes with custom dateFormat - if (this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) { - content = content.replace(xPattern, this.timestampToDate(x, this.tooltipOptions.xDateFormat, item.series.xaxis.options)); - } - if (this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) { - content = content.replace(yPattern, this.timestampToDate(y, this.tooltipOptions.yDateFormat, item.series.yaxis.options)); - } - - // set precision if defined - if (typeof x === 'number') { - content = this.adjustValPrecision(xPattern, content, x); - } - if (typeof y === 'number') { - content = this.adjustValPrecision(yPattern, content, y); - } - - // change x from number to given label, if given - if (typeof item.series.xaxis.ticks !== 'undefined') { - - var ticks; - if (this.hasRotatedXAxisTicks(item)) { - // xaxis.ticks will be an empty array if tickRotor is being used, but the values are available in rotatedTicks - ticks = 'rotatedTicks'; - } else { - ticks = 'ticks'; - } - - // see https://github.com/krzysu/flot.tooltip/issues/65 - var tickIndex = item.dataIndex + item.seriesIndex; - - for (var index in item.series.xaxis[ticks]) { - if (item.series.xaxis[ticks].hasOwnProperty(tickIndex) && !this.isTimeMode('xaxis', item)) { - var valueX = (this.isCategoriesMode('xaxis', item)) ? item.series.xaxis[ticks][tickIndex].label : item.series.xaxis[ticks][tickIndex].v; - if (valueX === x) { - content = content.replace(xPattern, item.series.xaxis[ticks][tickIndex].label); - } - } - } - } - - // change y from number to given label, if given - if (typeof item.series.yaxis.ticks !== 'undefined') { - for (var index in item.series.yaxis.ticks) { - if (item.series.yaxis.ticks.hasOwnProperty(index)) { - var valueY = (this.isCategoriesMode('yaxis', item)) ? item.series.yaxis.ticks[index].label : item.series.yaxis.ticks[index].v; - if (valueY === y) { - content = content.replace(yPattern, item.series.yaxis.ticks[index].label); - } - } - } - } - - // if no value customization, use tickFormatter by default - if (typeof item.series.xaxis.tickFormatter !== 'undefined') { - //escape dollar - content = content.replace(xPatternWithoutPrecision, item.series.xaxis.tickFormatter(x, item.series.xaxis).replace(/\$/g, '$$')); - } - if (typeof item.series.yaxis.tickFormatter !== 'undefined') { - //escape dollar - content = content.replace(yPatternWithoutPrecision, item.series.yaxis.tickFormatter(y, item.series.yaxis).replace(/\$/g, '$$')); - } - - if (customText) - content = content.replace(customTextPattern, customText); - - return content; - }; - - // helpers just for readability - FlotTooltip.prototype.isTimeMode = function (axisName, item) { - return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time'); - }; - - FlotTooltip.prototype.isXDateFormat = function (item) { - return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null); - }; - - FlotTooltip.prototype.isYDateFormat = function (item) { - return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null); - }; - - FlotTooltip.prototype.isCategoriesMode = function (axisName, item) { - return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'categories'); - }; - - // - FlotTooltip.prototype.timestampToDate = function (tmst, dateFormat, options) { - var theDate = $.plot.dateGenerator(tmst, options); - return $.plot.formatDate(theDate, dateFormat, this.tooltipOptions.monthNames, this.tooltipOptions.dayNames); - }; - - // - FlotTooltip.prototype.adjustValPrecision = function (pattern, content, value) { - - var precision; - var matchResult = content.match(pattern); - if( matchResult !== null ) { - if(RegExp.$1 !== '') { - precision = RegExp.$1; - value = value.toFixed(precision); - - // only replace content if precision exists, in other case use thickformater - content = content.replace(pattern, value); - } - } - return content; - }; - - // other plugins detection below - - // check if flot-axislabels plugin (https://github.com/markrcote/flot-axislabels) is used and that an axis label is given - FlotTooltip.prototype.hasAxisLabel = function (axisName, item) { - return ($.inArray(this.plotPlugins, 'axisLabels') !== -1 && typeof item.series[axisName].options.axisLabel !== 'undefined' && item.series[axisName].options.axisLabel.length > 0); - }; - - // check whether flot-tickRotor, a plugin which allows rotation of X-axis ticks, is being used - FlotTooltip.prototype.hasRotatedXAxisTicks = function (item) { - return ($.inArray(this.plotPlugins, 'tickRotor') !== -1 && typeof item.series.xaxis.rotatedTicks !== 'undefined'); - }; - - // - var init = function (plot) { - new FlotTooltip(plot); - }; - - // define Flot plugin - $.plot.plugins.push({ - init: init, - options: defaultOptions, - name: 'tooltip', - version: '0.8.5' - }); - -})(jQuery); diff --git a/app/assets/javascripts/radius-theme/modules/demo/demo-flot.js b/app/assets/javascripts/radius-theme/modules/demo/demo-flot.js deleted file mode 100644 index 887936f..0000000 --- a/app/assets/javascripts/radius-theme/modules/demo/demo-flot.js +++ /dev/null @@ -1,660 +0,0 @@ -// CHART SPLINE -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [{ - "label": "Uniques", - "color": "#768294", - "data": [ - ["Mar", 70], - ["Apr", 85], - ["May", 59], - ["Jun", 93], - ["Jul", 66], - ["Aug", 86], - ["Sep", 60] - ] - }, { - "label": "Recurrent", - "color": "#1f92fe", - "data": [ - ["Mar", 21], - ["Apr", 12], - ["May", 27], - ["Jun", 24], - ["Jul", 16], - ["Aug", 39], - ["Sep", 15] - ] - }]; - - var datav2 = [{ - "label": "Hours", - "color": "#23b7e5", - "data": [ - ["Jan", 70], - ["Feb", 20], - ["Mar", 70], - ["Apr", 85], - ["May", 59], - ["Jun", 93], - ["Jul", 66], - ["Aug", 86], - ["Sep", 60], - ["Oct", 60], - ["Nov", 12], - ["Dec", 50] - ] - }, { - "label": "Commits", - "color": "#7266ba", - "data": [ - ["Jan", 20], - ["Feb", 70], - ["Mar", 30], - ["Apr", 50], - ["May", 85], - ["Jun", 43], - ["Jul", 96], - ["Aug", 36], - ["Sep", 80], - ["Oct", 10], - ["Nov", 72], - ["Dec", 31] - ] - }]; - - var datav3 = [{ - "label": "Home", - "color": "#1ba3cd", - "data": [ - ["1", 38], - ["2", 40], - ["3", 42], - ["4", 48], - ["5", 50], - ["6", 70], - ["7", 145], - ["8", 70], - ["9", 59], - ["10", 48], - ["11", 38], - ["12", 29], - ["13", 30], - ["14", 22], - ["15", 28] - ] - }, { - "label": "Overall", - "color": "#3a3f51", - "data": [ - ["1", 16], - ["2", 18], - ["3", 17], - ["4", 16], - ["5", 30], - ["6", 110], - ["7", 19], - ["8", 18], - ["9", 110], - ["10", 19], - ["11", 16], - ["12", 10], - ["13", 20], - ["14", 10], - ["15", 20] - ] - }]; - - var options = { - series: { - lines: { - show: false - }, - points: { - show: true, - radius: 4 - }, - splines: { - show: true, - tension: 0.4, - lineWidth: 1, - fill: 0.5 - } - }, - grid: { - borderColor: '#eee', - borderWidth: 1, - hoverable: true, - backgroundColor: '#fcfcfc' - }, - tooltip: true, - tooltipOpts: { - content: function (label, x, y) { return x + ' : ' + y; } - }, - xaxis: { - tickColor: '#fcfcfc', - mode: 'categories' - }, - yaxis: { - min: 0, - max: 150, // optional: use it for a clear represetation - tickColor: '#eee', - //position: 'right' or 'left', - tickFormatter: function (v) { - return v/* + ' visitors'*/; - } - }, - shadowSize: 0 - }; - - var chart = $('.chart-spline'); - if(chart.length) - $.plot(chart, data, options); - - var chartv2 = $('.chart-splinev2'); - if(chartv2.length) - $.plot(chartv2, datav2, options); - - var chartv3 = $('.chart-splinev3'); - if(chartv3.length) - $.plot(chartv3, datav3, options); - - }); - -})(window, document, window.jQuery); - -// CHART AREA -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [{ - "label": "Uniques", - "color": "#aad874", - "data": [ - ["Mar", 50], - ["Apr", 84], - ["May", 52], - ["Jun", 88], - ["Jul", 69], - ["Aug", 92], - ["Sep", 58] - ] - }, { - "label": "Recurrent", - "color": "#7dc7df", - "data": [ - ["Mar", 13], - ["Apr", 44], - ["May", 44], - ["Jun", 27], - ["Jul", 38], - ["Aug", 11], - ["Sep", 39] - ] - }]; - - var options = { - series: { - lines: { - show: true, - fill: 0.8 - }, - points: { - show: true, - radius: 4 - } - }, - grid: { - borderColor: '#eee', - borderWidth: 1, - hoverable: true, - backgroundColor: '#fcfcfc' - }, - tooltip: true, - tooltipOpts: { - content: function (label, x, y) { return x + ' : ' + y; } - }, - xaxis: { - tickColor: '#fcfcfc', - mode: 'categories' - }, - yaxis: { - min: 0, - tickColor: '#eee', - // position: 'right' or 'left' - tickFormatter: function (v) { - return v + ' visitors'; - } - }, - shadowSize: 0 - }; - - var chart = $('.chart-area'); - if(chart.length) - $.plot(chart, data, options); - - }); - -})(window, document, window.jQuery); - -// CHART BAR -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [{ - "label": "Sales", - "color": "#9cd159", - "data": [ - ["Jan", 27], - ["Feb", 82], - ["Mar", 56], - ["Apr", 14], - ["May", 28], - ["Jun", 77], - ["Jul", 23], - ["Aug", 49], - ["Sep", 81], - ["Oct", 20] - ] - }]; - - var options = { - series: { - bars: { - align: 'center', - lineWidth: 0, - show: true, - barWidth: 0.6, - fill: 0.9 - } - }, - grid: { - borderColor: '#eee', - borderWidth: 1, - hoverable: true, - backgroundColor: '#fcfcfc' - }, - tooltip: true, - tooltipOpts: { - content: function (label, x, y) { return x + ' : ' + y; } - }, - xaxis: { - tickColor: '#fcfcfc', - mode: 'categories' - }, - yaxis: { - // position: 'right' or 'left' - tickColor: '#eee' - }, - shadowSize: 0 - }; - - var chart = $('.chart-bar'); - if(chart.length) - $.plot(chart, data, options); - - }); - -})(window, document, window.jQuery); - - -// CHART BAR STACKED -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [{ - "label": "Tweets", - "color": "#51bff2", - "data": [ - ["Jan", 56], - ["Feb", 81], - ["Mar", 97], - ["Apr", 44], - ["May", 24], - ["Jun", 85], - ["Jul", 94], - ["Aug", 78], - ["Sep", 52], - ["Oct", 17], - ["Nov", 90], - ["Dec", 62] - ] - }, { - "label": "Likes", - "color": "#4a8ef1", - "data": [ - ["Jan", 69], - ["Feb", 135], - ["Mar", 14], - ["Apr", 100], - ["May", 100], - ["Jun", 62], - ["Jul", 115], - ["Aug", 22], - ["Sep", 104], - ["Oct", 132], - ["Nov", 72], - ["Dec", 61] - ] - }, { - "label": "+1", - "color": "#f0693a", - "data": [ - ["Jan", 29], - ["Feb", 36], - ["Mar", 47], - ["Apr", 21], - ["May", 5], - ["Jun", 49], - ["Jul", 37], - ["Aug", 44], - ["Sep", 28], - ["Oct", 9], - ["Nov", 12], - ["Dec", 35] - ] - }]; - - var datav2 = [{ - "label": "Pending", - "color": "#9289ca", - "data": [ - ["Pj1", 86], - ["Pj2", 136], - ["Pj3", 97], - ["Pj4", 110], - ["Pj5", 62], - ["Pj6", 85], - ["Pj7", 115], - ["Pj8", 78], - ["Pj9", 104], - ["Pj10", 82], - ["Pj11", 97], - ["Pj12", 110], - ["Pj13", 62] - ] - }, { - "label": "Assigned", - "color": "#7266ba", - "data": [ - ["Pj1", 49], - ["Pj2", 81], - ["Pj3", 47], - ["Pj4", 44], - ["Pj5", 100], - ["Pj6", 49], - ["Pj7", 94], - ["Pj8", 44], - ["Pj9", 52], - ["Pj10", 17], - ["Pj11", 47], - ["Pj12", 44], - ["Pj13", 100] - ] - }, { - "label": "Completed", - "color": "#564aa3", - "data": [ - ["Pj1", 29], - ["Pj2", 56], - ["Pj3", 14], - ["Pj4", 21], - ["Pj5", 5], - ["Pj6", 24], - ["Pj7", 37], - ["Pj8", 22], - ["Pj9", 28], - ["Pj10", 9], - ["Pj11", 14], - ["Pj12", 21], - ["Pj13", 5] - ] - }]; - - var options = { - series: { - stack: true, - bars: { - align: 'center', - lineWidth: 0, - show: true, - barWidth: 0.6, - fill: 0.9 - } - }, - grid: { - borderColor: '#eee', - borderWidth: 1, - hoverable: true, - backgroundColor: '#fcfcfc' - }, - tooltip: true, - tooltipOpts: { - content: function (label, x, y) { return x + ' : ' + y; } - }, - xaxis: { - tickColor: '#fcfcfc', - mode: 'categories' - }, - yaxis: { - // position: 'right' or 'left' - tickColor: '#eee' - }, - shadowSize: 0 - }; - - var chart = $('.chart-bar-stacked'); - if(chart.length) - $.plot(chart, data, options); - - var chartv2 = $('.chart-bar-stackedv2'); - if(chartv2.length) - $.plot(chartv2, datav2, options); - - }); - -})(window, document, window.jQuery); - -// CHART DONUT -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [ { "color" : "#39C558", - "data" : 60, - "label" : "Coffee" - }, - { "color" : "#00b4ff", - "data" : 90, - "label" : "CSS" - }, - { "color" : "#FFBE41", - "data" : 50, - "label" : "LESS" - }, - { "color" : "#ff3e43", - "data" : 80, - "label" : "Jade" - }, - { "color" : "#937fc7", - "data" : 116, - "label" : "AngularJS" - } - ]; - - var options = { - series: { - pie: { - show: true, - innerRadius: 0.5 // This makes the donut shape - } - } - }; - - var chart = $('.chart-donut'); - if(chart.length) - $.plot(chart, data, options); - - }); - -})(window, document, window.jQuery); - -// CHART LINE -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [{ - "label": "Complete", - "color": "#5ab1ef", - "data": [ - ["Jan", 188], - ["Feb", 183], - ["Mar", 185], - ["Apr", 199], - ["May", 190], - ["Jun", 194], - ["Jul", 194], - ["Aug", 184], - ["Sep", 74] - ] - }, { - "label": "In Progress", - "color": "#f5994e", - "data": [ - ["Jan", 153], - ["Feb", 116], - ["Mar", 136], - ["Apr", 119], - ["May", 148], - ["Jun", 133], - ["Jul", 118], - ["Aug", 161], - ["Sep", 59] - ] - }, { - "label": "Cancelled", - "color": "#d87a80", - "data": [ - ["Jan", 111], - ["Feb", 97], - ["Mar", 93], - ["Apr", 110], - ["May", 102], - ["Jun", 93], - ["Jul", 92], - ["Aug", 92], - ["Sep", 44] - ] - }]; - - var options = { - series: { - lines: { - show: true, - fill: 0.01 - }, - points: { - show: true, - radius: 4 - } - }, - grid: { - borderColor: '#eee', - borderWidth: 1, - hoverable: true, - backgroundColor: '#fcfcfc' - }, - tooltip: true, - tooltipOpts: { - content: function (label, x, y) { return x + ' : ' + y; } - }, - xaxis: { - tickColor: '#eee', - mode: 'categories' - }, - yaxis: { - // position: 'right' or 'left' - tickColor: '#eee' - }, - shadowSize: 0 - }; - - var chart = $('.chart-line'); - if(chart.length) - $.plot(chart, data, options); - - }); - -})(window, document, window.jQuery); - - -// CHART PIE -// ----------------------------------- -(function(window, document, $, undefined){ - - $(function(){ - - var data = [{ - "label": "jQuery", - "color": "#4acab4", - "data": 30 - }, { - "label": "CSS", - "color": "#ffea88", - "data": 40 - }, { - "label": "LESS", - "color": "#ff8153", - "data": 90 - }, { - "label": "SASS", - "color": "#878bb6", - "data": 75 - }, { - "label": "Jade", - "color": "#b2d767", - "data": 120 - }]; - - var options = { - series: { - pie: { - show: true, - innerRadius: 0, - label: { - show: true, - radius: 0.8, - formatter: function (label, series) { - return '
' + - //label + ' : ' + - Math.round(series.percent) + - '%
'; - }, - background: { - opacity: 0.8, - color: '#222' - } - } - } - } - }; - - var chart = $('.chart-pie'); - if(chart.length) - $.plot(chart, data, options); - - }); - -})(window, document, window.jQuery); diff --git a/app/assets/stylesheets/radius-theme/app.scss b/app/assets/stylesheets/radius-theme/app.scss index c4c9fcd..46231a1 100644 --- a/app/assets/stylesheets/radius-theme/app.scss +++ b/app/assets/stylesheets/radius-theme/app.scss @@ -130,9 +130,9 @@ @import "app/todo"; @import "app/nestable"; -// Charts -@import "app/chart-flot"; -@import "app/chart-easypie"; +// Charts - comment out to avoid flot issue +//@import "app/chart-flot"; +//@import "app/chart-easypie"; // Form elements @import "app/form-elements";