Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/jqPlot/plugins/jqplot.canvasOverlay.js @ 9617

Last change on this file since 9617 was 9617, checked in by pfleck, 11 years ago

#2063:
Started integrating Hive statistics into statistics web project.
Added jqPlot library for charting.

File size: 36.3 KB
Line 
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    var objCounter = 0;
32    // class: $.jqplot.CanvasOverlay
33    $.jqplot.CanvasOverlay = function(opts){
34        var options = opts || {};
35        this.options = {
36            show: $.jqplot.config.enablePlugins,
37            deferDraw: false
38        };
39        // prop: objects
40        this.objects = [];
41        this.objectNames = [];
42        this.canvas = null;
43        this.markerRenderer = new $.jqplot.MarkerRenderer({style:'line'});
44        this.markerRenderer.init();
45        this.highlightObjectIndex = null;
46        if (options.objects) {
47            var objs = options.objects,
48                obj;
49            for (var i=0; i<objs.length; i++) {
50                obj = objs[i];
51                for (var n in obj) {
52                    switch (n) {
53                        case 'line':
54                            this.addLine(obj[n]);
55                            break;
56                        case 'horizontalLine':
57                            this.addHorizontalLine(obj[n]);
58                            break;
59                        case 'dashedHorizontalLine':
60                            this.addDashedHorizontalLine(obj[n]);
61                            break;
62                        case 'verticalLine':
63                            this.addVerticalLine(obj[n]);
64                            break;
65                        case 'dashedVerticalLine':
66                            this.addDashedVerticalLine(obj[n]);
67                            break;
68                        default:
69                            break;
70                    }
71                }   
72            }
73        }
74        $.extend(true, this.options, options);
75    };
76   
77    // called with scope of a plot object
78    $.jqplot.CanvasOverlay.postPlotInit = function (target, data, opts) {
79        var options = opts || {};
80        // add a canvasOverlay attribute to the plot
81        this.plugins.canvasOverlay = new $.jqplot.CanvasOverlay(options.canvasOverlay);     
82    };
83
84
85    function LineBase() {
86        this.uid = null;
87        this.type = null;
88        this.gridStart = null;
89        this.gridStop = null;
90        this.tooltipWidthFactor = 0;
91        this.options = {           
92            // prop: name
93            // Optional name for the overlay object.
94            // Can be later used to retrieve the object by name.
95            name: null,
96            // prop: show
97            // true to show (draw), false to not draw.
98            show: true,
99            // prop: lineWidth
100            // Width of the line.
101            lineWidth: 2,
102            // prop: lineCap
103            // Type of ending placed on the line ['round', 'butt', 'square']
104            lineCap: 'round',
105            // prop: color
106            // color of the line
107            color: '#666666',
108            // prop: shadow
109            // wether or not to draw a shadow on the line
110            shadow: true,
111            // prop: shadowAngle
112            // Shadow angle in degrees
113            shadowAngle: 45,
114            // prop: shadowOffset
115            // Shadow offset from line in pixels
116            shadowOffset: 1,
117            // prop: shadowDepth
118            // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
119            shadowDepth: 3,
120            // prop: shadowAlpha
121            // Alpha channel transparency of shadow.  0 = transparent.
122            shadowAlpha: '0.07',
123            // prop: xaxis
124            // X axis to use for positioning/scaling the line.
125            xaxis: 'xaxis',
126            // prop: yaxis
127            // Y axis to use for positioning/scaling the line.
128            yaxis: 'yaxis',
129            // prop: showTooltip
130            // Show a tooltip with data point values.
131            showTooltip: false,
132            // prop: showTooltipPrecision
133            // Controls how close to line cursor must be to show tooltip.
134            // Higher number = closer to line, lower number = farther from line.
135            // 1.0 = cursor must be over line.
136            showTooltipPrecision: 0.6,
137            // prop: tooltipLocation
138            // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
139            tooltipLocation: 'nw',
140            // prop: fadeTooltip
141            // true = fade in/out tooltip, flase = show/hide tooltip
142            fadeTooltip: true,
143            // prop: tooltipFadeSpeed
144            // 'slow', 'def', 'fast', or number of milliseconds.
145            tooltipFadeSpeed: "fast",
146            // prop: tooltipOffset
147            // Pixel offset of tooltip from the highlight.
148            tooltipOffset: 4,
149            // prop: tooltipFormatString
150            // Format string passed the x and y values of the cursor on the line.
151            // e.g., 'Dogs: %.2f, Cats: %d'.
152            tooltipFormatString: '%d, %d'
153        };
154    }
155
156    /**
157     * Class: Line
158     * A straight line.
159     */
160    function Line(options) {
161        LineBase.call(this);
162        this.type = 'line';
163        var opts = {
164            // prop: start
165            // [x, y] coordinates for the start of the line.
166            start: [],
167            // prop: stop
168            // [x, y] coordinates for the end of the line.
169            stop: []
170        };
171        $.extend(true, this.options, opts, options);
172
173        if (this.options.showTooltipPrecision < 0.01) {
174            this.options.showTooltipPrecision = 0.01;
175        }
176    }
177
178    Line.prototype = new LineBase();
179    Line.prototype.constructor = Line;
180
181
182    /**
183     * Class: HorizontalLine
184     * A straight horizontal line.
185     */
186    function HorizontalLine(options) {
187        LineBase.call(this);
188        this.type = 'horizontalLine';
189        var opts = {
190            // prop: y
191            // y value to position the line
192            y: null,
193            // prop: xmin
194            // x value for the start of the line, null to scale to axis min.
195            xmin: null,
196            // prop: xmax
197            // x value for the end of the line, null to scale to axis max.
198            xmax: null,
199            // prop xOffset
200            // offset ends of the line inside the grid.  Number
201            xOffset: '6px', // number or string.  Number interpreted as units, string as pixels.
202            xminOffset: null,
203            xmaxOffset: null
204        };
205        $.extend(true, this.options, opts, options);
206
207        if (this.options.showTooltipPrecision < 0.01) {
208            this.options.showTooltipPrecision = 0.01;
209        }
210    }
211
212    HorizontalLine.prototype = new LineBase();
213    HorizontalLine.prototype.constructor = HorizontalLine;
214   
215
216    /**
217     * Class: DashedHorizontalLine
218     * A straight dashed horizontal line.
219     */
220    function DashedHorizontalLine(options) {
221        LineBase.call(this);
222        this.type = 'dashedHorizontalLine';
223        var opts = {
224            y: null,
225            xmin: null,
226            xmax: null,
227            xOffset: '6px', // number or string.  Number interpreted as units, string as pixels.
228            xminOffset: null,
229            xmaxOffset: null,
230            // prop: dashPattern
231            // Array of line, space settings in pixels.
232            // Default is 8 pixel of line, 8 pixel of space.
233            // Note, limit to a 2 element array b/c of bug with higher order arrays.
234            dashPattern: [8,8]
235        };
236        $.extend(true, this.options, opts, options);
237
238        if (this.options.showTooltipPrecision < 0.01) {
239            this.options.showTooltipPrecision = 0.01;
240        }
241    }
242
243    DashedHorizontalLine.prototype = new LineBase();
244    DashedHorizontalLine.prototype.constructor = DashedHorizontalLine;
245   
246
247    /**
248     * Class: VerticalLine
249     * A straight vertical line.
250     */
251    function VerticalLine(options) {
252        LineBase.call(this);
253        this.type = 'verticalLine';
254        var opts = {
255            x: null,
256            ymin: null,
257            ymax: null,
258            yOffset: '6px', // number or string.  Number interpreted as units, string as pixels.
259            yminOffset: null,
260            ymaxOffset: null
261        };
262        $.extend(true, this.options, opts, options);
263
264        if (this.options.showTooltipPrecision < 0.01) {
265            this.options.showTooltipPrecision = 0.01;
266        }
267    }
268
269    VerticalLine.prototype = new LineBase();
270    VerticalLine.prototype.constructor = VerticalLine;
271   
272
273    /**
274     * Class: DashedVerticalLine
275     * A straight dashed vertical line.
276     */
277    function DashedVerticalLine(options) {
278        LineBase.call(this);
279        this.type = 'dashedVerticalLine';
280        this.start = null;
281        this.stop = null;
282        var opts = {
283            x: null,
284            ymin: null,
285            ymax: null,
286            yOffset: '6px', // number or string.  Number interpreted as units, string as pixels.
287            yminOffset: null,
288            ymaxOffset: null,
289            // prop: dashPattern
290            // Array of line, space settings in pixels.
291            // Default is 8 pixel of line, 8 pixel of space.
292            // Note, limit to a 2 element array b/c of bug with higher order arrays.
293            dashPattern: [8,8]
294        };
295        $.extend(true, this.options, opts, options);
296
297        if (this.options.showTooltipPrecision < 0.01) {
298            this.options.showTooltipPrecision = 0.01;
299        }
300    }
301
302    DashedVerticalLine.prototype = new LineBase();
303    DashedVerticalLine.prototype.constructor = DashedVerticalLine;
304   
305    $.jqplot.CanvasOverlay.prototype.addLine = function(opts) {
306        var line = new Line(opts);
307        line.uid = objCounter++;
308        this.objects.push(line);
309        this.objectNames.push(line.options.name);
310    };
311   
312    $.jqplot.CanvasOverlay.prototype.addHorizontalLine = function(opts) {
313        var line = new HorizontalLine(opts);
314        line.uid = objCounter++;
315        this.objects.push(line);
316        this.objectNames.push(line.options.name);
317    };
318   
319    $.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine = function(opts) {
320        var line = new DashedHorizontalLine(opts);
321        line.uid = objCounter++;
322        this.objects.push(line);
323        this.objectNames.push(line.options.name);
324    };
325   
326    $.jqplot.CanvasOverlay.prototype.addVerticalLine = function(opts) {
327        var line = new VerticalLine(opts);
328        line.uid = objCounter++;
329        this.objects.push(line);
330        this.objectNames.push(line.options.name);
331    };
332   
333    $.jqplot.CanvasOverlay.prototype.addDashedVerticalLine = function(opts) {
334        var line = new DashedVerticalLine(opts);
335        line.uid = objCounter++;
336        this.objects.push(line);
337        this.objectNames.push(line.options.name);
338    };
339   
340    $.jqplot.CanvasOverlay.prototype.removeObject = function(idx) {
341        // check if integer, remove by index
342        if ($.type(idx) == 'number') {
343            this.objects.splice(idx, 1);
344            this.objectNames.splice(idx, 1);
345        }
346        // if string, remove by name
347        else {
348            var id = $.inArray(idx, this.objectNames);
349            if (id != -1) {
350                this.objects.splice(id, 1);
351                this.objectNames.splice(id, 1);
352            }
353        }
354    };
355   
356    $.jqplot.CanvasOverlay.prototype.getObject = function(idx) {
357        // check if integer, remove by index
358        if ($.type(idx) == 'number') {
359            return this.objects[idx];
360        }
361        // if string, remove by name
362        else {
363            var id = $.inArray(idx, this.objectNames);
364            if (id != -1) {
365                return this.objects[id];
366            }
367        }
368    };
369   
370    // Set get as alias for getObject.
371    $.jqplot.CanvasOverlay.prototype.get = $.jqplot.CanvasOverlay.prototype.getObject;
372   
373    $.jqplot.CanvasOverlay.prototype.clear = function(plot) {
374        this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());
375    };
376   
377    $.jqplot.CanvasOverlay.prototype.draw = function(plot) {
378        var obj,
379            objs = this.objects,
380            mr = this.markerRenderer,
381            start,
382            stop;
383        if (this.options.show) {
384            this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());
385            for (var k=0; k<objs.length; k++) {
386                obj = objs[k];
387                var opts = $.extend(true, {}, obj.options);
388                if (obj.options.show) {
389                    // style and shadow properties should be set before
390                    // every draw of marker renderer.
391                    mr.shadow = obj.options.shadow;
392                    obj.tooltipWidthFactor = obj.options.lineWidth / obj.options.showTooltipPrecision;
393                    switch (obj.type) {
394                        case 'line':
395                            // style and shadow properties should be set before
396                            // every draw of marker renderer.
397                            mr.style = 'line';
398                            opts.closePath = false;
399                            start = [plot.axes[obj.options.xaxis].series_u2p(obj.options.start[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.start[1])];
400                            stop = [plot.axes[obj.options.xaxis].series_u2p(obj.options.stop[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.stop[1])];
401                            obj.gridStart = start;
402                            obj.gridStop = stop;
403                            mr.draw(start, stop, this.canvas._ctx, opts);
404                            break;
405                        case 'horizontalLine':
406                           
407                            // style and shadow properties should be set before
408                            // every draw of marker renderer.
409                            if (obj.options.y != null) {
410                                mr.style = 'line';
411                                opts.closePath = false;
412                                var xaxis = plot.axes[obj.options.xaxis],
413                                    xstart,
414                                    xstop,
415                                    y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),
416                                    xminoff = obj.options.xminOffset || obj.options.xOffset,
417                                    xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;
418                                if (obj.options.xmin != null) {
419                                    xstart = xaxis.series_u2p(obj.options.xmin);
420                                }
421                                else if (xminoff != null) {
422                                    if ($.type(xminoff) == "number") {
423                                        xstart = xaxis.series_u2p(xaxis.min + xminoff);
424                                    }
425                                    else if ($.type(xminoff) == "string") {
426                                        xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);
427                                    }
428                                }
429                                if (obj.options.xmax != null) {
430                                    xstop = xaxis.series_u2p(obj.options.xmax);
431                                }
432                                else if (xmaxoff != null) {
433                                    if ($.type(xmaxoff) == "number") {
434                                        xstop = xaxis.series_u2p(xaxis.max - xmaxoff);
435                                    }
436                                    else if ($.type(xmaxoff) == "string") {
437                                        xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);
438                                    }
439                                }
440                                if (xstop != null && xstart != null) {
441                                    obj.gridStart = [xstart, y];
442                                    obj.gridStop = [xstop, y];
443                                    mr.draw([xstart, y], [xstop, y], this.canvas._ctx, opts);
444                                }
445                            }
446                            break;
447
448                        case 'dashedHorizontalLine':
449                           
450                            var dashPat = obj.options.dashPattern;
451                            var dashPatLen = 0;
452                            for (var i=0; i<dashPat.length; i++) {
453                                dashPatLen += dashPat[i];
454                            }
455
456                            // style and shadow properties should be set before
457                            // every draw of marker renderer.
458                            if (obj.options.y != null) {
459                                mr.style = 'line';
460                                opts.closePath = false;
461                                var xaxis = plot.axes[obj.options.xaxis],
462                                    xstart,
463                                    xstop,
464                                    y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),
465                                    xminoff = obj.options.xminOffset || obj.options.xOffset,
466                                    xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;
467                                if (obj.options.xmin != null) {
468                                    xstart = xaxis.series_u2p(obj.options.xmin);
469                                }
470                                else if (xminoff != null) {
471                                    if ($.type(xminoff) == "number") {
472                                        xstart = xaxis.series_u2p(xaxis.min + xminoff);
473                                    }
474                                    else if ($.type(xminoff) == "string") {
475                                        xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);
476                                    }
477                                }
478                                if (obj.options.xmax != null) {
479                                    xstop = xaxis.series_u2p(obj.options.xmax);
480                                }
481                                else if (xmaxoff != null) {
482                                    if ($.type(xmaxoff) == "number") {
483                                        xstop = xaxis.series_u2p(xaxis.max - xmaxoff);
484                                    }
485                                    else if ($.type(xmaxoff) == "string") {
486                                        xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);
487                                    }
488                                }
489                                if (xstop != null && xstart != null) {
490                                    obj.gridStart = [xstart, y];
491                                    obj.gridStop = [xstop, y];
492                                    var numDash = Math.ceil((xstop - xstart)/dashPatLen);
493                                    var b=xstart, e;
494                                    for (var i=0; i<numDash; i++) {
495                                        for (var j=0; j<dashPat.length; j+=2) {
496                                            e = b+dashPat[j];
497                                            mr.draw([b, y], [e, y], this.canvas._ctx, opts);
498                                            b += dashPat[j];
499                                            if (j < dashPat.length-1) {
500                                                b += dashPat[j+1];
501                                            }
502                                        }
503                                    }
504                                }
505                            }
506                            break;
507
508                        case 'verticalLine':
509                           
510                            // style and shadow properties should be set before
511                            // every draw of marker renderer.
512                            if (obj.options.x != null) {
513                                mr.style = 'line';
514                                opts.closePath = false;
515                                var yaxis = plot.axes[obj.options.yaxis],
516                                    ystart,
517                                    ystop,
518                                    x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),
519                                    yminoff = obj.options.yminOffset || obj.options.yOffset,
520                                    ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;
521                                if (obj.options.ymin != null) {
522                                    ystart = yaxis.series_u2p(obj.options.ymin);
523                                }
524                                else if (yminoff != null) {
525                                    if ($.type(yminoff) == "number") {
526                                        ystart = yaxis.series_u2p(yaxis.min - yminoff);
527                                    }
528                                    else if ($.type(yminoff) == "string") {
529                                        ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);
530                                    }
531                                }
532                                if (obj.options.ymax != null) {
533                                    ystop = yaxis.series_u2p(obj.options.ymax);
534                                }
535                                else if (ymaxoff != null) {
536                                    if ($.type(ymaxoff) == "number") {
537                                        ystop = yaxis.series_u2p(yaxis.max + ymaxoff);
538                                    }
539                                    else if ($.type(ymaxoff) == "string") {
540                                        ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);
541                                    }
542                                }
543                                if (ystop != null && ystart != null) {
544                                    obj.gridStart = [x, ystart];
545                                    obj.gridStop = [x, ystop];
546                                    mr.draw([x, ystart], [x, ystop], this.canvas._ctx, opts);
547                                }
548                            }
549                            break;
550
551                        case 'dashedVerticalLine':
552                           
553                            var dashPat = obj.options.dashPattern;
554                            var dashPatLen = 0;
555                            for (var i=0; i<dashPat.length; i++) {
556                                dashPatLen += dashPat[i];
557                            }
558
559                            // style and shadow properties should be set before
560                            // every draw of marker renderer.
561                            if (obj.options.x != null) {
562                                mr.style = 'line';
563                                opts.closePath = false;
564                                var yaxis = plot.axes[obj.options.yaxis],
565                                    ystart,
566                                    ystop,
567                                    x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),
568                                    yminoff = obj.options.yminOffset || obj.options.yOffset,
569                                    ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;
570                                if (obj.options.ymin != null) {
571                                    ystart = yaxis.series_u2p(obj.options.ymin);
572                                }
573                                else if (yminoff != null) {
574                                    if ($.type(yminoff) == "number") {
575                                        ystart = yaxis.series_u2p(yaxis.min - yminoff);
576                                    }
577                                    else if ($.type(yminoff) == "string") {
578                                        ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);
579                                    }
580                                }
581                                if (obj.options.ymax != null) {
582                                    ystop = yaxis.series_u2p(obj.options.ymax);
583                                }
584                                else if (ymaxoff != null) {
585                                    if ($.type(ymaxoff) == "number") {
586                                        ystop = yaxis.series_u2p(yaxis.max + ymaxoff);
587                                    }
588                                    else if ($.type(ymaxoff) == "string") {
589                                        ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);
590                                    }
591                                }
592
593
594                                if (ystop != null && ystart != null) {
595                                    obj.gridStart = [x, ystart];
596                                    obj.gridStop = [x, ystop];
597                                    var numDash = Math.ceil((ystart - ystop)/dashPatLen);
598                                    var firstDashAdjust = ((numDash * dashPatLen) - (ystart - ystop))/2.0;
599                                    var b=ystart, e, bs, es;
600                                    for (var i=0; i<numDash; i++) {
601                                        for (var j=0; j<dashPat.length; j+=2) {
602                                            e = b - dashPat[j];
603                                            if (e < ystop) {
604                                                e = ystop;
605                                            }
606                                            if (b < ystop) {
607                                                b = ystop;
608                                            }
609                                            // es = e;
610                                            // if (i == 0) {
611                                            //  es += firstDashAdjust;
612                                            // }
613                                            mr.draw([x, b], [x, e], this.canvas._ctx, opts);
614                                            b -= dashPat[j];
615                                            if (j < dashPat.length-1) {
616                                                b -= dashPat[j+1];
617                                            }
618                                        }
619                                    }
620                                }
621                            }
622                            break;
623
624                        default:
625                            break;
626                    }
627                }
628            }
629        }
630    };
631   
632    // called within context of plot
633    // create a canvas which we can draw on.
634    // insert it before the eventCanvas, so eventCanvas will still capture events.
635    $.jqplot.CanvasOverlay.postPlotDraw = function() {
636        var co = this.plugins.canvasOverlay;
637        // Memory Leaks patch   
638        if (co && co.highlightCanvas) {
639            co.highlightCanvas.resetCanvas();
640            co.highlightCanvas = null;
641        }
642        co.canvas = new $.jqplot.GenericCanvas();
643       
644        this.eventCanvas._elem.before(co.canvas.createElement(this._gridPadding, 'jqplot-overlayCanvas-canvas', this._plotDimensions, this));
645        co.canvas.setContext();
646        if (!co.deferDraw) {
647            co.draw(this);
648        }
649
650        var elem = document.createElement('div');
651        co._tooltipElem = $(elem);
652        elem = null;
653        co._tooltipElem.addClass('jqplot-canvasOverlay-tooltip');
654        co._tooltipElem.css({position:'absolute', display:'none'});
655       
656        this.eventCanvas._elem.before(co._tooltipElem);
657        this.eventCanvas._elem.bind('mouseleave', { elem: co._tooltipElem }, function (ev) { ev.data.elem.hide(); });
658
659        var co = null;
660    };
661
662
663    function showTooltip(plot, obj, gridpos, datapos) {
664        var co = plot.plugins.canvasOverlay;
665        var elem = co._tooltipElem;
666
667        var opts = obj.options, x, y;
668
669        elem.html($.jqplot.sprintf(opts.tooltipFormatString, datapos[0], datapos[1]));
670       
671        switch (opts.tooltipLocation) {
672            case 'nw':
673                x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
674                y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
675                break;
676            case 'n':
677                x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;
678                y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
679                break;
680            case 'ne':
681                x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
682                y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
683                break;
684            case 'e':
685                x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
686                y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;
687                break;
688            case 'se':
689                x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
690                y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
691                break;
692            case 's':
693                x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;
694                y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
695                break;
696            case 'sw':
697                x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
698                y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
699                break;
700            case 'w':
701                x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
702                y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;
703                break;
704            default: // same as 'nw'
705                x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
706                y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
707                break;
708        }
709
710        elem.css('left', x);
711        elem.css('top', y);
712        if (opts.fadeTooltip) {
713            // Fix for stacked up animations.  Thnanks Trevor!
714            elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
715        }
716        else {
717            elem.show();
718        }
719        elem = null;
720    }
721
722
723    function isNearLine(point, lstart, lstop, width) {
724        // r is point to test, p and q are end points.
725        var rx = point[0];
726        var ry = point[1];
727        var px = Math.round(lstop[0]);
728        var py = Math.round(lstop[1]);
729        var qx = Math.round(lstart[0]);
730        var qy = Math.round(lstart[1]);
731
732        var l = Math.sqrt(Math.pow(px-qx, 2) + Math.pow(py-qy, 2));
733
734        // scale error term by length of line.
735        var eps = width*l;
736        var res = Math.abs((qx-px) * (ry-py) - (qy-py) * (rx-px));
737        var ret = (res < eps) ? true : false;
738        return ret;
739    }
740
741
742    function handleMove(ev, gridpos, datapos, neighbor, plot) {
743        var co = plot.plugins.canvasOverlay;
744        var objs = co.objects;
745        var l = objs.length;
746        var obj, haveHighlight=false;
747        var elem;
748        for (var i=0; i<l; i++) {
749            obj = objs[i];
750            if (obj.options.showTooltip) {
751                var n = isNearLine([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor);
752                datapos = [plot.axes[obj.options.xaxis].series_p2u(gridpos.x), plot.axes[obj.options.yaxis].series_p2u(gridpos.y)];
753
754                // cases:
755                //    near line, no highlighting
756                //    near line, highliting on this line
757                //    near line, highlighting another line
758                //    not near any line, highlighting
759                //    not near any line, no highlighting
760
761                // near line, not currently highlighting
762                if (n && co.highlightObjectIndex == null) {
763                    switch (obj.type) {
764                        case 'line':
765                            showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
766                            break;
767
768                        case 'horizontalLine':
769                        case 'dashedHorizontalLine':
770                            showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
771                            break;
772
773                        case 'verticalLine':
774                        case 'dashedVerticalLine':
775                            showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
776                            break;
777                        default:
778                            break;
779                    }
780                    co.highlightObjectIndex = i;
781                    haveHighlight = true;
782                    break;
783                }
784
785                // near line, highlighting another line.
786                else if (n && co.highlightObjectIndex !== i) {
787                    // turn off tooltip.
788                    elem = co._tooltipElem;
789                    if (obj.fadeTooltip) {
790                        elem.fadeOut(obj.tooltipFadeSpeed);
791                    }
792                    else {
793                        elem.hide();
794                    }
795
796                    // turn on right tooltip.
797                    switch (obj.type) {
798                        case 'line':
799                            showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
800                            break;
801
802                        case 'horizontalLine':
803                        case 'dashedHorizontalLine':
804                            showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
805                            break;
806
807                        case 'verticalLine':
808                        case 'dashedVerticalLine':
809                            showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
810                            break;
811                        default:
812                            break;
813                    }
814
815                    co.highlightObjectIndex = i;
816                    haveHighlight = true;
817                    break;
818                }
819
820                // near line, already highlighting this line, update
821                else if (n) {
822                    switch (obj.type) {
823                        case 'line':
824                            showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
825                            break;
826
827                        case 'horizontalLine':
828                        case 'dashedHorizontalLine':
829                            showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
830                            break;
831
832                        case 'verticalLine':
833                        case 'dashedVerticalLine':
834                            showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
835                            break;
836                        default:
837                            break;
838                    }
839
840                    haveHighlight = true;
841                    break;
842                }
843            }
844        }
845
846        // check if we are highlighting and not near a line, turn it off.
847        if (!haveHighlight && co.highlightObjectIndex !== null) {
848            elem = co._tooltipElem;
849            obj = co.getObject(co.highlightObjectIndex);
850            if (obj.fadeTooltip) {
851                elem.fadeOut(obj.tooltipFadeSpeed);
852            }
853            else {
854                elem.hide();
855            }
856            co.highlightObjectIndex = null;
857        }
858    }
859   
860    $.jqplot.postInitHooks.push($.jqplot.CanvasOverlay.postPlotInit);
861    $.jqplot.postDrawHooks.push($.jqplot.CanvasOverlay.postPlotDraw);
862    $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
863
864})(jQuery);
Note: See TracBrowser for help on using the repository browser.