};
}
+function getAlignedX(vm, align) {
+ return align === 'center'
+ ? vm.x + vm.width / 2
+ : align === 'right'
+ ? vm.x + vm.width - vm.xPadding
+ : vm.x + vm.xPadding;
+}
+
/**
* Helper to build before and after body lines
*/
var title = vm.title;
if (title.length) {
+ pt.x = getAlignedX(vm, vm._titleAlign);
+
ctx.textAlign = vm._titleAlign;
ctx.textBaseline = 'top';
drawBody: function(pt, vm, ctx) {
var bodyFontSize = vm.bodyFontSize;
var bodySpacing = vm.bodySpacing;
+ var bodyAlign = vm._bodyAlign;
var body = vm.body;
+ var drawColorBoxes = vm.displayColors;
+ var labelColors = vm.labelColors;
+ var xLinePadding = 0;
+ var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;
+ var textColor;
- ctx.textAlign = vm._bodyAlign;
+ ctx.textAlign = bodyAlign;
ctx.textBaseline = 'top';
ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+ pt.x = getAlignedX(vm, bodyAlign);
+
// Before Body
- var xLinePadding = 0;
var fillLineOfText = function(line) {
ctx.fillText(line, pt.x + xLinePadding, pt.y);
pt.y += bodyFontSize + bodySpacing;
ctx.fillStyle = vm.bodyFontColor;
helpers.each(vm.beforeBody, fillLineOfText);
- var drawColorBoxes = vm.displayColors;
- xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
+ xLinePadding = drawColorBoxes && bodyAlign !== 'right'
+ ? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)
+ : 0;
// Draw body lines now
helpers.each(body, function(bodyItem, i) {
- var textColor = vm.labelTextColors[i];
+ textColor = vm.labelTextColors[i];
ctx.fillStyle = textColor;
helpers.each(bodyItem.before, fillLineOfText);
if (drawColorBoxes) {
// Fill a white rect so that colours merge nicely if the opacity is < 1
ctx.fillStyle = vm.legendColorBackground;
- ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
+ ctx.fillRect(colorX, pt.y, bodyFontSize, bodyFontSize);
// Border
ctx.lineWidth = 1;
- ctx.strokeStyle = vm.labelColors[i].borderColor;
- ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
+ ctx.strokeStyle = labelColors[i].borderColor;
+ ctx.strokeRect(colorX, pt.y, bodyFontSize, bodyFontSize);
// Inner square
- ctx.fillStyle = vm.labelColors[i].backgroundColor;
- ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+ ctx.fillStyle = labelColors[i].backgroundColor;
+ ctx.fillRect(colorX + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
ctx.fillStyle = textColor;
}
var footer = vm.footer;
if (footer.length) {
+ pt.x = getAlignedX(vm, vm._footerAlign);
pt.y += vm.footerMarginTop;
ctx.textAlign = vm._footerAlign;
this.drawBackground(pt, vm, ctx, tooltipSize);
// Draw Title, Body, and Footer
- pt.x += vm.xPadding;
pt.y += vm.yPadding;
// Titles
}]
}));
});
+
+ describe('text align', function() {
+ var globalDefaults = Chart.defaults.global;
+ var makeView = function(title, body, footer) {
+ return {
+ // Positioning
+ x: 100,
+ y: 100,
+ width: 100,
+ height: 100,
+ xPadding: 5,
+ yPadding: 5,
+ xAlign: 'left',
+ yAlign: 'top',
+
+ // Body
+ bodyFontColor: '#fff',
+ _bodyFontFamily: globalDefaults.defaultFontFamily,
+ _bodyFontStyle: globalDefaults.defaultFontStyle,
+ _bodyAlign: body,
+ bodyFontSize: globalDefaults.defaultFontSize,
+ bodySpacing: 2,
+
+ // Title
+ titleFontColor: '#fff',
+ _titleFontFamily: globalDefaults.defaultFontFamily,
+ _titleFontStyle: 'bold',
+ titleFontSize: globalDefaults.defaultFontSize,
+ _titleAlign: title,
+ titleSpacing: 2,
+ titleMarginBottom: 6,
+
+ // Footer
+ footerFontColor: '#fff',
+ _footerFontFamily: globalDefaults.defaultFontFamily,
+ _footerFontStyle: 'bold',
+ footerFontSize: globalDefaults.defaultFontSize,
+ _footerAlign: footer,
+ footerSpacing: 2,
+ footerMarginTop: 6,
+
+ // Appearance
+ caretSize: 5,
+ cornerRadius: 6,
+ borderColor: '#aaa',
+ borderWidth: 1,
+ backgroundColor: 'rgba(0,0,0,0.8)',
+ opacity: 1,
+ legendColorBackground: '#fff',
+
+ // Text
+ title: ['title'],
+ beforeBody: [],
+ body: [{
+ before: [],
+ lines: ['label'],
+ after: []
+ }],
+ afterBody: [],
+ footer: ['footer'],
+ caretPadding: 2,
+ labelTextColors: ['#fff'],
+ labelColors: [{
+ borderColor: 'rgb(255, 0, 0)',
+ backgroundColor: 'rgb(0, 255, 0)'
+ }, {
+ borderColor: 'rgb(0, 0, 255)',
+ backgroundColor: 'rgb(0, 255, 255)'
+ }]
+ };
+ };
+ var drawBody = [
+ {name: 'save', args: []},
+ {name: 'setFillStyle', args: ['rgba(0,0,0,0.8)']},
+ {name: 'setStrokeStyle', args: ['#aaa']},
+ {name: 'setLineWidth', args: [1]},
+ {name: 'beginPath', args: []},
+ {name: 'moveTo', args: [106, 100]},
+ {name: 'lineTo', args: [106, 100]},
+ {name: 'lineTo', args: [111, 95]},
+ {name: 'lineTo', args: [116, 100]},
+ {name: 'lineTo', args: [194, 100]},
+ {name: 'quadraticCurveTo', args: [200, 100, 200, 106]},
+ {name: 'lineTo', args: [200, 194]},
+ {name: 'quadraticCurveTo', args: [200, 200, 194, 200]},
+ {name: 'lineTo', args: [106, 200]},
+ {name: 'quadraticCurveTo', args: [100, 200, 100, 194]},
+ {name: 'lineTo', args: [100, 106]},
+ {name: 'quadraticCurveTo', args: [100, 100, 106, 100]},
+ {name: 'closePath', args: []},
+ {name: 'fill', args: []},
+ {name: 'stroke', args: []}
+ ];
+
+ var mockContext = window.createMockContext();
+ var tooltip = new Chart.Tooltip({
+ _options: globalDefaults.tooltips,
+ _chart: {
+ ctx: mockContext,
+ }
+ });
+
+ it('Should go left', function() {
+ mockContext.resetCalls();
+ tooltip._view = makeView('left', 'left', 'left');
+ tooltip.draw();
+
+ expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['title', 105, 105]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['label', 105, 123]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['footer', 105, 141]},
+ {name: 'restore', args: []}
+ ]));
+ });
+
+ it('Should go right', function() {
+ mockContext.resetCalls();
+ tooltip._view = makeView('right', 'right', 'right');
+ tooltip.draw();
+
+ expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['title', 195, 105]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['label', 195, 123]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['footer', 195, 141]},
+ {name: 'restore', args: []}
+ ]));
+ });
+
+ it('Should center', function() {
+ mockContext.resetCalls();
+ tooltip._view = makeView('center', 'center', 'center');
+ tooltip.draw();
+
+ expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['title', 150, 105]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['label', 150, 123]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['footer', 150, 141]},
+ {name: 'restore', args: []}
+ ]));
+ });
+
+ it('Should allow mixed', function() {
+ mockContext.resetCalls();
+ tooltip._view = makeView('right', 'center', 'left');
+ tooltip.draw();
+
+ expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['title', 195, 105]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['label', 150, 123]},
+ {name: 'setFillStyle', args: ['#fff']},
+ {name: 'fillText', args: ['footer', 105, 141]},
+ {name: 'restore', args: []}
+ ]));
+ });
+ });
});