Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 11222 was 11222, checked in by mroscoe, 10 years ago
File size: 20.9 KB
Line 
1/**
2 * jqPlot
3 * Pure JavaScript plotting plugin using jQuery
4 *
5 * Version: 1.0.8
6 * Revision: 1250
7 *
8 * Copyright (c) 2009-2013 Chris Leonello
9 * jqPlot is currently available for use in all personal or commercial projects
10 * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
11 * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
12 * choose the license that best suits your project and use it accordingly.
13 *
14 * Although not required, the author would appreciate an email letting him
15 * know of any substantial use of jqPlot.  You can reach the author at:
16 * chris at jqplot dot com or see http://www.jqplot.com/info.php .
17 *
18 * If you are feeling kind and generous, consider supporting the project by
19 * making a donation at: http://www.jqplot.com/donate.php .
20 *
21 * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
22 *
23 *     version 2007.04.27
24 *     author Ash Searle
25 *     http://hexmen.com/blog/2007/03/printf-sprintf/
26 *     http://hexmen.com/js/sprintf.js
27 *     The author (Ash Searle) has placed this code in the public domain:
28 *     "This code is unrestricted: you are free to use it however you like."
29 *
30 */
31(function($) {
32    $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
33   
34    /**
35     * Class: $.jqplot.Highlighter
36     * Plugin which will highlight data points when they are moused over.
37     *
38     * To use this plugin, include the js
39     * file in your source:
40     *
41     * > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>
42     *
43     * A tooltip providing information about the data point is enabled by default.
44     * To disable the tooltip, set "showTooltip" to false.
45     *
46     * You can control what data is displayed in the tooltip with various
47     * options.  The "tooltipAxes" option controls whether the x, y or both
48     * data values are displayed.
49     *
50     * Some chart types (e.g. hi-low-close) have more than one y value per
51     * data point. To display the additional values in the tooltip, set the
52     * "yvalues" option to the desired number of y values present (3 for a hlc chart).
53     *
54     * By default, data values will be formatted with the same formatting
55     * specifiers as used to format the axis ticks.  A custom format code
56     * can be supplied with the tooltipFormatString option.  This will apply
57     * to all values in the tooltip. 
58     *
59     * For more complete control, the "formatString" option can be set.  This
60     * Allows conplete control over tooltip formatting.  Values are passed to
61     * the format string in an order determined by the "tooltipAxes" and "yvalues"
62     * options.  So, if you have a hi-low-close chart and you just want to display
63     * the hi-low-close values in the tooltip, you could set a formatString like:
64     *
65     * > highlighter: {
66     * >     tooltipAxes: 'y',
67     * >     yvalues: 3,
68     * >     formatString:'<table class="jqplot-highlighter">
69     * >         <tr><td>hi:</td><td>%s</td></tr>
70     * >         <tr><td>low:</td><td>%s</td></tr>
71     * >         <tr><td>close:</td><td>%s</td></tr></table>'
72     * > }
73     *
74     */
75    $.jqplot.Highlighter = function(options) {
76        // Group: Properties
77        //
78        //prop: show
79        // true to show the highlight.
80        this.show = $.jqplot.config.enablePlugins;
81        // prop: markerRenderer
82        // Renderer used to draw the marker of the highlighted point.
83        // Renderer will assimilate attributes from the data point being highlighted,
84        // so no attributes need set on the renderer directly.
85        // Default is to turn off shadow drawing on the highlighted point.
86        this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
87        // prop: showMarker
88        // true to show the marker
89        this.showMarker  = true;
90        // prop: lineWidthAdjust
91        // Pixels to add to the lineWidth of the highlight.
92        this.lineWidthAdjust = 2.5;
93        // prop: sizeAdjust
94        // Pixels to add to the overall size of the highlight.
95        this.sizeAdjust = 5;
96        // prop: showTooltip
97        // Show a tooltip with data point values.
98        this.showTooltip = true;
99        // prop: tooltipLocation
100        // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
101        this.tooltipLocation = 'nw';
102        // prop: fadeTooltip
103        // true = fade in/out tooltip, flase = show/hide tooltip
104        this.fadeTooltip = true;
105        // prop: tooltipFadeSpeed
106        // 'slow', 'def', 'fast', or number of milliseconds.
107        this.tooltipFadeSpeed = "fast";
108        // prop: tooltipOffset
109        // Pixel offset of tooltip from the highlight.
110        this.tooltipOffset = 2;
111        // prop: tooltipAxes
112        // Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'
113        // 'both' and 'xy' are equivalent, 'yx' reverses order of labels.
114        this.tooltipAxes = 'both';
115        // prop; tooltipSeparator
116        // String to use to separate x and y axes in tooltip.
117        this.tooltipSeparator = ', ';
118        // prop; tooltipContentEditor
119        // Function used to edit/augment/replace the formatted tooltip contents.
120        // Called as str = tooltipContentEditor(str, seriesIndex, pointIndex)
121        // where str is the generated tooltip html and seriesIndex and pointIndex identify
122        // the data point being highlighted. Should return the html for the tooltip contents.
123        this.tooltipContentEditor = null;
124        // prop: useAxesFormatters
125        // Use the x and y axes formatters to format the text in the tooltip.
126        this.useAxesFormatters = true;
127        // prop: tooltipFormatString
128        // sprintf format string for the tooltip.
129        // Uses Ash Searle's javascript sprintf implementation
130        // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
131        // See http://perldoc.perl.org/functions/sprintf.html for reference.
132        // Additional "p" and "P" format specifiers added by Chris Leonello.
133        this.tooltipFormatString = '%.5P';
134        // prop: formatString
135        // alternative to tooltipFormatString
136        // will format the whole tooltip text, populating with x, y values as
137        // indicated by tooltipAxes option.  So, you could have a tooltip like:
138        // 'Date: %s, number of cats: %d' to format the whole tooltip at one go.
139        // If useAxesFormatters is true, values will be formatted according to
140        // Axes formatters and you can populate your tooltip string with
141        // %s placeholders.
142        this.formatString = null;
143        // prop: yvalues
144        // Number of y values to expect in the data point array.
145        // Typically this is 1.  Certain plots, like OHLC, will
146        // have more y values in each data point array.
147        this.yvalues = 1;
148        // prop: bringSeriesToFront
149        // This option requires jQuery 1.4+
150        // True to bring the series of the highlighted point to the front
151        // of other series.
152        this.bringSeriesToFront = false;
153        this._tooltipElem;
154        this.isHighlighting = false;
155        this.currentNeighbor = null;
156
157        $.extend(true, this, options);
158    };
159   
160    var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
161    var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
162    var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
163   
164    // axis.renderer.tickrenderer.formatter
165   
166    // called with scope of plot
167    $.jqplot.Highlighter.init = function (target, data, opts){
168        var options = opts || {};
169        // add a highlighter attribute to the plot
170        this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);
171    };
172   
173    // called within scope of series
174    $.jqplot.Highlighter.parseOptions = function (defaults, options) {
175        // Add a showHighlight option to the series
176        // and set it to true by default.
177        this.showHighlight = true;
178    };
179   
180    // called within context of plot
181    // create a canvas which we can draw on.
182    // insert it before the eventCanvas, so eventCanvas will still capture events.
183    $.jqplot.Highlighter.postPlotDraw = function() {
184        // Memory Leaks patch   
185        if (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) {
186            this.plugins.highlighter.highlightCanvas.resetCanvas();
187            this.plugins.highlighter.highlightCanvas = null;
188        }
189
190        if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) {
191            this.plugins.highlighter._tooltipElem.emptyForce();
192            this.plugins.highlighter._tooltipElem = null;
193        }
194
195        this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas();
196       
197        this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this));
198        this.plugins.highlighter.highlightCanvas.setContext();
199
200        var elem = document.createElement('div');
201        this.plugins.highlighter._tooltipElem = $(elem);
202        elem = null;
203        this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip');
204        this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'});
205       
206        this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem);
207    };
208   
209    $.jqplot.preInitHooks.push($.jqplot.Highlighter.init);
210    $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);
211    $.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);
212   
213    function draw(plot, neighbor) {
214        var hl = plot.plugins.highlighter;
215        var s = plot.series[neighbor.seriesIndex];
216        var smr = s.markerRenderer;
217        var mr = hl.markerRenderer;
218        mr.style = smr.style;
219        mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;
220        mr.size = smr.size + hl.sizeAdjust;
221        var rgba = $.jqplot.getColorComponents(smr.color);
222        var newrgb = [rgba[0], rgba[1], rgba[2]];
223        var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
224        mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
225        mr.init();
226        mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx);
227    }
228   
229    function showTooltip(plot, series, neighbor) {
230        // neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}
231        // gridData should be x,y pixel coords on the grid.
232        // add the plot._gridPadding to that to get x,y in the target.
233        var hl = plot.plugins.highlighter;
234        var elem = hl._tooltipElem;
235        var serieshl = series.highlighter || {};
236
237        var opts = $.extend(true, {}, hl, serieshl);
238
239        if (opts.useAxesFormatters) {
240            var xf = series._xaxis._ticks[0].formatter;
241            var yf = series._yaxis._ticks[0].formatter;
242            var xfstr = series._xaxis._ticks[0].formatString;
243            var yfstr = series._yaxis._ticks[0].formatString;
244            var str;
245            var xstr = xf(xfstr, neighbor.data[0]);
246            var ystrs = [];
247            for (var i=1; i<opts.yvalues+1; i++) {
248                ystrs.push(yf(yfstr, neighbor.data[i]));
249            }
250            if (typeof opts.formatString === 'string') {
251                switch (opts.tooltipAxes) {
252                    case 'both':
253                    case 'xy':
254                        ystrs.unshift(xstr);
255                        ystrs.unshift(opts.formatString);
256                        str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
257                        break;
258                    case 'yx':
259                        ystrs.push(xstr);
260                        ystrs.unshift(opts.formatString);
261                        str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
262                        break;
263                    case 'x':
264                        str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]);
265                        break;
266                    case 'y':
267                        ystrs.unshift(opts.formatString);
268                        str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
269                        break;
270                    default: // same as xy
271                        ystrs.unshift(xstr);
272                        ystrs.unshift(opts.formatString);
273                        str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
274                        break;
275                }
276            }
277            else {
278                switch (opts.tooltipAxes) {
279                    case 'both':
280                    case 'xy':
281                        str = xstr;
282                        for (var i=0; i<ystrs.length; i++) {
283                            str += opts.tooltipSeparator + ystrs[i];
284                        }
285                        break;
286                    case 'yx':
287                        str = '';
288                        for (var i=0; i<ystrs.length; i++) {
289                            str += ystrs[i] + opts.tooltipSeparator;
290                        }
291                        str += xstr;
292                        break;
293                    case 'x':
294                        str = xstr;
295                        break;
296                    case 'y':
297                        str = ystrs.join(opts.tooltipSeparator);
298                        break;
299                    default: // same as 'xy'
300                        str = xstr;
301                        for (var i=0; i<ystrs.length; i++) {
302                            str += opts.tooltipSeparator + ystrs[i];
303                        }
304                        break;
305                   
306                }               
307            }
308        }
309        else {
310            var str;
311            if (typeof opts.formatString ===  'string') {
312                str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data));
313            }
314
315            else {
316                if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') {
317                    str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
318                }
319                else if (opts.tooltipAxes == 'yx') {
320                    str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
321                }
322                else if (opts.tooltipAxes == 'x') {
323                    str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
324                }
325                else if (opts.tooltipAxes == 'y') {
326                    str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
327                }
328            }
329        }
330        if ($.isFunction(opts.tooltipContentEditor)) {
331            // args str, seriesIndex, pointIndex are essential so the hook can look up
332            // extra data for the point.
333            str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);
334        }
335        elem.html(str);
336        var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};
337        var ms = 0;
338        var fact = 0.707;
339        if (series.markerRenderer.show == true) {
340            ms = (series.markerRenderer.size + opts.sizeAdjust)/2;
341        }
342
343        var loc = locations;
344        if (series.fillToZero && series.fill && neighbor.data[1] < 0) {
345          loc = oppositeLocations;
346        }
347
348        switch (loc[locationIndicies[opts.tooltipLocation]]) {
349            case 'nw':
350                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
351                var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
352                break;
353            case 'n':
354                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
355                var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms;
356                break;
357            case 'ne':
358                var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
359                var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
360                break;
361            case 'e':
362                var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms;
363                var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
364                break;
365            case 'se':
366                var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
367                var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
368                break;
369            case 's':
370                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
371                var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms;
372                break;
373            case 'sw':
374                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
375                var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
376                break;
377            case 'w':
378                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms;
379                var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
380                break;
381            default: // same as 'nw'
382                var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
383                var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
384                break;
385        }
386        elem.css('left', x);
387        elem.css('top', y);
388        if (opts.fadeTooltip) {
389            // Fix for stacked up animations.  Thnanks Trevor!
390            elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
391        }
392        else {
393            elem.show();
394        }
395        elem = null;
396       
397    }
398   
399    function handleMove(ev, gridpos, datapos, neighbor, plot) {
400        var hl = plot.plugins.highlighter;
401        var c = plot.plugins.cursor;
402        if (hl.show) {
403            if (neighbor == null && hl.isHighlighting) {
404                var evt = jQuery.Event('jqplotHighlighterUnhighlight');
405                plot.target.trigger(evt);
406
407                var ctx = hl.highlightCanvas._ctx;
408                ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
409                if (hl.fadeTooltip) {
410                    hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);
411                }
412                else {
413                    hl._tooltipElem.hide();
414                }
415                if (hl.bringSeriesToFront) {
416                    plot.restorePreviousSeriesOrder();
417                }
418                hl.isHighlighting = false;
419                hl.currentNeighbor = null;
420                ctx = null;
421            }
422            else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {
423                var evt = jQuery.Event('jqplotHighlighterHighlight');
424                evt.which = ev.which;
425                evt.pageX = ev.pageX;
426                evt.pageY = ev.pageY;
427                var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data, plot];
428                plot.target.trigger(evt, ins);
429
430                hl.isHighlighting = true;
431                hl.currentNeighbor = neighbor;
432                if (hl.showMarker) {
433                    draw(plot, neighbor);
434                }
435                if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) {
436                    showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
437                }
438                if (hl.bringSeriesToFront) {
439                    plot.moveSeriesToFront(neighbor.seriesIndex);
440                }
441            }
442            // check to see if we're highlighting the wrong point.
443            else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) {
444                // highlighting the wrong point.
445
446                // if new series allows highlighting, highlight new point.
447                if (plot.series[neighbor.seriesIndex].showHighlight) {
448                    var ctx = hl.highlightCanvas._ctx;
449                    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
450                    hl.isHighlighting = true;
451                    hl.currentNeighbor = neighbor;
452                    if (hl.showMarker) {
453                        draw(plot, neighbor);
454                    }
455                    if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) {
456                        showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
457                    }
458                    if (hl.bringSeriesToFront) {
459                        plot.moveSeriesToFront(neighbor.seriesIndex);
460                    }                   
461                }               
462            }
463        }
464    }
465})(jQuery);
Note: See TracBrowser for help on using the repository browser.