]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Avoid tooltip truncation in x axis if there is enough space (#3998)
authorKaido Hallik <kaidohallik@gmail.com>
Sat, 11 Nov 2017 23:02:05 +0000 (01:02 +0200)
committerEvert Timberg <evert.timberg+github@gmail.com>
Sat, 11 Nov 2017 23:02:05 +0000 (18:02 -0500)
* 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

src/core/core.tooltip.js
test/specs/core.tooltip.tests.js

index 73460f8d106401376fd6c225acf13f4ec2e0b405..0072580dfbf1141ea046755a260990a56768d59a 100644 (file)
@@ -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';
@@ -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;
@@ -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') {
@@ -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;
                        }
@@ -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;
                                }
index 632f8121daf36f09188f83c8f98814055b055c6b..c0a162968b183c00326e6a7fe11e1265a5602b29 100755 (executable)
@@ -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;
+                               }
+                       }
+               }
+       });
 });