'];
- var axes = getUsedAxes();
+ var axes = allAxes();
for (var j = 0; j < axes.length; ++j) {
var axis = axes[j], box = axis.box;
+ if (!axis.show)
+ continue;
//debug: html.push('
')
html.push('
');
for (var i = 0; i < axis.ticks.length; ++i) {
@@ -2198,6 +2267,13 @@
maxx = maxDistance / axisx.scale,
maxy = maxDistance / axisy.scale;
+ // 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];
@@ -2264,7 +2340,13 @@
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; });
@@ -2294,7 +2376,9 @@
for (var i = 0; i < highlights.length; ++i) {
var h = highlights[i];
if (h.auto == eventname &&
- !(item && h.series == item.series && h.point == item.datapoint))
+ !(item && h.series == item.series &&
+ h.point[0] == item.datapoint[0] &&
+ h.point[1] == item.datapoint[1]))
unhighlight(h.series, h.point);
}
@@ -2447,6 +2531,8 @@
return plot;
};
+ $.plot.version = "0.7";
+
$.plot.plugins = [];
// returns a string with the date d formatted according to fmt
diff --git a/htdocs/frontend/javascripts/flot/jquery.flot.navigate.js b/htdocs/frontend/javascripts/flot/jquery.flot.navigate.js
index 7e33efa..f2b9760 100644
--- a/htdocs/frontend/javascripts/flot/jquery.flot.navigate.js
+++ b/htdocs/frontend/javascripts/flot/jquery.flot.navigate.js
@@ -17,12 +17,13 @@ Options:
pan: {
interactive: false
+ cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer"
frameRate: 20
}
xaxis, yaxis, x2axis, y2axis: {
- zoomRange: null // or [number, number] (min range, max range)
- panRange: null // or [number, number] (min, max)
+ zoomRange: null // or [number, number] (min range, max range) or false
+ panRange: null // or [number, number] (min, max) or false
}
"interactive" enables the built-in drag/click behaviour. If you enable
@@ -32,6 +33,9 @@ moving around; the same for zoom.
"amount" specifies the default amount to zoom in (so 1.5 = 150%)
relative to the current viewport.
+"cursor" is a standard CSS mouse cursor string used for visual
+feedback to the user when dragging.
+
"frameRate" specifies the maximum number of times per second the plot
will update itself while the user is panning around on it (set to null
to disable intermediate pans, the plot will then not update until the
@@ -40,11 +44,13 @@ mouse button is released).
"zoomRange" is the interval in which zooming can happen, e.g. with
zoomRange: [1, 100] the zoom will never scale the axis so that the
difference between min and max is smaller than 1 or larger than 100.
-You can set either end to null to ignore, e.g. [1, null].
+You can set either end to null to ignore, e.g. [1, null]. If you set
+zoomRange to false, zooming on that axis will be disabled.
"panRange" confines the panning to stay within a range, e.g. with
panRange: [-10, 20] panning stops at -10 in one end and at 20 in the
-other. Either can be null, e.g. [-10, null].
+other. Either can be null, e.g. [-10, null]. If you set
+panRange to false, panning on that axis will be disabled.
Example API usage:
@@ -114,66 +120,78 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L
},
pan: {
interactive: false,
+ cursor: "move",
frameRate: 20
}
};
function init(plot) {
+ function onZoomClick(e, zoomOut) {
+ var c = plot.offset();
+ c.left = e.pageX - c.left;
+ c.top = e.pageY - c.top;
+ if (zoomOut)
+ plot.zoomOut({ center: c });
+ else
+ plot.zoom({ center: c });
+ }
+
+ function onMouseWheel(e, delta) {
+ onZoomClick(e, delta < 0);
+ return false;
+ }
+
+ var prevCursor = 'default', prevPageX = 0, prevPageY = 0,
+ panTimeout = null;
+
+ function onDragStart(e) {
+ if (e.which != 1) // only accept left-click
+ return false;
+ var c = plot.getPlaceholder().css('cursor');
+ if (c)
+ prevCursor = c;
+ plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
+ prevPageX = e.pageX;
+ prevPageY = e.pageY;
+ }
+
+ function onDrag(e) {
+ var frameRate = plot.getOptions().pan.frameRate;
+ if (panTimeout || !frameRate)
+ return;
+
+ panTimeout = setTimeout(function () {
+ plot.pan({ left: prevPageX - e.pageX,
+ top: prevPageY - e.pageY });
+ prevPageX = e.pageX;
+ prevPageY = e.pageY;
+
+ panTimeout = null;
+ }, 1 / frameRate * 1000);
+ }
+
+ function onDragEnd(e) {
+ if (panTimeout) {
+ clearTimeout(panTimeout);
+ panTimeout = null;
+ }
+
+ plot.getPlaceholder().css('cursor', prevCursor);
+ plot.pan({ left: prevPageX - e.pageX,
+ top: prevPageY - e.pageY });
+ }
+
function bindEvents(plot, eventHolder) {
var o = plot.getOptions();
if (o.zoom.interactive) {
- function clickHandler(e, zoomOut) {
- var c = plot.offset();
- c.left = e.pageX - c.left;
- c.top = e.pageY - c.top;
- if (zoomOut)
- plot.zoomOut({ center: c });
- else
- plot.zoom({ center: c });
- }
-
- eventHolder[o.zoom.trigger](clickHandler);
-
- eventHolder.mousewheel(function (e, delta) {
- clickHandler(e, delta < 0);
- return false;
- });
+ eventHolder[o.zoom.trigger](onZoomClick);
+ eventHolder.mousewheel(onMouseWheel);
}
- if (o.pan.interactive) {
- var prevCursor = 'default', pageX = 0, pageY = 0,
- panTimeout = null;
-
- eventHolder.bind("dragstart", { distance: 10 }, function (e) {
- if (e.which != 1) // only accept left-click
- return false;
- eventHolderCursor = eventHolder.css('cursor');
- eventHolder.css('cursor', 'move');
- pageX = e.pageX;
- pageY = e.pageY;
- });
- eventHolder.bind("drag", function (e) {
- if (panTimeout || !o.pan.frameRate)
- return;
- panTimeout = setTimeout(function () {
- plot.pan({ left: pageX - e.pageX,
- top: pageY - e.pageY });
- pageX = e.pageX;
- pageY = e.pageY;
-
- panTimeout = null;
- }, 1/o.pan.frameRate * 1000);
- });
- eventHolder.bind("dragend", function (e) {
- if (panTimeout) {
- clearTimeout(panTimeout);
- panTimeout = null;
- }
-
- eventHolder.css('cursor', prevCursor);
- plot.pan({ left: pageX - e.pageX,
- top: pageY - e.pageY });
- });
+ if (o.pan.interactive) {
+ eventHolder.bind("dragstart", { distance: 10 }, onDragStart);
+ eventHolder.bind("drag", onDrag);
+ eventHolder.bind("dragend", onDragEnd);
}
}
@@ -212,10 +230,14 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L
}
};
- $.each(plot.getUsedAxes(), function(i, axis) {
+ $.each(plot.getAxes(), function(_, axis) {
var opts = axis.options,
min = minmax[axis.direction].min,
- max = minmax[axis.direction].max
+ max = minmax[axis.direction].max,
+ zr = opts.zoomRange;
+
+ if (zr === false) // no zooming on this axis
+ return;
min = axis.c2p(min);
max = axis.c2p(max);
@@ -226,7 +248,7 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L
max = tmp;
}
- var range = max - min, zr = opts.zoomRange;
+ var range = max - min;
if (zr &&
((zr[0] != null && range < zr[0]) ||
(zr[1] != null && range > zr[1])))
@@ -254,7 +276,7 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L
if (isNaN(delta.y))
delta.y = 0;
- $.each(plot.getUsedAxes(), function (i, axis) {
+ $.each(plot.getAxes(), function (_, axis) {
var opts = axis.options,
min, max, d = delta[axis.direction];
@@ -262,6 +284,9 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L
max = axis.c2p(axis.p2c(axis.max) + d);
var pr = opts.panRange;
+ if (pr === false) // no panning on this axis
+ return;
+
if (pr) {
// check whether we hit the wall
if (pr[0] != null && pr[0] > min) {
@@ -287,14 +312,25 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L
if (!args.preventEvent)
plot.getPlaceholder().trigger("plotpan", [ plot ]);
}
+
+ function shutdown(plot, eventHolder) {
+ eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);
+ eventHolder.unbind("mousewheel", onMouseWheel);
+ eventHolder.unbind("dragstart", onDragStart);
+ eventHolder.unbind("drag", onDrag);
+ eventHolder.unbind("dragend", onDragEnd);
+ if (panTimeout)
+ clearTimeout(panTimeout);
+ }
plot.hooks.bindEvents.push(bindEvents);
+ plot.hooks.shutdown.push(shutdown);
}
$.plot.plugins.push({
init: init,
options: options,
name: 'navigate',
- version: '1.2'
+ version: '1.3'
});
})(jQuery);
diff --git a/htdocs/frontend/javascripts/flot/jquery.flot.pie.js b/htdocs/frontend/javascripts/flot/jquery.flot.pie.js
index ed01cf2..70941dd 100644
--- a/htdocs/frontend/javascripts/flot/jquery.flot.pie.js
+++ b/htdocs/frontend/javascripts/flot/jquery.flot.pie.js
@@ -403,7 +403,7 @@ More detail and specific examples can be found in the included HTML file.
}
ctx.beginPath();
- if (angle!=Math.PI*2)
+ if (Math.abs(angle - Math.PI*2) > 0.000000001)
ctx.moveTo(0,0); // Center of the pie
else if ($.browser.msie)
angle -= 0.0001;
@@ -607,12 +607,9 @@ More detail and specific examples can be found in the included HTML file.
}
}
- // if no slice was found, quit
- if (!item)
- return;
-
// highlight the slice
- highlight(item.series, eventname);
+ if (item)
+ highlight(item.series, eventname);
// trigger any hover bind events
var pos = { pageX: e.pageX, pageY: e.pageY };
@@ -691,7 +688,7 @@ More detail and specific examples can be found in the included HTML file.
octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
octx.beginPath();
- if (series.angle!=Math.PI*2)
+ if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
octx.moveTo(0,0); // Center of the pie
octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
octx.closePath();
@@ -750,4 +747,4 @@ More detail and specific examples can be found in the included HTML file.
name: "pie",
version: "1.0"
});
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/htdocs/frontend/javascripts/flot/jquery.flot.selection.js b/htdocs/frontend/javascripts/flot/jquery.flot.selection.js
index 1179a13..7f7b326 100644
--- a/htdocs/frontend/javascripts/flot/jquery.flot.selection.js
+++ b/htdocs/frontend/javascripts/flot/jquery.flot.selection.js
@@ -11,7 +11,9 @@ The plugin defines the following options:
Selection support is enabled by setting the mode to one of "x", "y" or
"xy". In "x" mode, the user will only be able to specify the x range,
similarly for "y" mode. For "xy", the selection becomes a rectangle
-where both ranges can be specified. "color" is color of the selection.
+where both ranges can be specified. "color" is color of the selection
+(if you need to change the color later on, you can get to it with
+plot.getOptions().selection.color).
When selection support is enabled, a "plotselected" event will be
emitted on the DOM element you passed into the plot function. The
@@ -79,11 +81,13 @@ The plugin allso adds the following methods to the plot object:
// make this plugin much slimmer.
var savedhandlers = {};
+ var mouseUpHandler = null;
+
function onMouseMove(e) {
if (selection.active) {
- plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
-
updateSelection(e);
+
+ plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
}
}
@@ -107,18 +111,24 @@ The plugin allso adds the following methods to the plot object:
setSelectionPos(selection.first, e);
selection.active = true;
+
+ // this is a bit silly, but we have to use a closure to be
+ // able to whack the same handler again
+ mouseUpHandler = function (e) { onMouseUp(e); };
- $(document).one("mouseup", onMouseUp);
+ $(document).one("mouseup", mouseUpHandler);
}
function onMouseUp(e) {
+ mouseUpHandler = null;
+
// revert drag stuff for old-school browsers
if (document.onselectstart !== undefined)
document.onselectstart = savedhandlers.onselectstart;
if (document.ondrag !== undefined)
document.ondrag = savedhandlers.ondrag;
- // no more draggy-dee-drag
+ // no more dragging
selection.active = false;
updateSelection(e);
@@ -197,13 +207,12 @@ The plugin allso adds the following methods to the plot object:
}
}
- // taken from markings support
+ // function taken from markings support in Flot
function extractRange(ranges, coord) {
- var axis, from, to, axes, key;
+ var axis, from, to, key, axes = plot.getAxes();
- axes = plot.getUsedAxes();
- for (i = 0; i < axes.length; ++i) {
- axis = axes[i];
+ for (var k in axes) {
+ axis = axes[k];
if (axis.direction == coord) {
key = coord + axis.n + "axis";
if (!ranges[key] && axis.n == 1)
@@ -233,7 +242,6 @@ The plugin allso adds the following methods to the plot object:
return { from: from, to: to, axis: axis };
}
-
function setSelection(ranges, preventEvent) {
var axis, range, o = plot.getOptions();
@@ -277,11 +285,10 @@ The plugin allso adds the following methods to the plot object:
plot.hooks.bindEvents.push(function(plot, eventHolder) {
var o = plot.getOptions();
- if (o.selection.mode != null)
+ if (o.selection.mode != null) {
eventHolder.mousemove(onMouseMove);
-
- if (o.selection.mode != null)
eventHolder.mousedown(onMouseDown);
+ }
});
@@ -312,6 +319,15 @@ The plugin allso adds the following methods to the plot object:
ctx.restore();
}
});
+
+ plot.hooks.shutdown.push(function (plot, eventHolder) {
+ eventHolder.unbind("mousemove", onMouseMove);
+ eventHolder.unbind("mousedown", onMouseDown);
+
+ if (mouseUpHandler)
+ $(document).unbind("mouseup", mouseUpHandler);
+ });
+
}
$.plot.plugins.push({
@@ -323,6 +339,6 @@ The plugin allso adds the following methods to the plot object:
}
},
name: 'selection',
- version: '1.0'
+ version: '1.1'
});
})(jQuery);
diff --git a/htdocs/frontend/javascripts/options.js b/htdocs/frontend/javascripts/options.js
index 94f85d7..816bdf7 100644
--- a/htdocs/frontend/javascripts/options.js
+++ b/htdocs/frontend/javascripts/options.js
@@ -32,6 +32,7 @@ vz.options = {
precision: 2, // TODO update from middleware capabilities?
render: 'lines',
refresh: false,
+ minTimeout: 3000, // minimum refresh time in ms
defaultInterval: 24*60*60*1000, // 1 day
timezoneOffset: -(new Date().getTimezoneOffset() * 60000) // TODO add option with timezone dropdown
};
diff --git a/htdocs/frontend/javascripts/wui.js b/htdocs/frontend/javascripts/wui.js
index e96262b..d69d4ee 100644
--- a/htdocs/frontend/javascripts/wui.js
+++ b/htdocs/frontend/javascripts/wui.js
@@ -28,6 +28,7 @@
* Initialize the WUI (Web User Interface)
*/
vz.wui.init = function() {
+ vz.wui.timeout = null;
// initialize dropdown accordion
$('#accordion h3').click(function() {
$(this).next().toggle('fast');
@@ -81,21 +82,14 @@ vz.wui.init = function() {
// auto refresh
if (vz.options.refresh) {
$('#refresh').attr('checked', true);
-
- var delta = vz.options.plot.xaxis.max - vz.options.plot.xaxis.min;
- this.timeout = window.setTimeout(
- this.refresh,
- (delta / 100 < 3000) ? 3000 : delta / 100
- );
+ vz.wui.setTimeout();
}
$('#refresh').change(function() {
vz.options.refresh = $(this).attr('checked');
-
if (vz.options.refresh) {
- vz.wui.timeout = window.setTimeout(vz.wui.refresh, 3000);
- }
- else {
- window.clearTimeout(this.timeout);
+ vz.wui.setTimeout();
+ } else {
+ vz.wui.clearTimeout();
}
});
@@ -252,13 +246,41 @@ vz.wui.refresh = function() {
vz.options.plot.xaxis.min = vz.options.plot.xaxis.max - delta; // move plot
vz.entities.loadData().done(function() {
vz.wui.drawPlot();
- vz.wui.timeout = window.setTimeout( // restart refresh timeout
- vz.wui.refresh, // self
- (delta / 100 < 3000) ? 3000 : delta / 100
- );
});
};
+/**
+ * refresh graphs after timeout ms, with a minimum f vz.options.minTimeout ms
+ */
+vz.wui.setTimeout = function() {
+ // clear an already set timeout
+ if (vz.wui.timeout != null) {
+ window.clearTimeout(vz.wui.timeout);
+ vz.wui.timeout = null;
+ }
+ // don't refresh if the end of the x axis is not the current time, i.e. we are looking at some old data
+ // we allow an offset of 1s, because loading data takes some time. this also means that if it takes more than 1s,
+ // we will not automatically refresh. this is a feature!
+ if (vz.options.plot.xaxis.max < Number(new Date()) - 1000) {
+ $('#refresh-time').html('(deactivated)');
+ return;
+ }
+
+ var t = Math.max((vz.options.plot.xaxis.max - vz.options.plot.xaxis.min)/vz.options.tuples, vz.options.minTimeout);
+ $('#refresh-time').html(Math.round(t/1000)+"s");
+ vz.wui.timeout = window.setTimeout(this.refresh, t);
+}
+
+/**
+ * stop auto-refresh of graphs
+ */
+vz.wui.clearTimeout = function() {
+ $('#refresh-time').html('');
+ var rc = window.clearTimeout(vz.wui.timeout);
+ vz.wui.timeout = null;
+ return rc;
+}
+
/**
* Move & zoom in the plotting area
*/
@@ -321,14 +343,14 @@ vz.wui.handleControls = function () {
// reenable autoscaling for yaxis
vz.options.plot.yaxis.max = null; // autoscaling
vz.options.plot.yaxis.min = 0; // fixed to 0
-
+
// we dont want to zoom/pan into the future
if (vz.options.plot.xaxis.max > new Date().getTime()) {
delta = vz.options.plot.xaxis.max - vz.options.plot.xaxis.min;
vz.options.plot.xaxis.max = new Date().getTime();
vz.options.plot.xaxis.min = new Date().getTime() - delta;
}
-
+
vz.entities.loadData().done(vz.wui.drawPlot);
};
@@ -536,6 +558,9 @@ vz.wui.drawPlot = function () {
}
vz.plot = $.plot($('#flot'), series, vz.options.plot);
+ if (vz.options.refresh) {
+ vz.wui.setTimeout();
+ }
};
/*