]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Initial tooltip tests + fix a bug when the tooltip beforeLabel and afterLabel callbac...
authorEvert Timberg <evert.timberg+github@gmail.com>
Sat, 28 May 2016 19:26:46 +0000 (15:26 -0400)
committerEvert Timberg <evert.timberg+github@gmail.com>
Sat, 28 May 2016 19:26:46 +0000 (15:26 -0400)
samples/tooltip-hooks.html
src/core/core.tooltip.js
test/core.tooltip.tests.js [new file with mode: 0644]

index 1f74df0b4419d9a3afdc490332103e8e706460ec..88a660515fed5850e3c0e0ee2bcedd237ee262d3 100644 (file)
                         afterBody: function() {
                             return '...afterBody';
                         },
+                        beforeLabel: function() {
+                            return '...beforeLabel';
+                        },
+                        afterLabel: function() {
+                            return '...afterLabel';
+                        },
                         beforeFooter: function() {
                             return '...beforeFooter';
                         },
index cd28499bf9a0270e52695e4be2a19f6cdb7a8e13..3b594c38c094ee95bf4b2639749de787559a009a 100644 (file)
@@ -163,15 +163,22 @@ module.exports = function(Chart) {
 
                // Args are: (tooltipItem, data)
                getBody: function(tooltipItems, data) {
-                       var lines = [];
+                       var bodyItems = [];
+
+                       helpers.each(tooltipItems, function(tooltipItem) {
+                               var bodyItem = {
+                                       before: [],
+                                       lines: [],
+                                       after: []
+                               };
+                               helpers.pushAllIfDefined(this._options.callbacks.beforeLabel.call(this, tooltipItem, data), bodyItem.before);
+                               helpers.pushAllIfDefined(this._options.callbacks.label.call(this, tooltipItem, data), bodyItem.lines);
+                               helpers.pushAllIfDefined(this._options.callbacks.afterLabel.call(this, tooltipItem, data), bodyItem.after);
 
-                       helpers.each(tooltipItems, function(bodyItem) {
-                               helpers.pushAllIfDefined(this._options.callbacks.beforeLabel.call(this, bodyItem, data), lines);
-                               helpers.pushAllIfDefined(this._options.callbacks.label.call(this, bodyItem, data), lines);
-                               helpers.pushAllIfDefined(this._options.callbacks.afterLabel.call(this, bodyItem, data), lines);
+                               bodyItems.push(bodyItem);
                        }, this);
 
-                       return lines;
+                       return bodyItems;
                },
 
                // Args are: (tooltipItem, data)
@@ -307,7 +314,13 @@ module.exports = function(Chart) {
                                height: vm.yPadding * 2, // Tooltip Padding
                                width: 0
                        };
-                       var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
+
+
+                       var combinedBodyLength = vm.body.reduce(function(count, bodyItem) {
+                               return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
+                       }, 0);
+                       // Count in before and after body sections
+                       combinedBodyLength += vm.beforeBody.length + vm.afterBody.length;
 
                        size.height += vm.title.length * vm.titleFontSize; // Title Lines
                        size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
@@ -328,9 +341,16 @@ module.exports = function(Chart) {
                        helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) {
                                size.width = Math.max(size.width, ctx.measureText(line).width);
                        });
-                       helpers.each(vm.body, function(line) {
-                               size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
-                       }, this);
+
+                       var _this = this;
+                       var maxBodyWidth = function(line) {
+                               size.width = Math.max(size.width, ctx.measureText(line).width + (_this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
+                       };
+                       helpers.each(vm.body, function(bodyItem) {
+                               helpers.each(bodyItem.before, maxBodyWidth);
+                               helpers.each(bodyItem.lines, maxBodyWidth);
+                               helpers.each(bodyItem.after, maxBodyWidth);
+                       });
 
                        ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
                        helpers.each(vm.footer, function(line) {
@@ -524,28 +544,38 @@ module.exports = function(Chart) {
                                pt.y += vm.bodyFontSize + vm.bodySpacing;
                        });
 
-                       helpers.each(vm.body, function(body, i) {
-                               // Draw Legend-like boxes if needed
-                               if (this._options.mode !== 'single') {
-                                       // Fill a white rect so that colours merge nicely if the opacity is < 1
-                                       ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
-                                       ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
+                       helpers.each(vm.body, function(bodyItem, i) {
+                               var _this = this;
+                               var fillLine = function(line) {
+                                       // Body Line
+                                       ctx.fillText(line, pt.x + (_this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
+                                       pt.y += vm.bodyFontSize + vm.bodySpacing;
+                               };
+
+                               helpers.each(bodyItem.before, fillLine);
 
-                                       // Border
-                                       ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
-                                       ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
+                               helpers.each(bodyItem.lines, function(line) {
+                                       // Draw Legend-like boxes if needed
+                                       if (this._options.mode !== 'single') {
+                                               // Fill a white rect so that colours merge nicely if the opacity is < 1
+                                               ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
+                                               ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
 
-                                       // Inner square
-                                       ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
-                                       ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
+                                               // Border
+                                               ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
+                                               ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
 
-                                       ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
-                               }
+                                               // Inner square
+                                               ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
+                                               ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
 
-                               // Body Line
-                               ctx.fillText(body, pt.x + (this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
+                                               ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
+                                       }
 
-                               pt.y += vm.bodyFontSize + vm.bodySpacing;
+                                       fillLine(line);
+                               }, this);
+                               
+                               helpers.each(bodyItem.after, fillLine);
                        }, this);
 
                        // After Body
diff --git a/test/core.tooltip.tests.js b/test/core.tooltip.tests.js
new file mode 100644 (file)
index 0000000..2141973
--- /dev/null
@@ -0,0 +1,375 @@
+// Test the rectangle element
+describe('tooltip tests', function() {
+
+       beforeEach(function() {
+               window.addDefaultMatchers(jasmine);
+       });
+
+       afterEach(function() {
+               window.releaseAllCharts();
+       });
+
+       it('Should display in label mode', function() {
+               var chartInstance = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       label: 'Dataset 1',
+                                       data: [10, 20, 30],
+                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
+                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+                               }, {
+                                       label: 'Dataset 2',
+                                       data: [40, 40, 40],
+                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
+                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+                               }],
+                               labels: ['Point 1', 'Point 2', 'Point 3']
+                       },
+                       options: {
+                               tooltips: {
+                                       mode: 'label'
+                               }
+                       }
+               });
+
+               // Trigger an event over top of the 
+               var meta = chartInstance.getDatasetMeta(0);
+               var point = meta.data[1];
+
+               var node = chartInstance.chart.canvas;
+               var rect = node.getBoundingClientRect();
+
+               var evt = new MouseEvent('mousemove', {
+                       view: window,
+                       bubbles: true,
+                       cancelable: true,
+                       clientX: rect.left + point._model.x,
+                       clientY: rect.top + point._model.y
+               });
+
+               // Manully trigger rather than having an async test
+               node.dispatchEvent(evt);
+
+               // Check and see if tooltip was displayed
+               var tooltip = chartInstance.tooltip;
+               var globalDefaults = Chart.defaults.global;
+
+               expect(tooltip._view).toEqual(jasmine.objectContaining({
+                       // Positioning
+                       xPadding: 6,
+                       yPadding: 6,
+                       xAlign: 'left',
+                       yAlign: 'center',
+
+                       // Body
+                       bodyColor: '#fff',
+                       _bodyFontFamily: globalDefaults.defaultFontFamily,
+                       _bodyFontStyle: globalDefaults.defaultFontStyle,
+                       _bodyAlign: 'left',
+                       bodyFontSize: globalDefaults.defaultFontSize,
+                       bodySpacing: 2,
+
+                       // Title
+                       titleColor: '#fff',
+                       _titleFontFamily: globalDefaults.defaultFontFamily,
+                       _titleFontStyle: 'bold',
+                       titleFontSize: globalDefaults.defaultFontSize,
+                       _titleAlign: 'left',
+                       titleSpacing: 2,
+                       titleMarginBottom: 6,
+
+                       // Footer
+                       footerColor: '#fff',
+                       _footerFontFamily: globalDefaults.defaultFontFamily,
+                       _footerFontStyle: 'bold',
+                       footerFontSize: globalDefaults.defaultFontSize,
+                       _footerAlign: 'left',
+                       footerSpacing: 2,
+                       footerMarginTop: 6,
+
+                       // Appearance
+                       caretSize: 5,
+                       cornerRadius: 6,
+                       backgroundColor: 'rgba(0,0,0,0.8)',
+                       opacity: 1,
+                       legendColorBackground: '#fff',
+
+                       // Text
+                       title: ['Point 2'],
+                       beforeBody: [],
+                       body: [{
+                               before: [],
+                               lines: ['Dataset 1: 20'],
+                               after: []
+                       }, {
+                               before: [],
+                               lines: ['Dataset 2: 40'],
+                               after: []
+                       }],
+                       afterBody: [],
+                       footer: [],
+                       x: 269,
+                       y: 155,
+                       caretPadding: 2,
+                       labelColors: [{
+                               borderColor: 'rgb(255, 0, 0)',
+                               backgroundColor: 'rgb(0, 255, 0)'
+                       }, {
+                               borderColor: 'rgb(0, 0, 255)',
+                               backgroundColor: 'rgb(0, 255, 255)'
+                       }]
+               }));
+       });
+
+       it('Should display in single mode', function() {
+               var chartInstance = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       label: 'Dataset 1',
+                                       data: [10, 20, 30],
+                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
+                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+                               }, {
+                                       label: 'Dataset 2',
+                                       data: [40, 40, 40],
+                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
+                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+                               }],
+                               labels: ['Point 1', 'Point 2', 'Point 3']
+                       },
+                       options: {
+                               tooltips: {
+                                       mode: 'single'
+                               }
+                       }
+               });
+
+               // Trigger an event over top of the 
+               var meta = chartInstance.getDatasetMeta(0);
+               var point = meta.data[1];
+
+               var node = chartInstance.chart.canvas;
+               var rect = node.getBoundingClientRect();
+
+               var evt = new MouseEvent('mousemove', {
+                       view: window,
+                       bubbles: true,
+                       cancelable: true,
+                       clientX: rect.left + point._model.x,
+                       clientY: rect.top + point._model.y
+               });
+
+               // Manully trigger rather than having an async test
+               node.dispatchEvent(evt);
+
+               // Check and see if tooltip was displayed
+               var tooltip = chartInstance.tooltip;
+               var globalDefaults = Chart.defaults.global;
+
+               expect(tooltip._view).toEqual(jasmine.objectContaining({
+                       // Positioning
+                       xPadding: 6,
+                       yPadding: 6,
+                       xAlign: 'left',
+                       yAlign: 'center',
+
+                       // Body
+                       bodyColor: '#fff',
+                       _bodyFontFamily: globalDefaults.defaultFontFamily,
+                       _bodyFontStyle: globalDefaults.defaultFontStyle,
+                       _bodyAlign: 'left',
+                       bodyFontSize: globalDefaults.defaultFontSize,
+                       bodySpacing: 2,
+
+                       // Title
+                       titleColor: '#fff',
+                       _titleFontFamily: globalDefaults.defaultFontFamily,
+                       _titleFontStyle: 'bold',
+                       titleFontSize: globalDefaults.defaultFontSize,
+                       _titleAlign: 'left',
+                       titleSpacing: 2,
+                       titleMarginBottom: 6,
+
+                       // Footer
+                       footerColor: '#fff',
+                       _footerFontFamily: globalDefaults.defaultFontFamily,
+                       _footerFontStyle: 'bold',
+                       footerFontSize: globalDefaults.defaultFontSize,
+                       _footerAlign: 'left',
+                       footerSpacing: 2,
+                       footerMarginTop: 6,
+
+                       // Appearance
+                       caretSize: 5,
+                       cornerRadius: 6,
+                       backgroundColor: 'rgba(0,0,0,0.8)',
+                       opacity: 1,
+                       legendColorBackground: '#fff',
+
+                       // Text
+                       title: ['Point 2'],
+                       beforeBody: [],
+                       body: [{
+                               before: [],
+                               lines: ['Dataset 1: 20'],
+                               after: []
+                       }],
+                       afterBody: [],
+                       footer: [],
+                       x: 269,
+                       y: 312,
+                       caretPadding: 2,
+                       labelColors: []
+               }));
+       });
+
+       it('Should display information from user callbacks', function() {
+               var chartInstance = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       label: 'Dataset 1',
+                                       data: [10, 20, 30],
+                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
+                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+                               }, {
+                                       label: 'Dataset 2',
+                                       data: [40, 40, 40],
+                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
+                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+                               }],
+                               labels: ['Point 1', 'Point 2', 'Point 3']
+                       },
+                       options: {
+                               tooltips: {
+                                       mode: 'label',
+                                       callbacks: {
+                                               beforeTitle: function() {
+                                                       return 'beforeTitle';
+                                               },
+                                               title: function() {
+                                                       return 'title';
+                                               },
+                                               afterTitle: function() {
+                                                       return 'afterTitle'
+                                               },
+                                               beforeBody: function() {
+                                                       return 'beforeBody';
+                                               },
+                                               beforeLabel: function() {
+                                                       return 'beforeLabel';
+                                               },
+                                               label: function() {
+                                                       return 'label';
+                                               },
+                                               afterLabel: function() {
+                                                       return 'afterLabel';
+                                               },
+                                               afterBody: function() {
+                                                       return 'afterBody';
+                                               },
+                                               beforeFooter: function() {
+                                                       return 'beforeFooter';
+                                               },
+                                               footer: function() {
+                                                       return 'footer';
+                                               },
+                                               afterFooter: function() {
+                                                       return 'afterFooter'
+                                               }
+                                       }
+                               }
+                       }
+               });
+
+               // Trigger an event over top of the 
+               var meta = chartInstance.getDatasetMeta(0);
+               var point = meta.data[1];
+
+               var node = chartInstance.chart.canvas;
+               var rect = node.getBoundingClientRect();
+
+               var evt = new MouseEvent('mousemove', {
+                       view: window,
+                       bubbles: true,
+                       cancelable: true,
+                       clientX: rect.left + point._model.x,
+                       clientY: rect.top + point._model.y
+               });
+
+               // Manully trigger rather than having an async test
+               node.dispatchEvent(evt);
+
+               // Check and see if tooltip was displayed
+               var tooltip = chartInstance.tooltip;
+               var globalDefaults = Chart.defaults.global;
+
+               expect(tooltip._view).toEqual(jasmine.objectContaining({
+                       // Positioning
+                       xPadding: 6,
+                       yPadding: 6,
+                       xAlign: 'center',
+                       yAlign: 'top',
+
+                       // Body
+                       bodyColor: '#fff',
+                       _bodyFontFamily: globalDefaults.defaultFontFamily,
+                       _bodyFontStyle: globalDefaults.defaultFontStyle,
+                       _bodyAlign: 'left',
+                       bodyFontSize: globalDefaults.defaultFontSize,
+                       bodySpacing: 2,
+
+                       // Title
+                       titleColor: '#fff',
+                       _titleFontFamily: globalDefaults.defaultFontFamily,
+                       _titleFontStyle: 'bold',
+                       titleFontSize: globalDefaults.defaultFontSize,
+                       _titleAlign: 'left',
+                       titleSpacing: 2,
+                       titleMarginBottom: 6,
+
+                       // Footer
+                       footerColor: '#fff',
+                       _footerFontFamily: globalDefaults.defaultFontFamily,
+                       _footerFontStyle: 'bold',
+                       footerFontSize: globalDefaults.defaultFontSize,
+                       _footerAlign: 'left',
+                       footerSpacing: 2,
+                       footerMarginTop: 6,
+
+                       // Appearance
+                       caretSize: 5,
+                       cornerRadius: 6,
+                       backgroundColor: 'rgba(0,0,0,0.8)',
+                       opacity: 1,
+                       legendColorBackground: '#fff',
+
+                       // Text
+                       title: ['beforeTitle', 'title', 'afterTitle'],
+                       beforeBody: ['beforeBody'],
+                       body: [{
+                               before: ['beforeLabel'],
+                               lines: ['label'],
+                               after: ['afterLabel']
+                       }, {
+                               before: ['beforeLabel'],
+                               lines: ['label'],
+                               after: ['afterLabel']
+                       }],
+                       afterBody: ['afterBody'],
+                       footer: ['beforeFooter', 'footer', 'afterFooter'],
+                       x: 216,
+                       y: 190,
+                       caretPadding: 2,
+                       labelColors: [{
+                               borderColor: 'rgb(255, 0, 0)',
+                               backgroundColor: 'rgb(0, 255, 0)'
+                       }, {
+                               borderColor: 'rgb(0, 0, 255)',
+                               backgroundColor: 'rgb(0, 255, 255)'
+                       }]
+               }));
+       });
+});