Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,26 @@ define(function (require) {
var OFFSET = 10;
var $clone;

function positionTooltip($window, $chart, $tooltip, $sizer, event) {
$chart = $($chart);
$tooltip = $($tooltip);

if (!$chart.size() || !$tooltip.size()) return;

var size = getTtSize($tooltip, $sizer);
function positionTooltip(opts) {
if (!opts) return;
var $chart = $(opts.$chart);
var $el = $(opts.$el);
var $window = $(opts.$window || window);
var $sizer = $(opts.$sizer);
var prev = opts.prev || {};
var event = opts.event;

if (!$chart.size() || !$el.size()) return;

var size = getTtSize($el, $sizer);
var pos = getBasePosition(size, event);

var overflow = getOverflow(size, pos, [$chart, $window]);

return placeToAvoidOverflow(pos, overflow);
return placeToAvoidOverflow(pos, prev, overflow);
}

function getTtSize($tooltip, $sizer) {
var ttHtml = $tooltip.html();
function getTtSize($el, $sizer) {
var ttHtml = $el.html();
if ($sizer.html() !== ttHtml) {
$sizer.html(ttHtml);
}
Expand Down Expand Up @@ -77,29 +81,32 @@ define(function (require) {
});
}

function placeToAvoidOverflow(pos, overflow) {
var placement = {};
function pickPlacement(prop, pos, overflow, prev, pref, fallback, placement) {
var stash = '_' + prop;

if (overflow.south > 0) {
if (overflow.north < 0) {
placement.top = pos.north;
} else {
placement.top = pos.south - overflow.south;
}
} else {
placement.top = pos.south;
}
// first choice
var first = prev[stash] || pref;
// second choice
var second = first === pref ? fallback : pref;

if (overflow.east > 0) {
if (overflow.west < 0) {
placement.left = pos.west;
if (overflow[first] > 0) {
if (overflow[second] < 0) {
placement[prop] = pos[second];
placement[stash] = second;
} else {
placement.left = pos.east - overflow.east;
placement[prop] = pos[first] - overflow[first];
placement[stash] = first;
}
} else {
placement.left = pos.east;
placement[prop] = pos[first];
placement[stash] = first;
}
}

function placeToAvoidOverflow(pos, prev, overflow) {
var placement = {};
pickPlacement('top', pos, overflow, prev, 'south', 'north', placement);
pickPlacement('left', pos, overflow, prev, 'east', 'west', placement);
return placement;
}

Expand Down
25 changes: 18 additions & 7 deletions src/kibana/components/vislib/components/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,29 @@ define(function (require) {
self.container = d3.select(self.el).select('.' + self.containerClass);
}

self.$chart.on('mouseleave', function (event) {
// if the mouse moves fast enough, it can "leave"
// by entering the tooltip
if ($tooltip.is(event.relatedTarget)) return;

// only clear when we leave the chart, so that
// moving between points doesn't make it reposition
self.previousPlacement = null;
});

selection.each(function (d, i) {
var element = d3.select(this);

element
.on('mousemove.tip', function () {
var placement = self.getTooltipPlacement(
self.$window,
self.$chart,
$tooltip,
$sizer,
d3.event
);
var placement = self.previousPlacement = self.getTooltipPlacement({
$window: self.$window,
$chart: self.$chart,
$el: $tooltip,
$sizer: $sizer,
event: d3.event,
prev: self.previousPlacement
});
if (!placement) return;

var events = self.events ? self.events.eventResponse(d, i) : d;
Expand Down
25 changes: 23 additions & 2 deletions test/unit/specs/vislib/components/tooltip/_positioning.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,17 @@ define(function (require) {
expect(posTT(null, $(), $()) === void 0).to.be(true);
});

function check(xPercent, yPercent/*, directions... */) {
function check(xPercent, yPercent/*, prev, directions... */) {
var directions = _.rest(arguments, 2);
var event = makeEvent(xPercent, yPercent);
var placement = posTT($window, $chart, $tooltip, $sizer, event);
var placement = posTT({
$window: $window,
$chart: $chart,
$sizer: $sizer,
event: event,
$el: $tooltip,
prev: _.isObject(directions[0]) ? directions.shift() : null
});

expect(placement).to.have.property('top').and.property('left');

Expand All @@ -179,6 +186,8 @@ define(function (require) {
return;
}
});

return placement;
}

describe('calculates placement of the tooltip properly', function () {
Expand All @@ -202,6 +211,18 @@ define(function (require) {
check(0.10, 0.99, 'top', 'right');
});
});

describe('maintain the direction of the tooltip on reposition', function () {
it('mouse moves from the top right to the middle', function () {
var pos = check(0.99, 0.10, 'bottom', 'left');
check(0.50, 0.50, pos, 'bottom', 'left');
});

it('mouse moves from the bottom left to the middle', function () {
var pos = check(0.10, 0.99, 'top', 'right');
check(0.50, 0.50, pos, 'top', 'right');
});
});
});
});
};
Expand Down