mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 12:19:08 +02:00
Initial tooltip tests + fix a bug when the tooltip beforeLabel and afterLabel callbacks returned strings
This commit is contained in:
parent
9269411799
commit
8d20379e29
@ -73,6 +73,12 @@
|
||||
afterBody: function() {
|
||||
return '...afterBody';
|
||||
},
|
||||
beforeLabel: function() {
|
||||
return '...beforeLabel';
|
||||
},
|
||||
afterLabel: function() {
|
||||
return '...afterLabel';
|
||||
},
|
||||
beforeFooter: function() {
|
||||
return '...beforeFooter';
|
||||
},
|
||||
|
@ -163,15 +163,22 @@ module.exports = function(Chart) {
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
getBody: function(tooltipItems, data) {
|
||||
var lines = [];
|
||||
var bodyItems = [];
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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,7 +544,17 @@ module.exports = function(Chart) {
|
||||
pt.y += vm.bodyFontSize + vm.bodySpacing;
|
||||
});
|
||||
|
||||
helpers.each(vm.body, function(body, i) {
|
||||
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);
|
||||
|
||||
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
|
||||
@ -542,10 +572,10 @@ module.exports = function(Chart) {
|
||||
ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
|
||||
}
|
||||
|
||||
// Body Line
|
||||
ctx.fillText(body, pt.x + (this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
|
||||
fillLine(line);
|
||||
}, this);
|
||||
|
||||
pt.y += vm.bodyFontSize + vm.bodySpacing;
|
||||
helpers.each(bodyItem.after, fillLine);
|
||||
}, this);
|
||||
|
||||
// After Body
|
||||
|
375
test/core.tooltip.tests.js
Normal file
375
test/core.tooltip.tests.js
Normal file
@ -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)'
|
||||
}]
|
||||
}));
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user