UNPKG

kibana-123

Version:

Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elastic

186 lines (159 loc) 4.55 kB
import d3 from 'd3'; import _ from 'lodash'; import Binder from 'ui/binder'; import positionTooltip from './position_tooltip'; import $ from 'jquery'; let allContents = []; /** * Add tooltip and listeners to visualization elements * * @class Tooltip * @constructor * @param el {HTMLElement} Reference to DOM element * @param formatter {Function} Tooltip formatter * @param events {Constructor} Allows tooltip to return event response data */ function Tooltip(id, el, formatter, events) { if (!(this instanceof Tooltip)) { return new Tooltip(id, el, formatter, events); } this.id = id; // unique id for this tooltip type this.el = el; this.order = 100; // higher ordered contents are rendered below the others this.formatter = formatter; this.events = events; this.containerClass = 'vis-wrapper'; this.tooltipClass = 'vis-tooltip'; this.tooltipSizerClass = 'vis-tooltip-sizing-clone'; this.showCondition = _.constant(true); this.binder = new Binder(); } /** * Get jquery reference to the tooltip node * * @return {Object} jQuery node object */ Tooltip.prototype.$get = _.once(function () { return $('<div>').addClass(this.tooltipClass).appendTo(document.body); }); /** * Get jquery reference to the tooltip sizer node * * @return {Object} jQuery node object */ Tooltip.prototype.$getSizer = _.once(function () { return this.$get() .clone() .removeClass(this.tooltipClass) .addClass(this.tooltipSizerClass) .appendTo(document.body); }); /** * Show the tooltip, positioning it based on the content and chart container */ Tooltip.prototype.show = function () { const $tooltip = this.$get(); const $chart = this.$getChart(); const html = $tooltip.html(); if (!$chart) return; const placement = positionTooltip({ $window: $(window), $chart: $chart, $el: $tooltip, $sizer: this.$getSizer(), event: d3.event }, html); $tooltip.css({ visibility: 'visible', left: placement.left, top: placement.top }); }; /** * Hide the tooltip, clearing its contents */ Tooltip.prototype.hide = function () { const $tooltip = this.$get(); allContents = []; $tooltip.css({ visibility: 'hidden', left: '-500px', top: '-500px' }); }; /** * Get the jQuery chart node, based on the container object * NOTE: the container is a d3 selection * * @return {Object} jQuery node for the chart */ Tooltip.prototype.$getChart = function () { const chart = $(this.container && this.container.node()); return chart.size() ? chart : false; }; /** * Renders tooltip * * @method render * @return {Function} Renders tooltip on a D3 selection */ Tooltip.prototype.render = function () { const self = this; /** * Calculates values for the tooltip placement * * @param {Object} selection D3 selection object */ return function (selection) { const $tooltip = self.$get(); const id = self.id; const order = self.order; if (self.container === undefined || self.container !== d3.select(self.el).select('.' + self.containerClass)) { self.container = d3.select(self.el).select('.' + self.containerClass); } const $chart = self.$getChart(); if ($chart) { self.binder.jqOn($chart, 'mouseleave', function () { // only clear when we leave the chart, so that // moving between points doesn't make it reposition $chart.removeData('previousPlacement'); }); } selection.each(function (d, i) { const element = d3.select(this); function render(html) { allContents = _.filter(allContents, function (content) { return content.id !== id; }); if (html) allContents.push({ id: id, html: html, order: order }); const allHtml = _(allContents) .sortBy('order') .pluck('html') .compact() .join('\n'); if (allHtml) { $tooltip.html(allHtml); self.show(); } else { self.hide(); } } self.binder.fakeD3Bind(this, 'mousemove', function () { if (!self.showCondition.call(element, d, i)) { return render(); } const events = self.events ? self.events.eventResponse(d, i) : d; return render(self.formatter(events)); }); self.binder.fakeD3Bind(this, 'mouseleave', function () { render(); }); }); }; }; Tooltip.prototype.destroy = function () { this.binder.destroy(); }; module.exports = function TooltipFactoryProvider() { return Tooltip; };