]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Use font lineHeight for tooltip alignment (#8631)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sat, 13 Mar 2021 20:14:48 +0000 (15:14 -0500)
committerGitHub <noreply@github.com>
Sat, 13 Mar 2021 20:14:48 +0000 (15:14 -0500)
* Use font lineHeight for tooltip alignment
* Remove toFontString usage from tooltip

src/plugins/plugin.tooltip.js
test/specs/plugin.tooltip.tests.js

index 16aef128d7e5c4e69dee319d8fef3569d9b7d758..9660e2cfd2c7762c305fd81f99a78a0aac96c0d9 100644 (file)
@@ -1,10 +1,10 @@
 import Animations from '../core/core.animations';
 import Element from '../core/core.element';
 import {each, noop, isNullOrUndef, isArray, _elementsEqual} from '../helpers/helpers.core';
-import {toPadding} from '../helpers/helpers.options';
+import {toFont, toPadding} from '../helpers/helpers.options';
 import {getRtlAdapter, overrideTextDirection, restoreTextDirection} from '../helpers/helpers.rtl';
 import {distanceBetweenPoints} from '../helpers/helpers.math';
-import {drawPoint, toFontString} from '../helpers';
+import {drawPoint} from '../helpers';
 
 /**
  * @typedef { import("../platform/platform.base").ChartEvent } ChartEvent
@@ -139,7 +139,10 @@ function createTooltipItem(chart, item) {
 function getTooltipSize(tooltip, options) {
   const ctx = tooltip._chart.ctx;
   const {body, footer, title} = tooltip;
-  const {bodyFont, footerFont, titleFont, boxWidth, boxHeight} = options;
+  const {boxWidth, boxHeight} = options;
+  const bodyFont = toFont(options.bodyFont);
+  const titleFont = toFont(options.titleFont);
+  const footerFont = toFont(options.footerFont);
   const titleLineCount = title.length;
   const footerLineCount = footer.length;
   const bodyLineItemCount = body.length;
@@ -153,20 +156,20 @@ function getTooltipSize(tooltip, options) {
   combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
 
   if (titleLineCount) {
-    height += titleLineCount * titleFont.size
+    height += titleLineCount * titleFont.lineHeight
                        + (titleLineCount - 1) * options.titleSpacing
                        + options.titleMarginBottom;
   }
   if (combinedBodyLength) {
     // Body lines may include some extra height depending on boxHeight
-    const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.size) : bodyFont.size;
+    const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
     height += bodyLineItemCount * bodyLineHeight
-                       + (combinedBodyLength - bodyLineItemCount) * bodyFont.size
+                       + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight
                        + (combinedBodyLength - 1) * options.bodySpacing;
   }
   if (footerLineCount) {
     height += options.footerMarginTop
-                       + footerLineCount * footerFont.size
+                       + footerLineCount * footerFont.lineHeight
                        + (footerLineCount - 1) * options.footerSpacing;
   }
 
@@ -178,11 +181,11 @@ function getTooltipSize(tooltip, options) {
 
   ctx.save();
 
-  ctx.font = toFontString(titleFont);
+  ctx.font = titleFont.string;
   each(tooltip.title, maxLineWidth);
 
   // Body width
-  ctx.font = toFontString(bodyFont);
+  ctx.font = bodyFont.string;
   each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
 
   // Body lines may include some extra width due to the color box
@@ -197,7 +200,7 @@ function getTooltipSize(tooltip, options) {
   widthPadding = 0;
 
   // Footer width
-  ctx.font = toFontString(footerFont);
+  ctx.font = footerFont.string;
   each(tooltip.footer, maxLineWidth);
 
   ctx.restore();
@@ -652,15 +655,15 @@ export class Tooltip extends Element {
       ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
       ctx.textBaseline = 'middle';
 
-      titleFont = options.titleFont;
+      titleFont = toFont(options.titleFont);
       titleSpacing = options.titleSpacing;
 
       ctx.fillStyle = options.titleColor;
-      ctx.font = toFontString(titleFont);
+      ctx.font = titleFont.string;
 
       for (i = 0; i < length; ++i) {
-        ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.size / 2);
-        pt.y += titleFont.size + titleSpacing; // Line Height and spacing
+        ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);
+        pt.y += titleFont.lineHeight + titleSpacing; // Line Height and spacing
 
         if (i + 1 === length) {
           pt.y += options.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
@@ -676,10 +679,11 @@ export class Tooltip extends Element {
     const me = this;
     const labelColors = me.labelColors[i];
     const labelPointStyle = me.labelPointStyles[i];
-    const {boxHeight, boxWidth, bodyFont} = options;
+    const {boxHeight, boxWidth} = options;
+    const bodyFont = toFont(options.bodyFont);
     const colorX = getAlignedX(me, 'left', options);
     const rtlColorX = rtlHelper.x(colorX);
-    const yOffSet = boxHeight < bodyFont.size ? (bodyFont.size - boxHeight) / 2 : 0;
+    const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
     const colorY = pt.y + yOffSet;
 
     if (options.usePointStyle) {
@@ -725,8 +729,9 @@ export class Tooltip extends Element {
   drawBody(pt, ctx, options) {
     const me = this;
     const {body} = me;
-    const {bodyFont, bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth} = options;
-    let bodyLineHeight = bodyFont.size;
+    const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth} = options;
+    const bodyFont = toFont(options.bodyFont);
+    let bodyLineHeight = bodyFont.lineHeight;
     let xLinePadding = 0;
 
     const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
@@ -741,7 +746,7 @@ export class Tooltip extends Element {
 
     ctx.textAlign = bodyAlign;
     ctx.textBaseline = 'middle';
-    ctx.font = toFontString(bodyFont);
+    ctx.font = bodyFont.string;
 
     pt.x = getAlignedX(me, bodyAlignForCalculation, options);
 
@@ -765,13 +770,13 @@ export class Tooltip extends Element {
       // Draw Legend-like boxes if needed
       if (displayColors && lines.length) {
         me._drawColorBox(ctx, pt, i, rtlHelper, options);
-        bodyLineHeight = Math.max(bodyFont.size, boxHeight);
+        bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
       }
 
       for (j = 0, jlen = lines.length; j < jlen; ++j) {
         fillLineOfText(lines[j]);
         // Reset for any lines that don't include colorbox
-        bodyLineHeight = bodyFont.size;
+        bodyLineHeight = bodyFont.lineHeight;
       }
 
       each(bodyItem.after, fillLineOfText);
@@ -779,7 +784,7 @@ export class Tooltip extends Element {
 
     // Reset back to 0 for after body
     xLinePadding = 0;
-    bodyLineHeight = bodyFont.size;
+    bodyLineHeight = bodyFont.lineHeight;
 
     // After body lines
     each(me.afterBody, fillLineOfText);
@@ -801,14 +806,14 @@ export class Tooltip extends Element {
       ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
       ctx.textBaseline = 'middle';
 
-      footerFont = options.footerFont;
+      footerFont = toFont(options.footerFont);
 
       ctx.fillStyle = options.footerColor;
-      ctx.font = toFontString(footerFont);
+      ctx.font = footerFont.string;
 
       for (i = 0; i < length; ++i) {
-        ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.size / 2);
-        pt.y += footerFont.size + options.footerSpacing;
+        ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);
+        pt.y += footerFont.lineHeight + options.footerSpacing;
       }
     }
   }
index 836b499fa782c82106ce9ac6e536f1b71f463a36..9dbd198e62703c57f498152a6c62ad2d0c113077 100644 (file)
@@ -163,8 +163,8 @@ describe('Plugin.Tooltip', function() {
         }]
       }));
 
-      expect(tooltip.x).toBeCloseToPixel(267);
-      expect(tooltip.y).toBeCloseToPixel(155);
+      expect(tooltip.x).toBeCloseToPixel(266);
+      expect(tooltip.y).toBeCloseToPixel(150);
     });
 
     it('Should only display if intersecting if intersect is set', async function() {
@@ -311,7 +311,7 @@ describe('Plugin.Tooltip', function() {
     }]);
 
     expect(tooltip.x).toBeCloseToPixel(267);
-    expect(tooltip.y).toBeCloseToPixel(312);
+    expect(tooltip.y).toBeCloseToPixel(308);
   });
 
   it('Should display information from user callbacks', async function() {
@@ -475,7 +475,7 @@ describe('Plugin.Tooltip', function() {
     }));
 
     expect(tooltip.x).toBeCloseToPixel(267);
-    expect(tooltip.y).toBeCloseToPixel(75);
+    expect(tooltip.y).toBeCloseToPixel(58);
   });
 
   it('Should provide context object to user callbacks', async function() {
@@ -581,7 +581,7 @@ describe('Plugin.Tooltip', function() {
     }));
 
     expect(tooltip.x).toBeCloseToPixel(267);
-    expect(tooltip.y).toBeCloseToPixel(155);
+    expect(tooltip.y).toBeCloseToPixel(150);
   });
 
   it('Should allow reversing items', async function() {
@@ -649,7 +649,7 @@ describe('Plugin.Tooltip', function() {
     }));
 
     expect(tooltip.x).toBeCloseToPixel(267);
-    expect(tooltip.y).toBeCloseToPixel(155);
+    expect(tooltip.y).toBeCloseToPixel(150);
   });
 
   it('Should follow dataset order', async function() {
@@ -718,7 +718,7 @@ describe('Plugin.Tooltip', function() {
     }));
 
     expect(tooltip.x).toBeCloseToPixel(267);
-    expect(tooltip.y).toBeCloseToPixel(155);
+    expect(tooltip.y).toBeCloseToPixel(150);
   });
 
   it('should filter items from the tooltip using the callback', async function() {
@@ -1393,18 +1393,18 @@ describe('Plugin.Tooltip', function() {
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['title', 105, 111]},
+        {name: 'fillText', args: ['title', 105, 112.2]},
         {name: 'setTextAlign', args: ['left']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFillStyle', args: ['#fff']},
-        {name: 'fillText', args: ['label', 105, 129]},
+        {name: 'fillText', args: ['label', 105, 132.6]},
         {name: 'setTextAlign', args: ['left']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['footer', 105, 147]},
+        {name: 'fillText', args: ['footer', 105, 153]},
         {name: 'restore', args: []}
       ]));
     });
@@ -1419,18 +1419,18 @@ describe('Plugin.Tooltip', function() {
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['title', 195, 111]},
+        {name: 'fillText', args: ['title', 195, 112.2]},
         {name: 'setTextAlign', args: ['right']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFillStyle', args: ['#fff']},
-        {name: 'fillText', args: ['label', 195, 129]},
+        {name: 'fillText', args: ['label', 195, 132.6]},
         {name: 'setTextAlign', args: ['right']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['footer', 195, 147]},
+        {name: 'fillText', args: ['footer', 195, 153]},
         {name: 'restore', args: []}
       ]));
     });
@@ -1445,18 +1445,18 @@ describe('Plugin.Tooltip', function() {
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['title', 150, 111]},
+        {name: 'fillText', args: ['title', 150, 112.2]},
         {name: 'setTextAlign', args: ['center']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFillStyle', args: ['#fff']},
-        {name: 'fillText', args: ['label', 150, 129]},
+        {name: 'fillText', args: ['label', 150, 132.6]},
         {name: 'setTextAlign', args: ['center']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['footer', 150, 147]},
+        {name: 'fillText', args: ['footer', 150, 153]},
         {name: 'restore', args: []}
       ]));
     });
@@ -1471,18 +1471,18 @@ describe('Plugin.Tooltip', function() {
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['title', 195, 111]},
+        {name: 'fillText', args: ['title', 195, 112.2]},
         {name: 'setTextAlign', args: ['center']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFillStyle', args: ['#fff']},
-        {name: 'fillText', args: ['label', 150, 129]},
+        {name: 'fillText', args: ['label', 150, 132.6]},
         {name: 'setTextAlign', args: ['left']},
         {name: 'setTextBaseline', args: ['middle']},
         {name: 'setFillStyle', args: ['#fff']},
         {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-        {name: 'fillText', args: ['footer', 105, 147]},
+        {name: 'fillText', args: ['footer', 105, 153]},
         {name: 'restore', args: []}
       ]));
     });