]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Enable per-corner border radius in tooltip (#9620)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sun, 5 Sep 2021 17:07:28 +0000 (13:07 -0400)
committerGitHub <noreply@github.com>
Sun, 5 Sep 2021 17:07:28 +0000 (13:07 -0400)
docs/configuration/tooltip.md
src/plugins/plugin.tooltip.js
test/fixtures/plugin.tooltip/corner-radius.js [new file with mode: 0644]
test/fixtures/plugin.tooltip/corner-radius.png [new file with mode: 0644]
types/index.esm.d.ts

index 4874120f1cbe90cbb006d0ce983c96d040b4f9ba..936f9202c575e11a5c52b633eaf71b6a0433ebb9 100644 (file)
@@ -32,7 +32,7 @@ Namespace: `options.plugins.tooltip`, the global options for the chart tooltips
 | `padding` | [`Padding`](../general/padding.md) | `6` | Padding inside the tooltip.
 | `caretPadding` | `number` | `2` | Extra distance to move the end of the tooltip arrow away from the tooltip point.
 | `caretSize` | `number` | `5` | Size, in px, of the tooltip arrow.
-| `cornerRadius` | `number` | `6` | Radius of tooltip corner curves.
+| `cornerRadius` | `number`\|`object` | `6` | Radius of tooltip corner curves.
 | `multiKeyBackground` | [`Color`](../general/colors.md) | `'#fff'` | Color to draw behind the colored boxes when multiple items are in the tooltip.
 | `displayColors` | `boolean` | `true` | If true, color boxes are shown in the tooltip.
 | `boxWidth` | `number` | `bodyFont.size` | Width of the color box if displayColors is true.
index b852e7ee47ac68d563e085f64882231eded45418..231506b73636be2e152adc5832c37431031d5189 100644 (file)
@@ -294,7 +294,7 @@ function getBackgroundPoint(options, size, alignment, chart) {
   const {caretSize, caretPadding, cornerRadius} = options;
   const {xAlign, yAlign} = alignment;
   const paddingAndSize = caretSize + caretPadding;
-  const radiusAndPadding = cornerRadius + caretPadding;
+  const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius);
 
   let x = alignX(size, xAlign);
   const y = alignY(size, yAlign, paddingAndSize);
@@ -306,9 +306,9 @@ function getBackgroundPoint(options, size, alignment, chart) {
       x -= paddingAndSize;
     }
   } else if (xAlign === 'left') {
-    x -= radiusAndPadding;
+    x -= Math.max(topLeft, bottomLeft) + caretPadding;
   } else if (xAlign === 'right') {
-    x += radiusAndPadding;
+    x += Math.max(topRight, bottomRight) + caretPadding;
   }
 
   return {
@@ -588,7 +588,8 @@ export class Tooltip extends Element {
 
   getCaretPosition(tooltipPoint, size, options) {
     const {xAlign, yAlign} = this;
-    const {cornerRadius, caretSize} = options;
+    const {caretSize, cornerRadius} = options;
+    const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius);
     const {x: ptX, y: ptY} = tooltipPoint;
     const {width, height} = size;
     let x1, x2, x3, y1, y2, y3;
@@ -615,9 +616,9 @@ export class Tooltip extends Element {
       x3 = x1;
     } else {
       if (xAlign === 'left') {
-        x2 = ptX + cornerRadius + (caretSize);
+        x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize);
       } else if (xAlign === 'right') {
-        x2 = ptX + width - cornerRadius - caretSize;
+        x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
       } else {
         x2 = this.caretX;
       }
@@ -855,34 +856,34 @@ export class Tooltip extends Element {
     const {xAlign, yAlign} = this;
     const {x, y} = pt;
     const {width, height} = tooltipSize;
-    const radius = options.cornerRadius;
+    const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius);
 
     ctx.fillStyle = options.backgroundColor;
     ctx.strokeStyle = options.borderColor;
     ctx.lineWidth = options.borderWidth;
 
     ctx.beginPath();
-    ctx.moveTo(x + radius, y);
+    ctx.moveTo(x + topLeft, y);
     if (yAlign === 'top') {
       this.drawCaret(pt, ctx, tooltipSize, options);
     }
-    ctx.lineTo(x + width - radius, y);
-    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+    ctx.lineTo(x + width - topRight, y);
+    ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);
     if (yAlign === 'center' && xAlign === 'right') {
       this.drawCaret(pt, ctx, tooltipSize, options);
     }
-    ctx.lineTo(x + width, y + height - radius);
-    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+    ctx.lineTo(x + width, y + height - bottomRight);
+    ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);
     if (yAlign === 'bottom') {
       this.drawCaret(pt, ctx, tooltipSize, options);
     }
-    ctx.lineTo(x + radius, y + height);
-    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+    ctx.lineTo(x + bottomLeft, y + height);
+    ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);
     if (yAlign === 'center' && xAlign === 'left') {
       this.drawCaret(pt, ctx, tooltipSize, options);
     }
-    ctx.lineTo(x, y + radius);
-    ctx.quadraticCurveTo(x, y, x + radius, y);
+    ctx.lineTo(x, y + topLeft);
+    ctx.quadraticCurveTo(x, y, x + topLeft, y);
     ctx.closePath();
 
     ctx.fill();
diff --git a/test/fixtures/plugin.tooltip/corner-radius.js b/test/fixtures/plugin.tooltip/corner-radius.js
new file mode 100644 (file)
index 0000000..e5c98a4
--- /dev/null
@@ -0,0 +1,78 @@
+const data = [];
+for (let x = 0; x < 3; x++) {
+  for (let y = 0; y < 3; y++) {
+    data.push({x, y});
+  }
+}
+
+module.exports = {
+  config: {
+    type: 'scatter',
+    data: {
+      datasets: [{
+        data,
+        backgroundColor: 'red',
+        radius: 1,
+        hoverRadius: 0
+      }],
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        filler: false,
+        tooltip: {
+          mode: 'point',
+          intersect: true,
+          // spriteText: use white background to hide any gaps between fonts
+          backgroundColor: 'white',
+          borderColor: 'black',
+          borderWidth: 1,
+          callbacks: {
+            beforeLabel: () => 'before label',
+            label: () => 'label',
+            afterLabel: () => 'after1\nafter2\nafter3\nafter4\nafter5'
+          },
+          cornerRadius: {
+            topLeft: 10,
+            topRight: 20,
+            bottomRight: 5,
+            bottomLeft: 0,
+          }
+        },
+      },
+    },
+    plugins: [{
+      afterDraw: function(chart) {
+        const canvas = chart.canvas;
+        const rect = canvas.getBoundingClientRect();
+        const meta = chart.getDatasetMeta(0);
+        let point, event;
+
+        for (let i = 0; i < data.length; i++) {
+          point = meta.data[i];
+          event = {
+            type: 'mousemove',
+            target: canvas,
+            clientX: rect.left + point.x,
+            clientY: rect.top + point.y
+          };
+          chart._handleEvent(event);
+          chart.tooltip.handleEvent(event);
+          chart.tooltip.draw(chart.ctx);
+        }
+      }
+    }]
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 400,
+      width: 500
+    }
+  }
+};
diff --git a/test/fixtures/plugin.tooltip/corner-radius.png b/test/fixtures/plugin.tooltip/corner-radius.png
new file mode 100644 (file)
index 0000000..0e71cb2
Binary files /dev/null and b/test/fixtures/plugin.tooltip/corner-radius.png differ
index 58c705974f862adab20dc25e4117f4be477bb625..1e3485e5364c511e8075e90a08dc364ba18d0a98 100644 (file)
@@ -2604,7 +2604,7 @@ export interface TooltipOptions<TType extends ChartType = ChartType> extends Cor
    * Radius of tooltip corner curves.
    * @default 6
    */
-  cornerRadius: Scriptable<number, ScriptableTooltipContext<TType>>;
+  cornerRadius: Scriptable<number | BorderRadius, ScriptableTooltipContext<TType>>;
   /**
    * Color to draw behind the colored boxes when multiple items are in the tooltip.
    * @default '#fff'