Skip to content

Commit

Permalink
Avoid tooltip truncation in x axis if there is enough space (#3998)
Browse files Browse the repository at this point in the history
* In tooltip x align calculation take into account caretSize

Truncation up to caretSize pixels could happen if label text produced tooltip element with size width:
* left side tooltip: width < x and width > x - caretSize
* right side tooltip: width < chartWidth - x and width > chartWidth - x - caretSize
Default caretSize = 5, so with default configuration truncation up to 5 pixels could happen.

* avoid tooltip truncation if possible
use whole chart area for displaying tooltip

* in xAlign calculation take into account caretPadding

* add tests for tooltip truncation avoid logic

* use caretX instead of xCaret

* fix lint errors
  • Loading branch information
kaidohallik authored and etimberg committed Nov 11, 2017
1 parent 939756c commit 683e86e
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/core/core.tooltip.js
Expand Up @@ -299,10 +299,10 @@ module.exports = function(Chart) {
}

olf = function(x) {
return x + size.width > chart.width;
return x + size.width + model.caretSize + model.caretPadding > chart.width;
};
orf = function(x) {
return x - size.width < 0;
return x - size.width - model.caretSize - model.caretPadding < 0;
};
yf = function(y) {
return y <= midY ? 'top' : 'bottom';
Expand Down Expand Up @@ -336,7 +336,7 @@ module.exports = function(Chart) {
/**
* @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
*/
function getBackgroundPoint(vm, size, alignment) {
function getBackgroundPoint(vm, size, alignment, chart) {
// Background Position
var x = vm.x;
var y = vm.y;
Expand All @@ -353,6 +353,12 @@ module.exports = function(Chart) {
x -= size.width;
} else if (xAlign === 'center') {
x -= (size.width / 2);
if (x + size.width > chart.width) {
x = chart.width - size.width;
}
if (x < 0) {
x = 0;
}
}

if (yAlign === 'top') {
Expand Down Expand Up @@ -545,7 +551,7 @@ module.exports = function(Chart) {
tooltipSize = getTooltipSize(this, model);
alignment = determineAlignment(this, tooltipSize);
// Final Size and Position
backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment);
backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
} else {
model.opacity = 0;
}
Expand Down Expand Up @@ -617,7 +623,7 @@ module.exports = function(Chart) {
x1 = x2 - caretSize;
x3 = x2 + caretSize;
} else {
x2 = ptX + (width / 2);
x2 = vm.caretX;
x1 = x2 - caretSize;
x3 = x2 + caretSize;
}
Expand Down
67 changes: 67 additions & 0 deletions test/specs/core.tooltip.tests.js
Expand Up @@ -882,4 +882,71 @@ describe('Core.Tooltip', function() {
expect(fn.calls.first().object instanceof Chart.Tooltip).toBe(true);
});
});

it('Should avoid tooltip truncation in x axis if there is enough space to show tooltip without truncation', function() {
var chart = window.acquireChart({
type: 'pie',
data: {
datasets: [{
data: [
50,
50
],
backgroundColor: [
'rgb(255, 0, 0)',
'rgb(0, 255, 0)'
],
label: 'Dataset 1'
}],
labels: [
'Red long tooltip text to avoid unnecessary loop steps',
'Green long tooltip text to avoid unnecessary loop steps'
]
},
options: {
responsive: true,
animation: {
// without this slice center point is calculated wrong
animateRotate: false
}
}
});

// Trigger an event over top of the slice
for (var slice = 0; slice < 2; slice++) {
var meta = chart.getDatasetMeta(0);
var point = meta.data[slice].getCenterPoint();
var tooltipPosition = meta.data[slice].tooltipPosition();
var node = chart.canvas;
var rect = node.getBoundingClientRect();

var mouseMoveEvent = new MouseEvent('mousemove', {
view: window,
bubbles: true,
cancelable: true,
clientX: rect.left + point.x,
clientY: rect.top + point.y
});
var mouseOutEvent = new MouseEvent('mouseout');

// Lets cycle while tooltip is narrower than chart area
var infiniteCycleDefense = 70;
for (var i = 0; i < infiniteCycleDefense; i++) {
chart.config.data.labels[slice] = chart.config.data.labels[slice] + 'l';
chart.update();
node.dispatchEvent(mouseOutEvent);
node.dispatchEvent(mouseMoveEvent);
var model = chart.tooltip._model;
expect(model.x).toBeGreaterThanOrEqual(0);
if (model.width <= chart.width) {
expect(model.x + model.width).toBeLessThanOrEqual(chart.width);
}
expect(model.caretX).toBe(tooltipPosition.x);
// if tooltip is longer than chart area then all tests done
if (model.width > chart.width) {
break;
}
}
}
});
});

0 comments on commit 683e86e

Please sign in to comment.