Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
875 lars 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);