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 @ 11222

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