1 | /** |
---|
2 | * jqPlot |
---|
3 | * Pure JavaScript plotting plugin using jQuery |
---|
4 | * |
---|
5 | * Version: 1.0.0b2_r1012 |
---|
6 | * |
---|
7 | * Copyright (c) 2009-2011 Chris Leonello |
---|
8 | * jqPlot is currently available for use in all personal or commercial projects |
---|
9 | * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL |
---|
10 | * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can |
---|
11 | * choose the license that best suits your project and use it accordingly. |
---|
12 | * |
---|
13 | * Although not required, the author would appreciate an email letting him |
---|
14 | * know of any substantial use of jqPlot. You can reach the author at: |
---|
15 | * chris at jqplot dot com or see http://www.jqplot.com/info.php . |
---|
16 | * |
---|
17 | * If you are feeling kind and generous, consider supporting the project by |
---|
18 | * making a donation at: http://www.jqplot.com/donate.php . |
---|
19 | * |
---|
20 | * sprintf functions contained in jqplot.sprintf.js by Ash Searle: |
---|
21 | * |
---|
22 | * version 2007.04.27 |
---|
23 | * author Ash Searle |
---|
24 | * http://hexmen.com/blog/2007/03/printf-sprintf/ |
---|
25 | * http://hexmen.com/js/sprintf.js |
---|
26 | * The author (Ash Searle) has placed this code in the public domain: |
---|
27 | * "This code is unrestricted: you are free to use it however you like." |
---|
28 | * |
---|
29 | */ |
---|
30 | (function($) { |
---|
31 | |
---|
32 | /** |
---|
33 | * Class: $.jqplot.Cursor |
---|
34 | * Plugin class representing the cursor as displayed on the plot. |
---|
35 | */ |
---|
36 | $.jqplot.Cursor = function(options) { |
---|
37 | // Group: Properties |
---|
38 | // |
---|
39 | // prop: style |
---|
40 | // CSS spec for cursor style |
---|
41 | this.style = 'crosshair'; |
---|
42 | this.previousCursor = 'auto'; |
---|
43 | // prop: show |
---|
44 | // wether to show the cursor or not. |
---|
45 | this.show = $.jqplot.config.enablePlugins; |
---|
46 | // prop: showTooltip |
---|
47 | // show a cursor position tooltip. Location of the tooltip |
---|
48 | // will be controlled by followMouse and tooltipLocation. |
---|
49 | this.showTooltip = true; |
---|
50 | // prop: followMouse |
---|
51 | // Tooltip follows the mouse, it is not at a fixed location. |
---|
52 | // Tooltip will show on the grid at the location given by |
---|
53 | // tooltipLocation, offset from the grid edge by tooltipOffset. |
---|
54 | this.followMouse = false; |
---|
55 | // prop: tooltipLocation |
---|
56 | // Where to position tooltip. If followMouse is true, this is |
---|
57 | // relative to the cursor, otherwise, it is relative to the grid. |
---|
58 | // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' |
---|
59 | this.tooltipLocation = 'se'; |
---|
60 | // prop: tooltipOffset |
---|
61 | // Pixel offset of tooltip from the grid boudaries or cursor center. |
---|
62 | this.tooltipOffset = 6; |
---|
63 | // prop: showTooltipGridPosition |
---|
64 | // show the grid pixel coordinates of the mouse. |
---|
65 | this.showTooltipGridPosition = false; |
---|
66 | // prop: showTooltipUnitPosition |
---|
67 | // show the unit (data) coordinates of the mouse. |
---|
68 | this.showTooltipUnitPosition = true; |
---|
69 | // prop: showTooltipDataPosition |
---|
70 | // Used with showVerticalLine to show intersecting data points in the tooltip. |
---|
71 | this.showTooltipDataPosition = false; |
---|
72 | // prop: tooltipFormatString |
---|
73 | // sprintf format string for the tooltip. |
---|
74 | // Uses Ash Searle's javascript sprintf implementation |
---|
75 | // found here: http://hexmen.com/blog/2007/03/printf-sprintf/ |
---|
76 | // See http://perldoc.perl.org/functions/sprintf.html for reference |
---|
77 | // Note, if showTooltipDataPosition is true, the default tooltipFormatString |
---|
78 | // will be set to the cursorLegendFormatString, not the default given here. |
---|
79 | this.tooltipFormatString = '%.4P, %.4P'; |
---|
80 | // prop: useAxesFormatters |
---|
81 | // Use the x and y axes formatters to format the text in the tooltip. |
---|
82 | this.useAxesFormatters = true; |
---|
83 | // prop: tooltipAxisGroups |
---|
84 | // Show position for the specified axes. |
---|
85 | // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']] |
---|
86 | // Default is to compute automatically for all visible axes. |
---|
87 | this.tooltipAxisGroups = []; |
---|
88 | // prop: zoom |
---|
89 | // Enable plot zooming. |
---|
90 | this.zoom = false; |
---|
91 | // zoomProxy and zoomTarget properties are not directly set by user. |
---|
92 | // They Will be set through call to zoomProxy method. |
---|
93 | this.zoomProxy = false; |
---|
94 | this.zoomTarget = false; |
---|
95 | // prop: looseZoom |
---|
96 | // Will expand zoom range to provide more rounded tick values. |
---|
97 | // Works only with linear, log and date axes. |
---|
98 | this.looseZoom = true; |
---|
99 | // prop: clickReset |
---|
100 | // Will reset plot zoom if single click on plot without drag. |
---|
101 | this.clickReset = false; |
---|
102 | // prop: dblClickReset |
---|
103 | // Will reset plot zoom if double click on plot without drag. |
---|
104 | this.dblClickReset = true; |
---|
105 | // prop: showVerticalLine |
---|
106 | // draw a vertical line across the plot which follows the cursor. |
---|
107 | // When the line is near a data point, a special legend and/or tooltip can |
---|
108 | // be updated with the data values. |
---|
109 | this.showVerticalLine = false; |
---|
110 | // prop: showHorizontalLine |
---|
111 | // draw a horizontal line across the plot which follows the cursor. |
---|
112 | this.showHorizontalLine = false; |
---|
113 | // prop: constrainZoomTo |
---|
114 | // 'none', 'x' or 'y' |
---|
115 | this.constrainZoomTo = 'none'; |
---|
116 | // // prop: autoscaleConstraint |
---|
117 | // // when a constrained axis is specified, true will |
---|
118 | // // auatoscale the adjacent axis. |
---|
119 | // this.autoscaleConstraint = true; |
---|
120 | this.shapeRenderer = new $.jqplot.ShapeRenderer(); |
---|
121 | this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}}; |
---|
122 | this._tooltipElem; |
---|
123 | this.zoomCanvas; |
---|
124 | this.cursorCanvas; |
---|
125 | // prop: intersectionThreshold |
---|
126 | // pixel distance from data point or marker to consider cursor lines intersecting with point. |
---|
127 | // If data point markers are not shown, this should be >= 1 or will often miss point intersections. |
---|
128 | this.intersectionThreshold = 2; |
---|
129 | // prop: showCursorLegend |
---|
130 | // Replace the plot legend with an enhanced legend displaying intersection information. |
---|
131 | this.showCursorLegend = false; |
---|
132 | // prop: cursorLegendFormatString |
---|
133 | // Format string used in the cursor legend. If showTooltipDataPosition is true, |
---|
134 | // this will also be the default format string used by tooltipFormatString. |
---|
135 | this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString; |
---|
136 | // whether the cursor is over the grid or not. |
---|
137 | this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null}; |
---|
138 | // prop: constrainOutsideZoom |
---|
139 | // True to limit actual zoom area to edges of grid, even when zooming |
---|
140 | // outside of plot area. That is, can't zoom out by mousing outside plot. |
---|
141 | this.constrainOutsideZoom = true; |
---|
142 | // prop: showTooltipOutsideZoom |
---|
143 | // True will keep updating the tooltip when zooming of the grid. |
---|
144 | this.showTooltipOutsideZoom = false; |
---|
145 | // true if mouse is over grid, false if not. |
---|
146 | this.onGrid = false; |
---|
147 | $.extend(true, this, options); |
---|
148 | }; |
---|
149 | |
---|
150 | $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s'; |
---|
151 | |
---|
152 | // called with scope of plot |
---|
153 | $.jqplot.Cursor.init = function (target, data, opts){ |
---|
154 | // add a cursor attribute to the plot |
---|
155 | var options = opts || {}; |
---|
156 | this.plugins.cursor = new $.jqplot.Cursor(options.cursor); |
---|
157 | var c = this.plugins.cursor; |
---|
158 | |
---|
159 | if (c.show) { |
---|
160 | $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]); |
---|
161 | $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]); |
---|
162 | $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]); |
---|
163 | |
---|
164 | if (c.showCursorLegend) { |
---|
165 | opts.legend = opts.legend || {}; |
---|
166 | opts.legend.renderer = $.jqplot.CursorLegendRenderer; |
---|
167 | opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString; |
---|
168 | opts.legend.show = true; |
---|
169 | } |
---|
170 | |
---|
171 | if (c.zoom) { |
---|
172 | $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]); |
---|
173 | |
---|
174 | if (c.clickReset) { |
---|
175 | $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]); |
---|
176 | } |
---|
177 | |
---|
178 | if (c.dblClickReset) { |
---|
179 | $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]); |
---|
180 | } |
---|
181 | } |
---|
182 | |
---|
183 | this.resetZoom = function() { |
---|
184 | var axes = this.axes; |
---|
185 | if (!c.zoomProxy) { |
---|
186 | for (var ax in axes) { |
---|
187 | axes[ax].reset(); |
---|
188 | axes[ax]._ticks = []; |
---|
189 | // fake out tick creation algorithm to make sure original auto |
---|
190 | // computed format string is used if _overrideFormatString is true |
---|
191 | if (c._zoom.axes[ax] !== undefined) { |
---|
192 | axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString; |
---|
193 | } |
---|
194 | } |
---|
195 | this.redraw(); |
---|
196 | } |
---|
197 | else { |
---|
198 | var ctx = this.plugins.cursor.zoomCanvas._ctx; |
---|
199 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
200 | ctx = null; |
---|
201 | } |
---|
202 | this.plugins.cursor._zoom.isZoomed = false; |
---|
203 | this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]); |
---|
204 | }; |
---|
205 | |
---|
206 | |
---|
207 | if (c.showTooltipDataPosition) { |
---|
208 | c.showTooltipUnitPosition = false; |
---|
209 | c.showTooltipGridPosition = false; |
---|
210 | if (options.cursor.tooltipFormatString == undefined) { |
---|
211 | c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString; |
---|
212 | } |
---|
213 | } |
---|
214 | } |
---|
215 | }; |
---|
216 | |
---|
217 | // called with context of plot |
---|
218 | $.jqplot.Cursor.postDraw = function() { |
---|
219 | var c = this.plugins.cursor; |
---|
220 | |
---|
221 | // Memory Leaks patch |
---|
222 | if (c.zoomCanvas) { |
---|
223 | c.zoomCanvas.resetCanvas(); |
---|
224 | c.zoomCanvas = null; |
---|
225 | } |
---|
226 | |
---|
227 | if (c.cursorCanvas) { |
---|
228 | c.cursorCanvas.resetCanvas(); |
---|
229 | c.cursorCanvas = null; |
---|
230 | } |
---|
231 | |
---|
232 | if (c._tooltipElem) { |
---|
233 | c._tooltipElem.emptyForce(); |
---|
234 | c._tooltipElem = null; |
---|
235 | } |
---|
236 | |
---|
237 | |
---|
238 | if (c.zoom) { |
---|
239 | c.zoomCanvas = new $.jqplot.GenericCanvas(); |
---|
240 | this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this)); |
---|
241 | c.zoomCanvas.setContext(); |
---|
242 | } |
---|
243 | |
---|
244 | var elem = document.createElement('div'); |
---|
245 | c._tooltipElem = $(elem); |
---|
246 | elem = null; |
---|
247 | c._tooltipElem.addClass('jqplot-cursor-tooltip'); |
---|
248 | c._tooltipElem.css({position:'absolute', display:'none'}); |
---|
249 | |
---|
250 | |
---|
251 | if (c.zoomCanvas) { |
---|
252 | c.zoomCanvas._elem.before(c._tooltipElem); |
---|
253 | } |
---|
254 | |
---|
255 | else { |
---|
256 | this.eventCanvas._elem.before(c._tooltipElem); |
---|
257 | } |
---|
258 | |
---|
259 | if (c.showVerticalLine || c.showHorizontalLine) { |
---|
260 | c.cursorCanvas = new $.jqplot.GenericCanvas(); |
---|
261 | this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this)); |
---|
262 | c.cursorCanvas.setContext(); |
---|
263 | } |
---|
264 | |
---|
265 | // if we are showing the positions in unit coordinates, and no axes groups |
---|
266 | // were specified, create a default set. |
---|
267 | if (c.showTooltipUnitPosition){ |
---|
268 | if (c.tooltipAxisGroups.length === 0) { |
---|
269 | var series = this.series; |
---|
270 | var s; |
---|
271 | var temp = []; |
---|
272 | for (var i=0; i<series.length; i++) { |
---|
273 | s = series[i]; |
---|
274 | var ax = s.xaxis+','+s.yaxis; |
---|
275 | if ($.inArray(ax, temp) == -1) { |
---|
276 | temp.push(ax); |
---|
277 | } |
---|
278 | } |
---|
279 | for (var i=0; i<temp.length; i++) { |
---|
280 | c.tooltipAxisGroups.push(temp[i].split(',')); |
---|
281 | } |
---|
282 | } |
---|
283 | } |
---|
284 | }; |
---|
285 | |
---|
286 | // Group: methods |
---|
287 | // |
---|
288 | // method: $.jqplot.Cursor.zoomProxy |
---|
289 | // links targetPlot to controllerPlot so that plot zooming of |
---|
290 | // targetPlot will be controlled by zooming on the controllerPlot. |
---|
291 | // controllerPlot will not actually zoom, but acts as an |
---|
292 | // overview plot. Note, the zoom options must be set to true for |
---|
293 | // zoomProxy to work. |
---|
294 | $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) { |
---|
295 | var tc = targetPlot.plugins.cursor; |
---|
296 | var cc = controllerPlot.plugins.cursor; |
---|
297 | tc.zoomTarget = true; |
---|
298 | tc.zoom = true; |
---|
299 | tc.style = 'auto'; |
---|
300 | tc.dblClickReset = false; |
---|
301 | cc.zoom = true; |
---|
302 | cc.zoomProxy = true; |
---|
303 | |
---|
304 | controllerPlot.target.bind('jqplotZoom', plotZoom); |
---|
305 | controllerPlot.target.bind('jqplotResetZoom', plotReset); |
---|
306 | |
---|
307 | function plotZoom(ev, gridpos, datapos, plot, cursor) { |
---|
308 | tc.doZoom(gridpos, datapos, targetPlot, cursor); |
---|
309 | } |
---|
310 | |
---|
311 | function plotReset(ev, plot, cursor) { |
---|
312 | targetPlot.resetZoom(); |
---|
313 | } |
---|
314 | }; |
---|
315 | |
---|
316 | $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) { |
---|
317 | var axes = plot.axes; |
---|
318 | var cax = cursor._zoom.axes; |
---|
319 | if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) { |
---|
320 | for (var ax in axes) { |
---|
321 | // axes[ax]._ticks = []; |
---|
322 | // axes[ax].min = cax[ax].min; |
---|
323 | // axes[ax].max = cax[ax].max; |
---|
324 | // axes[ax].numberTicks = cax[ax].numberTicks; |
---|
325 | // axes[ax].tickInterval = cax[ax].tickInterval; |
---|
326 | // // for date axes |
---|
327 | // axes[ax].daTickInterval = cax[ax].daTickInterval; |
---|
328 | axes[ax].reset(); |
---|
329 | axes[ax]._ticks = []; |
---|
330 | // fake out tick creation algorithm to make sure original auto |
---|
331 | // computed format string is used if _overrideFormatString is true |
---|
332 | axes[ax]._autoFormatString = cax[ax].tickFormatString; |
---|
333 | } |
---|
334 | plot.redraw(); |
---|
335 | cursor._zoom.isZoomed = false; |
---|
336 | } |
---|
337 | else { |
---|
338 | var ctx = cursor.zoomCanvas._ctx; |
---|
339 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
340 | ctx = null; |
---|
341 | } |
---|
342 | plot.target.trigger('jqplotResetZoom', [plot, cursor]); |
---|
343 | }; |
---|
344 | |
---|
345 | $.jqplot.Cursor.resetZoom = function(plot) { |
---|
346 | plot.resetZoom(); |
---|
347 | }; |
---|
348 | |
---|
349 | $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) { |
---|
350 | var c = cursor; |
---|
351 | var axes = plot.axes; |
---|
352 | var zaxes = c._zoom.axes; |
---|
353 | var start = zaxes.start; |
---|
354 | var end = zaxes.end; |
---|
355 | var min, max, dp, span, |
---|
356 | newmin, newmax, curax, _numberTicks, ret; |
---|
357 | var ctx = plot.plugins.cursor.zoomCanvas._ctx; |
---|
358 | // don't zoom if zoom area is too small (in pixels) |
---|
359 | if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) { |
---|
360 | if (!plot.plugins.cursor.zoomProxy) { |
---|
361 | for (var ax in datapos) { |
---|
362 | // make a copy of the original axes to revert back. |
---|
363 | if (c._zoom.axes[ax] == undefined) { |
---|
364 | c._zoom.axes[ax] = {}; |
---|
365 | c._zoom.axes[ax].numberTicks = axes[ax].numberTicks; |
---|
366 | c._zoom.axes[ax].tickInterval = axes[ax].tickInterval; |
---|
367 | // for date axes... |
---|
368 | c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval; |
---|
369 | c._zoom.axes[ax].min = axes[ax].min; |
---|
370 | c._zoom.axes[ax].max = axes[ax].max; |
---|
371 | c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString : ''; |
---|
372 | } |
---|
373 | |
---|
374 | |
---|
375 | if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) { |
---|
376 | dp = datapos[ax]; |
---|
377 | if (dp != null) { |
---|
378 | if (dp > start[ax]) { |
---|
379 | newmin = start[ax]; |
---|
380 | newmax = dp; |
---|
381 | } |
---|
382 | else { |
---|
383 | span = start[ax] - dp; |
---|
384 | newmin = dp; |
---|
385 | newmax = start[ax]; |
---|
386 | } |
---|
387 | |
---|
388 | curax = axes[ax]; |
---|
389 | |
---|
390 | _numberTicks = null; |
---|
391 | |
---|
392 | // if aligning this axis, use number of ticks from previous axis. |
---|
393 | // Do I need to reset somehow if alignTicks is changed and then graph is replotted?? |
---|
394 | if (curax.alignTicks) { |
---|
395 | if (curax.name === 'x2axis' && plot.axes.xaxis.show) { |
---|
396 | _numberTicks = plot.axes.xaxis.numberTicks; |
---|
397 | } |
---|
398 | else if (curax.name.charAt(0) === 'y' && curax.name !== 'yaxis' && curax.name !== 'yMidAxis' && plot.axes.yaxis.show) { |
---|
399 | _numberTicks = plot.axes.yaxis.numberTicks; |
---|
400 | } |
---|
401 | } |
---|
402 | |
---|
403 | if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer )) { //} || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) { |
---|
404 | |
---|
405 | ret = $.jqplot.LinearTickGenerator(newmin, newmax, curax._scalefact, _numberTicks); |
---|
406 | |
---|
407 | // if new minimum is less than "true" minimum of axis display, adjust it |
---|
408 | if (axes[ax].tickInset && ret[0] < axes[ax].min + axes[ax].tickInset * axes[ax].tickInterval) { |
---|
409 | ret[0] += ret[4]; |
---|
410 | ret[2] -= 1; |
---|
411 | } |
---|
412 | |
---|
413 | // if new maximum is greater than "true" max of axis display, adjust it |
---|
414 | if (axes[ax].tickInset && ret[1] > axes[ax].max - axes[ax].tickInset * axes[ax].tickInterval) { |
---|
415 | ret[1] -= ret[4]; |
---|
416 | ret[2] -= 1; |
---|
417 | } |
---|
418 | |
---|
419 | // for log axes, don't fall below current minimum, this will look bad and can't have 0 in range anyway. |
---|
420 | if (axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer && ret[0] < axes[ax].min) { |
---|
421 | // remove a tick and shift min up |
---|
422 | ret[0] += ret[4]; |
---|
423 | ret[2] -= 1; |
---|
424 | } |
---|
425 | |
---|
426 | axes[ax].min = ret[0]; |
---|
427 | axes[ax].max = ret[1]; |
---|
428 | axes[ax]._autoFormatString = ret[3]; |
---|
429 | axes[ax].numberTicks = ret[2]; |
---|
430 | axes[ax].tickInterval = ret[4]; |
---|
431 | // for date axes... |
---|
432 | axes[ax].daTickInterval = [ret[4]/1000, 'seconds']; |
---|
433 | } |
---|
434 | else { |
---|
435 | axes[ax].min = newmin; |
---|
436 | axes[ax].max = newmax; |
---|
437 | axes[ax].tickInterval = null; |
---|
438 | axes[ax].numberTicks = null; |
---|
439 | // for date axes... |
---|
440 | axes[ax].daTickInterval = null; |
---|
441 | } |
---|
442 | |
---|
443 | axes[ax]._ticks = []; |
---|
444 | } |
---|
445 | } |
---|
446 | |
---|
447 | // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) { |
---|
448 | // dp = datapos[ax]; |
---|
449 | // if (dp != null) { |
---|
450 | // axes[ax].max == null; |
---|
451 | // axes[ax].min = null; |
---|
452 | // } |
---|
453 | // } |
---|
454 | } |
---|
455 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
456 | plot.redraw(); |
---|
457 | c._zoom.isZoomed = true; |
---|
458 | ctx = null; |
---|
459 | } |
---|
460 | plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]); |
---|
461 | } |
---|
462 | }; |
---|
463 | |
---|
464 | $.jqplot.preInitHooks.push($.jqplot.Cursor.init); |
---|
465 | $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw); |
---|
466 | |
---|
467 | function updateTooltip(gridpos, datapos, plot) { |
---|
468 | var c = plot.plugins.cursor; |
---|
469 | var s = ''; |
---|
470 | var addbr = false; |
---|
471 | if (c.showTooltipGridPosition) { |
---|
472 | s = gridpos.x+', '+gridpos.y; |
---|
473 | addbr = true; |
---|
474 | } |
---|
475 | if (c.showTooltipUnitPosition) { |
---|
476 | var g; |
---|
477 | for (var i=0; i<c.tooltipAxisGroups.length; i++) { |
---|
478 | g = c.tooltipAxisGroups[i]; |
---|
479 | if (addbr) { |
---|
480 | s += '<br />'; |
---|
481 | } |
---|
482 | if (c.useAxesFormatters) { |
---|
483 | var xf = plot.axes[g[0]]._ticks[0].formatter; |
---|
484 | var yf = plot.axes[g[1]]._ticks[0].formatter; |
---|
485 | var xfstr = plot.axes[g[0]]._ticks[0].formatString; |
---|
486 | var yfstr = plot.axes[g[1]]._ticks[0].formatString; |
---|
487 | s += xf(xfstr, datapos[g[0]]) + ', '+ yf(yfstr, datapos[g[1]]); |
---|
488 | } |
---|
489 | else { |
---|
490 | s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]); |
---|
491 | } |
---|
492 | addbr = true; |
---|
493 | } |
---|
494 | } |
---|
495 | |
---|
496 | if (c.showTooltipDataPosition) { |
---|
497 | var series = plot.series; |
---|
498 | var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); |
---|
499 | var addbr = false; |
---|
500 | |
---|
501 | for (var i = 0; i< series.length; i++) { |
---|
502 | if (series[i].show) { |
---|
503 | var idx = series[i].index; |
---|
504 | var label = series[i].label.toString(); |
---|
505 | var cellid = $.inArray(idx, ret.indices); |
---|
506 | var sx = undefined; |
---|
507 | var sy = undefined; |
---|
508 | if (cellid != -1) { |
---|
509 | var data = ret.data[cellid].data; |
---|
510 | if (c.useAxesFormatters) { |
---|
511 | var xf = series[i]._xaxis._ticks[0].formatter; |
---|
512 | var yf = series[i]._yaxis._ticks[0].formatter; |
---|
513 | var xfstr = series[i]._xaxis._ticks[0].formatString; |
---|
514 | var yfstr = series[i]._yaxis._ticks[0].formatString; |
---|
515 | sx = xf(xfstr, data[0]); |
---|
516 | sy = yf(yfstr, data[1]); |
---|
517 | } |
---|
518 | else { |
---|
519 | sx = data[0]; |
---|
520 | sy = data[1]; |
---|
521 | } |
---|
522 | if (addbr) { |
---|
523 | s += '<br />'; |
---|
524 | } |
---|
525 | s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy); |
---|
526 | addbr = true; |
---|
527 | } |
---|
528 | } |
---|
529 | } |
---|
530 | |
---|
531 | } |
---|
532 | c._tooltipElem.html(s); |
---|
533 | } |
---|
534 | |
---|
535 | function moveLine(gridpos, plot) { |
---|
536 | var c = plot.plugins.cursor; |
---|
537 | var ctx = c.cursorCanvas._ctx; |
---|
538 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
539 | if (c.showVerticalLine) { |
---|
540 | c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]); |
---|
541 | } |
---|
542 | if (c.showHorizontalLine) { |
---|
543 | c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]); |
---|
544 | } |
---|
545 | var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); |
---|
546 | if (c.showCursorLegend) { |
---|
547 | var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); |
---|
548 | for (var i=0; i<cells.length; i++) { |
---|
549 | var idx = $(cells[i]).data('seriesIndex'); |
---|
550 | var series = plot.series[idx]; |
---|
551 | var label = series.label.toString(); |
---|
552 | var cellid = $.inArray(idx, ret.indices); |
---|
553 | var sx = undefined; |
---|
554 | var sy = undefined; |
---|
555 | if (cellid != -1) { |
---|
556 | var data = ret.data[cellid].data; |
---|
557 | if (c.useAxesFormatters) { |
---|
558 | var xf = series._xaxis._ticks[0].formatter; |
---|
559 | var yf = series._yaxis._ticks[0].formatter; |
---|
560 | var xfstr = series._xaxis._ticks[0].formatString; |
---|
561 | var yfstr = series._yaxis._ticks[0].formatString; |
---|
562 | sx = xf(xfstr, data[0]); |
---|
563 | sy = yf(yfstr, data[1]); |
---|
564 | } |
---|
565 | else { |
---|
566 | sx = data[0]; |
---|
567 | sy = data[1]; |
---|
568 | } |
---|
569 | } |
---|
570 | if (plot.legend.escapeHtml) { |
---|
571 | $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); |
---|
572 | } |
---|
573 | else { |
---|
574 | $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); |
---|
575 | } |
---|
576 | } |
---|
577 | } |
---|
578 | ctx = null; |
---|
579 | } |
---|
580 | |
---|
581 | function getIntersectingPoints(plot, x, y) { |
---|
582 | var ret = {indices:[], data:[]}; |
---|
583 | var s, i, d0, d, j, r, p; |
---|
584 | var threshold; |
---|
585 | var c = plot.plugins.cursor; |
---|
586 | for (var i=0; i<plot.series.length; i++) { |
---|
587 | s = plot.series[i]; |
---|
588 | r = s.renderer; |
---|
589 | if (s.show) { |
---|
590 | threshold = c.intersectionThreshold; |
---|
591 | if (s.showMarker) { |
---|
592 | threshold += s.markerRenderer.size/2; |
---|
593 | } |
---|
594 | for (var j=0; j<s.gridData.length; j++) { |
---|
595 | p = s.gridData[j]; |
---|
596 | // check vertical line |
---|
597 | if (c.showVerticalLine) { |
---|
598 | if (Math.abs(x-p[0]) <= threshold) { |
---|
599 | ret.indices.push(i); |
---|
600 | ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}); |
---|
601 | } |
---|
602 | } |
---|
603 | } |
---|
604 | } |
---|
605 | } |
---|
606 | return ret; |
---|
607 | } |
---|
608 | |
---|
609 | function moveTooltip(gridpos, plot) { |
---|
610 | var c = plot.plugins.cursor; |
---|
611 | var elem = c._tooltipElem; |
---|
612 | switch (c.tooltipLocation) { |
---|
613 | case 'nw': |
---|
614 | var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; |
---|
615 | var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); |
---|
616 | break; |
---|
617 | case 'n': |
---|
618 | var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; |
---|
619 | var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); |
---|
620 | break; |
---|
621 | case 'ne': |
---|
622 | var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; |
---|
623 | var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); |
---|
624 | break; |
---|
625 | case 'e': |
---|
626 | var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; |
---|
627 | var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; |
---|
628 | break; |
---|
629 | case 'se': |
---|
630 | var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; |
---|
631 | var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; |
---|
632 | break; |
---|
633 | case 's': |
---|
634 | var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; |
---|
635 | var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; |
---|
636 | break; |
---|
637 | case 'sw': |
---|
638 | var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; |
---|
639 | var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; |
---|
640 | break; |
---|
641 | case 'w': |
---|
642 | var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; |
---|
643 | var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; |
---|
644 | break; |
---|
645 | default: |
---|
646 | var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; |
---|
647 | var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; |
---|
648 | break; |
---|
649 | } |
---|
650 | |
---|
651 | elem.css('left', x); |
---|
652 | elem.css('top', y); |
---|
653 | elem = null; |
---|
654 | } |
---|
655 | |
---|
656 | function positionTooltip(plot) { |
---|
657 | // fake a grid for positioning |
---|
658 | var grid = plot._gridPadding; |
---|
659 | var c = plot.plugins.cursor; |
---|
660 | var elem = c._tooltipElem; |
---|
661 | switch (c.tooltipLocation) { |
---|
662 | case 'nw': |
---|
663 | var a = grid.left + c.tooltipOffset; |
---|
664 | var b = grid.top + c.tooltipOffset; |
---|
665 | elem.css('left', a); |
---|
666 | elem.css('top', b); |
---|
667 | break; |
---|
668 | case 'n': |
---|
669 | var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; |
---|
670 | var b = grid.top + c.tooltipOffset; |
---|
671 | elem.css('left', a); |
---|
672 | elem.css('top', b); |
---|
673 | break; |
---|
674 | case 'ne': |
---|
675 | var a = grid.right + c.tooltipOffset; |
---|
676 | var b = grid.top + c.tooltipOffset; |
---|
677 | elem.css({right:a, top:b}); |
---|
678 | break; |
---|
679 | case 'e': |
---|
680 | var a = grid.right + c.tooltipOffset; |
---|
681 | var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; |
---|
682 | elem.css({right:a, top:b}); |
---|
683 | break; |
---|
684 | case 'se': |
---|
685 | var a = grid.right + c.tooltipOffset; |
---|
686 | var b = grid.bottom + c.tooltipOffset; |
---|
687 | elem.css({right:a, bottom:b}); |
---|
688 | break; |
---|
689 | case 's': |
---|
690 | var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; |
---|
691 | var b = grid.bottom + c.tooltipOffset; |
---|
692 | elem.css({left:a, bottom:b}); |
---|
693 | break; |
---|
694 | case 'sw': |
---|
695 | var a = grid.left + c.tooltipOffset; |
---|
696 | var b = grid.bottom + c.tooltipOffset; |
---|
697 | elem.css({left:a, bottom:b}); |
---|
698 | break; |
---|
699 | case 'w': |
---|
700 | var a = grid.left + c.tooltipOffset; |
---|
701 | var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; |
---|
702 | elem.css({left:a, top:b}); |
---|
703 | break; |
---|
704 | default: // same as 'se' |
---|
705 | var a = grid.right - c.tooltipOffset; |
---|
706 | var b = grid.bottom + c.tooltipOffset; |
---|
707 | elem.css({right:a, bottom:b}); |
---|
708 | break; |
---|
709 | } |
---|
710 | elem = null; |
---|
711 | } |
---|
712 | |
---|
713 | function handleClick (ev, gridpos, datapos, neighbor, plot) { |
---|
714 | ev.preventDefault(); |
---|
715 | ev.stopImmediatePropagation(); |
---|
716 | var c = plot.plugins.cursor; |
---|
717 | if (c.clickReset) { |
---|
718 | c.resetZoom(plot, c); |
---|
719 | } |
---|
720 | var sel = window.getSelection; |
---|
721 | if (document.selection && document.selection.empty) |
---|
722 | { |
---|
723 | document.selection.empty(); |
---|
724 | } |
---|
725 | else if (sel && !sel().isCollapsed) { |
---|
726 | sel().collapse(); |
---|
727 | } |
---|
728 | return false; |
---|
729 | } |
---|
730 | |
---|
731 | function handleDblClick (ev, gridpos, datapos, neighbor, plot) { |
---|
732 | ev.preventDefault(); |
---|
733 | ev.stopImmediatePropagation(); |
---|
734 | var c = plot.plugins.cursor; |
---|
735 | if (c.dblClickReset) { |
---|
736 | c.resetZoom(plot, c); |
---|
737 | } |
---|
738 | var sel = window.getSelection; |
---|
739 | if (document.selection && document.selection.empty) |
---|
740 | { |
---|
741 | document.selection.empty(); |
---|
742 | } |
---|
743 | else if (sel && !sel().isCollapsed) { |
---|
744 | sel().collapse(); |
---|
745 | } |
---|
746 | return false; |
---|
747 | } |
---|
748 | |
---|
749 | function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) { |
---|
750 | var c = plot.plugins.cursor; |
---|
751 | c.onGrid = false; |
---|
752 | if (c.show) { |
---|
753 | $(ev.target).css('cursor', c.previousCursor); |
---|
754 | if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) { |
---|
755 | c._tooltipElem.hide(); |
---|
756 | } |
---|
757 | if (c.zoom) { |
---|
758 | c._zoom.gridpos = gridpos; |
---|
759 | c._zoom.datapos = datapos; |
---|
760 | } |
---|
761 | if (c.showVerticalLine || c.showHorizontalLine) { |
---|
762 | var ctx = c.cursorCanvas._ctx; |
---|
763 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
764 | ctx = null; |
---|
765 | } |
---|
766 | if (c.showCursorLegend) { |
---|
767 | var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); |
---|
768 | for (var i=0; i<cells.length; i++) { |
---|
769 | var idx = $(cells[i]).data('seriesIndex'); |
---|
770 | var series = plot.series[idx]; |
---|
771 | var label = series.label.toString(); |
---|
772 | if (plot.legend.escapeHtml) { |
---|
773 | $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); |
---|
774 | } |
---|
775 | else { |
---|
776 | $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); |
---|
777 | } |
---|
778 | |
---|
779 | } |
---|
780 | } |
---|
781 | } |
---|
782 | } |
---|
783 | |
---|
784 | function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) { |
---|
785 | var c = plot.plugins.cursor; |
---|
786 | c.onGrid = true; |
---|
787 | if (c.show) { |
---|
788 | c.previousCursor = ev.target.style.cursor; |
---|
789 | ev.target.style.cursor = c.style; |
---|
790 | if (c.showTooltip) { |
---|
791 | updateTooltip(gridpos, datapos, plot); |
---|
792 | if (c.followMouse) { |
---|
793 | moveTooltip(gridpos, plot); |
---|
794 | } |
---|
795 | else { |
---|
796 | positionTooltip(plot); |
---|
797 | } |
---|
798 | c._tooltipElem.show(); |
---|
799 | } |
---|
800 | if (c.showVerticalLine || c.showHorizontalLine) { |
---|
801 | moveLine(gridpos, plot); |
---|
802 | } |
---|
803 | } |
---|
804 | |
---|
805 | } |
---|
806 | |
---|
807 | function handleMouseMove(ev, gridpos, datapos, neighbor, plot) { |
---|
808 | var c = plot.plugins.cursor; |
---|
809 | if (c.show) { |
---|
810 | if (c.showTooltip) { |
---|
811 | updateTooltip(gridpos, datapos, plot); |
---|
812 | if (c.followMouse) { |
---|
813 | moveTooltip(gridpos, plot); |
---|
814 | } |
---|
815 | } |
---|
816 | if (c.showVerticalLine || c.showHorizontalLine) { |
---|
817 | moveLine(gridpos, plot); |
---|
818 | } |
---|
819 | } |
---|
820 | } |
---|
821 | |
---|
822 | function getEventPosition(ev) { |
---|
823 | var plot = ev.data.plot; |
---|
824 | var go = plot.eventCanvas._elem.offset(); |
---|
825 | var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; |
---|
826 | ////// |
---|
827 | // TO DO: handle yMidAxis |
---|
828 | ////// |
---|
829 | var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null}; |
---|
830 | var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis']; |
---|
831 | var ax = plot.axes; |
---|
832 | var n, axis; |
---|
833 | for (n=11; n>0; n--) { |
---|
834 | axis = an[n-1]; |
---|
835 | if (ax[axis].show) { |
---|
836 | dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); |
---|
837 | } |
---|
838 | } |
---|
839 | |
---|
840 | return {offsets:go, gridPos:gridPos, dataPos:dataPos}; |
---|
841 | } |
---|
842 | |
---|
843 | function handleZoomMove(ev) { |
---|
844 | var plot = ev.data.plot; |
---|
845 | var c = plot.plugins.cursor; |
---|
846 | // don't do anything if not on grid. |
---|
847 | if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) { |
---|
848 | var ctx = c.zoomCanvas._ctx; |
---|
849 | var positions = getEventPosition(ev); |
---|
850 | var gridpos = positions.gridPos; |
---|
851 | var datapos = positions.dataPos; |
---|
852 | c._zoom.gridpos = gridpos; |
---|
853 | c._zoom.datapos = datapos; |
---|
854 | c._zoom.zooming = true; |
---|
855 | var xpos = gridpos.x; |
---|
856 | var ypos = gridpos.y; |
---|
857 | var height = ctx.canvas.height; |
---|
858 | var width = ctx.canvas.width; |
---|
859 | if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) { |
---|
860 | updateTooltip(gridpos, datapos, plot); |
---|
861 | if (c.followMouse) { |
---|
862 | moveTooltip(gridpos, plot); |
---|
863 | } |
---|
864 | } |
---|
865 | if (c.constrainZoomTo == 'x') { |
---|
866 | c._zoom.end = [xpos, height]; |
---|
867 | } |
---|
868 | else if (c.constrainZoomTo == 'y') { |
---|
869 | c._zoom.end = [width, ypos]; |
---|
870 | } |
---|
871 | else { |
---|
872 | c._zoom.end = [xpos, ypos]; |
---|
873 | } |
---|
874 | var sel = window.getSelection; |
---|
875 | if (document.selection && document.selection.empty) |
---|
876 | { |
---|
877 | document.selection.empty(); |
---|
878 | } |
---|
879 | else if (sel && !sel().isCollapsed) { |
---|
880 | sel().collapse(); |
---|
881 | } |
---|
882 | drawZoomBox.call(c); |
---|
883 | ctx = null; |
---|
884 | } |
---|
885 | } |
---|
886 | |
---|
887 | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { |
---|
888 | var c = plot.plugins.cursor; |
---|
889 | $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp); |
---|
890 | var axes = plot.axes; |
---|
891 | if (document.onselectstart != undefined) { |
---|
892 | c._oldHandlers.onselectstart = document.onselectstart; |
---|
893 | document.onselectstart = function () { return false; }; |
---|
894 | } |
---|
895 | if (document.ondrag != undefined) { |
---|
896 | c._oldHandlers.ondrag = document.ondrag; |
---|
897 | document.ondrag = function () { return false; }; |
---|
898 | } |
---|
899 | if (document.onmousedown != undefined) { |
---|
900 | c._oldHandlers.onmousedown = document.onmousedown; |
---|
901 | document.onmousedown = function () { return false; }; |
---|
902 | } |
---|
903 | if (c.zoom) { |
---|
904 | if (!c.zoomProxy) { |
---|
905 | var ctx = c.zoomCanvas._ctx; |
---|
906 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
907 | ctx = null; |
---|
908 | } |
---|
909 | if (c.constrainZoomTo == 'x') { |
---|
910 | c._zoom.start = [gridpos.x, 0]; |
---|
911 | } |
---|
912 | else if (c.constrainZoomTo == 'y') { |
---|
913 | c._zoom.start = [0, gridpos.y]; |
---|
914 | } |
---|
915 | else { |
---|
916 | c._zoom.start = [gridpos.x, gridpos.y]; |
---|
917 | } |
---|
918 | c._zoom.started = true; |
---|
919 | for (var ax in datapos) { |
---|
920 | // get zoom starting position. |
---|
921 | c._zoom.axes.start[ax] = datapos[ax]; |
---|
922 | } |
---|
923 | $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove); |
---|
924 | } |
---|
925 | } |
---|
926 | |
---|
927 | function handleMouseUp(ev) { |
---|
928 | var plot = ev.data.plot; |
---|
929 | var c = plot.plugins.cursor; |
---|
930 | if (c.zoom && c._zoom.zooming && !c.zoomTarget) { |
---|
931 | var xpos = c._zoom.gridpos.x; |
---|
932 | var ypos = c._zoom.gridpos.y; |
---|
933 | var datapos = c._zoom.datapos; |
---|
934 | var height = c.zoomCanvas._ctx.canvas.height; |
---|
935 | var width = c.zoomCanvas._ctx.canvas.width; |
---|
936 | var axes = plot.axes; |
---|
937 | |
---|
938 | if (c.constrainOutsideZoom && !c.onGrid) { |
---|
939 | if (xpos < 0) { xpos = 0; } |
---|
940 | else if (xpos > width) { xpos = width; } |
---|
941 | if (ypos < 0) { ypos = 0; } |
---|
942 | else if (ypos > height) { ypos = height; } |
---|
943 | |
---|
944 | for (var axis in datapos) { |
---|
945 | if (datapos[axis]) { |
---|
946 | if (axis.charAt(0) == 'x') { |
---|
947 | datapos[axis] = axes[axis].series_p2u(xpos); |
---|
948 | } |
---|
949 | else { |
---|
950 | datapos[axis] = axes[axis].series_p2u(ypos); |
---|
951 | } |
---|
952 | } |
---|
953 | } |
---|
954 | } |
---|
955 | |
---|
956 | if (c.constrainZoomTo == 'x') { |
---|
957 | ypos = height; |
---|
958 | } |
---|
959 | else if (c.constrainZoomTo == 'y') { |
---|
960 | xpos = width; |
---|
961 | } |
---|
962 | c._zoom.end = [xpos, ypos]; |
---|
963 | c._zoom.gridpos = {x:xpos, y:ypos}; |
---|
964 | |
---|
965 | c.doZoom(c._zoom.gridpos, datapos, plot, c); |
---|
966 | } |
---|
967 | c._zoom.started = false; |
---|
968 | c._zoom.zooming = false; |
---|
969 | |
---|
970 | $(document).unbind('mousemove.jqplotCursor', handleZoomMove); |
---|
971 | |
---|
972 | if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){ |
---|
973 | document.onselectstart = c._oldHandlers.onselectstart; |
---|
974 | c._oldHandlers.onselectstart = null; |
---|
975 | } |
---|
976 | if (document.ondrag != undefined && c._oldHandlers.ondrag != null){ |
---|
977 | document.ondrag = c._oldHandlers.ondrag; |
---|
978 | c._oldHandlers.ondrag = null; |
---|
979 | } |
---|
980 | if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){ |
---|
981 | document.onmousedown = c._oldHandlers.onmousedown; |
---|
982 | c._oldHandlers.onmousedown = null; |
---|
983 | } |
---|
984 | |
---|
985 | } |
---|
986 | |
---|
987 | function drawZoomBox() { |
---|
988 | var start = this._zoom.start; |
---|
989 | var end = this._zoom.end; |
---|
990 | var ctx = this.zoomCanvas._ctx; |
---|
991 | var l, t, h, w; |
---|
992 | if (end[0] > start[0]) { |
---|
993 | l = start[0]; |
---|
994 | w = end[0] - start[0]; |
---|
995 | } |
---|
996 | else { |
---|
997 | l = end[0]; |
---|
998 | w = start[0] - end[0]; |
---|
999 | } |
---|
1000 | if (end[1] > start[1]) { |
---|
1001 | t = start[1]; |
---|
1002 | h = end[1] - start[1]; |
---|
1003 | } |
---|
1004 | else { |
---|
1005 | t = end[1]; |
---|
1006 | h = start[1] - end[1]; |
---|
1007 | } |
---|
1008 | ctx.fillStyle = 'rgba(0,0,0,0.2)'; |
---|
1009 | ctx.strokeStyle = '#999999'; |
---|
1010 | ctx.lineWidth = 1.0; |
---|
1011 | ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
1012 | ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height); |
---|
1013 | ctx.clearRect(l, t, w, h); |
---|
1014 | // IE won't show transparent fill rect, so stroke a rect also. |
---|
1015 | ctx.strokeRect(l,t,w,h); |
---|
1016 | ctx = null; |
---|
1017 | } |
---|
1018 | |
---|
1019 | $.jqplot.CursorLegendRenderer = function(options) { |
---|
1020 | $.jqplot.TableLegendRenderer.call(this, options); |
---|
1021 | this.formatString = '%s'; |
---|
1022 | }; |
---|
1023 | |
---|
1024 | $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); |
---|
1025 | $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer; |
---|
1026 | |
---|
1027 | // called in context of a Legend |
---|
1028 | $.jqplot.CursorLegendRenderer.prototype.draw = function() { |
---|
1029 | if (this._elem) { |
---|
1030 | this._elem.emptyForce(); |
---|
1031 | this._elem = null; |
---|
1032 | } |
---|
1033 | if (this.show) { |
---|
1034 | var series = this._series, s; |
---|
1035 | // make a table. one line label per row. |
---|
1036 | var elem = document.createElement('div'); |
---|
1037 | this._elem = $(elem); |
---|
1038 | elem = null; |
---|
1039 | this._elem.addClass('jqplot-legend jqplot-cursor-legend'); |
---|
1040 | this._elem.css('position', 'absolute'); |
---|
1041 | |
---|
1042 | var pad = false; |
---|
1043 | for (var i = 0; i< series.length; i++) { |
---|
1044 | s = series[i]; |
---|
1045 | if (s.show && s.showLabel) { |
---|
1046 | var lt = $.jqplot.sprintf(this.formatString, s.label.toString()); |
---|
1047 | if (lt) { |
---|
1048 | var color = s.color; |
---|
1049 | if (s._stack && !s.fill) { |
---|
1050 | color = ''; |
---|
1051 | } |
---|
1052 | addrow.call(this, lt, color, pad, i); |
---|
1053 | pad = true; |
---|
1054 | } |
---|
1055 | // let plugins add more rows to legend. Used by trend line plugin. |
---|
1056 | for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) { |
---|
1057 | var item = $.jqplot.addLegendRowHooks[j].call(this, s); |
---|
1058 | if (item) { |
---|
1059 | addrow.call(this, item.label, item.color, pad); |
---|
1060 | pad = true; |
---|
1061 | } |
---|
1062 | } |
---|
1063 | } |
---|
1064 | } |
---|
1065 | series = s = null; |
---|
1066 | delete series; |
---|
1067 | delete s; |
---|
1068 | } |
---|
1069 | |
---|
1070 | function addrow(label, color, pad, idx) { |
---|
1071 | var rs = (pad) ? this.rowSpacing : '0'; |
---|
1072 | var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem); |
---|
1073 | tr.data('seriesIndex', idx); |
---|
1074 | $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+ |
---|
1075 | '<div style="border:1px solid #cccccc;padding:0.2em;">'+ |
---|
1076 | '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+ |
---|
1077 | '</div></td>').appendTo(tr); |
---|
1078 | var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>'); |
---|
1079 | td.appendTo(tr); |
---|
1080 | td.data('seriesIndex', idx); |
---|
1081 | if (this.escapeHtml) { |
---|
1082 | td.text(label); |
---|
1083 | } |
---|
1084 | else { |
---|
1085 | td.html(label); |
---|
1086 | } |
---|
1087 | tr = null; |
---|
1088 | td = null; |
---|
1089 | } |
---|
1090 | return this._elem; |
---|
1091 | }; |
---|
1092 | |
---|
1093 | })(jQuery); |
---|