mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Handle '\n' as new line in tooltips (#5521)
This commit is contained in:
parent
8a7278052f
commit
8198d760bb
@ -190,6 +190,20 @@ function pushOrConcat(base, toPush) {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of strings split by newline
|
||||
* @param {String} value - The value to split by newline.
|
||||
* @returns {Array} value if newline present - Returned from String split() method
|
||||
* @function
|
||||
*/
|
||||
function splitNewlines(str) {
|
||||
if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
|
||||
return str.split('\n');
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// Private helper to create a tooltip item model
|
||||
// @param element : the chart element (point, arc, bar) to create the tooltip item for
|
||||
// @return : new tooltip item
|
||||
@ -404,7 +418,7 @@ function determineAlignment(tooltip, size) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
|
||||
* Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
|
||||
*/
|
||||
function getBackgroundPoint(vm, size, alignment, chart) {
|
||||
// Background Position
|
||||
@ -457,6 +471,13 @@ function getBackgroundPoint(vm, size, alignment, chart) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to build before and after body lines
|
||||
*/
|
||||
function getBeforeAfterBodyLines(callback) {
|
||||
return pushOrConcat([], splitNewlines(callback));
|
||||
}
|
||||
|
||||
var exports = module.exports = Element.extend({
|
||||
initialize: function() {
|
||||
this._model = getBaseModel(this._options);
|
||||
@ -475,17 +496,16 @@ var exports = module.exports = Element.extend({
|
||||
var afterTitle = callbacks.afterTitle.apply(me, arguments);
|
||||
|
||||
var lines = [];
|
||||
lines = pushOrConcat(lines, beforeTitle);
|
||||
lines = pushOrConcat(lines, title);
|
||||
lines = pushOrConcat(lines, afterTitle);
|
||||
lines = pushOrConcat(lines, splitNewlines(beforeTitle));
|
||||
lines = pushOrConcat(lines, splitNewlines(title));
|
||||
lines = pushOrConcat(lines, splitNewlines(afterTitle));
|
||||
|
||||
return lines;
|
||||
},
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
getBeforeBody: function() {
|
||||
var lines = this._options.callbacks.beforeBody.apply(this, arguments);
|
||||
return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
|
||||
return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments));
|
||||
},
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
@ -500,9 +520,9 @@ var exports = module.exports = Element.extend({
|
||||
lines: [],
|
||||
after: []
|
||||
};
|
||||
pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
|
||||
pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data)));
|
||||
pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
|
||||
pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
|
||||
pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data)));
|
||||
|
||||
bodyItems.push(bodyItem);
|
||||
});
|
||||
@ -512,8 +532,7 @@ var exports = module.exports = Element.extend({
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
getAfterBody: function() {
|
||||
var lines = this._options.callbacks.afterBody.apply(this, arguments);
|
||||
return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
|
||||
return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments));
|
||||
},
|
||||
|
||||
// Get the footer and beforeFooter and afterFooter lines
|
||||
@ -527,9 +546,9 @@ var exports = module.exports = Element.extend({
|
||||
var afterFooter = callbacks.afterFooter.apply(me, arguments);
|
||||
|
||||
var lines = [];
|
||||
lines = pushOrConcat(lines, beforeFooter);
|
||||
lines = pushOrConcat(lines, footer);
|
||||
lines = pushOrConcat(lines, afterFooter);
|
||||
lines = pushOrConcat(lines, splitNewlines(beforeFooter));
|
||||
lines = pushOrConcat(lines, splitNewlines(footer));
|
||||
lines = pushOrConcat(lines, splitNewlines(afterFooter));
|
||||
|
||||
return lines;
|
||||
},
|
||||
|
||||
@ -949,4 +949,152 @@ describe('Core.Tooltip', function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('Should split newlines into separate lines in user callbacks', function() {
|
||||
var chart = 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\nnewline';
|
||||
},
|
||||
title: function() {
|
||||
return 'title\nnewline';
|
||||
},
|
||||
afterTitle: function() {
|
||||
return 'afterTitle\nnewline';
|
||||
},
|
||||
beforeBody: function() {
|
||||
return 'beforeBody\nnewline';
|
||||
},
|
||||
beforeLabel: function() {
|
||||
return 'beforeLabel\nnewline';
|
||||
},
|
||||
label: function() {
|
||||
return 'label';
|
||||
},
|
||||
afterLabel: function() {
|
||||
return 'afterLabel\nnewline';
|
||||
},
|
||||
afterBody: function() {
|
||||
return 'afterBody\nnewline';
|
||||
},
|
||||
beforeFooter: function() {
|
||||
return 'beforeFooter\nnewline';
|
||||
},
|
||||
footer: function() {
|
||||
return 'footer\nnewline';
|
||||
},
|
||||
afterFooter: function() {
|
||||
return 'afterFooter\nnewline';
|
||||
},
|
||||
labelTextColor: function() {
|
||||
return 'labelTextColor';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger an event over top of the
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
var point = meta.data[1];
|
||||
var node = 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
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
node.dispatchEvent(evt);
|
||||
|
||||
// Check and see if tooltip was displayed
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xPadding: 6,
|
||||
yPadding: 6,
|
||||
xAlign: 'center',
|
||||
yAlign: 'top',
|
||||
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: 'left',
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: 'left',
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
|
||||
// Footer
|
||||
footerFontColor: '#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', 'newline', 'title', 'newline', 'afterTitle', 'newline'],
|
||||
beforeBody: ['beforeBody', 'newline'],
|
||||
body: [{
|
||||
before: ['beforeLabel', 'newline'],
|
||||
lines: ['label'],
|
||||
after: ['afterLabel', 'newline']
|
||||
}, {
|
||||
before: ['beforeLabel', 'newline'],
|
||||
lines: ['label'],
|
||||
after: ['afterLabel', 'newline']
|
||||
}],
|
||||
afterBody: ['afterBody', 'newline'],
|
||||
footer: ['beforeFooter', 'newline', 'footer', 'newline', 'afterFooter', 'newline'],
|
||||
caretPadding: 2,
|
||||
labelTextColors: ['labelTextColor', 'labelTextColor'],
|
||||
labelColors: [{
|
||||
borderColor: 'rgb(255, 0, 0)',
|
||||
backgroundColor: 'rgb(0, 255, 0)'
|
||||
}, {
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
backgroundColor: 'rgb(0, 255, 255)'
|
||||
}]
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user