]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add support for CanvasPattern and CanvasGradient in tooltip (#5869)
authorAkihiko Kusanagi <nagi@nagi-p.com>
Thu, 29 Nov 2018 12:52:56 +0000 (20:52 +0800)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Thu, 29 Nov 2018 12:52:56 +0000 (13:52 +0100)
src/core/core.tooltip.js
test/fixtures/core.tooltip/opacity.js [new file with mode: 0644]
test/fixtures/core.tooltip/opacity.png [new file with mode: 0644]
test/specs/core.tooltip.tests.js

index c529812cc617055786cad3fdcd7c955ce7749a3b..c3245d9cf1eccf99cb0267cf4293d6e34a6a8fc2 100644 (file)
@@ -168,14 +168,6 @@ var positioners = {
        }
 };
 
-/**
- * Helper method to merge the opacity into a color
- */
-function mergeOpacity(colorString, opacity) {
-       var color = helpers.color(colorString);
-       return color.alpha(opacity * color.alpha()).rgbaString();
-}
-
 // Helper to push or concat based on if the 2nd parameter is an array or not
 function pushOrConcat(base, toPush) {
        if (toPush) {
@@ -734,7 +726,7 @@ var exports = module.exports = Element.extend({
                return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
        },
 
-       drawTitle: function(pt, vm, ctx, opacity) {
+       drawTitle: function(pt, vm, ctx) {
                var title = vm.title;
 
                if (title.length) {
@@ -744,7 +736,7 @@ var exports = module.exports = Element.extend({
                        var titleFontSize = vm.titleFontSize;
                        var titleSpacing = vm.titleSpacing;
 
-                       ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
+                       ctx.fillStyle = vm.titleFontColor;
                        ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
 
                        var i, len;
@@ -759,7 +751,7 @@ var exports = module.exports = Element.extend({
                }
        },
 
-       drawBody: function(pt, vm, ctx, opacity) {
+       drawBody: function(pt, vm, ctx) {
                var bodyFontSize = vm.bodyFontSize;
                var bodySpacing = vm.bodySpacing;
                var body = vm.body;
@@ -776,7 +768,7 @@ var exports = module.exports = Element.extend({
                };
 
                // Before body lines
-               ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
+               ctx.fillStyle = vm.bodyFontColor;
                helpers.each(vm.beforeBody, fillLineOfText);
 
                var drawColorBoxes = vm.displayColors;
@@ -784,7 +776,7 @@ var exports = module.exports = Element.extend({
 
                // Draw body lines now
                helpers.each(body, function(bodyItem, i) {
-                       var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
+                       var textColor = vm.labelTextColors[i];
                        ctx.fillStyle = textColor;
                        helpers.each(bodyItem.before, fillLineOfText);
 
@@ -792,16 +784,16 @@ var exports = module.exports = Element.extend({
                                // Draw Legend-like boxes if needed
                                if (drawColorBoxes) {
                                        // Fill a white rect so that colours merge nicely if the opacity is < 1
-                                       ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
+                                       ctx.fillStyle = vm.legendColorBackground;
                                        ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
 
                                        // Border
                                        ctx.lineWidth = 1;
-                                       ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
+                                       ctx.strokeStyle = vm.labelColors[i].borderColor;
                                        ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
 
                                        // Inner square
-                                       ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
+                                       ctx.fillStyle = vm.labelColors[i].backgroundColor;
                                        ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
                                        ctx.fillStyle = textColor;
                                }
@@ -820,7 +812,7 @@ var exports = module.exports = Element.extend({
                pt.y -= bodySpacing; // Remove last body spacing
        },
 
-       drawFooter: function(pt, vm, ctx, opacity) {
+       drawFooter: function(pt, vm, ctx) {
                var footer = vm.footer;
 
                if (footer.length) {
@@ -829,7 +821,7 @@ var exports = module.exports = Element.extend({
                        ctx.textAlign = vm._footerAlign;
                        ctx.textBaseline = 'top';
 
-                       ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
+                       ctx.fillStyle = vm.footerFontColor;
                        ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
 
                        helpers.each(footer, function(line) {
@@ -839,9 +831,9 @@ var exports = module.exports = Element.extend({
                }
        },
 
-       drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
-               ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
-               ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
+       drawBackground: function(pt, vm, ctx, tooltipSize) {
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.strokeStyle = vm.borderColor;
                ctx.lineWidth = vm.borderWidth;
                var xAlign = vm.xAlign;
                var yAlign = vm.yAlign;
@@ -906,21 +898,26 @@ var exports = module.exports = Element.extend({
                var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
 
                if (this._options.enabled && hasTooltipContent) {
+                       ctx.save();
+                       ctx.globalAlpha = opacity;
+
                        // Draw Background
-                       this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
+                       this.drawBackground(pt, vm, ctx, tooltipSize);
 
                        // Draw Title, Body, and Footer
                        pt.x += vm.xPadding;
                        pt.y += vm.yPadding;
 
                        // Titles
-                       this.drawTitle(pt, vm, ctx, opacity);
+                       this.drawTitle(pt, vm, ctx);
 
                        // Body
-                       this.drawBody(pt, vm, ctx, opacity);
+                       this.drawBody(pt, vm, ctx);
 
                        // Footer
-                       this.drawFooter(pt, vm, ctx, opacity);
+                       this.drawFooter(pt, vm, ctx);
+
+                       ctx.restore();
                }
        },
 
diff --git a/test/fixtures/core.tooltip/opacity.js b/test/fixtures/core.tooltip/opacity.js
new file mode 100644 (file)
index 0000000..8b872e7
--- /dev/null
@@ -0,0 +1,104 @@
+var patternCanvas = document.createElement('canvas');
+var patternContext = patternCanvas.getContext('2d');
+
+patternCanvas.width = 6;
+patternCanvas.height = 6;
+patternContext.fillStyle = '#ff0000';
+patternContext.fillRect(0, 0, 6, 6);
+patternContext.fillStyle = '#ffff00';
+patternContext.fillRect(0, 0, 4, 4);
+
+var pattern = patternContext.createPattern(patternCanvas, 'repeat');
+
+var gradient;
+
+module.exports = {
+       config: {
+               type: 'line',
+               data: {
+                       datasets: [{
+                               data: [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
+                               pointBorderColor: '#ff0000',
+                               pointBackgroundColor: '#00ff00',
+                               showLine: false
+                       }, {
+                               label: '',
+                               data: [4, 4, 4, 4, 4, 5, 3, 4, 4, 4, 4],
+                               pointBorderColor: pattern,
+                               pointBackgroundColor: pattern,
+                               showLine: false
+                       }, {
+                               label: '',
+                               data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+                               showLine: false
+                       }],
+                       labels: ['', '', '', '', '', '', '', '', '', '', '']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               xAxes: [{display: false}],
+                               yAxes: [{display: false}]
+                       },
+                       elements: {
+                               line: {
+                                       fill: false
+                               }
+                       },
+                       tooltips: {
+                               mode: 'nearest',
+                               intersect: false,
+                               callbacks: {
+                                       label: function() {
+                                               return '\u200b';
+                                       }
+                               }
+                       },
+                       layout: {
+                               padding: 15
+                       }
+               },
+               plugins: [{
+                       beforeDatasetsUpdate: function(chart) {
+                               if (!gradient) {
+                                       gradient = chart.ctx.createLinearGradient(0, 0, 512, 256);
+                                       gradient.addColorStop(0, '#ff0000');
+                                       gradient.addColorStop(1, '#0000ff');
+                               }
+                               chart.config.data.datasets[2].pointBorderColor = gradient;
+                               chart.config.data.datasets[2].pointBackgroundColor = gradient;
+
+                               return true;
+                       },
+                       afterDraw: function(chart) {
+                               var canvas = chart.canvas;
+                               var rect = canvas.getBoundingClientRect();
+                               var point, event;
+
+                               for (var i = 0; i < 3; ++i) {
+                                       for (var j = 0; j < 11; ++j) {
+                                               point = chart.getDatasetMeta(i).data[j];
+                                               event = {
+                                                       type: 'mousemove',
+                                                       target: canvas,
+                                                       clientX: rect.left + point._model.x,
+                                                       clientY: rect.top + point._model.y
+                                               };
+                                               chart.handleEvent(event);
+                                               chart.tooltip.handleEvent(event);
+                                               chart.tooltip.transition(1);
+                                               chart.tooltip._view.opacity = j / 10;
+                                               chart.tooltip.draw();
+                                       }
+                               }
+                       }
+               }]
+       },
+       options: {
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.tooltip/opacity.png b/test/fixtures/core.tooltip/opacity.png
new file mode 100644 (file)
index 0000000..142dcc0
Binary files /dev/null and b/test/fixtures/core.tooltip/opacity.png differ
index 9d858a49e10e7444764eee2d280fed6aaefcba84..c342fe64618ae4ccda114016e3e32f2c9a4b20e5 100755 (executable)
@@ -1,5 +1,7 @@
 // Test the rectangle element
 describe('Core.Tooltip', function() {
+       describe('auto', jasmine.fixture.specs('core.tooltip'));
+
        describe('config', function() {
                it('should not include the dataset label in the body string if not defined', function() {
                        var data = {