return this;
},
- draw: function() {
-
-
- var ctx = this._chart.ctx;
+ getTooltipSize: function getTooltipSize() {
var vm = this._view;
+ var ctx = this._chart.ctx;
- if (this._view.opacity === 0) {
- return;
- }
-
- // Get Dimensions
-
- vm.position = "top";
-
- var caretPadding = vm.caretPadding || 2;
-
+ var size = {
+ height: vm.yPadding * 2, // Tooltip Padding
+ width: 0
+ };
var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
- // Height
- var tooltipHeight = vm.yPadding * 2; // Tooltip Padding
-
- tooltipHeight += vm.title.length * vm.titleFontSize; // Title Lines
- tooltipHeight += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
- tooltipHeight += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
-
- tooltipHeight += combinedBodyLength * vm.bodyFontSize; // Body Lines
- tooltipHeight += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing
-
- tooltipHeight += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
- tooltipHeight += vm.footer.length * (vm.footerFontSize); // Footer Lines
- tooltipHeight += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing
+ size.height += vm.title.length * vm.titleFontSize; // Title Lines
+ size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
+ size.height += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
+ size.height += combinedBodyLength * vm.bodyFontSize; // Body Lines
+ size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing
+ size.height += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
+ size.height += vm.footer.length * (vm.footerFontSize); // Footer Lines
+ size.height += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing
// Width
- var tooltipWidth = 0;
+ ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
helpers.each(vm.title, function(line) {
- ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
- tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
+ size.width = Math.max(size.width, ctx.measureText(line).width);
});
- helpers.each(vm.beforeBody, function(line) {
- ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
- tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
+
+ ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+ helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) {
+ size.width = Math.max(size.width, ctx.measureText(line).width);
}, this);
helpers.each(vm.body, function(line) {
- ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
- tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
- }, this);
- helpers.each(vm.afterBody, function(line) {
- ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
- tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
+ size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
}, this);
+
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
helpers.each(vm.footer, function(line) {
- ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
- tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
+ size.width = Math.max(size.width, ctx.measureText(line).width);
});
- tooltipWidth += 2 * vm.xPadding;
- var tooltipTotalWidth = tooltipWidth + vm.caretSize + caretPadding;
-
+ size.width += 2 * vm.xPadding;
-
- // Smart Tooltip placement to stay on the canvas
- // Top, center, or bottom
+ return size;
+ },
+ determineAlignment: function determineAlignment(size) {
+ var vm = this._view;
vm.yAlign = "center";
- if (vm.y - (tooltipHeight / 2) < 0) {
+ if (vm.y - (size.height / 2) < 0) {
vm.yAlign = "top";
- } else if (vm.y + (tooltipHeight / 2) > this._chart.height) {
+ } else if (vm.y + (size.height / 2) > this._chart.height) {
vm.yAlign = "bottom";
}
-
// Left or Right
vm.xAlign = "right";
- if (vm.x + tooltipTotalWidth > this._chart.width) {
+ if (vm.x + size.width > this._chart.width) {
vm.xAlign = "left";
}
-
-
+ },
+ getBackgroundPoint: function getBackgroundPoint(size, caretPadding) {
+ var vm = this._view;
// Background Position
- var tooltipX = vm.x,
- tooltipY = vm.y;
+ var pt = {
+ x: vm.x,
+ y: vm.y
+ };
if (vm.yAlign === 'top') {
- tooltipY = vm.y - vm.caretSize - vm.cornerRadius;
+ pt.y = vm.y - vm.caretSize - vm.cornerRadius;
} else if (vm.yAlign === 'bottom') {
- tooltipY = vm.y - tooltipHeight + vm.caretSize + vm.cornerRadius;
+ pt.y = vm.y - size.height + vm.caretSize + vm.cornerRadius;
} else {
- tooltipY = vm.y - (tooltipHeight / 2);
+ pt.y = vm.y - (size.height / 2);
}
if (vm.xAlign === 'left') {
- tooltipX = vm.x - tooltipTotalWidth;
+ pt.x = vm.x - size.width;
} else if (vm.xAlign === 'right') {
- tooltipX = vm.x + caretPadding + vm.caretSize;
+ pt.x = vm.x + caretPadding + vm.caretSize;
} else {
- tooltipX = vm.x + (tooltipTotalWidth / 2);
+ pt.x = vm.x + (size.width / 2);
}
- // Draw Background
+ return pt;
+ },
+ drawCaret: function drawCaret(opacity, caretPadding) {
+ var vm = this._view;
+ var ctx = this._chart.ctx;
- // IE11/Edge does not like very small opacities, so snap to 0
- var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
+ ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
+ ctx.beginPath();
- if (this._options.tooltips.enabled) {
- ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
- helpers.drawRoundedRectangle(ctx, tooltipX, tooltipY, tooltipWidth, tooltipHeight, vm.cornerRadius);
- ctx.fill();
+ if (vm.xAlign === 'left') {
+ ctx.moveTo(vm.x - caretPadding, vm.y);
+ ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize);
+ ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize);
+ } else {
+ ctx.moveTo(vm.x + caretPadding, vm.y);
+ ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize);
+ ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize);
}
+ ctx.closePath();
+ ctx.fill();
+ },
+ drawTitle: function drawTitle(pt, vm, ctx, opacity) {
+ if (vm.title.length) {
+ ctx.textAlign = vm._titleAlign;
+ ctx.textBaseline = "top";
+ ctx.fillStyle = helpers.color(vm.titleColor).alpha(opacity).rgbString();
+ ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
- // Draw Caret
- if (this._options.tooltips.enabled) {
- ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
-
- if (vm.xAlign === 'left') {
-
- ctx.beginPath();
- ctx.moveTo(vm.x - caretPadding, vm.y);
- ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize);
- ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize);
- ctx.closePath();
- ctx.fill();
- } else {
- ctx.beginPath();
- ctx.moveTo(vm.x + caretPadding, vm.y);
- ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize);
- ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize);
- ctx.closePath();
- ctx.fill();
- }
+ helpers.each(vm.title, function(title, i) {
+ ctx.fillText(title, pt.x, pt.y);
+ pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
+
+ if (i + 1 === vm.title.length) {
+ pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
+ }
+ }, this);
}
+ },
+ drawBody: function drawBody(pt, vm, ctx, opacity) {
+ ctx.textAlign = vm._bodyAlign;
+ ctx.textBaseline = "top";
+ ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbString();
+ ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+ // Before Body
+ helpers.each(vm.beforeBody, function(beforeBody) {
+ ctx.fillText(beforeBody, pt.x, pt.y);
+ pt.y += vm.bodyFontSize + vm.bodySpacing;
+ });
- // Draw Title, Body, and Footer
-
- if (this._options.tooltips.enabled) {
+ helpers.each(vm.body, function(body, i) {
+ // Draw Legend-like boxes if needed
+ if (this._options.tooltips.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);
- var yBase = tooltipY + vm.yPadding;
- var xBase = tooltipX + vm.xPadding;
+ // Border
+ ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
+ ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
- // Titles
+ // 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);
- if (vm.title.length) {
- ctx.textAlign = vm._titleAlign;
- ctx.textBaseline = "top";
- ctx.fillStyle = helpers.color(vm.titleColor).alpha(opacity).rgbString();
- ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
-
- helpers.each(vm.title, function(title, i) {
- ctx.fillText(title, xBase, yBase);
- yBase += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
- if (i + 1 === vm.title.length) {
- yBase += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
- }
- }, this);
+ ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
}
+ // Body Line
+ ctx.fillText(body, pt.x + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
- // Body
- ctx.textAlign = vm._bodyAlign;
- ctx.textBaseline = "top";
- ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbString();
- ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+ pt.y += vm.bodyFontSize + vm.bodySpacing;
+ }, this);
- // Before Body
- helpers.each(vm.beforeBody, function(beforeBody) {
- ctx.fillText(beforeBody, xBase, yBase);
- yBase += vm.bodyFontSize + vm.bodySpacing;
- });
+ // After Body
+ helpers.each(vm.afterBody, function(afterBody) {
+ ctx.fillText(afterBody, pt.x, pt.y);
+ pt.y += vm.bodyFontSize;
+ });
- helpers.each(vm.body, function(body, i) {
+ pt.y -= vm.bodySpacing; // Remove last body spacing
+ },
+ drawFooter: function drawFooter(pt, vm, ctx, opacity) {
+ if (vm.footer.length) {
+ pt.y += vm.footerMarginTop;
+ ctx.textAlign = vm._footerAlign;
+ ctx.textBaseline = "top";
+ ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString();
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
- // Draw Legend-like boxes if needed
- if (this._options.tooltips.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(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize);
+ helpers.each(vm.footer, function(footer) {
+ ctx.fillText(footer, pt.x, pt.y);
+ pt.y += vm.footerFontSize + vm.footerSpacing;
+ }, this);
+ }
+ },
+ draw: function draw() {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
- // Border
- ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
- ctx.strokeRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize);
+ if (vm.opacity === 0) {
+ return;
+ }
- // Inner square
- ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
- ctx.fillRect(xBase + 1, yBase + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
+ var caretPadding = vm.caretPadding || 2;
+ var tooltipSize = this.getTooltipSize();
+ var backgroundWidth = tooltipSize.width;
+
+ // Expand to be new total size (including caret)
+ tooltipSize.width += vm.caretSize + caretPadding;
- ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
- }
+ // Smart Tooltip placement to stay on the canvas
+ // Top, center, or bottom
+ this.determineAlignment(tooltipSize);
- // Body Line
- ctx.fillText(body, xBase + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), yBase);
+ var pt = this.getBackgroundPoint(tooltipSize, caretPadding);
- yBase += vm.bodyFontSize + vm.bodySpacing;
+ // IE11/Edge does not like very small opacities, so snap to 0
+ var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
- }, this);
+ if (this._options.tooltips.enabled) {
+ // Draw Background
+ ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
+ helpers.drawRoundedRectangle(ctx, pt.x, pt.y, backgroundWidth, tooltipSize.height, vm.cornerRadius);
+ ctx.fill();
- // After Body
- helpers.each(vm.afterBody, function(afterBody) {
- ctx.fillText(afterBody, xBase, yBase);
- yBase += vm.bodyFontSize;
- });
+ // Draw Caret
+ this.drawCaret(opacity, caretPadding);
+
+ // Draw Title, Body, and Footer
+ pt.x += vm.xPadding;
+ pt.y += vm.yPadding;
- yBase -= vm.bodySpacing; // Remove last body spacing
+ // Titles
+ this.drawTitle(pt, vm, ctx, opacity);
+ // Body
+ this.drawBody(pt, vm, ctx, opacity);
// Footer
- if (vm.footer.length) {
-
- yBase += vm.footerMarginTop;
-
- ctx.textAlign = vm._footerAlign;
- ctx.textBaseline = "top";
- ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString();
- ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
-
- helpers.each(vm.footer, function(footer) {
- ctx.fillText(footer, xBase, yBase);
- yBase += vm.footerFontSize + vm.footerSpacing;
- }, this);
- }
-
+ this.drawFooter(pt, vm, ctx, opacity);
}
- },
+ }
});
}).call(this);