Free cookie consent management tool by TermsFeed Policy Generator

source: branches/1888_OaaS/HeuristicLab.Services.Optimization.Web/Content/jqplot/src/plugins/jqplot.cursor.js

Last change on this file was 9062, checked in by fschoepp, 12 years ago

#1888:
Backend changes:

  • Simplified job state detection (only one hive call will be made to detect all states now, instead of one additional call per job)
  • Reorganized classes (moved model classes into Model folder)

Website changes:

  • Website now heavily uses JavaScript to achieve better user experience
  • JavaScript degrades gracefully, except for plots
  • Tables: Added jquery-datatable-plugin to extend tables (pagination + search functionality)
  • OaaS-Website now uses the design of the HL websites (found in WebApplication branch)
  • Added jqplot to render zoomable line plots for HL-Datatables
  • Styling.js: Plots will be generated by using an ajax call; additional jquery-styling occurs within this file.
  • Added jquery-ui-1.9.2 which is capable of handling/rendering tabs, accordions and resizers.
File size: 42.2 KB
Line 
1/**
2 * jqPlot
3 * Pure JavaScript plotting plugin using jQuery
4 *
5 * Version: @VERSION
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 axes and date axes.
98        this.looseZoom = false;
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                        axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString;
192                    }
193                    this.redraw();
194                }
195                else {
196                    var ctx = this.plugins.cursor.zoomCanvas._ctx;
197                    ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
198                    ctx = null;
199                }
200                this.plugins.cursor._zoom.isZoomed = false;
201                this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]);
202            };
203           
204
205            if (c.showTooltipDataPosition) {
206                c.showTooltipUnitPosition = false;
207                c.showTooltipGridPosition = false;
208                if (options.cursor.tooltipFormatString == undefined) {
209                    c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString;
210                }
211            }
212        }
213    };
214   
215    // called with context of plot
216    $.jqplot.Cursor.postDraw = function() {
217        var c = this.plugins.cursor;
218       
219        // Memory Leaks patch
220        if (c.zoomCanvas) {
221            c.zoomCanvas.resetCanvas();
222            c.zoomCanvas = null;
223        }
224       
225        if (c.cursorCanvas) {
226            c.cursorCanvas.resetCanvas();
227            c.cursorCanvas = null;
228        }
229       
230        if (c._tooltipElem) {
231            c._tooltipElem.emptyForce();
232            c._tooltipElem = null;
233        }
234
235       
236        if (c.zoom) {
237            c.zoomCanvas = new $.jqplot.GenericCanvas();
238            this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this));
239            c.zoomCanvas.setContext();
240        }
241
242        var elem = document.createElement('div');
243        c._tooltipElem = $(elem);
244        elem = null;
245        c._tooltipElem.addClass('jqplot-cursor-tooltip');
246        c._tooltipElem.css({position:'absolute', display:'none'});
247       
248       
249        if (c.zoomCanvas) {
250            c.zoomCanvas._elem.before(c._tooltipElem);
251        }
252
253        else {
254            this.eventCanvas._elem.before(c._tooltipElem);
255        }
256
257        if (c.showVerticalLine || c.showHorizontalLine) {
258            c.cursorCanvas = new $.jqplot.GenericCanvas();
259            this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this));
260            c.cursorCanvas.setContext();
261        }
262
263        // if we are showing the positions in unit coordinates, and no axes groups
264        // were specified, create a default set.
265        if (c.showTooltipUnitPosition){
266            if (c.tooltipAxisGroups.length === 0) {
267                var series = this.series;
268                var s;
269                var temp = [];
270                for (var i=0; i<series.length; i++) {
271                    s = series[i];
272                    var ax = s.xaxis+','+s.yaxis;
273                    if ($.inArray(ax, temp) == -1) {
274                        temp.push(ax);
275                    }
276                }
277                for (var i=0; i<temp.length; i++) {
278                    c.tooltipAxisGroups.push(temp[i].split(','));
279                }
280            }
281        }
282    };
283   
284    // Group: methods
285    //
286    // method: $.jqplot.Cursor.zoomProxy
287    // links targetPlot to controllerPlot so that plot zooming of
288    // targetPlot will be controlled by zooming on the controllerPlot.
289    // controllerPlot will not actually zoom, but acts as an
290    // overview plot.  Note, the zoom options must be set to true for
291    // zoomProxy to work.
292    $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) {
293        var tc = targetPlot.plugins.cursor;
294        var cc = controllerPlot.plugins.cursor;
295        tc.zoomTarget = true;
296        tc.zoom = true;
297        tc.style = 'auto';
298        tc.dblClickReset = false;
299        cc.zoom = true;
300        cc.zoomProxy = true;
301             
302        controllerPlot.target.bind('jqplotZoom', plotZoom);
303        controllerPlot.target.bind('jqplotResetZoom', plotReset);
304
305        function plotZoom(ev, gridpos, datapos, plot, cursor) {
306            tc.doZoom(gridpos, datapos, targetPlot, cursor);
307        }
308
309        function plotReset(ev, plot, cursor) {
310            targetPlot.resetZoom();
311        }
312    };
313   
314    $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) {
315        var axes = plot.axes;
316        var cax = cursor._zoom.axes;
317        if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) {
318            for (var ax in axes) {
319                // axes[ax]._ticks = [];
320                // axes[ax].min = cax[ax].min;
321                // axes[ax].max = cax[ax].max;
322                // axes[ax].numberTicks = cax[ax].numberTicks;
323                // axes[ax].tickInterval = cax[ax].tickInterval;
324                // // for date axes
325                // axes[ax].daTickInterval = cax[ax].daTickInterval;
326                axes[ax].reset();
327                axes[ax]._ticks = [];
328                // fake out tick creation algorithm to make sure original auto
329                // computed format string is used if _overrideFormatString is true
330                axes[ax]._autoFormatString = cax[ax].tickFormatString;
331            }
332            plot.redraw();
333            cursor._zoom.isZoomed = false;
334        }
335        else {
336            var ctx = cursor.zoomCanvas._ctx;
337            ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
338            ctx = null;
339        }
340        plot.target.trigger('jqplotResetZoom', [plot, cursor]);
341    };
342   
343    $.jqplot.Cursor.resetZoom = function(plot) {
344        plot.resetZoom();
345    };
346   
347    $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) {
348        var c = cursor;
349        var axes = plot.axes;
350        var zaxes = c._zoom.axes;
351        var start = zaxes.start;
352        var end = zaxes.end;
353        var min, max, dp, span;
354        var ctx = plot.plugins.cursor.zoomCanvas._ctx;
355        // don't zoom if zoom area is too small (in pixels)
356        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)) {
357            if (!plot.plugins.cursor.zoomProxy) {
358                for (var ax in datapos) {
359                    // make a copy of the original axes to revert back.
360                    if (c._zoom.axes[ax] == undefined) {
361                        c._zoom.axes[ax] = {};
362                        c._zoom.axes[ax].numberTicks = axes[ax].numberTicks;
363                        c._zoom.axes[ax].tickInterval = axes[ax].tickInterval;
364                        // for date axes...
365                        c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval;
366                        c._zoom.axes[ax].min = axes[ax].min;
367                        c._zoom.axes[ax].max = axes[ax].max;
368                        c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString :  '';
369                    }
370
371
372                    if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) {   
373                        dp = datapos[ax];
374                        if (dp != null) { 
375                            var newmin, newmax;         
376                            if (dp > start[ax]) {
377                                newmin = start[ax];
378                                newmax = dp;
379                            }
380                            else {
381                                span = start[ax] - dp;
382                                newmin = dp;
383                                newmax = start[ax];
384                            }
385                           
386                            if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) {
387                                var ret = $.jqplot.LinearTickGenerator(newmin, newmax);
388                                axes[ax].min = ret[0];
389                                axes[ax].max = ret[1];
390                                axes[ax]._autoFormatString = ret[3];
391                                axes[ax].numberTicks = ret[2];
392                                axes[ax].tickInterval = ret[4];
393                                // for date axes...
394                                axes[ax].daTickInterval = [ret[4]/1000, 'seconds'];
395                            }
396                            else {
397                                axes[ax].min = newmin;
398                                axes[ax].max = newmax;
399                                axes[ax].tickInterval = null;
400                                // for date axes...
401                                axes[ax].daTickInterval = null;
402                            }
403
404                            axes[ax]._ticks = [];
405                        }
406                    }
407                           
408                    // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) {
409                    //     dp = datapos[ax];
410                    //     if (dp != null) {
411                    //         axes[ax].max == null;
412                    //         axes[ax].min = null;
413                    //     }
414                    // }
415                }
416                ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
417                plot.redraw();
418                c._zoom.isZoomed = true;
419                ctx = null;
420            }
421            plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]);
422        }
423    };
424   
425    $.jqplot.preInitHooks.push($.jqplot.Cursor.init);
426    $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw);
427   
428    function updateTooltip(gridpos, datapos, plot) {
429        var c = plot.plugins.cursor;
430        var s = '';
431        var addbr = false;
432        if (c.showTooltipGridPosition) {
433            s = gridpos.x+', '+gridpos.y;
434            addbr = true;
435        }
436        if (c.showTooltipUnitPosition) {
437            var g;
438            for (var i=0; i<c.tooltipAxisGroups.length; i++) {
439                g = c.tooltipAxisGroups[i];
440                if (addbr) {
441                    s += '<br />';
442                }
443                if (c.useAxesFormatters) {
444                    var xf = plot.axes[g[0]]._ticks[0].formatter;
445                    var yf = plot.axes[g[1]]._ticks[0].formatter;
446                    var xfstr = plot.axes[g[0]]._ticks[0].formatString;
447                    var yfstr = plot.axes[g[1]]._ticks[0].formatString;
448                    s += xf(xfstr, datapos[g[0]]) + ', '+ yf(yfstr, datapos[g[1]]);
449                }
450                else {
451                    s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]);
452                }
453                addbr = true;
454            }
455        }
456       
457        if (c.showTooltipDataPosition) {
458            var series = plot.series;
459            var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
460            var addbr = false;
461       
462            for (var i = 0; i< series.length; i++) {
463                if (series[i].show) {
464                    var idx = series[i].index;
465                    var label = series[i].label.toString();
466                    var cellid = $.inArray(idx, ret.indices);
467                    var sx = undefined;
468                    var sy = undefined;
469                    if (cellid != -1) {
470                        var data = ret.data[cellid].data;
471                        if (c.useAxesFormatters) {
472                            var xf = series[i]._xaxis._ticks[0].formatter;
473                            var yf = series[i]._yaxis._ticks[0].formatter;
474                            var xfstr = series[i]._xaxis._ticks[0].formatString;
475                            var yfstr = series[i]._yaxis._ticks[0].formatString;
476                            sx = xf(xfstr, data[0]);
477                            sy = yf(yfstr, data[1]);
478                        }
479                        else {
480                            sx = data[0];
481                            sy = data[1];
482                        }
483                        if (addbr) {
484                            s += '<br />';
485                        }
486                        s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy);
487                        addbr = true;
488                    }
489                }
490            }
491           
492        }
493        c._tooltipElem.html(s);
494    }
495   
496    function moveLine(gridpos, plot) {
497        var c = plot.plugins.cursor;
498        var ctx = c.cursorCanvas._ctx;
499        ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
500        if (c.showVerticalLine) {
501            c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]);
502        }
503        if (c.showHorizontalLine) {
504            c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]);
505        }
506        var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
507        if (c.showCursorLegend) {
508            var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
509            for (var i=0; i<cells.length; i++) {
510                var idx = $(cells[i]).data('seriesIndex');
511                var series = plot.series[idx];
512                var label = series.label.toString();
513                var cellid = $.inArray(idx, ret.indices);
514                var sx = undefined;
515                var sy = undefined;
516                if (cellid != -1) {
517                    var data = ret.data[cellid].data;
518                    if (c.useAxesFormatters) {
519                        var xf = series._xaxis._ticks[0].formatter;
520                        var yf = series._yaxis._ticks[0].formatter;
521                        var xfstr = series._xaxis._ticks[0].formatString;
522                        var yfstr = series._yaxis._ticks[0].formatString;
523                        sx = xf(xfstr, data[0]);
524                        sy = yf(yfstr, data[1]);
525                    }
526                    else {
527                        sx = data[0];
528                        sy = data[1];
529                    }
530                }
531                if (plot.legend.escapeHtml) {
532                    $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
533                }
534                else {
535                    $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
536                }
537            }       
538        }
539        ctx = null;
540    }
541       
542    function getIntersectingPoints(plot, x, y) {
543        var ret = {indices:[], data:[]};
544        var s, i, d0, d, j, r, p;
545        var threshold;
546        var c = plot.plugins.cursor;
547        for (var i=0; i<plot.series.length; i++) {
548            s = plot.series[i];
549            r = s.renderer;
550            if (s.show) {
551                threshold = c.intersectionThreshold;
552                if (s.showMarker) {
553                    threshold += s.markerRenderer.size/2;
554                }
555                for (var j=0; j<s.gridData.length; j++) {
556                    p = s.gridData[j];
557                    // check vertical line
558                    if (c.showVerticalLine) {
559                        if (Math.abs(x-p[0]) <= threshold) {
560                            ret.indices.push(i);
561                            ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]});
562                        }
563                    }
564                }
565            }
566        }
567        return ret;
568    }
569   
570    function moveTooltip(gridpos, plot) {
571        var c = plot.plugins.cursor; 
572        var elem = c._tooltipElem;
573        switch (c.tooltipLocation) {
574            case 'nw':
575                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
576                var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
577                break;
578            case 'n':
579                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
580                var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
581                break;
582            case 'ne':
583                var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
584                var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
585                break;
586            case 'e':
587                var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
588                var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
589                break;
590            case 'se':
591                var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
592                var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
593                break;
594            case 's':
595                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
596                var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
597                break;
598            case 'sw':
599                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
600                var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
601                break;
602            case 'w':
603                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
604                var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
605                break;
606            default:
607                var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
608                var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
609                break;
610        }
611           
612        elem.css('left', x);
613        elem.css('top', y);
614      elem = null;
615    }
616   
617    function positionTooltip(plot) {
618        // fake a grid for positioning
619        var grid = plot._gridPadding;
620        var c = plot.plugins.cursor;
621        var elem = c._tooltipElem; 
622        switch (c.tooltipLocation) {
623            case 'nw':
624                var a = grid.left + c.tooltipOffset;
625                var b = grid.top + c.tooltipOffset;
626                elem.css('left', a);
627                elem.css('top', b);
628                break;
629            case 'n':
630                var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
631                var b = grid.top + c.tooltipOffset;
632                elem.css('left', a);
633                elem.css('top', b);
634                break;
635            case 'ne':
636                var a = grid.right + c.tooltipOffset;
637                var b = grid.top + c.tooltipOffset;
638                elem.css({right:a, top:b});
639                break;
640            case 'e':
641                var a = grid.right + c.tooltipOffset;
642                var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
643                elem.css({right:a, top:b});
644                break;
645            case 'se':
646                var a = grid.right + c.tooltipOffset;
647                var b = grid.bottom + c.tooltipOffset;
648                elem.css({right:a, bottom:b});
649                break;
650            case 's':
651                var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
652                var b = grid.bottom + c.tooltipOffset;
653                elem.css({left:a, bottom:b});
654                break;
655            case 'sw':
656                var a = grid.left + c.tooltipOffset;
657                var b = grid.bottom + c.tooltipOffset;
658                elem.css({left:a, bottom:b});
659                break;
660            case 'w':
661                var a = grid.left + c.tooltipOffset;
662                var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
663                elem.css({left:a, top:b});
664                break;
665            default:  // same as 'se'
666                var a = grid.right - c.tooltipOffset;
667                var b = grid.bottom + c.tooltipOffset;
668                elem.css({right:a, bottom:b});
669                break;
670        }
671        elem = null;
672    }
673   
674    function handleClick (ev, gridpos, datapos, neighbor, plot) {
675        ev.preventDefault();
676        ev.stopImmediatePropagation();
677        var c = plot.plugins.cursor;
678        if (c.clickReset) {
679            c.resetZoom(plot, c);
680        }
681        var sel = window.getSelection;
682        if (document.selection && document.selection.empty)
683        {
684            document.selection.empty();
685        }
686        else if (sel && !sel().isCollapsed) {
687            sel().collapse();
688        }
689        return false;
690    }
691   
692    function handleDblClick (ev, gridpos, datapos, neighbor, plot) {
693        ev.preventDefault();
694        ev.stopImmediatePropagation();
695        var c = plot.plugins.cursor;
696        if (c.dblClickReset) {
697            c.resetZoom(plot, c);
698        }
699        var sel = window.getSelection;
700        if (document.selection && document.selection.empty)
701        {
702            document.selection.empty();
703        }
704        else if (sel && !sel().isCollapsed) {
705            sel().collapse();
706        }
707        return false;
708    }
709   
710    function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) {
711        var c = plot.plugins.cursor;
712        c.onGrid = false;
713        if (c.show) {
714            $(ev.target).css('cursor', c.previousCursor);
715            if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) {
716                c._tooltipElem.hide();
717            }
718            if (c.zoom) {
719                c._zoom.gridpos = gridpos;
720                c._zoom.datapos = datapos;
721            }
722            if (c.showVerticalLine || c.showHorizontalLine) {
723                var ctx = c.cursorCanvas._ctx;
724                ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
725                ctx = null;
726            }
727            if (c.showCursorLegend) {
728                var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
729                for (var i=0; i<cells.length; i++) {
730                    var idx = $(cells[i]).data('seriesIndex');
731                    var series = plot.series[idx];
732                    var label = series.label.toString();
733                    if (plot.legend.escapeHtml) {
734                        $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
735                    }
736                    else {
737                        $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
738                    }
739               
740                }       
741            }
742        }
743    }
744   
745    function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) {
746        var c = plot.plugins.cursor;
747        c.onGrid = true;
748        if (c.show) {
749            c.previousCursor = ev.target.style.cursor;
750            ev.target.style.cursor = c.style;
751            if (c.showTooltip) {
752                updateTooltip(gridpos, datapos, plot);
753                if (c.followMouse) {
754                    moveTooltip(gridpos, plot);
755                }
756                else {
757                    positionTooltip(plot);
758                }
759                c._tooltipElem.show();
760            }
761            if (c.showVerticalLine || c.showHorizontalLine) {
762                moveLine(gridpos, plot);
763            }
764        }
765
766    }   
767   
768    function handleMouseMove(ev, gridpos, datapos, neighbor, plot) {
769        var c = plot.plugins.cursor;
770        if (c.show) {
771            if (c.showTooltip) {
772                updateTooltip(gridpos, datapos, plot);
773                if (c.followMouse) {
774                    moveTooltip(gridpos, plot);
775                }
776            }
777            if (c.showVerticalLine || c.showHorizontalLine) {
778                moveLine(gridpos, plot);
779            }
780        }
781    }
782           
783    function getEventPosition(ev) {
784        var plot = ev.data.plot;
785        var go = plot.eventCanvas._elem.offset();
786        var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
787        var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null};
788        var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
789        var ax = plot.axes;
790        var n, axis;
791        for (n=11; n>0; n--) {
792            axis = an[n-1];
793            if (ax[axis].show) {
794                dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
795            }
796        }
797
798        return {offsets:go, gridPos:gridPos, dataPos:dataPos};
799    }   
800   
801    function handleZoomMove(ev) {
802        var plot = ev.data.plot;
803        var c = plot.plugins.cursor;
804        // don't do anything if not on grid.
805        if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) {
806            var ctx = c.zoomCanvas._ctx;
807            var positions = getEventPosition(ev);
808            var gridpos = positions.gridPos;
809            var datapos = positions.dataPos;
810            c._zoom.gridpos = gridpos;
811            c._zoom.datapos = datapos;
812            c._zoom.zooming = true;
813            var xpos = gridpos.x;
814            var ypos = gridpos.y;
815            var height = ctx.canvas.height;
816            var width = ctx.canvas.width;
817            if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) {
818                updateTooltip(gridpos, datapos, plot);
819                if (c.followMouse) {
820                    moveTooltip(gridpos, plot);
821                }
822            }
823            if (c.constrainZoomTo == 'x') {
824                c._zoom.end = [xpos, height];
825            }
826            else if (c.constrainZoomTo == 'y') {
827                c._zoom.end = [width, ypos];
828            }
829            else {
830                c._zoom.end = [xpos, ypos];
831            }
832            var sel = window.getSelection;
833            if (document.selection && document.selection.empty)
834            {
835                document.selection.empty();
836            }
837            else if (sel && !sel().isCollapsed) {
838                sel().collapse();
839            }
840            drawZoomBox.call(c);
841            ctx = null;
842        }
843    }
844   
845    function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
846        var c = plot.plugins.cursor;
847        $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp);
848        var axes = plot.axes;
849        if (document.onselectstart != undefined) {
850            c._oldHandlers.onselectstart = document.onselectstart;
851            document.onselectstart = function () { return false; };
852        }
853        if (document.ondrag != undefined) {
854            c._oldHandlers.ondrag = document.ondrag;
855            document.ondrag = function () { return false; };
856        }
857        if (document.onmousedown != undefined) {
858            c._oldHandlers.onmousedown = document.onmousedown;
859            document.onmousedown = function () { return false; };
860        }
861        if (c.zoom) {
862            if (!c.zoomProxy) {
863                var ctx = c.zoomCanvas._ctx;
864                ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
865                ctx = null;
866            }
867            if (c.constrainZoomTo == 'x') {
868                c._zoom.start = [gridpos.x, 0];
869            }
870            else if (c.constrainZoomTo == 'y') {
871                c._zoom.start = [0, gridpos.y];
872            }
873            else {
874                c._zoom.start = [gridpos.x, gridpos.y];
875            }
876            c._zoom.started = true;
877            for (var ax in datapos) {
878                // get zoom starting position.
879                c._zoom.axes.start[ax] = datapos[ax];
880            } 
881            $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove);             
882        }
883    }
884   
885    function handleMouseUp(ev) {
886        var plot = ev.data.plot;
887        var c = plot.plugins.cursor;
888        if (c.zoom && c._zoom.zooming && !c.zoomTarget) {
889            var xpos = c._zoom.gridpos.x;
890            var ypos = c._zoom.gridpos.y;
891            var datapos = c._zoom.datapos;
892            var height = c.zoomCanvas._ctx.canvas.height;
893            var width = c.zoomCanvas._ctx.canvas.width;
894            var axes = plot.axes;
895           
896            if (c.constrainOutsideZoom && !c.onGrid) {
897                if (xpos < 0) { xpos = 0; }
898                else if (xpos > width) { xpos = width; }
899                if (ypos < 0) { ypos = 0; }
900                else if (ypos > height) { ypos = height; }
901               
902                for (var axis in datapos) {
903                    if (datapos[axis]) {
904                        if (axis.charAt(0) == 'x') {
905                            datapos[axis] = axes[axis].series_p2u(xpos);
906                        }
907                        else {
908                            datapos[axis] = axes[axis].series_p2u(ypos);
909                        }
910                    }
911                }
912            }
913           
914            if (c.constrainZoomTo == 'x') {
915                ypos = height;
916            }
917            else if (c.constrainZoomTo == 'y') {
918                xpos = width;
919            }
920            c._zoom.end = [xpos, ypos];
921            c._zoom.gridpos = {x:xpos, y:ypos};
922           
923            c.doZoom(c._zoom.gridpos, datapos, plot, c);
924        }
925        c._zoom.started = false;
926        c._zoom.zooming = false;
927       
928        $(document).unbind('mousemove.jqplotCursor', handleZoomMove);
929       
930        if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){
931            document.onselectstart = c._oldHandlers.onselectstart;
932            c._oldHandlers.onselectstart = null;
933        }
934        if (document.ondrag != undefined && c._oldHandlers.ondrag != null){
935            document.ondrag = c._oldHandlers.ondrag;
936            c._oldHandlers.ondrag = null;
937        }
938        if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){
939            document.onmousedown = c._oldHandlers.onmousedown;
940            c._oldHandlers.onmousedown = null;
941        }
942
943    }
944   
945    function drawZoomBox() {
946        var start = this._zoom.start;
947        var end = this._zoom.end;
948        var ctx = this.zoomCanvas._ctx;
949        var l, t, h, w;
950        if (end[0] > start[0]) {
951            l = start[0];
952            w = end[0] - start[0];
953        }
954        else {
955            l = end[0];
956            w = start[0] - end[0];
957        }
958        if (end[1] > start[1]) {
959            t = start[1];
960            h = end[1] - start[1];
961        }
962        else {
963            t = end[1];
964            h = start[1] - end[1];
965        }
966        ctx.fillStyle = 'rgba(0,0,0,0.2)';
967        ctx.strokeStyle = '#999999';
968        ctx.lineWidth = 1.0;
969        ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
970        ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height);
971        ctx.clearRect(l, t, w, h);
972        // IE won't show transparent fill rect, so stroke a rect also.
973        ctx.strokeRect(l,t,w,h);
974        ctx = null;
975    }
976   
977    $.jqplot.CursorLegendRenderer = function(options) {
978        $.jqplot.TableLegendRenderer.call(this, options);
979        this.formatString = '%s';
980    };
981   
982    $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
983    $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer;
984   
985    // called in context of a Legend
986    $.jqplot.CursorLegendRenderer.prototype.draw = function() {
987        if (this._elem) {
988            this._elem.emptyForce();
989            this._elem = null;
990        }
991        if (this.show) {
992            var series = this._series, s;
993            // make a table.  one line label per row.
994            var elem = document.createElement('div');
995            this._elem = $(elem);
996            elem = null;
997            this._elem.addClass('jqplot-legend jqplot-cursor-legend');
998            this._elem.css('position', 'absolute');
999       
1000            var pad = false;
1001            for (var i = 0; i< series.length; i++) {
1002                s = series[i];
1003                if (s.show && s.showLabel) {
1004                    var lt = $.jqplot.sprintf(this.formatString, s.label.toString());
1005                    if (lt) {
1006                        var color = s.color;
1007                        if (s._stack && !s.fill) {
1008                            color = '';
1009                        }
1010                        addrow.call(this, lt, color, pad, i);
1011                        pad = true;
1012                    }
1013                    // let plugins add more rows to legend.  Used by trend line plugin.
1014                    for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
1015                        var item = $.jqplot.addLegendRowHooks[j].call(this, s);
1016                        if (item) {
1017                            addrow.call(this, item.label, item.color, pad);
1018                            pad = true;
1019                        }
1020                    }
1021                }
1022            }
1023            series = s = null;
1024            delete series;
1025            delete s;
1026        }
1027       
1028        function addrow(label, color, pad, idx) {
1029            var rs = (pad) ? this.rowSpacing : '0';
1030            var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem);
1031            tr.data('seriesIndex', idx);
1032            $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+
1033                '<div style="border:1px solid #cccccc;padding:0.2em;">'+
1034                '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+
1035                '</div></td>').appendTo(tr);
1036            var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>');
1037            td.appendTo(tr);
1038            td.data('seriesIndex', idx);
1039            if (this.escapeHtml) {
1040                td.text(label);
1041            }
1042            else {
1043                td.html(label);
1044            }
1045            tr = null;
1046            td = null;
1047        }
1048        return this._elem;
1049    };
1050   
1051})(jQuery);
Note: See TracBrowser for help on using the repository browser.