Skip to content

Commit

Permalink
Handle '\n' as new line in tooltips (#5521)
Browse files Browse the repository at this point in the history
  • Loading branch information
CWSites authored and simonbrunel committed Jun 5, 2018
1 parent 8a72780 commit 8198d76
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 13 deletions.
45 changes: 32 additions & 13 deletions src/core/core.tooltip.js
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand All @@ -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);
});
Expand All @@ -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
Expand All @@ -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;
},
Expand Down
148 changes: 148 additions & 0 deletions test/specs/core.tooltip.tests.js
Expand Up @@ -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)'
}]
}));
});
});

0 comments on commit 8198d76

Please sign in to comment.