added flot as the new plot library
This commit is contained in:
798
frontend/lib/flot/jquery.flot.navigate.js
Normal file
798
frontend/lib/flot/jquery.flot.navigate.js
Normal file
@@ -0,0 +1,798 @@
|
||||
/* Flot plugin for adding the ability to pan and zoom the plot.
|
||||
|
||||
Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||
Copyright (c) 2016 Ciprian Ceteras.
|
||||
Copyright (c) 2017 Raluca Portase.
|
||||
Licensed under the MIT license.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
## jquery.flot.navigate.js
|
||||
|
||||
This flot plugin is used for adding the ability to pan and zoom the plot.
|
||||
A higher level overview is available at [interactions](interactions.md) documentation.
|
||||
|
||||
The default behaviour is scrollwheel up/down to zoom in, drag
|
||||
to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and
|
||||
plot.pan( offset ) so you easily can add custom controls. It also fires
|
||||
"plotpan" and "plotzoom" events, useful for synchronizing plots.
|
||||
|
||||
The plugin supports these options:
|
||||
```js
|
||||
zoom: {
|
||||
interactive: false,
|
||||
active: false,
|
||||
amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
|
||||
}
|
||||
|
||||
pan: {
|
||||
interactive: false,
|
||||
active: false,
|
||||
cursor: "move", // CSS mouse cursor value used when dragging, e.g. "pointer"
|
||||
frameRate: 60,
|
||||
mode: "smart" // enable smart pan mode
|
||||
}
|
||||
|
||||
xaxis: {
|
||||
axisZoom: true, //zoom axis when mouse over it is allowed
|
||||
plotZoom: true, //zoom axis is allowed for plot zoom
|
||||
axisPan: true, //pan axis when mouse over it is allowed
|
||||
plotPan: true //pan axis is allowed for plot pan
|
||||
}
|
||||
|
||||
yaxis: {
|
||||
axisZoom: true, //zoom axis when mouse over it is allowed
|
||||
plotZoom: true, //zoom axis is allowed for plot zoom
|
||||
axisPan: true, //pan axis when mouse over it is allowed
|
||||
plotPan: true //pan axis is allowed for plot pan
|
||||
}
|
||||
```
|
||||
**interactive** enables the built-in drag/click behaviour. If you enable
|
||||
interactive for pan, then you'll have a basic plot that supports moving
|
||||
around; the same for zoom.
|
||||
|
||||
**active** is true after a touch tap on plot. This enables plot navigation.
|
||||
Once activated, zoom and pan cannot be deactivated. When the plot becomes active,
|
||||
"plotactivated" event is triggered.
|
||||
|
||||
**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 mouse button is
|
||||
released).
|
||||
|
||||
**mode** a string specifies the pan mode for mouse interaction. Accepted values:
|
||||
'manual': no pan hint or direction snapping;
|
||||
'smart': The graph shows pan hint bar and the pan movement will snap
|
||||
to one direction when the drag direction is close to it;
|
||||
'smartLock'. The graph shows pan hint bar and the pan movement will always
|
||||
snap to a direction that the drag diorection started with.
|
||||
|
||||
Example API usage:
|
||||
```js
|
||||
plot = $.plot(...);
|
||||
|
||||
// zoom default amount in on the pixel ( 10, 20 )
|
||||
plot.zoom({ center: { left: 10, top: 20 } });
|
||||
|
||||
// zoom out again
|
||||
plot.zoomOut({ center: { left: 10, top: 20 } });
|
||||
|
||||
// zoom 200% in on the pixel (10, 20)
|
||||
plot.zoom({ amount: 2, center: { left: 10, top: 20 } });
|
||||
|
||||
// pan 100 pixels to the left (changing x-range in a positive way) and 20 down
|
||||
plot.pan({ left: -100, top: 20 })
|
||||
```
|
||||
|
||||
Here, "center" specifies where the center of the zooming should happen. Note
|
||||
that this is defined in pixel space, not the space of the data points (you can
|
||||
use the p2c helpers on the axes in Flot to help you convert between these).
|
||||
|
||||
**amount** is the amount to zoom the viewport relative to the current range, so
|
||||
1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You
|
||||
can set the default in the options.
|
||||
*/
|
||||
|
||||
/* eslint-enable */
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var options = {
|
||||
zoom: {
|
||||
interactive: false,
|
||||
active: false,
|
||||
amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
|
||||
},
|
||||
pan: {
|
||||
interactive: false,
|
||||
active: false,
|
||||
cursor: "move",
|
||||
frameRate: 60,
|
||||
mode: 'smart'
|
||||
},
|
||||
recenter: {
|
||||
interactive: true
|
||||
},
|
||||
xaxis: {
|
||||
axisZoom: true, //zoom axis when mouse over it is allowed
|
||||
plotZoom: true, //zoom axis is allowed for plot zoom
|
||||
axisPan: true, //pan axis when mouse over it is allowed
|
||||
plotPan: true //pan axis is allowed for plot pan
|
||||
},
|
||||
yaxis: {
|
||||
axisZoom: true,
|
||||
plotZoom: true,
|
||||
axisPan: true,
|
||||
plotPan: true
|
||||
}
|
||||
};
|
||||
|
||||
var saturated = $.plot.saturated;
|
||||
var browser = $.plot.browser;
|
||||
var SNAPPING_CONSTANT = $.plot.uiConstants.SNAPPING_CONSTANT;
|
||||
var PANHINT_LENGTH_CONSTANT = $.plot.uiConstants.PANHINT_LENGTH_CONSTANT;
|
||||
|
||||
function init(plot) {
|
||||
plot.hooks.processOptions.push(initNevigation);
|
||||
}
|
||||
|
||||
function initNevigation(plot, options) {
|
||||
var panAxes = null;
|
||||
var canDrag = false;
|
||||
var useManualPan = options.pan.mode === 'manual',
|
||||
smartPanLock = options.pan.mode === 'smartLock',
|
||||
useSmartPan = smartPanLock || options.pan.mode === 'smart';
|
||||
|
||||
function onZoomClick(e, zoomOut, amount) {
|
||||
var page = browser.getPageXY(e);
|
||||
|
||||
var c = plot.offset();
|
||||
c.left = page.X - c.left;
|
||||
c.top = page.Y - c.top;
|
||||
|
||||
var ec = plot.getPlaceholder().offset();
|
||||
ec.left = page.X - ec.left;
|
||||
ec.top = page.Y - ec.top;
|
||||
|
||||
var axes = plot.getXAxes().concat(plot.getYAxes()).filter(function (axis) {
|
||||
var box = axis.box;
|
||||
if (box !== undefined) {
|
||||
return (ec.left > box.left) && (ec.left < box.left + box.width) &&
|
||||
(ec.top > box.top) && (ec.top < box.top + box.height);
|
||||
}
|
||||
});
|
||||
|
||||
if (axes.length === 0) {
|
||||
axes = undefined;
|
||||
}
|
||||
|
||||
if (zoomOut) {
|
||||
plot.zoomOut({
|
||||
center: c,
|
||||
axes: axes,
|
||||
amount: amount
|
||||
});
|
||||
} else {
|
||||
plot.zoom({
|
||||
center: c,
|
||||
axes: axes,
|
||||
amount: amount
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var prevCursor = 'default',
|
||||
panHint = null,
|
||||
panTimeout = null,
|
||||
plotState,
|
||||
prevDragPosition = { x: 0, y: 0 },
|
||||
isPanAction = false;
|
||||
|
||||
function onMouseWheel(e, delta) {
|
||||
var maxAbsoluteDeltaOnMac = 1,
|
||||
isMacScroll = Math.abs(e.originalEvent.deltaY) <= maxAbsoluteDeltaOnMac,
|
||||
defaultNonMacScrollAmount = null,
|
||||
macMagicRatio = 50,
|
||||
amount = isMacScroll ? 1 + Math.abs(e.originalEvent.deltaY) / macMagicRatio : defaultNonMacScrollAmount;
|
||||
|
||||
if (isPanAction) {
|
||||
onDragEnd(e);
|
||||
}
|
||||
|
||||
if (plot.getOptions().zoom.active) {
|
||||
e.preventDefault();
|
||||
onZoomClick(e, delta < 0, amount);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
plot.navigationState = function(startPageX, startPageY) {
|
||||
var axes = this.getAxes();
|
||||
var result = {};
|
||||
Object.keys(axes).forEach(function(axisName) {
|
||||
var axis = axes[axisName];
|
||||
result[axisName] = {
|
||||
navigationOffset: { below: axis.options.offset.below || 0,
|
||||
above: axis.options.offset.above || 0},
|
||||
axisMin: axis.min,
|
||||
axisMax: axis.max,
|
||||
diagMode: false
|
||||
}
|
||||
});
|
||||
|
||||
result.startPageX = startPageX || 0;
|
||||
result.startPageY = startPageY || 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
canDrag = true;
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
canDrag = false;
|
||||
}
|
||||
|
||||
function isLeftMouseButtonPressed(e) {
|
||||
return e.button === 0;
|
||||
}
|
||||
|
||||
function onDragStart(e) {
|
||||
if (!canDrag || !isLeftMouseButtonPressed(e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isPanAction = true;
|
||||
var page = browser.getPageXY(e);
|
||||
|
||||
var ec = plot.getPlaceholder().offset();
|
||||
ec.left = page.X - ec.left;
|
||||
ec.top = page.Y - ec.top;
|
||||
|
||||
panAxes = plot.getXAxes().concat(plot.getYAxes()).filter(function (axis) {
|
||||
var box = axis.box;
|
||||
if (box !== undefined) {
|
||||
return (ec.left > box.left) && (ec.left < box.left + box.width) &&
|
||||
(ec.top > box.top) && (ec.top < box.top + box.height);
|
||||
}
|
||||
});
|
||||
|
||||
if (panAxes.length === 0) {
|
||||
panAxes = undefined;
|
||||
}
|
||||
|
||||
var c = plot.getPlaceholder().css('cursor');
|
||||
if (c) {
|
||||
prevCursor = c;
|
||||
}
|
||||
|
||||
plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
|
||||
|
||||
if (useSmartPan) {
|
||||
plotState = plot.navigationState(page.X, page.Y);
|
||||
} else if (useManualPan) {
|
||||
prevDragPosition.x = page.X;
|
||||
prevDragPosition.y = page.Y;
|
||||
}
|
||||
}
|
||||
|
||||
function onDrag(e) {
|
||||
if (!isPanAction) {
|
||||
return;
|
||||
}
|
||||
|
||||
var page = browser.getPageXY(e);
|
||||
var frameRate = plot.getOptions().pan.frameRate;
|
||||
|
||||
if (frameRate === -1) {
|
||||
if (useSmartPan) {
|
||||
plot.smartPan({
|
||||
x: plotState.startPageX - page.X,
|
||||
y: plotState.startPageY - page.Y
|
||||
}, plotState, panAxes, false, smartPanLock);
|
||||
} else if (useManualPan) {
|
||||
plot.pan({
|
||||
left: prevDragPosition.x - page.X,
|
||||
top: prevDragPosition.y - page.Y,
|
||||
axes: panAxes
|
||||
});
|
||||
prevDragPosition.x = page.X;
|
||||
prevDragPosition.y = page.Y;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (panTimeout || !frameRate) return;
|
||||
|
||||
panTimeout = setTimeout(function() {
|
||||
if (useSmartPan) {
|
||||
plot.smartPan({
|
||||
x: plotState.startPageX - page.X,
|
||||
y: plotState.startPageY - page.Y
|
||||
}, plotState, panAxes, false, smartPanLock);
|
||||
} else if (useManualPan) {
|
||||
plot.pan({
|
||||
left: prevDragPosition.x - page.X,
|
||||
top: prevDragPosition.y - page.Y,
|
||||
axes: panAxes
|
||||
});
|
||||
prevDragPosition.x = page.X;
|
||||
prevDragPosition.y = page.Y;
|
||||
}
|
||||
|
||||
panTimeout = null;
|
||||
}, 1 / frameRate * 1000);
|
||||
}
|
||||
|
||||
function onDragEnd(e) {
|
||||
if (!isPanAction) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (panTimeout) {
|
||||
clearTimeout(panTimeout);
|
||||
panTimeout = null;
|
||||
}
|
||||
|
||||
isPanAction = false;
|
||||
var page = browser.getPageXY(e);
|
||||
|
||||
plot.getPlaceholder().css('cursor', prevCursor);
|
||||
|
||||
if (useSmartPan) {
|
||||
plot.smartPan({
|
||||
x: plotState.startPageX - page.X,
|
||||
y: plotState.startPageY - page.Y
|
||||
}, plotState, panAxes, false, smartPanLock);
|
||||
plot.smartPan.end();
|
||||
} else if (useManualPan) {
|
||||
plot.pan({
|
||||
left: prevDragPosition.x - page.X,
|
||||
top: prevDragPosition.y - page.Y,
|
||||
axes: panAxes
|
||||
});
|
||||
prevDragPosition.x = 0;
|
||||
prevDragPosition.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function onDblClick(e) {
|
||||
plot.activate();
|
||||
var o = plot.getOptions()
|
||||
|
||||
if (!o.recenter.interactive) { return; }
|
||||
|
||||
var axes = plot.getTouchedAxis(e.clientX, e.clientY),
|
||||
event;
|
||||
|
||||
plot.recenter({ axes: axes[0] ? axes : null });
|
||||
|
||||
if (axes[0]) {
|
||||
event = new $.Event('re-center', { detail: {
|
||||
axisTouched: axes[0]
|
||||
}});
|
||||
} else {
|
||||
event = new $.Event('re-center', { detail: e });
|
||||
}
|
||||
plot.getPlaceholder().trigger(event);
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
plot.activate();
|
||||
|
||||
if (isPanAction) {
|
||||
onDragEnd(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
plot.activate = function() {
|
||||
var o = plot.getOptions();
|
||||
if (!o.pan.active || !o.zoom.active) {
|
||||
o.pan.active = true;
|
||||
o.zoom.active = true;
|
||||
plot.getPlaceholder().trigger("plotactivated", [plot]);
|
||||
}
|
||||
}
|
||||
|
||||
function bindEvents(plot, eventHolder) {
|
||||
var o = plot.getOptions();
|
||||
if (o.zoom.interactive) {
|
||||
eventHolder.mousewheel(onMouseWheel);
|
||||
}
|
||||
|
||||
if (o.pan.interactive) {
|
||||
plot.addEventHandler("dragstart", onDragStart, eventHolder, 0);
|
||||
plot.addEventHandler("drag", onDrag, eventHolder, 0);
|
||||
plot.addEventHandler("dragend", onDragEnd, eventHolder, 0);
|
||||
eventHolder.bind("mousedown", onMouseDown);
|
||||
eventHolder.bind("mouseup", onMouseUp);
|
||||
}
|
||||
|
||||
eventHolder.dblclick(onDblClick);
|
||||
eventHolder.click(onClick);
|
||||
}
|
||||
|
||||
plot.zoomOut = function(args) {
|
||||
if (!args) {
|
||||
args = {};
|
||||
}
|
||||
|
||||
if (!args.amount) {
|
||||
args.amount = plot.getOptions().zoom.amount;
|
||||
}
|
||||
|
||||
args.amount = 1 / args.amount;
|
||||
plot.zoom(args);
|
||||
};
|
||||
|
||||
plot.zoom = function(args) {
|
||||
if (!args) {
|
||||
args = {};
|
||||
}
|
||||
|
||||
var c = args.center,
|
||||
amount = args.amount || plot.getOptions().zoom.amount,
|
||||
w = plot.width(),
|
||||
h = plot.height(),
|
||||
axes = args.axes || plot.getAxes();
|
||||
|
||||
if (!c) {
|
||||
c = {
|
||||
left: w / 2,
|
||||
top: h / 2
|
||||
};
|
||||
}
|
||||
|
||||
var xf = c.left / w,
|
||||
yf = c.top / h,
|
||||
minmax = {
|
||||
x: {
|
||||
min: c.left - xf * w / amount,
|
||||
max: c.left + (1 - xf) * w / amount
|
||||
},
|
||||
y: {
|
||||
min: c.top - yf * h / amount,
|
||||
max: c.top + (1 - yf) * h / amount
|
||||
}
|
||||
};
|
||||
|
||||
for (var key in axes) {
|
||||
if (!axes.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var axis = axes[key],
|
||||
opts = axis.options,
|
||||
min = minmax[axis.direction].min,
|
||||
max = minmax[axis.direction].max,
|
||||
navigationOffset = axis.options.offset;
|
||||
|
||||
//skip axis without axisZoom when zooming only on certain axis or axis without plotZoom for zoom on entire plot
|
||||
if ((!opts.axisZoom && args.axes) || (!args.axes && !opts.plotZoom)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
min = $.plot.saturated.saturate(axis.c2p(min));
|
||||
max = $.plot.saturated.saturate(axis.c2p(max));
|
||||
if (min > max) {
|
||||
// make sure min < max
|
||||
var tmp = min;
|
||||
min = max;
|
||||
max = tmp;
|
||||
}
|
||||
|
||||
var offsetBelow = $.plot.saturated.saturate(navigationOffset.below - (axis.min - min));
|
||||
var offsetAbove = $.plot.saturated.saturate(navigationOffset.above - (axis.max - max));
|
||||
opts.offset = { below: offsetBelow, above: offsetAbove };
|
||||
};
|
||||
|
||||
plot.setupGrid(true);
|
||||
plot.draw();
|
||||
|
||||
if (!args.preventEvent) {
|
||||
plot.getPlaceholder().trigger("plotzoom", [plot, args]);
|
||||
}
|
||||
};
|
||||
|
||||
plot.pan = function(args) {
|
||||
var delta = {
|
||||
x: +args.left,
|
||||
y: +args.top
|
||||
};
|
||||
|
||||
if (isNaN(delta.x)) delta.x = 0;
|
||||
if (isNaN(delta.y)) delta.y = 0;
|
||||
|
||||
$.each(args.axes || plot.getAxes(), function(_, axis) {
|
||||
var opts = axis.options,
|
||||
d = delta[axis.direction];
|
||||
|
||||
//skip axis without axisPan when panning only on certain axis or axis without plotPan for pan the entire plot
|
||||
if ((!opts.axisPan && args.axes) || (!opts.plotPan && !args.axes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (d !== 0) {
|
||||
var navigationOffsetBelow = saturated.saturate(axis.c2p(axis.p2c(axis.min) + d) - axis.c2p(axis.p2c(axis.min))),
|
||||
navigationOffsetAbove = saturated.saturate(axis.c2p(axis.p2c(axis.max) + d) - axis.c2p(axis.p2c(axis.max)));
|
||||
|
||||
if (!isFinite(navigationOffsetBelow)) {
|
||||
navigationOffsetBelow = 0;
|
||||
}
|
||||
|
||||
if (!isFinite(navigationOffsetAbove)) {
|
||||
navigationOffsetAbove = 0;
|
||||
}
|
||||
|
||||
opts.offset = {
|
||||
below: saturated.saturate(navigationOffsetBelow + (opts.offset.below || 0)),
|
||||
above: saturated.saturate(navigationOffsetAbove + (opts.offset.above || 0))
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
plot.setupGrid(true);
|
||||
plot.draw();
|
||||
if (!args.preventEvent) {
|
||||
plot.getPlaceholder().trigger("plotpan", [plot, args]);
|
||||
}
|
||||
};
|
||||
|
||||
plot.recenter = function(args) {
|
||||
$.each(args.axes || plot.getAxes(), function(_, axis) {
|
||||
if (args.axes) {
|
||||
if (this.direction === 'x') {
|
||||
axis.options.offset = { below: 0 };
|
||||
} else if (this.direction === 'y') {
|
||||
axis.options.offset = { above: 0 };
|
||||
}
|
||||
} else {
|
||||
axis.options.offset = { below: 0, above: 0 };
|
||||
}
|
||||
});
|
||||
plot.setupGrid(true);
|
||||
plot.draw();
|
||||
};
|
||||
|
||||
var shouldSnap = function(delta) {
|
||||
return (Math.abs(delta.y) < SNAPPING_CONSTANT && Math.abs(delta.x) >= SNAPPING_CONSTANT) ||
|
||||
(Math.abs(delta.x) < SNAPPING_CONSTANT && Math.abs(delta.y) >= SNAPPING_CONSTANT);
|
||||
}
|
||||
|
||||
// adjust delta so the pan action is constrained on the vertical or horizontal direction
|
||||
// it the movements in the other direction are small
|
||||
var adjustDeltaToSnap = function(delta) {
|
||||
if (Math.abs(delta.x) < SNAPPING_CONSTANT && Math.abs(delta.y) >= SNAPPING_CONSTANT) {
|
||||
return {x: 0, y: delta.y};
|
||||
}
|
||||
|
||||
if (Math.abs(delta.y) < SNAPPING_CONSTANT && Math.abs(delta.x) >= SNAPPING_CONSTANT) {
|
||||
return {x: delta.x, y: 0};
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
var lockedDirection = null;
|
||||
var lockDeltaDirection = function(delta) {
|
||||
if (!lockedDirection && Math.max(Math.abs(delta.x), Math.abs(delta.y)) >= SNAPPING_CONSTANT) {
|
||||
lockedDirection = Math.abs(delta.x) < Math.abs(delta.y) ? 'y' : 'x';
|
||||
}
|
||||
|
||||
switch (lockedDirection) {
|
||||
case 'x':
|
||||
return { x: delta.x, y: 0 };
|
||||
case 'y':
|
||||
return { x: 0, y: delta.y };
|
||||
default:
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
var isDiagonalMode = function(delta) {
|
||||
if (Math.abs(delta.x) > 0 && Math.abs(delta.y) > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var restoreAxisOffset = function(axes, initialState, delta) {
|
||||
var axis;
|
||||
Object.keys(axes).forEach(function(axisName) {
|
||||
axis = axes[axisName];
|
||||
if (delta[axis.direction] === 0) {
|
||||
axis.options.offset.below = initialState[axisName].navigationOffset.below;
|
||||
axis.options.offset.above = initialState[axisName].navigationOffset.above;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var prevDelta = { x: 0, y: 0 };
|
||||
plot.smartPan = function(delta, initialState, panAxes, preventEvent, smartLock) {
|
||||
var snap = smartLock ? true : shouldSnap(delta),
|
||||
axes = plot.getAxes(),
|
||||
opts;
|
||||
delta = smartLock ? lockDeltaDirection(delta) : adjustDeltaToSnap(delta);
|
||||
|
||||
if (isDiagonalMode(delta)) {
|
||||
initialState.diagMode = true;
|
||||
}
|
||||
|
||||
if (snap && initialState.diagMode === true) {
|
||||
initialState.diagMode = false;
|
||||
restoreAxisOffset(axes, initialState, delta);
|
||||
}
|
||||
|
||||
if (snap) {
|
||||
panHint = {
|
||||
start: {
|
||||
x: initialState.startPageX - plot.offset().left + plot.getPlotOffset().left,
|
||||
y: initialState.startPageY - plot.offset().top + plot.getPlotOffset().top
|
||||
},
|
||||
end: {
|
||||
x: initialState.startPageX - delta.x - plot.offset().left + plot.getPlotOffset().left,
|
||||
y: initialState.startPageY - delta.y - plot.offset().top + plot.getPlotOffset().top
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panHint = {
|
||||
start: {
|
||||
x: initialState.startPageX - plot.offset().left + plot.getPlotOffset().left,
|
||||
y: initialState.startPageY - plot.offset().top + plot.getPlotOffset().top
|
||||
},
|
||||
end: false
|
||||
}
|
||||
}
|
||||
|
||||
if (isNaN(delta.x)) delta.x = 0;
|
||||
if (isNaN(delta.y)) delta.y = 0;
|
||||
|
||||
if (panAxes) {
|
||||
axes = panAxes;
|
||||
}
|
||||
|
||||
var axis, axisMin, axisMax, p, d;
|
||||
Object.keys(axes).forEach(function(axisName) {
|
||||
axis = axes[axisName];
|
||||
axisMin = axis.min;
|
||||
axisMax = axis.max;
|
||||
opts = axis.options;
|
||||
|
||||
d = delta[axis.direction];
|
||||
p = prevDelta[axis.direction];
|
||||
|
||||
//skip axis without axisPan when panning only on certain axis or axis without plotPan for pan the entire plot
|
||||
if ((!opts.axisPan && panAxes) || (!panAxes && !opts.plotPan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (d !== 0) {
|
||||
var navigationOffsetBelow = saturated.saturate(axis.c2p(axis.p2c(axisMin) - (p - d)) - axis.c2p(axis.p2c(axisMin))),
|
||||
navigationOffsetAbove = saturated.saturate(axis.c2p(axis.p2c(axisMax) - (p - d)) - axis.c2p(axis.p2c(axisMax)));
|
||||
|
||||
if (!isFinite(navigationOffsetBelow)) {
|
||||
navigationOffsetBelow = 0;
|
||||
}
|
||||
|
||||
if (!isFinite(navigationOffsetAbove)) {
|
||||
navigationOffsetAbove = 0;
|
||||
}
|
||||
|
||||
axis.options.offset.below = saturated.saturate(navigationOffsetBelow + (axis.options.offset.below || 0));
|
||||
axis.options.offset.above = saturated.saturate(navigationOffsetAbove + (axis.options.offset.above || 0));
|
||||
}
|
||||
});
|
||||
|
||||
prevDelta = delta;
|
||||
plot.setupGrid(true);
|
||||
plot.draw();
|
||||
|
||||
if (!preventEvent) {
|
||||
plot.getPlaceholder().trigger("plotpan", [plot, delta, panAxes, initialState]);
|
||||
}
|
||||
};
|
||||
|
||||
plot.smartPan.end = function() {
|
||||
panHint = null;
|
||||
lockedDirection = null;
|
||||
prevDelta = { x: 0, y: 0 };
|
||||
plot.triggerRedrawOverlay();
|
||||
}
|
||||
|
||||
function shutdown(plot, eventHolder) {
|
||||
eventHolder.unbind("mousewheel", onMouseWheel);
|
||||
eventHolder.unbind("mousedown", onMouseDown);
|
||||
eventHolder.unbind("mouseup", onMouseUp);
|
||||
eventHolder.unbind("dragstart", onDragStart);
|
||||
eventHolder.unbind("drag", onDrag);
|
||||
eventHolder.unbind("dragend", onDragEnd);
|
||||
eventHolder.unbind("dblclick", onDblClick);
|
||||
eventHolder.unbind("click", onClick);
|
||||
|
||||
if (panTimeout) clearTimeout(panTimeout);
|
||||
}
|
||||
|
||||
function drawOverlay(plot, ctx) {
|
||||
if (panHint) {
|
||||
ctx.strokeStyle = 'rgba(96, 160, 208, 0.7)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.lineJoin = "round";
|
||||
var startx = Math.round(panHint.start.x),
|
||||
starty = Math.round(panHint.start.y),
|
||||
endx, endy;
|
||||
|
||||
if (panAxes) {
|
||||
if (panAxes[0].direction === 'x') {
|
||||
endy = Math.round(panHint.start.y);
|
||||
endx = Math.round(panHint.end.x);
|
||||
} else if (panAxes[0].direction === 'y') {
|
||||
endx = Math.round(panHint.start.x);
|
||||
endy = Math.round(panHint.end.y);
|
||||
}
|
||||
} else {
|
||||
endx = Math.round(panHint.end.x);
|
||||
endy = Math.round(panHint.end.y);
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
if (panHint.end === false) {
|
||||
ctx.moveTo(startx, starty - PANHINT_LENGTH_CONSTANT);
|
||||
ctx.lineTo(startx, starty + PANHINT_LENGTH_CONSTANT);
|
||||
|
||||
ctx.moveTo(startx + PANHINT_LENGTH_CONSTANT, starty);
|
||||
ctx.lineTo(startx - PANHINT_LENGTH_CONSTANT, starty);
|
||||
} else {
|
||||
var dirX = starty === endy;
|
||||
|
||||
ctx.moveTo(startx - (dirX ? 0 : PANHINT_LENGTH_CONSTANT), starty - (dirX ? PANHINT_LENGTH_CONSTANT : 0));
|
||||
ctx.lineTo(startx + (dirX ? 0 : PANHINT_LENGTH_CONSTANT), starty + (dirX ? PANHINT_LENGTH_CONSTANT : 0));
|
||||
|
||||
ctx.moveTo(startx, starty);
|
||||
ctx.lineTo(endx, endy);
|
||||
|
||||
ctx.moveTo(endx - (dirX ? 0 : PANHINT_LENGTH_CONSTANT), endy - (dirX ? PANHINT_LENGTH_CONSTANT : 0));
|
||||
ctx.lineTo(endx + (dirX ? 0 : PANHINT_LENGTH_CONSTANT), endy + (dirX ? PANHINT_LENGTH_CONSTANT : 0));
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
plot.getTouchedAxis = function(touchPointX, touchPointY) {
|
||||
var ec = plot.getPlaceholder().offset();
|
||||
ec.left = touchPointX - ec.left;
|
||||
ec.top = touchPointY - ec.top;
|
||||
|
||||
var axis = plot.getXAxes().concat(plot.getYAxes()).filter(function (axis) {
|
||||
var box = axis.box;
|
||||
if (box !== undefined) {
|
||||
return (ec.left > box.left) && (ec.left < box.left + box.width) &&
|
||||
(ec.top > box.top) && (ec.top < box.top + box.height);
|
||||
}
|
||||
});
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
plot.hooks.drawOverlay.push(drawOverlay);
|
||||
plot.hooks.bindEvents.push(bindEvents);
|
||||
plot.hooks.shutdown.push(shutdown);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'navigate',
|
||||
version: '1.3'
|
||||
});
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user