Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** jqPlot* Pure JavaScript plotting plugin using jQuery** Version: 1.0.8* Revision: 1250** Copyright (c) 2009-2013 Chris Leonello* jqPlot is currently available for use in all personal or commercial projects* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can* choose the license that best suits your project and use it accordingly.** Although not required, the author would appreciate an email letting him* know of any substantial use of jqPlot. You can reach the author at:* chris at jqplot dot com or see http://www.jqplot.com/info.php .** If you are feeling kind and generous, consider supporting the project by* making a donation at: http://www.jqplot.com/donate.php .** sprintf functions contained in jqplot.sprintf.js by Ash Searle:** version 2007.04.27* author Ash Searle* http://hexmen.com/blog/2007/03/printf-sprintf/* http://hexmen.com/js/sprintf.js* The author (Ash Searle) has placed this code in the public domain:* "This code is unrestricted: you are free to use it however you like."**/(function($) {var objCounter = 0;// class: $.jqplot.CanvasOverlay$.jqplot.CanvasOverlay = function(opts){var options = opts || {};this.options = {show: $.jqplot.config.enablePlugins,deferDraw: false};// prop: objectsthis.objects = [];this.objectNames = [];this.canvas = null;this.markerRenderer = new $.jqplot.MarkerRenderer({style:'line'});this.markerRenderer.init();this.highlightObjectIndex = null;if (options.objects) {var objs = options.objects,obj;for (var i=0; i<objs.length; i++) {obj = objs[i];for (var n in obj) {switch (n) {case 'line':this.addLine(obj[n]);break;case 'horizontalLine':this.addHorizontalLine(obj[n]);break;case 'dashedHorizontalLine':this.addDashedHorizontalLine(obj[n]);break;case 'verticalLine':this.addVerticalLine(obj[n]);break;case 'dashedVerticalLine':this.addDashedVerticalLine(obj[n]);break;case 'rectangle':this.addRectangle(obj[n]);break;default:break;}}}}$.extend(true, this.options, options);};// called with scope of a plot object$.jqplot.CanvasOverlay.postPlotInit = function (target, data, opts) {var options = opts || {};// add a canvasOverlay attribute to the plotthis.plugins.canvasOverlay = new $.jqplot.CanvasOverlay(options.canvasOverlay);};function LineBase() {this.uid = null;this.type = null;this.gridStart = null;this.gridStop = null;this.tooltipWidthFactor = 0;this.options = {// prop: name// Optional name for the overlay object.// Can be later used to retrieve the object by name.name: null,// prop: show// true to show (draw), false to not draw.show: true,// prop: lineWidth// Width of the line.lineWidth: 2,// prop: lineCap// Type of ending placed on the line ['round', 'butt', 'square']lineCap: 'round',// prop: color// color of the linecolor: '#666666',// prop: shadow// whether or not to draw a shadow on the lineshadow: true,// prop: shadowAngle// Shadow angle in degreesshadowAngle: 45,// prop: shadowOffset// Shadow offset from line in pixelsshadowOffset: 1,// prop: shadowDepth// Number of times shadow is stroked, each stroke offset shadowOffset from the last.shadowDepth: 3,// prop: shadowAlpha// Alpha channel transparency of shadow. 0 = transparent.shadowAlpha: '0.07',// prop: xaxis// X axis to use for positioning/scaling the line.xaxis: 'xaxis',// prop: yaxis// Y axis to use for positioning/scaling the line.yaxis: 'yaxis',// prop: showTooltip// Show a tooltip with data point values.showTooltip: false,// prop: showTooltipPrecision// Controls how close to line cursor must be to show tooltip.// Higher number = closer to line, lower number = farther from line.// 1.0 = cursor must be over line.showTooltipPrecision: 0.6,// prop: tooltipLocation// Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'tooltipLocation: 'nw',// prop: fadeTooltip// true = fade in/out tooltip, flase = show/hide tooltipfadeTooltip: true,// prop: tooltipFadeSpeed// 'slow', 'def', 'fast', or number of milliseconds.tooltipFadeSpeed: "fast",// prop: tooltipOffset// Pixel offset of tooltip from the highlight.tooltipOffset: 4,// prop: tooltipFormatString// Format string passed the x and y values of the cursor on the line.// e.g., 'Dogs: %.2f, Cats: %d'.tooltipFormatString: '%d, %d'};}function Rectangle(options) {LineBase.call(this);this.type = 'rectangle';var opts = {// prop: xmin// x value for the start of the line, null to scale to axis min.xmin: null,// prop: xmax// x value for the end of the line, null to scale to axis max.xmax: null,// prop xOffset// offset ends of the line inside the grid. NumberxOffset: '6px', // number or string. Number interpreted as units, string as pixels.xminOffset: null,xmaxOffset: null,ymin: null,ymax: null,yOffset: '6px', // number or string. Number interpreted as units, string as pixels.yminOffset: null,ymaxOffset: null};$.extend(true, this.options, opts, options);if (this.options.showTooltipPrecision < 0.01) {this.options.showTooltipPrecision = 0.01;}}Rectangle.prototype = new LineBase();Rectangle.prototype.constructor = Rectangle;/*** Class: Line* A straight line.*/function Line(options) {LineBase.call(this);this.type = 'line';var opts = {// prop: start// [x, y] coordinates for the start of the line.start: [],// prop: stop// [x, y] coordinates for the end of the line.stop: []};$.extend(true, this.options, opts, options);if (this.options.showTooltipPrecision < 0.01) {this.options.showTooltipPrecision = 0.01;}}Line.prototype = new LineBase();Line.prototype.constructor = Line;/*** Class: HorizontalLine* A straight horizontal line.*/function HorizontalLine(options) {LineBase.call(this);this.type = 'horizontalLine';var opts = {// prop: y// y value to position the liney: null,// prop: xmin// x value for the start of the line, null to scale to axis min.xmin: null,// prop: xmax// x value for the end of the line, null to scale to axis max.xmax: null,// prop xOffset// offset ends of the line inside the grid. NumberxOffset: '6px', // number or string. Number interpreted as units, string as pixels.xminOffset: null,xmaxOffset: null};$.extend(true, this.options, opts, options);if (this.options.showTooltipPrecision < 0.01) {this.options.showTooltipPrecision = 0.01;}}HorizontalLine.prototype = new LineBase();HorizontalLine.prototype.constructor = HorizontalLine;/*** Class: DashedHorizontalLine* A straight dashed horizontal line.*/function DashedHorizontalLine(options) {LineBase.call(this);this.type = 'dashedHorizontalLine';var opts = {y: null,xmin: null,xmax: null,xOffset: '6px', // number or string. Number interpreted as units, string as pixels.xminOffset: null,xmaxOffset: null,// prop: dashPattern// Array of line, space settings in pixels.// Default is 8 pixel of line, 8 pixel of space.// Note, limit to a 2 element array b/c of bug with higher order arrays.dashPattern: [8,8]};$.extend(true, this.options, opts, options);if (this.options.showTooltipPrecision < 0.01) {this.options.showTooltipPrecision = 0.01;}}DashedHorizontalLine.prototype = new LineBase();DashedHorizontalLine.prototype.constructor = DashedHorizontalLine;/*** Class: VerticalLine* A straight vertical line.*/function VerticalLine(options) {LineBase.call(this);this.type = 'verticalLine';var opts = {x: null,ymin: null,ymax: null,yOffset: '6px', // number or string. Number interpreted as units, string as pixels.yminOffset: null,ymaxOffset: null};$.extend(true, this.options, opts, options);if (this.options.showTooltipPrecision < 0.01) {this.options.showTooltipPrecision = 0.01;}}VerticalLine.prototype = new LineBase();VerticalLine.prototype.constructor = VerticalLine;/*** Class: DashedVerticalLine* A straight dashed vertical line.*/function DashedVerticalLine(options) {LineBase.call(this);this.type = 'dashedVerticalLine';this.start = null;this.stop = null;var opts = {x: null,ymin: null,ymax: null,yOffset: '6px', // number or string. Number interpreted as units, string as pixels.yminOffset: null,ymaxOffset: null,// prop: dashPattern// Array of line, space settings in pixels.// Default is 8 pixel of line, 8 pixel of space.// Note, limit to a 2 element array b/c of bug with higher order arrays.dashPattern: [8,8]};$.extend(true, this.options, opts, options);if (this.options.showTooltipPrecision < 0.01) {this.options.showTooltipPrecision = 0.01;}}DashedVerticalLine.prototype = new LineBase();DashedVerticalLine.prototype.constructor = DashedVerticalLine;$.jqplot.CanvasOverlay.prototype.addLine = function(opts) {var line = new Line(opts);line.uid = objCounter++;this.objects.push(line);this.objectNames.push(line.options.name);};$.jqplot.CanvasOverlay.prototype.addHorizontalLine = function(opts) {var line = new HorizontalLine(opts);line.uid = objCounter++;this.objects.push(line);this.objectNames.push(line.options.name);};$.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine = function(opts) {var line = new DashedHorizontalLine(opts);line.uid = objCounter++;this.objects.push(line);this.objectNames.push(line.options.name);};$.jqplot.CanvasOverlay.prototype.addVerticalLine = function(opts) {var line = new VerticalLine(opts);line.uid = objCounter++;this.objects.push(line);this.objectNames.push(line.options.name);};$.jqplot.CanvasOverlay.prototype.addDashedVerticalLine = function(opts) {var line = new DashedVerticalLine(opts);line.uid = objCounter++;this.objects.push(line);this.objectNames.push(line.options.name);};$.jqplot.CanvasOverlay.prototype.addRectangle = function(opts) {var line = new Rectangle(opts);line.uid = objCounter++;this.objects.push(line);this.objectNames.push(line.options.name);};$.jqplot.CanvasOverlay.prototype.removeObject = function(idx) {// check if integer, remove by indexif ($.type(idx) == 'number') {this.objects.splice(idx, 1);this.objectNames.splice(idx, 1);}// if string, remove by nameelse {var id = $.inArray(idx, this.objectNames);if (id != -1) {this.objects.splice(id, 1);this.objectNames.splice(id, 1);}}};$.jqplot.CanvasOverlay.prototype.getObject = function(idx) {// check if integer, remove by indexif ($.type(idx) == 'number') {return this.objects[idx];}// if string, remove by nameelse {var id = $.inArray(idx, this.objectNames);if (id != -1) {return this.objects[id];}}};// Set get as alias for getObject.$.jqplot.CanvasOverlay.prototype.get = $.jqplot.CanvasOverlay.prototype.getObject;$.jqplot.CanvasOverlay.prototype.clear = function(plot) {this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());};$.jqplot.CanvasOverlay.prototype.draw = function(plot) {var obj,objs = this.objects,mr = this.markerRenderer,start,stop;if (this.options.show) {this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());for (var k=0; k<objs.length; k++) {obj = objs[k];var opts = $.extend(true, {}, obj.options);if (obj.options.show) {// style and shadow properties should be set before// every draw of marker renderer.mr.shadow = obj.options.shadow;obj.tooltipWidthFactor = obj.options.lineWidth / obj.options.showTooltipPrecision;switch (obj.type) {case 'line':// style and shadow properties should be set before// every draw of marker renderer.mr.style = 'line';opts.closePath = false;start = [plot.axes[obj.options.xaxis].series_u2p(obj.options.start[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.start[1])];stop = [plot.axes[obj.options.xaxis].series_u2p(obj.options.stop[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.stop[1])];obj.gridStart = start;obj.gridStop = stop;mr.draw(start, stop, this.canvas._ctx, opts);break;case 'horizontalLine':// style and shadow properties should be set before// every draw of marker renderer.if (obj.options.y != null) {mr.style = 'line';opts.closePath = false;var xaxis = plot.axes[obj.options.xaxis],xstart,xstop,y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),xminoff = obj.options.xminOffset || obj.options.xOffset,xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;if (obj.options.xmin != null) {xstart = xaxis.series_u2p(obj.options.xmin);}else if (xminoff != null) {if ($.type(xminoff) == "number") {xstart = xaxis.series_u2p(xaxis.min + xminoff);}else if ($.type(xminoff) == "string") {xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);}}if (obj.options.xmax != null) {xstop = xaxis.series_u2p(obj.options.xmax);}else if (xmaxoff != null) {if ($.type(xmaxoff) == "number") {xstop = xaxis.series_u2p(xaxis.max - xmaxoff);}else if ($.type(xmaxoff) == "string") {xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);}}if (xstop != null && xstart != null) {obj.gridStart = [xstart, y];obj.gridStop = [xstop, y];mr.draw([xstart, y], [xstop, y], this.canvas._ctx, opts);}}break;case 'dashedHorizontalLine':var dashPat = obj.options.dashPattern;var dashPatLen = 0;for (var i=0; i<dashPat.length; i++) {dashPatLen += dashPat[i];}// style and shadow properties should be set before// every draw of marker renderer.if (obj.options.y != null) {mr.style = 'line';opts.closePath = false;var xaxis = plot.axes[obj.options.xaxis],xstart,xstop,y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),xminoff = obj.options.xminOffset || obj.options.xOffset,xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;if (obj.options.xmin != null) {xstart = xaxis.series_u2p(obj.options.xmin);}else if (xminoff != null) {if ($.type(xminoff) == "number") {xstart = xaxis.series_u2p(xaxis.min + xminoff);}else if ($.type(xminoff) == "string") {xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);}}if (obj.options.xmax != null) {xstop = xaxis.series_u2p(obj.options.xmax);}else if (xmaxoff != null) {if ($.type(xmaxoff) == "number") {xstop = xaxis.series_u2p(xaxis.max - xmaxoff);}else if ($.type(xmaxoff) == "string") {xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);}}if (xstop != null && xstart != null) {obj.gridStart = [xstart, y];obj.gridStop = [xstop, y];var numDash = Math.ceil((xstop - xstart)/dashPatLen);var b=xstart, e;for (var i=0; i<numDash; i++) {for (var j=0; j<dashPat.length; j+=2) {e = b+dashPat[j];mr.draw([b, y], [e, y], this.canvas._ctx, opts);b += dashPat[j];if (j < dashPat.length-1) {b += dashPat[j+1];}}}}}break;case 'verticalLine':// style and shadow properties should be set before// every draw of marker renderer.if (obj.options.x != null) {mr.style = 'line';opts.closePath = false;var yaxis = plot.axes[obj.options.yaxis],ystart,ystop,x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),yminoff = obj.options.yminOffset || obj.options.yOffset,ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;if (obj.options.ymin != null) {ystart = yaxis.series_u2p(obj.options.ymin);}else if (yminoff != null) {if ($.type(yminoff) == "number") {ystart = yaxis.series_u2p(yaxis.min - yminoff);}else if ($.type(yminoff) == "string") {ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);}}if (obj.options.ymax != null) {ystop = yaxis.series_u2p(obj.options.ymax);}else if (ymaxoff != null) {if ($.type(ymaxoff) == "number") {ystop = yaxis.series_u2p(yaxis.max + ymaxoff);}else if ($.type(ymaxoff) == "string") {ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);}}if (ystop != null && ystart != null) {obj.gridStart = [x, ystart];obj.gridStop = [x, ystop];mr.draw([x, ystart], [x, ystop], this.canvas._ctx, opts);}}break;case 'dashedVerticalLine':var dashPat = obj.options.dashPattern;var dashPatLen = 0;for (var i=0; i<dashPat.length; i++) {dashPatLen += dashPat[i];}// style and shadow properties should be set before// every draw of marker renderer.if (obj.options.x != null) {mr.style = 'line';opts.closePath = false;var yaxis = plot.axes[obj.options.yaxis],ystart,ystop,x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),yminoff = obj.options.yminOffset || obj.options.yOffset,ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;if (obj.options.ymin != null) {ystart = yaxis.series_u2p(obj.options.ymin);}else if (yminoff != null) {if ($.type(yminoff) == "number") {ystart = yaxis.series_u2p(yaxis.min - yminoff);}else if ($.type(yminoff) == "string") {ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);}}if (obj.options.ymax != null) {ystop = yaxis.series_u2p(obj.options.ymax);}else if (ymaxoff != null) {if ($.type(ymaxoff) == "number") {ystop = yaxis.series_u2p(yaxis.max + ymaxoff);}else if ($.type(ymaxoff) == "string") {ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);}}if (ystop != null && ystart != null) {obj.gridStart = [x, ystart];obj.gridStop = [x, ystop];var numDash = Math.ceil((ystart - ystop)/dashPatLen);var firstDashAdjust = ((numDash * dashPatLen) - (ystart - ystop))/2.0;var b=ystart, e, bs, es;for (var i=0; i<numDash; i++) {for (var j=0; j<dashPat.length; j+=2) {e = b - dashPat[j];if (e < ystop) {e = ystop;}if (b < ystop) {b = ystop;}// es = e;// if (i == 0) {// es += firstDashAdjust;// }mr.draw([x, b], [x, e], this.canvas._ctx, opts);b -= dashPat[j];if (j < dashPat.length-1) {b -= dashPat[j+1];}}}}}break;case 'rectangle':// style and shadow properties should be set before// every draw of marker renderer.mr.style = 'line';opts.closePath = true;var xaxis = plot.axes[obj.options.xaxis],xstart,xstop,y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),xminoff = obj.options.xminOffset || obj.options.xOffset,xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;if (obj.options.xmin != null) {xstart = xaxis.series_u2p(obj.options.xmin);}else if (xminoff != null) {if ($.type(xminoff) == "number") {xstart = xaxis.series_u2p(xaxis.min + xminoff);}else if ($.type(xminoff) == "string") {xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);}}if (obj.options.xmax != null) {xstop = xaxis.series_u2p(obj.options.xmax);}else if (xmaxoff != null) {if ($.type(xmaxoff) == "number") {xstop = xaxis.series_u2p(xaxis.max - xmaxoff);}else if ($.type(xmaxoff) == "string") {xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);}}var yaxis = plot.axes[obj.options.yaxis],ystart,ystop,x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),yminoff = obj.options.yminOffset || obj.options.yOffset,ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;if (obj.options.ymin != null) {ystart = yaxis.series_u2p(obj.options.ymin);}else if (yminoff != null) {if ($.type(yminoff) == "number") {ystart = yaxis.series_u2p(yaxis.min - yminoff);}else if ($.type(yminoff) == "string") {ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);}}if (obj.options.ymax != null) {ystop = yaxis.series_u2p(obj.options.ymax);}else if (ymaxoff != null) {if ($.type(ymaxoff) == "number") {ystop = yaxis.series_u2p(yaxis.max + ymaxoff);}else if ($.type(ymaxoff) == "string") {ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);}}if (xstop != null && xstart != null && ystop != null && ystart != null) {obj.gridStart = [xstart, ystart];obj.gridStop = [xstop, ystop];this.canvas._ctx.fillStyle = obj.options.color;this.canvas._ctx.fillRect(xstart, ystart, xstop - xstart, ystop - ystart);}break;default:break;}}}}};// called within context of plot// create a canvas which we can draw on.// insert it before the eventCanvas, so eventCanvas will still capture events.$.jqplot.CanvasOverlay.postPlotDraw = function() {var co = this.plugins.canvasOverlay;// Memory Leaks patchif (co && co.highlightCanvas) {co.highlightCanvas.resetCanvas();co.highlightCanvas = null;}co.canvas = new $.jqplot.GenericCanvas();this.eventCanvas._elem.before(co.canvas.createElement(this._gridPadding, 'jqplot-overlayCanvas-canvas', this._plotDimensions, this));co.canvas.setContext();if (!co.deferDraw) {co.draw(this);}var elem = document.createElement('div');co._tooltipElem = $(elem);elem = null;co._tooltipElem.addClass('jqplot-canvasOverlay-tooltip');co._tooltipElem.css({position:'absolute', display:'none'});this.eventCanvas._elem.before(co._tooltipElem);this.eventCanvas._elem.bind('mouseleave', { elem: co._tooltipElem }, function (ev) { ev.data.elem.hide(); });var co = null;};function showTooltip(plot, obj, gridpos, datapos) {var co = plot.plugins.canvasOverlay;var elem = co._tooltipElem;var opts = obj.options, x, y;elem.html($.jqplot.sprintf(opts.tooltipFormatString, datapos[0], datapos[1]));switch (opts.tooltipLocation) {case 'nw':x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);break;case 'n':x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);break;case 'ne':x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);break;case 'e':x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;break;case 'se':x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;break;case 's':x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;break;case 'sw':x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;break;case 'w':x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;break;default: // same as 'nw'x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);break;}elem.css('left', x);elem.css('top', y);if (opts.fadeTooltip) {// Fix for stacked up animations. Thnanks Trevor!elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);}else {elem.show();}elem = null;}function isNearLine(point, lstart, lstop, width) {// r is point to test, p and q are end points.var rx = point[0];var ry = point[1];var px = Math.round(lstop[0]);var py = Math.round(lstop[1]);var qx = Math.round(lstart[0]);var qy = Math.round(lstart[1]);var l = Math.sqrt(Math.pow(px-qx, 2) + Math.pow(py-qy, 2));// scale error term by length of line.var eps = width*l;var res = Math.abs((qx-px) * (ry-py) - (qy-py) * (rx-px));var ret = (res < eps) ? true : false;return ret;}function isNearRectangle(point, lstart, lstop, width) {// r is point to test, p and q are end points.var rx = point[0];var ry = point[1];var px = Math.round(lstop[0]);var py = Math.round(lstop[1]);var qx = Math.round(lstart[0]);var qy = Math.round(lstart[1]);var temp;if (px > qx) { temp = px; px = qx; qx = temp; }if (py > qy) { temp = py; py = qy; qy = temp; }var ret = (rx >= px && rx <= qx && ry >= py && ry <= qy);return ret;}function handleMove(ev, gridpos, datapos, neighbor, plot) {var co = plot.plugins.canvasOverlay;var objs = co.objects;var l = objs.length;var obj, haveHighlight=false;var elem;for (var i=0; i<l; i++) {obj = objs[i];if (obj.options.showTooltip) {var n;if (obj.type === 'rectangle') {n = isNearRectangle([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor);} else {n = isNearLine([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor);}datapos = [plot.axes[obj.options.xaxis].series_p2u(gridpos.x), plot.axes[obj.options.yaxis].series_p2u(gridpos.y)];// cases:// near line, no highlighting// near line, highliting on this line// near line, highlighting another line// not near any line, highlighting// not near any line, no highlighting// near line, not currently highlightingif (n && co.highlightObjectIndex == null) {switch (obj.type) {case 'line':showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);break;case 'horizontalLine':case 'dashedHorizontalLine':showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);break;case 'verticalLine':case 'dashedVerticalLine':showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);break;case 'rectangle':showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);break;default:break;}co.highlightObjectIndex = i;haveHighlight = true;break;}// near line, highlighting another line.else if (n && co.highlightObjectIndex !== i) {// turn off tooltip.elem = co._tooltipElem;if (obj.fadeTooltip) {elem.fadeOut(obj.tooltipFadeSpeed);}else {elem.hide();}// turn on right tooltip.switch (obj.type) {case 'line':showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);break;case 'horizontalLine':case 'dashedHorizontalLine':showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);break;case 'verticalLine':case 'dashedVerticalLine':showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);break;case 'rectangle':showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);break;default:break;}co.highlightObjectIndex = i;haveHighlight = true;break;}// near line, already highlighting this line, updateelse if (n) {switch (obj.type) {case 'line':showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);break;case 'horizontalLine':case 'dashedHorizontalLine':showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);break;case 'verticalLine':case 'dashedVerticalLine':showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);break;case 'rectangle':showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);break;default:break;}haveHighlight = true;break;}}}// check if we are highlighting and not near a line, turn it off.if (!haveHighlight && co.highlightObjectIndex !== null) {elem = co._tooltipElem;obj = co.getObject(co.highlightObjectIndex);if (obj.fadeTooltip) {elem.fadeOut(obj.tooltipFadeSpeed);}else {elem.hide();}co.highlightObjectIndex = null;}}$.jqplot.postInitHooks.push($.jqplot.CanvasOverlay.postPlotInit);$.jqplot.postDrawHooks.push($.jqplot.CanvasOverlay.postPlotDraw);$.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);})(jQuery);