riemann-dash 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/lib/riemann/dash/public/clock.js +12 -8
  2. data/lib/riemann/dash/public/strings.js +8 -2
  3. data/lib/riemann/dash/public/subs.js +8 -4
  4. data/lib/riemann/dash/public/util.js +19 -5
  5. data/lib/riemann/dash/public/vendor/flot/jquery.colorhelpers.js +179 -0
  6. data/lib/riemann/dash/public/vendor/flot/jquery.colorhelpers.min.js +21 -0
  7. data/lib/riemann/dash/public/vendor/flot/jquery.flot.canvas.js +345 -0
  8. data/lib/riemann/dash/public/vendor/flot/jquery.flot.canvas.min.js +28 -0
  9. data/lib/riemann/dash/public/vendor/flot/jquery.flot.categories.js +190 -0
  10. data/lib/riemann/dash/public/vendor/flot/jquery.flot.categories.min.js +44 -0
  11. data/lib/riemann/dash/public/vendor/flot/jquery.flot.crosshair.js +176 -0
  12. data/lib/riemann/dash/public/vendor/flot/jquery.flot.crosshair.min.js +59 -0
  13. data/lib/riemann/dash/public/vendor/flot/jquery.flot.errorbars.js +353 -0
  14. data/lib/riemann/dash/public/vendor/flot/jquery.flot.errorbars.min.js +63 -0
  15. data/lib/riemann/dash/public/vendor/flot/jquery.flot.fillbetween.js +226 -0
  16. data/lib/riemann/dash/public/vendor/flot/jquery.flot.fillbetween.min.js +30 -0
  17. data/lib/riemann/dash/public/vendor/flot/jquery.flot.image.js +241 -0
  18. data/lib/riemann/dash/public/vendor/flot/jquery.flot.image.min.js +53 -0
  19. data/lib/riemann/dash/public/vendor/flot/jquery.flot.js +3061 -0
  20. data/lib/riemann/dash/public/vendor/flot/jquery.flot.min.js +29 -0
  21. data/lib/riemann/dash/public/vendor/flot/jquery.flot.navigate.js +346 -0
  22. data/lib/riemann/dash/public/vendor/flot/jquery.flot.navigate.min.js +86 -0
  23. data/lib/riemann/dash/public/vendor/flot/jquery.flot.pie.js +817 -0
  24. data/lib/riemann/dash/public/vendor/flot/jquery.flot.pie.min.js +56 -0
  25. data/lib/riemann/dash/public/vendor/flot/jquery.flot.resize.js +60 -0
  26. data/lib/riemann/dash/public/vendor/flot/jquery.flot.resize.min.js +19 -0
  27. data/lib/riemann/dash/public/vendor/flot/jquery.flot.selection.js +360 -0
  28. data/lib/riemann/dash/public/vendor/flot/jquery.flot.selection.min.js +79 -0
  29. data/lib/riemann/dash/public/vendor/flot/jquery.flot.stack.js +188 -0
  30. data/lib/riemann/dash/public/vendor/flot/jquery.flot.stack.min.js +36 -0
  31. data/lib/riemann/dash/public/vendor/flot/jquery.flot.symbol.js +71 -0
  32. data/lib/riemann/dash/public/vendor/flot/jquery.flot.symbol.min.js +14 -0
  33. data/lib/riemann/dash/public/vendor/flot/jquery.flot.threshold.js +142 -0
  34. data/lib/riemann/dash/public/vendor/flot/jquery.flot.threshold.min.js +43 -0
  35. data/lib/riemann/dash/public/vendor/flot/jquery.flot.time.js +431 -0
  36. data/lib/riemann/dash/public/vendor/flot/jquery.flot.time.min.js +9 -0
  37. data/lib/riemann/dash/public/view.js +11 -7
  38. data/lib/riemann/dash/public/views/flot.js +248 -0
  39. data/lib/riemann/dash/public/views/grid.js +1 -5
  40. data/lib/riemann/dash/version.rb +1 -1
  41. data/lib/riemann/dash/views/css.scss +24 -0
  42. data/lib/riemann/dash/views/index.erubis +6 -0
  43. metadata +35 -2
@@ -0,0 +1,56 @@
1
+ /* Flot plugin for rendering pie charts.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The plugin assumes that each series has a single data value, and that each
7
+ value is a positive integer or zero. Negative numbers don't make sense for a
8
+ pie chart, and have unpredictable results. The values do NOT need to be
9
+ passed in as percentages; the plugin will calculate the total and per-slice
10
+ percentages internally.
11
+
12
+ * Created by Brian Medendorp
13
+
14
+ * Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars
15
+
16
+ The plugin supports these options:
17
+
18
+ series: {
19
+ pie: {
20
+ show: true/false
21
+ radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
22
+ innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
23
+ startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
24
+ tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
25
+ offset: {
26
+ top: integer value to move the pie up or down
27
+ left: integer value to move the pie left or right, or 'auto'
28
+ },
29
+ stroke: {
30
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
31
+ width: integer pixel width of the stroke
32
+ },
33
+ label: {
34
+ show: true/false, or 'auto'
35
+ formatter: a user-defined function that modifies the text/style of the label text
36
+ radius: 0-1 for percentage of fullsize, or a specified pixel length
37
+ background: {
38
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
39
+ opacity: 0-1
40
+ },
41
+ threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
42
+ },
43
+ combine: {
44
+ threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
45
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
46
+ label: any text value of what the combined slice should be labeled
47
+ }
48
+ highlight: {
49
+ opacity: 0-1
50
+ }
51
+ }
52
+ }
53
+
54
+ More detail and specific examples can be found in the included HTML file.
55
+
56
+ */(function(e){function r(r){function p(t,n,r){l||(l=!0,s=t.getCanvas(),o=e(s).parent(),i=t.getOptions(),t.setData(d(t.getData())))}function d(t){var n=0,r=0,s=0,o=i.series.pie.combine.color,u=[];for(var a=0;a<t.length;++a){var f=t[a].data;e.isArray(f)&&f.length==1&&(f=f[0]),e.isArray(f)?!isNaN(parseFloat(f[1]))&&isFinite(f[1])?f[1]=+f[1]:f[1]=0:!isNaN(parseFloat(f))&&isFinite(f)?f=[1,+f]:f=[1,0],t[a].data=[f]}for(var a=0;a<t.length;++a)n+=t[a].data[0][1];for(var a=0;a<t.length;++a){var f=t[a].data[0][1];f/n<=i.series.pie.combine.threshold&&(r+=f,s++,o||(o=t[a].color))}for(var a=0;a<t.length;++a){var f=t[a].data[0][1];(s<2||f/n>i.series.pie.combine.threshold)&&u.push({data:[[1,f]],color:t[a].color,label:t[a].label,angle:f*Math.PI*2/n,percent:f/(n/100)})}return s>1&&u.push({data:[[1,r]],color:o,label:i.series.pie.combine.label,angle:r*Math.PI*2/n,percent:r/(n/100)}),u}function v(r,s){function y(){c.clearRect(0,0,h,p),o.children().filter(".pieLabel, .pieLabelBackground").remove()}function b(){var e=i.series.pie.shadow.left,t=i.series.pie.shadow.top,n=10,r=i.series.pie.shadow.alpha,s=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;if(s>=h/2-e||s*i.series.pie.tilt>=p/2-t||s<=n)return;c.save(),c.translate(e,t),c.globalAlpha=r,c.fillStyle="#000",c.translate(a,f),c.scale(1,i.series.pie.tilt);for(var o=1;o<=n;o++)c.beginPath(),c.arc(0,0,s,0,Math.PI*2,!1),c.fill(),s-=o;c.restore()}function w(){function l(e,t,i){if(e<=0||isNaN(e))return;i?c.fillStyle=t:(c.strokeStyle=t,c.lineJoin="round"),c.beginPath(),Math.abs(e-Math.PI*2)>1e-9&&c.moveTo(0,0),c.arc(0,0,n,r,r+e/2,!1),c.arc(0,0,n,r+e/2,r+e,!1),c.closePath(),r+=e,i?c.fill():c.stroke()}function d(){function l(t,n,s){if(t.data[0][1]==0)return!0;var u=i.legend.labelFormatter,l,c=i.series.pie.label.formatter;u?l=u(t.label,t):l=t.label,c&&(l=c(l,t));var d=(n+t.angle+n)/2,v=a+Math.round(Math.cos(d)*r),m=f+Math.round(Math.sin(d)*r)*i.series.pie.tilt,g="<span class='pieLabel' id='pieLabel"+s+"' style='position:absolute;top:"+m+"px;left:"+v+"px;'>"+l+"</span>";o.append(g);var y=o.children("#pieLabel"+s),b=m-y.height()/2,w=v-y.width()/2;y.css("top",b),y.css("left",w);if(0-b>0||0-w>0||p-(b+y.height())<0||h-(w+y.width())<0)return!1;if(i.series.pie.label.background.opacity!=0){var E=i.series.pie.label.background.color;E==null&&(E=t.color);var S="top:"+b+"px;left:"+w+"px;";e("<div class='pieLabelBackground' style='position:absolute;width:"+y.width()+"px;height:"+y.height()+"px;"+S+"background-color:"+E+";'></div>").css("opacity",i.series.pie.label.background.opacity).insertBefore(y)}return!0}var n=t,r=i.series.pie.label.radius>1?i.series.pie.label.radius:u*i.series.pie.label.radius;for(var s=0;s<v.length;++s){if(v[s].percent>=i.series.pie.label.threshold*100&&!l(v[s],n,s))return!1;n+=v[s].angle}return!0}var t=Math.PI*i.series.pie.startAngle,n=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;c.save(),c.translate(a,f),c.scale(1,i.series.pie.tilt),c.save();var r=t;for(var s=0;s<v.length;++s)v[s].startAngle=r,l(v[s].angle,v[s].color,!0);c.restore();if(i.series.pie.stroke.width>0){c.save(),c.lineWidth=i.series.pie.stroke.width,r=t;for(var s=0;s<v.length;++s)l(v[s].angle,i.series.pie.stroke.color,!1);c.restore()}return m(c),c.restore(),i.series.pie.label.show?d():!0}if(!o)return;var h=r.getPlaceholder().width(),p=r.getPlaceholder().height(),d=o.children().filter(".legend").children().width()||0;c=s,l=!1,u=Math.min(h,p/i.series.pie.tilt)/2,f=p/2+i.series.pie.offset.top,a=h/2,i.series.pie.offset.left=="auto"?i.legend.position.match("w")?a+=d/2:a-=d/2:a+=i.series.pie.offset.left,a<u?a=u:a>h-u&&(a=h-u);var v=r.getData(),g=0;do g>0&&(u*=n),g+=1,y(),i.series.pie.tilt<=.8&&b();while(!w()&&g<t);g>=t&&(y(),o.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>")),r.setSeries&&r.insertLegend&&(r.setSeries(v),r.insertLegend())}function m(e){if(i.series.pie.innerRadius>0){e.save();var t=i.series.pie.innerRadius>1?i.series.pie.innerRadius:u*i.series.pie.innerRadius;e.globalCompositeOperation="destination-out",e.beginPath(),e.fillStyle=i.series.pie.stroke.color,e.arc(0,0,t,0,Math.PI*2,!1),e.fill(),e.closePath(),e.restore(),e.save(),e.beginPath(),e.strokeStyle=i.series.pie.stroke.color,e.arc(0,0,t,0,Math.PI*2,!1),e.stroke(),e.closePath(),e.restore()}}function g(e,t){for(var n=!1,r=-1,i=e.length,s=i-1;++r<i;s=r)(e[r][1]<=t[1]&&t[1]<e[s][1]||e[s][1]<=t[1]&&t[1]<e[r][1])&&t[0]<(e[s][0]-e[r][0])*(t[1]-e[r][1])/(e[s][1]-e[r][1])+e[r][0]&&(n=!n);return n}function y(e,t){var n=r.getData(),i=r.getOptions(),s=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius,o,l;for(var h=0;h<n.length;++h){var p=n[h];if(p.pie.show){c.save(),c.beginPath(),c.moveTo(0,0),c.arc(0,0,s,p.startAngle,p.startAngle+p.angle/2,!1),c.arc(0,0,s,p.startAngle+p.angle/2,p.startAngle+p.angle,!1),c.closePath(),o=e-a,l=t-f;if(c.isPointInPath){if(c.isPointInPath(e-a,t-f))return c.restore(),{datapoint:[p.percent,p.data],dataIndex:0,series:p,seriesIndex:h}}else{var d=s*Math.cos(p.startAngle),v=s*Math.sin(p.startAngle),m=s*Math.cos(p.startAngle+p.angle/4),y=s*Math.sin(p.startAngle+p.angle/4),b=s*Math.cos(p.startAngle+p.angle/2),w=s*Math.sin(p.startAngle+p.angle/2),E=s*Math.cos(p.startAngle+p.angle/1.5),S=s*Math.sin(p.startAngle+p.angle/1.5),x=s*Math.cos(p.startAngle+p.angle),T=s*Math.sin(p.startAngle+p.angle),N=[[0,0],[d,v],[m,y],[b,w],[E,S],[x,T]],C=[o,l];if(g(N,C))return c.restore(),{datapoint:[p.percent,p.data],dataIndex:0,series:p,seriesIndex:h}}c.restore()}}return null}function b(e){E("plothover",e)}function w(e){E("plotclick",e)}function E(e,t){var n=r.offset(),s=parseInt(t.pageX-n.left),u=parseInt(t.pageY-n.top),a=y(s,u);if(i.grid.autoHighlight)for(var f=0;f<h.length;++f){var l=h[f];l.auto==e&&(!a||l.series!=a.series)&&x(l.series)}a&&S(a.series,e);var c={pageX:t.pageX,pageY:t.pageY};o.trigger(e,[c,a])}function S(e,t){var n=T(e);n==-1?(h.push({series:e,auto:t}),r.triggerRedrawOverlay()):t||(h[n].auto=!1)}function x(e){e==null&&(h=[],r.triggerRedrawOverlay());var t=T(e);t!=-1&&(h.splice(t,1),r.triggerRedrawOverlay())}function T(e){for(var t=0;t<h.length;++t){var n=h[t];if(n.series==e)return t}return-1}function N(e,t){function s(e){if(e.angle<=0||isNaN(e.angle))return;t.fillStyle="rgba(255, 255, 255, "+n.series.pie.highlight.opacity+")",t.beginPath(),Math.abs(e.angle-Math.PI*2)>1e-9&&t.moveTo(0,0),t.arc(0,0,r,e.startAngle,e.startAngle+e.angle/2,!1),t.arc(0,0,r,e.startAngle+e.angle/2,e.startAngle+e.angle,!1),t.closePath(),t.fill()}var n=e.getOptions(),r=n.series.pie.radius>1?n.series.pie.radius:u*n.series.pie.radius;t.save(),t.translate(a,f),t.scale(1,n.series.pie.tilt);for(var i=0;i<h.length;++i)s(h[i].series);m(t),t.restore()}var s=null,o=null,u=null,a=null,f=null,l=!1,c=null,h=[];r.hooks.processOptions.push(function(e,t){t.series.pie.show&&(t.grid.show=!1,t.series.pie.label.show=="auto"&&(t.legend.show?t.series.pie.label.show=!1:t.series.pie.label.show=!0),t.series.pie.radius=="auto"&&(t.series.pie.label.show?t.series.pie.radius=.75:t.series.pie.radius=1),t.series.pie.tilt>1?t.series.pie.tilt=1:t.series.pie.tilt<0&&(t.series.pie.tilt=0))}),r.hooks.bindEvents.push(function(e,t){var n=e.getOptions();n.series.pie.show&&(n.grid.hoverable&&t.unbind("mousemove").mousemove(b),n.grid.clickable&&t.unbind("click").click(w))}),r.hooks.processDatapoints.push(function(e,t,n,r){var i=e.getOptions();i.series.pie.show&&p(e,t,n,r)}),r.hooks.drawOverlay.push(function(e,t){var n=e.getOptions();n.series.pie.show&&N(e,t)}),r.hooks.draw.push(function(e,t){var n=e.getOptions();n.series.pie.show&&v(e,t)})}var t=10,n=.95,i={series:{pie:{show:!1,radius:"auto",innerRadius:0,startAngle:1.5,tilt:1,shadow:{left:5,top:15,alpha:.02},offset:{top:0,left:"auto"},stroke:{color:"#fff",width:1},label:{show:"auto",formatter:function(e,t){return"<div style='font-size:x-small;text-align:center;padding:2px;color:"+t.color+";'>"+e+"<br/>"+Math.round(t.percent)+"%</div>"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:.5}}}};e.plot.plugins.push({init:r,options:i,name:"pie",version:"1.1"})})(jQuery);
@@ -0,0 +1,60 @@
1
+ /* Flot plugin for automatically redrawing plots as the placeholder resizes.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ It works by listening for changes on the placeholder div (through the jQuery
7
+ resize event plugin) - if the size changes, it will redraw the plot.
8
+
9
+ There are no options. If you need to disable the plugin for some plots, you
10
+ can just fix the size of their placeholders.
11
+
12
+ */
13
+
14
+ /* Inline dependency:
15
+ * jQuery resize event - v1.1 - 3/14/2010
16
+ * http://benalman.com/projects/jquery-resize-plugin/
17
+ *
18
+ * Copyright (c) 2010 "Cowboy" Ben Alman
19
+ * Dual licensed under the MIT and GPL licenses.
20
+ * http://benalman.com/about/license/
21
+ */
22
+
23
+ (function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);
24
+
25
+ (function ($) {
26
+ var options = { }; // no options
27
+
28
+ function init(plot) {
29
+ function onResize() {
30
+ var placeholder = plot.getPlaceholder();
31
+
32
+ // somebody might have hidden us and we can't plot
33
+ // when we don't have the dimensions
34
+ if (placeholder.width() == 0 || placeholder.height() == 0)
35
+ return;
36
+
37
+ plot.resize();
38
+ plot.setupGrid();
39
+ plot.draw();
40
+ }
41
+
42
+ function bindEvents(plot, eventHolder) {
43
+ plot.getPlaceholder().resize(onResize);
44
+ }
45
+
46
+ function shutdown(plot, eventHolder) {
47
+ plot.getPlaceholder().unbind("resize", onResize);
48
+ }
49
+
50
+ plot.hooks.bindEvents.push(bindEvents);
51
+ plot.hooks.shutdown.push(shutdown);
52
+ }
53
+
54
+ $.plot.plugins.push({
55
+ init: init,
56
+ options: options,
57
+ name: 'resize',
58
+ version: '1.0'
59
+ });
60
+ })(jQuery);
@@ -0,0 +1,19 @@
1
+ /* Flot plugin for automatically redrawing plots as the placeholder resizes.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ It works by listening for changes on the placeholder div (through the jQuery
7
+ resize event plugin) - if the size changes, it will redraw the plot.
8
+
9
+ There are no options. If you need to disable the plugin for some plots, you
10
+ can just fix the size of their placeholders.
11
+
12
+ *//* Inline dependency:
13
+ * jQuery resize event - v1.1 - 3/14/2010
14
+ * http://benalman.com/projects/jquery-resize-plugin/
15
+ *
16
+ * Copyright (c) 2010 "Cowboy" Ben Alman
17
+ * Dual licensed under the MIT and GPL licenses.
18
+ * http://benalman.com/about/license/
19
+ */(function(e,t,n){function c(){s=t[o](function(){r.each(function(){var t=e(this),n=t.width(),r=t.height(),i=e.data(this,a);(n!==i.w||r!==i.h)&&t.trigger(u,[i.w=n,i.h=r])}),c()},i[f])}var r=e([]),i=e.resize=e.extend(e.resize,{}),s,o="setTimeout",u="resize",a=u+"-special-event",f="delay",l="throttleWindow";i[f]=250,i[l]=!0,e.event.special[u]={setup:function(){if(!i[l]&&this[o])return!1;var t=e(this);r=r.add(t),e.data(this,a,{w:t.width(),h:t.height()}),r.length===1&&c()},teardown:function(){if(!i[l]&&this[o])return!1;var t=e(this);r=r.not(t),t.removeData(a),r.length||clearTimeout(s)},add:function(t){function s(t,i,s){var o=e(this),u=e.data(this,a);u.w=i!==n?i:o.width(),u.h=s!==n?s:o.height(),r.apply(this,arguments)}if(!i[l]&&this[o])return!1;var r;if(e.isFunction(t))return r=t,s;r=t.handler,t.handler=s}}})(jQuery,this),function(e){function n(e){function t(){var t=e.getPlaceholder();if(t.width()==0||t.height()==0)return;e.resize(),e.setupGrid(),e.draw()}function n(e,n){e.getPlaceholder().resize(t)}function r(e,n){e.getPlaceholder().unbind("resize",t)}e.hooks.bindEvents.push(n),e.hooks.shutdown.push(r)}var t={};e.plot.plugins.push({init:n,options:t,name:"resize",version:"1.0"})}(jQuery);
@@ -0,0 +1,360 @@
1
+ /* Flot plugin for selecting regions of a plot.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The plugin supports these options:
7
+
8
+ selection: {
9
+ mode: null or "x" or "y" or "xy",
10
+ color: color,
11
+ shape: "round" or "miter" or "bevel",
12
+ minSize: number of pixels
13
+ }
14
+
15
+ Selection support is enabled by setting the mode to one of "x", "y" or "xy".
16
+ In "x" mode, the user will only be able to specify the x range, similarly for
17
+ "y" mode. For "xy", the selection becomes a rectangle where both ranges can be
18
+ specified. "color" is color of the selection (if you need to change the color
19
+ later on, you can get to it with plot.getOptions().selection.color). "shape"
20
+ is the shape of the corners of the selection.
21
+
22
+ "minSize" is the minimum size a selection can be in pixels. This value can
23
+ be customized to determine the smallest size a selection can be and still
24
+ have the selection rectangle be displayed. When customizing this value, the
25
+ fact that it refers to pixels, not axis units must be taken into account.
26
+ Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
27
+ minute, setting "minSize" to 1 will not make the minimum selection size 1
28
+ minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
29
+ "plotunselected" events from being fired when the user clicks the mouse without
30
+ dragging.
31
+
32
+ When selection support is enabled, a "plotselected" event will be emitted on
33
+ the DOM element you passed into the plot function. The event handler gets a
34
+ parameter with the ranges selected on the axes, like this:
35
+
36
+ placeholder.bind( "plotselected", function( event, ranges ) {
37
+ alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
38
+ // similar for yaxis - with multiple axes, the extra ones are in
39
+ // x2axis, x3axis, ...
40
+ });
41
+
42
+ The "plotselected" event is only fired when the user has finished making the
43
+ selection. A "plotselecting" event is fired during the process with the same
44
+ parameters as the "plotselected" event, in case you want to know what's
45
+ happening while it's happening,
46
+
47
+ A "plotunselected" event with no arguments is emitted when the user clicks the
48
+ mouse to remove the selection. As stated above, setting "minSize" to 0 will
49
+ destroy this behavior.
50
+
51
+ The plugin allso adds the following methods to the plot object:
52
+
53
+ - setSelection( ranges, preventEvent )
54
+
55
+ Set the selection rectangle. The passed in ranges is on the same form as
56
+ returned in the "plotselected" event. If the selection mode is "x", you
57
+ should put in either an xaxis range, if the mode is "y" you need to put in
58
+ an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
59
+ this:
60
+
61
+ setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
62
+
63
+ setSelection will trigger the "plotselected" event when called. If you don't
64
+ want that to happen, e.g. if you're inside a "plotselected" handler, pass
65
+ true as the second parameter. If you are using multiple axes, you can
66
+ specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
67
+ xaxis, the plugin picks the first one it sees.
68
+
69
+ - clearSelection( preventEvent )
70
+
71
+ Clear the selection rectangle. Pass in true to avoid getting a
72
+ "plotunselected" event.
73
+
74
+ - getSelection()
75
+
76
+ Returns the current selection in the same format as the "plotselected"
77
+ event. If there's currently no selection, the function returns null.
78
+
79
+ */
80
+
81
+ (function ($) {
82
+ function init(plot) {
83
+ var selection = {
84
+ first: { x: -1, y: -1}, second: { x: -1, y: -1},
85
+ show: false,
86
+ active: false
87
+ };
88
+
89
+ // FIXME: The drag handling implemented here should be
90
+ // abstracted out, there's some similar code from a library in
91
+ // the navigation plugin, this should be massaged a bit to fit
92
+ // the Flot cases here better and reused. Doing this would
93
+ // make this plugin much slimmer.
94
+ var savedhandlers = {};
95
+
96
+ var mouseUpHandler = null;
97
+
98
+ function onMouseMove(e) {
99
+ if (selection.active) {
100
+ updateSelection(e);
101
+
102
+ plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
103
+ }
104
+ }
105
+
106
+ function onMouseDown(e) {
107
+ if (e.which != 1) // only accept left-click
108
+ return;
109
+
110
+ // cancel out any text selections
111
+ document.body.focus();
112
+
113
+ // prevent text selection and drag in old-school browsers
114
+ if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
115
+ savedhandlers.onselectstart = document.onselectstart;
116
+ document.onselectstart = function () { return false; };
117
+ }
118
+ if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
119
+ savedhandlers.ondrag = document.ondrag;
120
+ document.ondrag = function () { return false; };
121
+ }
122
+
123
+ setSelectionPos(selection.first, e);
124
+
125
+ selection.active = true;
126
+
127
+ // this is a bit silly, but we have to use a closure to be
128
+ // able to whack the same handler again
129
+ mouseUpHandler = function (e) { onMouseUp(e); };
130
+
131
+ $(document).one("mouseup", mouseUpHandler);
132
+ }
133
+
134
+ function onMouseUp(e) {
135
+ mouseUpHandler = null;
136
+
137
+ // revert drag stuff for old-school browsers
138
+ if (document.onselectstart !== undefined)
139
+ document.onselectstart = savedhandlers.onselectstart;
140
+ if (document.ondrag !== undefined)
141
+ document.ondrag = savedhandlers.ondrag;
142
+
143
+ // no more dragging
144
+ selection.active = false;
145
+ updateSelection(e);
146
+
147
+ if (selectionIsSane())
148
+ triggerSelectedEvent();
149
+ else {
150
+ // this counts as a clear
151
+ plot.getPlaceholder().trigger("plotunselected", [ ]);
152
+ plot.getPlaceholder().trigger("plotselecting", [ null ]);
153
+ }
154
+
155
+ return false;
156
+ }
157
+
158
+ function getSelection() {
159
+ if (!selectionIsSane())
160
+ return null;
161
+
162
+ if (!selection.show) return null;
163
+
164
+ var r = {}, c1 = selection.first, c2 = selection.second;
165
+ $.each(plot.getAxes(), function (name, axis) {
166
+ if (axis.used) {
167
+ var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
168
+ r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
169
+ }
170
+ });
171
+ return r;
172
+ }
173
+
174
+ function triggerSelectedEvent() {
175
+ var r = getSelection();
176
+
177
+ plot.getPlaceholder().trigger("plotselected", [ r ]);
178
+
179
+ // backwards-compat stuff, to be removed in future
180
+ if (r.xaxis && r.yaxis)
181
+ plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
182
+ }
183
+
184
+ function clamp(min, value, max) {
185
+ return value < min ? min: (value > max ? max: value);
186
+ }
187
+
188
+ function setSelectionPos(pos, e) {
189
+ var o = plot.getOptions();
190
+ var offset = plot.getPlaceholder().offset();
191
+ var plotOffset = plot.getPlotOffset();
192
+ pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
193
+ pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
194
+
195
+ if (o.selection.mode == "y")
196
+ pos.x = pos == selection.first ? 0 : plot.width();
197
+
198
+ if (o.selection.mode == "x")
199
+ pos.y = pos == selection.first ? 0 : plot.height();
200
+ }
201
+
202
+ function updateSelection(pos) {
203
+ if (pos.pageX == null)
204
+ return;
205
+
206
+ setSelectionPos(selection.second, pos);
207
+ if (selectionIsSane()) {
208
+ selection.show = true;
209
+ plot.triggerRedrawOverlay();
210
+ }
211
+ else
212
+ clearSelection(true);
213
+ }
214
+
215
+ function clearSelection(preventEvent) {
216
+ if (selection.show) {
217
+ selection.show = false;
218
+ plot.triggerRedrawOverlay();
219
+ if (!preventEvent)
220
+ plot.getPlaceholder().trigger("plotunselected", [ ]);
221
+ }
222
+ }
223
+
224
+ // function taken from markings support in Flot
225
+ function extractRange(ranges, coord) {
226
+ var axis, from, to, key, axes = plot.getAxes();
227
+
228
+ for (var k in axes) {
229
+ axis = axes[k];
230
+ if (axis.direction == coord) {
231
+ key = coord + axis.n + "axis";
232
+ if (!ranges[key] && axis.n == 1)
233
+ key = coord + "axis"; // support x1axis as xaxis
234
+ if (ranges[key]) {
235
+ from = ranges[key].from;
236
+ to = ranges[key].to;
237
+ break;
238
+ }
239
+ }
240
+ }
241
+
242
+ // backwards-compat stuff - to be removed in future
243
+ if (!ranges[key]) {
244
+ axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
245
+ from = ranges[coord + "1"];
246
+ to = ranges[coord + "2"];
247
+ }
248
+
249
+ // auto-reverse as an added bonus
250
+ if (from != null && to != null && from > to) {
251
+ var tmp = from;
252
+ from = to;
253
+ to = tmp;
254
+ }
255
+
256
+ return { from: from, to: to, axis: axis };
257
+ }
258
+
259
+ function setSelection(ranges, preventEvent) {
260
+ var axis, range, o = plot.getOptions();
261
+
262
+ if (o.selection.mode == "y") {
263
+ selection.first.x = 0;
264
+ selection.second.x = plot.width();
265
+ }
266
+ else {
267
+ range = extractRange(ranges, "x");
268
+
269
+ selection.first.x = range.axis.p2c(range.from);
270
+ selection.second.x = range.axis.p2c(range.to);
271
+ }
272
+
273
+ if (o.selection.mode == "x") {
274
+ selection.first.y = 0;
275
+ selection.second.y = plot.height();
276
+ }
277
+ else {
278
+ range = extractRange(ranges, "y");
279
+
280
+ selection.first.y = range.axis.p2c(range.from);
281
+ selection.second.y = range.axis.p2c(range.to);
282
+ }
283
+
284
+ selection.show = true;
285
+ plot.triggerRedrawOverlay();
286
+ if (!preventEvent && selectionIsSane())
287
+ triggerSelectedEvent();
288
+ }
289
+
290
+ function selectionIsSane() {
291
+ var minSize = plot.getOptions().selection.minSize;
292
+ return Math.abs(selection.second.x - selection.first.x) >= minSize &&
293
+ Math.abs(selection.second.y - selection.first.y) >= minSize;
294
+ }
295
+
296
+ plot.clearSelection = clearSelection;
297
+ plot.setSelection = setSelection;
298
+ plot.getSelection = getSelection;
299
+
300
+ plot.hooks.bindEvents.push(function(plot, eventHolder) {
301
+ var o = plot.getOptions();
302
+ if (o.selection.mode != null) {
303
+ eventHolder.mousemove(onMouseMove);
304
+ eventHolder.mousedown(onMouseDown);
305
+ }
306
+ });
307
+
308
+
309
+ plot.hooks.drawOverlay.push(function (plot, ctx) {
310
+ // draw selection
311
+ if (selection.show && selectionIsSane()) {
312
+ var plotOffset = plot.getPlotOffset();
313
+ var o = plot.getOptions();
314
+
315
+ ctx.save();
316
+ ctx.translate(plotOffset.left, plotOffset.top);
317
+
318
+ var c = $.color.parse(o.selection.color);
319
+
320
+ ctx.strokeStyle = c.scale('a', 0.8).toString();
321
+ ctx.lineWidth = 1;
322
+ ctx.lineJoin = o.selection.shape;
323
+ ctx.fillStyle = c.scale('a', 0.4).toString();
324
+
325
+ var x = Math.min(selection.first.x, selection.second.x) + 0.5,
326
+ y = Math.min(selection.first.y, selection.second.y) + 0.5,
327
+ w = Math.abs(selection.second.x - selection.first.x) - 1,
328
+ h = Math.abs(selection.second.y - selection.first.y) - 1;
329
+
330
+ ctx.fillRect(x, y, w, h);
331
+ ctx.strokeRect(x, y, w, h);
332
+
333
+ ctx.restore();
334
+ }
335
+ });
336
+
337
+ plot.hooks.shutdown.push(function (plot, eventHolder) {
338
+ eventHolder.unbind("mousemove", onMouseMove);
339
+ eventHolder.unbind("mousedown", onMouseDown);
340
+
341
+ if (mouseUpHandler)
342
+ $(document).unbind("mouseup", mouseUpHandler);
343
+ });
344
+
345
+ }
346
+
347
+ $.plot.plugins.push({
348
+ init: init,
349
+ options: {
350
+ selection: {
351
+ mode: null, // one of null, "x", "y" or "xy"
352
+ color: "#e8cfac",
353
+ shape: "round", // one of "round", "miter", or "bevel"
354
+ minSize: 5 // minimum number of pixels
355
+ }
356
+ },
357
+ name: 'selection',
358
+ version: '1.1'
359
+ });
360
+ })(jQuery);
@@ -0,0 +1,79 @@
1
+ /* Flot plugin for selecting regions of a plot.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The plugin supports these options:
7
+
8
+ selection: {
9
+ mode: null or "x" or "y" or "xy",
10
+ color: color,
11
+ shape: "round" or "miter" or "bevel",
12
+ minSize: number of pixels
13
+ }
14
+
15
+ Selection support is enabled by setting the mode to one of "x", "y" or "xy".
16
+ In "x" mode, the user will only be able to specify the x range, similarly for
17
+ "y" mode. For "xy", the selection becomes a rectangle where both ranges can be
18
+ specified. "color" is color of the selection (if you need to change the color
19
+ later on, you can get to it with plot.getOptions().selection.color). "shape"
20
+ is the shape of the corners of the selection.
21
+
22
+ "minSize" is the minimum size a selection can be in pixels. This value can
23
+ be customized to determine the smallest size a selection can be and still
24
+ have the selection rectangle be displayed. When customizing this value, the
25
+ fact that it refers to pixels, not axis units must be taken into account.
26
+ Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
27
+ minute, setting "minSize" to 1 will not make the minimum selection size 1
28
+ minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
29
+ "plotunselected" events from being fired when the user clicks the mouse without
30
+ dragging.
31
+
32
+ When selection support is enabled, a "plotselected" event will be emitted on
33
+ the DOM element you passed into the plot function. The event handler gets a
34
+ parameter with the ranges selected on the axes, like this:
35
+
36
+ placeholder.bind( "plotselected", function( event, ranges ) {
37
+ alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
38
+ // similar for yaxis - with multiple axes, the extra ones are in
39
+ // x2axis, x3axis, ...
40
+ });
41
+
42
+ The "plotselected" event is only fired when the user has finished making the
43
+ selection. A "plotselecting" event is fired during the process with the same
44
+ parameters as the "plotselected" event, in case you want to know what's
45
+ happening while it's happening,
46
+
47
+ A "plotunselected" event with no arguments is emitted when the user clicks the
48
+ mouse to remove the selection. As stated above, setting "minSize" to 0 will
49
+ destroy this behavior.
50
+
51
+ The plugin allso adds the following methods to the plot object:
52
+
53
+ - setSelection( ranges, preventEvent )
54
+
55
+ Set the selection rectangle. The passed in ranges is on the same form as
56
+ returned in the "plotselected" event. If the selection mode is "x", you
57
+ should put in either an xaxis range, if the mode is "y" you need to put in
58
+ an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
59
+ this:
60
+
61
+ setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
62
+
63
+ setSelection will trigger the "plotselected" event when called. If you don't
64
+ want that to happen, e.g. if you're inside a "plotselected" handler, pass
65
+ true as the second parameter. If you are using multiple axes, you can
66
+ specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
67
+ xaxis, the plugin picks the first one it sees.
68
+
69
+ - clearSelection( preventEvent )
70
+
71
+ Clear the selection rectangle. Pass in true to avoid getting a
72
+ "plotunselected" event.
73
+
74
+ - getSelection()
75
+
76
+ Returns the current selection in the same format as the "plotselected"
77
+ event. If there's currently no selection, the function returns null.
78
+
79
+ */(function(e){function t(t){function s(e){n.active&&(h(e),t.getPlaceholder().trigger("plotselecting",[a()]))}function o(t){if(t.which!=1)return;document.body.focus(),document.onselectstart!==undefined&&r.onselectstart==null&&(r.onselectstart=document.onselectstart,document.onselectstart=function(){return!1}),document.ondrag!==undefined&&r.ondrag==null&&(r.ondrag=document.ondrag,document.ondrag=function(){return!1}),c(n.first,t),n.active=!0,i=function(e){u(e)},e(document).one("mouseup",i)}function u(e){return i=null,document.onselectstart!==undefined&&(document.onselectstart=r.onselectstart),document.ondrag!==undefined&&(document.ondrag=r.ondrag),n.active=!1,h(e),m()?f():(t.getPlaceholder().trigger("plotunselected",[]),t.getPlaceholder().trigger("plotselecting",[null])),!1}function a(){if(!m())return null;if(!n.show)return null;var r={},i=n.first,s=n.second;return e.each(t.getAxes(),function(e,t){if(t.used){var n=t.c2p(i[t.direction]),o=t.c2p(s[t.direction]);r[e]={from:Math.min(n,o),to:Math.max(n,o)}}}),r}function f(){var e=a();t.getPlaceholder().trigger("plotselected",[e]),e.xaxis&&e.yaxis&&t.getPlaceholder().trigger("selected",[{x1:e.xaxis.from,y1:e.yaxis.from,x2:e.xaxis.to,y2:e.yaxis.to}])}function l(e,t,n){return t<e?e:t>n?n:t}function c(e,r){var i=t.getOptions(),s=t.getPlaceholder().offset(),o=t.getPlotOffset();e.x=l(0,r.pageX-s.left-o.left,t.width()),e.y=l(0,r.pageY-s.top-o.top,t.height()),i.selection.mode=="y"&&(e.x=e==n.first?0:t.width()),i.selection.mode=="x"&&(e.y=e==n.first?0:t.height())}function h(e){if(e.pageX==null)return;c(n.second,e),m()?(n.show=!0,t.triggerRedrawOverlay()):p(!0)}function p(e){n.show&&(n.show=!1,t.triggerRedrawOverlay(),e||t.getPlaceholder().trigger("plotunselected",[]))}function d(e,n){var r,i,s,o,u=t.getAxes();for(var a in u){r=u[a];if(r.direction==n){o=n+r.n+"axis",!e[o]&&r.n==1&&(o=n+"axis");if(e[o]){i=e[o].from,s=e[o].to;break}}}e[o]||(r=n=="x"?t.getXAxes()[0]:t.getYAxes()[0],i=e[n+"1"],s=e[n+"2"]);if(i!=null&&s!=null&&i>s){var f=i;i=s,s=f}return{from:i,to:s,axis:r}}function v(e,r){var i,s,o=t.getOptions();o.selection.mode=="y"?(n.first.x=0,n.second.x=t.width()):(s=d(e,"x"),n.first.x=s.axis.p2c(s.from),n.second.x=s.axis.p2c(s.to)),o.selection.mode=="x"?(n.first.y=0,n.second.y=t.height()):(s=d(e,"y"),n.first.y=s.axis.p2c(s.from),n.second.y=s.axis.p2c(s.to)),n.show=!0,t.triggerRedrawOverlay(),!r&&m()&&f()}function m(){var e=t.getOptions().selection.minSize;return Math.abs(n.second.x-n.first.x)>=e&&Math.abs(n.second.y-n.first.y)>=e}var n={first:{x:-1,y:-1},second:{x:-1,y:-1},show:!1,active:!1},r={},i=null;t.clearSelection=p,t.setSelection=v,t.getSelection=a,t.hooks.bindEvents.push(function(e,t){var n=e.getOptions();n.selection.mode!=null&&(t.mousemove(s),t.mousedown(o))}),t.hooks.drawOverlay.push(function(t,r){if(n.show&&m()){var i=t.getPlotOffset(),s=t.getOptions();r.save(),r.translate(i.left,i.top);var o=e.color.parse(s.selection.color);r.strokeStyle=o.scale("a",.8).toString(),r.lineWidth=1,r.lineJoin=s.selection.shape,r.fillStyle=o.scale("a",.4).toString();var u=Math.min(n.first.x,n.second.x)+.5,a=Math.min(n.first.y,n.second.y)+.5,f=Math.abs(n.second.x-n.first.x)-1,l=Math.abs(n.second.y-n.first.y)-1;r.fillRect(u,a,f,l),r.strokeRect(u,a,f,l),r.restore()}}),t.hooks.shutdown.push(function(t,n){n.unbind("mousemove",s),n.unbind("mousedown",o),i&&e(document).unbind("mouseup",i)})}e.plot.plugins.push({init:t,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery);