minor fixes
[sgn.git] / js / flot / tooltip.js
blobed5b37ce7a3f658cce402f78fd083758f878f015
1 /*
2  * jquery.flot.tooltip
3  * 
4  * description: easy-to-use tooltips for Flot charts
5  * version: 0.6
6  * author: Krzysztof Urbas @krzysu [myviews.pl]
7  * website: https://github.com/krzysu/flot.tooltip
8  * 
9  * build on 2013-01-07
10  * released under MIT License, 2012
13 (function ($) {
15     // plugin options, default values
16     var defaultOptions = {
17         tooltip: false,
18         tooltipOpts: {
19             content: "%s | X: %x | Y: %y",
20             // allowed templates are:
21             // %s -> series label,
22             // %x -> X value,
23             // %y -> Y value,
24             // %x.2 -> precision of X value,
25             // %p -> percent
26             xDateFormat: null,
27             yDateFormat: null,
28             shifts: {
29                 x: 10,
30                 y: 20
31             },
32             defaultTheme: true,
34             // callbacks
35             onHover: function(flotItem, $tooltipEl) {}
36         }
37     };
39     // object
40     var FlotTooltip = function(plot) {
42         // variables
43         this.tipPosition = {x: 0, y: 0};
45         this.init(plot);
46     };
48     // main plugin function
49     FlotTooltip.prototype.init = function(plot) {
50             
51         var that = this;
53         plot.hooks.bindEvents.push(function (plot, eventHolder) {
55             // get plot options            
56             that.plotOptions = plot.getOptions();
58             // if not enabled return
59             if (that.plotOptions.tooltip === false || typeof that.plotOptions.tooltip === 'undefined') return;
61             // shortcut to access tooltip options
62             that.tooltipOptions = that.plotOptions.tooltipOpts;
64             // create tooltip DOM element
65             var $tip = that.getDomElement();
66             
67             // bind event
68             $( plot.getPlaceholder() ).bind("plothover", function (event, pos, item) {
69                 if (item) {                    
70                     var tipText;
71                     
72                     // convert tooltip content template to real tipText
73                     tipText = that.stringFormat(that.tooltipOptions.content, item);
74                     
75                     $tip.html( tipText )
76                         .css({
77                             left: that.tipPosition.x + that.tooltipOptions.shifts.x,
78                             top: that.tipPosition.y + that.tooltipOptions.shifts.y
79                         })
80                         .show();
81                 
82                     // run callback
83                     if(typeof that.tooltipOptions.onHover === 'function') {
84                         that.tooltipOptions.onHover(item, $tip);
85                     }
86                 }
87                 else {
88                     $tip.hide().html('');
89                 }
90             });
91             
92             eventHolder.mousemove( function(e) {
93                 var pos = {};
94                 pos.x = e.pageX;
95                 pos.y = e.pageY;
96                 that.updateTooltipPosition(pos);
97             });
98         });
99     };
101     /**
102      * get or create tooltip DOM element 
103      * @return jQuery object
104      */
105     FlotTooltip.prototype.getDomElement = function() {
106         var $tip;
108         if( $('#flotTip').length > 0 ){
109             $tip = $('#flotTip');
110         }
111         else {
112             $tip = $('<div />').attr('id', 'flotTip');
113             $tip.appendTo('body').hide().css({position: 'absolute'});
114         
115             if(this.tooltipOptions.defaultTheme) {
116                 $tip.css({
117                     'background': '#fff',
118                     'z-index': '100',
119                     'padding': '0.4em 0.6em',
120                     'border-radius': '0.5em',
121                     'font-size': '0.8em',
122                     'border': '1px solid #111'
123                 });
124             }
125         }
127         return $tip;
128     };
130     // as the name says
131     FlotTooltip.prototype.updateTooltipPosition = function(pos) {
132         this.tipPosition.x = pos.x;
133         this.tipPosition.y = pos.y;
134     };
135     
136     /**
137      * core function, create tooltip content
138      * @param  {string} content - template with tooltip content
139      * @param  {object} item - Flot item
140      * @return {string} real tooltip content for current item
141      */
142     FlotTooltip.prototype.stringFormat = function(content, item) {
143         
144         var percentPattern = /%p\.{0,1}(\d{0,})/;
145         var seriesPattern = /%s/;
146         var xPattern = /%x\.{0,1}(\d{0,})/;
147         var yPattern = /%y\.{0,1}(\d{0,})/;
149         // if it is a function callback get the content string
150         if( typeof(content) === 'function' ) {
151             content = content(item.series.data[item.dataIndex][0], item.series.data[item.dataIndex][1]);
152         }
154         // percent match for pie charts
155         if( typeof (item.series.percent) !== 'undefined' ) {
156             content = this.adjustValPrecision(percentPattern, content, item.series.percent);
157         }
158         
159         // series match
160         if( typeof(item.series.label) !== 'undefined' ) {
161             content = content.replace(seriesPattern, item.series.label);
162         }
164         // time mode axes with custom dateFormat
165         if(this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) {
166             content = content.replace(xPattern, this.timestampToDate(item.series.data[item.dataIndex][0], this.tooltipOptions.xDateFormat));
167         }
169         if(this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) {
170             content = content.replace(yPattern, this.timestampToDate(item.series.data[item.dataIndex][1], this.tooltipOptions.yDateFormat));
171         }
173         // set precision if defined
174         if( typeof item.series.data[item.dataIndex][0] === 'number' ) {
175             content = this.adjustValPrecision(xPattern, content, item.series.data[item.dataIndex][0]);
176         }
177         if( typeof item.series.data[item.dataIndex][1] === 'number' ) {
178             content = this.adjustValPrecision(yPattern, content, item.series.data[item.dataIndex][1]);
179         }
181         // if no value customization, use tickFormatter by default
182         if(typeof item.series.xaxis.tickFormatter !== 'undefined') {
183             content = content.replace(xPattern, item.series.xaxis.tickFormatter(item.series.data[item.dataIndex][0], item.series.xaxis));
184         }
185         if(typeof item.series.yaxis.tickFormatter !== 'undefined') {
186             content = content.replace(yPattern, item.series.yaxis.tickFormatter(item.series.data[item.dataIndex][1], item.series.yaxis));
187         }
189         return content;
190     };
192     // helpers just for readability
193     FlotTooltip.prototype.isTimeMode = function(axisName, item) {
194         return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time');
195     };
197     FlotTooltip.prototype.isXDateFormat = function(item) {
198         return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null);
199     };
201     FlotTooltip.prototype.isYDateFormat = function(item) {
202         return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null);
203     };
205     // 
206     FlotTooltip.prototype.timestampToDate = function(tmst, dateFormat) {
207         var theDate = new Date(tmst);
208         return $.plot.formatDate(theDate, dateFormat);
209     };
210     
211     // 
212     FlotTooltip.prototype.adjustValPrecision = function(pattern, content, value) {
213         
214         var precision;
215         if( content.match(pattern) !== null ) {
216             if(RegExp.$1 !== '') {
217                 precision = RegExp.$1;
218                 value = value.toFixed(precision);
220                 // only replace content if precision exists
221                 content = content.replace(pattern, value);
222             }
223         }
224     
225         return content;
226     };
227     
228     // to have controll over existing instances
229     var tooltipsCollection = [];
231     // 
232     var init = function(plot) {
233         tooltipsCollection.push( new FlotTooltip(plot) );
234     };
236     // define Flot plugin
237     $.plot.plugins.push({
238         init: init,
239         options: defaultOptions,
240         name: 'tooltip',
241         version: '0.6'
242     });
244 })(jQuery);