OSDN Git Service

jqplotをバージョンアップ(v1.0.8)。
[magic3/magic3.git] / scripts / jquery / jqplot1.0.8 / plugins / jqplot.canvasOverlay.js
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);