1 
  2 /**
  3  * @fileoverview A base chart tooltip.
  4  * @version 1.0.0
  5  * @see https://google.github.io/styleguide/jsguide.html
  6  * @see https://github.com/google/closure-compiler/wiki
  7  */
  8 
  9 
 10 
 11 /**
 12  * A base chart tooltip.
 13  * @constructor
 14  */
 15 charts.Tooltip = function() {
 16 
 17   /**
 18    * Sets configuration options.
 19    * @param {!Object} options The configuration options.
 20    * @see charts.BaseChart#getOptions
 21    * @example
 22    * options: {
 23    *   'tooltip': {
 24    *     'paddings': '5px',
 25    *     'bgcolor': '#fff',
 26    *     'opacity': 0.9
 27    *   }
 28    * }
 29    */
 30   this.setOptions = function(options) {
 31     options_ = options;
 32     options_['tooltip'] = options_['tooltip'] || {};
 33     options_['tooltip']['paddings'] = options_['tooltip']['paddings'] || '5px';
 34     options_['tooltip']['bgcolor'] = options_['tooltip']['bgcolor'] || '#fff';
 35     options_['tooltip']['opacity'] = options_['tooltip']['opacity'] || '0.9';
 36     options_['tooltip']['template'] = options_['tooltip']['template'] ||
 37         '<b>{{ arg.0 }}</b><br>{{ arg.1 }}: {{ arg.2 }}';
 38   };
 39 
 40   /**
 41    * Shows tooltip element.
 42    * @param {Event} e The mouse event.
 43    * @param {number=} opt_x The optional X coord.
 44    * @param {number=} opt_y The optional Y coord.
 45    */
 46   this.show = function(e, opt_x, opt_y) {
 47     /** @type {!Object.<string, number>}  */ var coords = getCoords_(e);
 48     /** @type {string} */ var text = getTooltipText_(e);
 49     /** @type {number} */ var scrollTop =
 50         dom.document.documentElement.scrollTop + dom.document.body.scrollTop;
 51     /** @type {number} */ var offsetWidth =
 52         window.innerWidth ||
 53             (dom.document.documentElement || dom.document.body).offsetWidth;
 54 
 55     if (text) {
 56       self_.getTooltipElement().innerHTML = text;
 57       tooltip_.style.display = 'block';
 58       if (coords.y - scrollTop < tooltip_.offsetHeight)
 59         coords.y += tooltip_.offsetHeight;
 60       opt_y = opt_y || coords.y - tooltip_.offsetHeight - 5;
 61       if (offsetWidth < coords.x + tooltip_.offsetWidth)
 62         coords.x -= tooltip_.offsetWidth;
 63       opt_x = opt_x || coords.x + 5;
 64       tooltip_.style.top = opt_y + 'px';
 65       tooltip_.style.left = opt_x + 'px';
 66     }
 67   };
 68 
 69   /**
 70    * Hides tooltip element.
 71    * @param {Event} e The mouse event.
 72    */
 73   this.hide = function(e) {
 74     e = e || window.event || {};
 75     /** @type {Element} */ var target = e.target || e.srcElement;
 76     /** @type {Element} */ var related = e.relatedTarget || e.fromElement;
 77     if (tooltip_ && tooltip_ != target && tooltip_ != related)
 78       tooltip_.style.display = 'none';
 79   };
 80 
 81   /**
 82    * Gets reference to tooltip HTML element.
 83    * @return {!Node} Returns reference to tooltip HTML element.
 84    */
 85   this.getTooltipElement = function() {
 86     if (!tooltip_) {
 87       tooltip_ = dom.document.body.appendChild(dom.createElement('DIV'));
 88       /** @type {CSSStyleDeclaration} */ var style = tooltip_.style;
 89       style.display = 'none';
 90       style.zIndex = 999;
 91       style.cursor = 'default';
 92       style.whiteSpace = 'nowrap';
 93       //style.maxWidth = '150px';
 94       style.position = 'absolute';
 95       style.border = 'solid 1px #ccc';
 96       style.fontFamily = options_['font']['family'];
 97       style.fontSize = options_['font']['size'] + 'px';
 98       style.padding = options_['tooltip']['paddings'];
 99       style.background = options_['tooltip']['bgcolor'];
100       style.borderRadius = '3px';
101       style.opacity = options_['tooltip']['opacity'];
102       style.filter =
103           'alpha(opacity=' + (options_['tooltip']['opacity'] * 100) + ')';
104       tooltip_.onmouseout = function() {
105         style.display = 'none';
106       };
107     }
108     return tooltip_;
109   };
110 
111   /**
112    * Parses tooltip template content.
113    * @param {...*} var_args
114    * @return {string} Returns parsed tooltip template content.
115    */
116   this.parse = function(var_args) {
117     /** @type {string} */ var content = options_['tooltip']['template'];
118     /** @type {!Object.<string, *>} */ var params = {};
119     for (/** @type {number} */ var i = 0; i < arguments.length; i++) {
120       params['arg.' + i] = arguments[i];
121     }
122     return template_.parse(content, params);
123   };
124 
125   /**
126    * @param {Event} e The mouse event.
127    * @return {!Object.<string, number>} Returns X and Y coordinates.
128    * @private
129    */
130   function getCoords_(e) {
131     e = e || window.event;
132     /** @type {!Object.<string, number>} */ var result = {x: 0, y: 0};
133     if (e.pageX || e.pageY) {
134       result = {x: e.pageX, y: e.pageY};
135     } else if (e.clientX || e.clientY) {
136       /** @type {Element} */ var body = dom.document.body;
137       /** @type {Element} */ var root = dom.document.documentElement;
138       result = {
139         x: e.clientX + (body.scrollLeft || 0) + (root.scrollLeft || 0),
140         y: e.clientY + (body.scrollTop || 0) + (root.scrollTop || 0)
141       };
142     }
143     return result;
144   }
145 
146   /**
147    * @param {Event} e The mouse event.
148    * @return {string} Returns tooltip text.
149    * @private
150    */
151   function getTooltipText_(e) {
152     e = e || window.event || {};
153     /** @type {string} */ var text = '';
154     /** @type {Element} */ var target = e.target || e.srcElement;
155     /** @type {Element} */ var related = e.relatedTarget || e.fromElement ||
156         target.previousSibling || target.parentNode;
157 
158     try {
159       if ('text' == target.tagName) text = related.getAttribute('tooltip');
160       else text = target.getAttribute('tooltip');
161     } catch (ex) {}
162 
163     if (!text) {
164       try {
165         text = target.getAttribute('title') || related.getAttribute('tooltip');
166         target.setAttribute('tooltip', text);
167         target.removeAttribute('title');
168       } catch (ex) {}
169     }
170     return text;
171   }
172 
173   /**
174    * The reference to current class instance. Used in private methods.
175    * @type {!charts.Tooltip}
176    * @private
177    */
178   var self_ = this;
179 
180   /**
181    * Reference to tooltip HTML element.
182    * @type {Node}
183    * @private
184    */
185   var tooltip_ = null;
186 
187   /**
188    * Storage for configuration options.
189    * @dict
190    * @private
191    */
192   var options_ = null;
193 
194   /**
195    * Instance of <code>dom.Template</code>.
196    * @type {!dom.Template}
197    * @see dom.Template
198    * @private
199    */
200   var template_ = new dom.Template;
201 };
202