mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[vislib/tooltip] prevent creating unneeded tooltip elements
This commit is contained in:
parent
129c10fb78
commit
245b317c4f
4 changed files with 49 additions and 35 deletions
|
@ -5,13 +5,13 @@ define(function (require) {
|
|||
var OFFSET = 10;
|
||||
var $clone;
|
||||
|
||||
function positionTooltip($window, $chart, $tooltip, event) {
|
||||
function positionTooltip($window, $chart, $tooltip, $sizer, event) {
|
||||
$chart = $($chart);
|
||||
$tooltip = $($tooltip);
|
||||
|
||||
if (!$chart.size() || !$tooltip.size()) return;
|
||||
|
||||
var size = getTtSize($tooltip);
|
||||
var size = getTtSize($tooltip, $sizer);
|
||||
var pos = getBasePosition(size, event);
|
||||
|
||||
var overflow = getOverflow(size, pos, [$chart, $window]);
|
||||
|
@ -19,25 +19,15 @@ define(function (require) {
|
|||
return placeToAvoidOverflow(pos, overflow);
|
||||
}
|
||||
|
||||
function getTtSize($tooltip) {
|
||||
if (!$clone || $clone.html() !== $tooltip.html()) {
|
||||
$clone && $clone.remove();
|
||||
|
||||
$clone = $tooltip
|
||||
.clone()
|
||||
.addClass('vis-tooltip-sizing-clone')
|
||||
.css({
|
||||
visibility: 'hidden',
|
||||
position: 'absolute',
|
||||
top: -500,
|
||||
left: -500
|
||||
})
|
||||
.appendTo('body');
|
||||
function getTtSize($tooltip, $sizer) {
|
||||
var ttHtml = $tooltip.html();
|
||||
if ($sizer.html() !== ttHtml) {
|
||||
$sizer.html(ttHtml);
|
||||
}
|
||||
|
||||
var size = {
|
||||
width: $clone.outerWidth(),
|
||||
height: $clone.outerHeight()
|
||||
width: $sizer.outerWidth(),
|
||||
height: $sizer.outerHeight()
|
||||
};
|
||||
|
||||
return size;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
define(function (require) {
|
||||
return function TooltipFactory(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
|
||||
require('css!components/vislib/styles/main');
|
||||
|
@ -20,13 +21,26 @@ define(function (require) {
|
|||
this.el = el;
|
||||
this.formatter = formatter;
|
||||
this.events = events;
|
||||
this.tooltipClass = 'vis-tooltip';
|
||||
this.containerClass = 'vis-wrapper';
|
||||
this.tooltipClass = 'vis-tooltip';
|
||||
this.tooltipSizerClass = 'vis-tooltip-sizing-clone';
|
||||
|
||||
this.$window = $(window);
|
||||
this.$chart = $(el).find('.' + this.containerClass);
|
||||
}
|
||||
|
||||
Tooltip.prototype.$get = _.once(function () {
|
||||
return $('<div>').addClass(this.tooltipClass).appendTo(document.body);
|
||||
});
|
||||
|
||||
Tooltip.prototype.$getSizer = _.once(function () {
|
||||
return this.$get()
|
||||
.clone()
|
||||
.removeClass(this.tooltipClass)
|
||||
.addClass(this.tooltipSizerClass)
|
||||
.appendTo(document.body);
|
||||
});
|
||||
|
||||
/**
|
||||
* Calculates values for the tooltip placement
|
||||
*
|
||||
|
@ -47,17 +61,14 @@ define(function (require) {
|
|||
var tooltipFormatter = this.formatter;
|
||||
|
||||
return function (selection) {
|
||||
|
||||
if (d3.select('body').select('.' + self.tooltipClass)[0][0] === null) {
|
||||
d3.select('body').append('div').attr('class', self.tooltipClass);
|
||||
}
|
||||
var $tooltip = self.$get();
|
||||
var $sizer = self.$getSizer();
|
||||
var tooltipSelection = d3.select($tooltip.get(0));
|
||||
|
||||
if (self.container === undefined || self.container !== d3.select(self.el).select('.' + self.containerClass)) {
|
||||
self.container = d3.select(self.el).select('.' + self.containerClass);
|
||||
}
|
||||
|
||||
var tooltipDiv = d3.select('.' + self.tooltipClass);
|
||||
|
||||
selection.each(function (d, i) {
|
||||
var element = d3.select(this);
|
||||
|
||||
|
@ -66,7 +77,8 @@ define(function (require) {
|
|||
var placement = self.getTooltipPlacement(
|
||||
self.$window,
|
||||
self.$chart,
|
||||
$('.' + self.tooltipClass),
|
||||
$tooltip,
|
||||
$sizer,
|
||||
d3.event
|
||||
);
|
||||
if (!placement) return;
|
||||
|
@ -74,14 +86,14 @@ define(function (require) {
|
|||
var events = self.events ? self.events.eventResponse(d, i) : d;
|
||||
|
||||
// return text and position for tooltip
|
||||
return tooltipDiv.datum(events)
|
||||
return tooltipSelection.datum(events)
|
||||
.html(tooltipFormatter)
|
||||
.style('visibility', 'visible')
|
||||
.style('left', placement.left + 'px')
|
||||
.style('top', placement.top + 'px');
|
||||
})
|
||||
.on('mouseout.tip', function () {
|
||||
return tooltipDiv.style('visibility', 'hidden')
|
||||
return tooltipSelection.style('visibility', 'hidden')
|
||||
.style('left', '-500px')
|
||||
.style('top', '-500px');
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@import (reference) "../../../styles/main";
|
||||
|
||||
.vis-tooltip {
|
||||
.vis-tooltip,
|
||||
.vis-tooltip-sizing-clone {
|
||||
visibility: hidden;
|
||||
line-height: 1.1;
|
||||
font-size: 12px;
|
||||
|
@ -34,3 +35,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vis-tooltip-sizing-clone {
|
||||
visibility: hidden;
|
||||
position: fixed;
|
||||
top: -500px;
|
||||
left: -500px;
|
||||
}
|
|
@ -11,6 +11,7 @@ define(function (require) {
|
|||
var $window;
|
||||
var $chart;
|
||||
var $tooltip;
|
||||
var $sizer;
|
||||
|
||||
function testEl(width, height, $children) {
|
||||
var $el = $('<div>');
|
||||
|
@ -42,11 +43,13 @@ define(function (require) {
|
|||
$tooltip = testEl([50, 100], [35, 75])
|
||||
)
|
||||
);
|
||||
|
||||
$sizer = $tooltip.clone().appendTo($window);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
$window.remove();
|
||||
$window = $chart = $tooltip = null;
|
||||
$window = $chart = $tooltip = $sizer = null;
|
||||
posTT.removeClone();
|
||||
});
|
||||
|
||||
|
@ -67,7 +70,7 @@ define(function (require) {
|
|||
var w = sinon.spy($.fn, 'outerWidth');
|
||||
var h = sinon.spy($.fn, 'outerHeight');
|
||||
|
||||
posTT.getTtSize($tooltip);
|
||||
posTT.getTtSize($tooltip, $sizer);
|
||||
|
||||
[w, h].forEach(function (spy) {
|
||||
expect(spy).to.have.property('callCount', 1);
|
||||
|
@ -81,7 +84,7 @@ define(function (require) {
|
|||
|
||||
describe('getBasePosition()', function () {
|
||||
it('calculates the offset values for the four positions', function () {
|
||||
var size = posTT.getTtSize($tooltip);
|
||||
var size = posTT.getTtSize($tooltip, $sizer);
|
||||
var pos = posTT.getBasePosition(size, makeEvent());
|
||||
|
||||
positions.forEach(function (p) {
|
||||
|
@ -110,7 +113,8 @@ define(function (require) {
|
|||
it('determines how much the base placement overflows the containing bounds in each direction', function () {
|
||||
// size the tooltip very small so it won't collide with the edges
|
||||
$tooltip.css({ width: 15, height: 15 });
|
||||
var size = posTT.getTtSize($tooltip);
|
||||
$sizer.css({ width: 15, height: 15 });
|
||||
var size = posTT.getTtSize($tooltip, $sizer);
|
||||
expect(size).to.have.property('width', 15);
|
||||
expect(size).to.have.property('height', 15);
|
||||
|
||||
|
@ -127,7 +131,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
it('identifies an overflow with a positive value in that direction', function () {
|
||||
var size = posTT.getTtSize($tooltip);
|
||||
var size = posTT.getTtSize($tooltip, $sizer);
|
||||
|
||||
// position the element based on a mouse that is in the bottom right hand courner of the chart
|
||||
var pos = posTT.getBasePosition(size, makeEvent(0.99, 0.99));
|
||||
|
@ -155,7 +159,7 @@ define(function (require) {
|
|||
function check(xPercent, yPercent/*, directions... */) {
|
||||
var directions = _.rest(arguments, 2);
|
||||
var event = makeEvent(xPercent, yPercent);
|
||||
var placement = posTT($window, $chart, $tooltip, event);
|
||||
var placement = posTT($window, $chart, $tooltip, $sizer, event);
|
||||
|
||||
expect(placement).to.have.property('top').and.property('left');
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue