text: "use strict";
  
  module.exports = function(Chart) {
  
  	var helpers = Chart.helpers;
  
  	Chart.defaults.global.tooltips = {
  		enabled: true,
  		custom: null,
  		mode: 'single',
  		backgroundColor: "rgba(0,0,0,0.8)",
  		titleFontStyle: "bold",
  		titleSpacing: 2,
  		titleMarginBottom: 6,
  		titleColor: "#fff",
  		titleAlign: "left",
  		bodySpacing: 2,
  		bodyColor: "#fff",
  		bodyAlign: "left",
  		footerFontStyle: "bold",
  		footerSpacing: 2,
  		footerMarginTop: 6,
  		footerColor: "#fff",
  		footerAlign: "left",
  		yPadding: 6,
  		xPadding: 6,
  		yAlign : 'center',
  		xAlign : 'center',
  		caretSize: 5,
  		cornerRadius: 6,
  		multiKeyBackground: '#fff',
  		callbacks: {
  			// Args are: (tooltipItems, data)
  			beforeTitle: helpers.noop,
  			title: function(tooltipItems, data) {
  				// Pick first xLabel for now
  				var title = '';
  				var labels = data.labels;
  				var labelCount = labels ? labels.length : 0;
  
  				if (tooltipItems.length > 0) {
  					var item = tooltipItems[0];
  
  					if (item.xLabel) {
  						title = item.xLabel;
  					} else if (labelCount > 0 && item.index < labelCount) {
  						title = labels[item.index];
  					}
  				}
  
  				return title;
  			},
  			afterTitle: helpers.noop,
  
  			// Args are: (tooltipItems, data)
  			beforeBody: helpers.noop,
  
  			// Args are: (tooltipItem, data)
  			beforeLabel: helpers.noop,
  			label: function(tooltipItem, data) {
  				var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
  				return datasetLabel + ': ' + tooltipItem.yLabel;
  			},
  			labelColor: function(tooltipItem, chartInstance) {
  				var meta = chartInstance.getDatasetMeta(tooltipItem.datasetIndex);
  				var activeElement = meta.data[tooltipItem.index];
  				var view = activeElement._view;
  				return {
  					borderColor: view.borderColor,
  					backgroundColor: view.backgroundColor
  				};
  			},
  			afterLabel: helpers.noop,
  
  			// Args are: (tooltipItems, data)
  			afterBody: helpers.noop,
  
  			// Args are: (tooltipItems, data)
  			beforeFooter: helpers.noop,
  			footer: helpers.noop,
  			afterFooter: helpers.noop
  		}
  	};
  
  	// Helper to push or concat based on if the 2nd parameter is an array or not
  	function pushOrConcat(base, toPush) {
  		if (toPush) {
  			if (helpers.isArray(toPush)) {
  				base = base.concat(toPush);
  			} else {
  				base.push(toPush);
  			}
  		}
  
  		return base;
  	}
  
  	function getAveragePosition(elements) {
  		if (!elements.length) {
  			return false;
  		}
  
  		var i, len;
  		var xPositions = [];
  		var yPositions = [];
  
  		for (i = 0, len = elements.length; i < len; ++i) {
  			var el = elements[i];
  			if (el && el.hasValue()){
  				var pos = el.tooltipPosition();
  				xPositions.push(pos.x);
  				yPositions.push(pos.y);
  			}
  		}
  
  		var x = 0,
  			y = 0;
  		for (i = 0, len - xPositions.length; i < len; ++i) {
  			x += xPositions[i];
  			y += yPositions[i];
  		}
  
  		return {
  			x: Math.round(x / xPositions.length),
  			y: Math.round(y / xPositions.length)
  		};
  	}
  
  	// Private helper to create a tooltip iteam model
  	// @param element : the chart element (point, arc, bar) to create the tooltip item for
  	// @return : new tooltip item
  	function createTooltipItem(element) {
  		var xScale = element._xScale;
  		var yScale = element._yScale || element._scale; // handle radar || polarArea charts
  		var index = element._index,
  			datasetIndex = element._datasetIndex;
  
  		return {
  			xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
  			yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
  			index: index,
  			datasetIndex: datasetIndex
  		};
  	}
  
  	Chart.Tooltip = Chart.Element.extend({
  		initialize: function() {
  			var me = this;
  			var globalDefaults = Chart.defaults.global;
  			var tooltipOpts = me._options;
  			var getValueOrDefault = helpers.getValueOrDefault;
  
  			helpers.extend(me, {
  				_model: {
  					// Positioning
  					xPadding: tooltipOpts.xPadding,
  					yPadding: tooltipOpts.yPadding,
  					xAlign : tooltipOpts.yAlign,
  					yAlign : tooltipOpts.xAlign,
  
  					// Body
  					bodyColor: tooltipOpts.bodyColor,
  					_bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
  					_bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
  					_bodyAlign: tooltipOpts.bodyAlign,
  					bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
  					bodySpacing: tooltipOpts.bodySpacing,
  
  					// Title
  					titleColor: tooltipOpts.titleColor,
  					_titleFontFamily: getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
  					_titleFontStyle: getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
  					titleFontSize: getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
  					_titleAlign: tooltipOpts.titleAlign,
  					titleSpacing: tooltipOpts.titleSpacing,
  					titleMarginBottom: tooltipOpts.titleMarginBottom,
  
  					// Footer
  					footerColor: tooltipOpts.footerColor,
  					_footerFontFamily: getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
  					_footerFontStyle: getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
  					footerFontSize: getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
  					_footerAlign: tooltipOpts.footerAlign,
  					footerSpacing: tooltipOpts.footerSpacing,
  					footerMarginTop: tooltipOpts.footerMarginTop,
  
  					// Appearance
  					caretSize: tooltipOpts.caretSize,
  					cornerRadius: tooltipOpts.cornerRadius,
  					backgroundColor: tooltipOpts.backgroundColor,
  					opacity: 0,
  					legendColorBackground: tooltipOpts.multiKeyBackground
  				}
  			});
  		},
  
  		// Get the title
  		// Args are: (tooltipItem, data)
  		getTitle: function() {
  			var me = this;
  			var opts = me._options;
  			var callbacks = opts.callbacks;
  
  			var beforeTitle = callbacks.beforeTitle.apply(me, arguments),
  				title = callbacks.title.apply(me, arguments),
  				afterTitle = callbacks.afterTitle.apply(me, arguments);
  
  			var lines = [];
  			lines = pushOrConcat(lines, beforeTitle);
  			lines = pushOrConcat(lines, title);
  			lines = pushOrConcat(lines, afterTitle);
  
  			return lines;
  		},
  
  		// Args are: (tooltipItem, data)
  		getBeforeBody: function() {
  			var me = this;
  			var lines = me._options.callbacks.beforeBody.apply(me, arguments);
  			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
  		},
  
  		// Args are: (tooltipItem, data)
  		getBody: function(tooltipItems, data) {
  			var me = this;
  			var callbacks = me._options.callbacks;
  			var bodyItems = [];
  
  			helpers.each(tooltipItems, function(tooltipItem) {
  				var bodyItem = {
  					before: [],
  					lines: [],
  					after: []
  				};
  				pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
  				pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
  				pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
  
  				bodyItems.push(bodyItem);
  			});
  
  			return bodyItems;
  		},
  
  		// Args are: (tooltipItem, data)
  		getAfterBody: function() {
  			var me = this;
  			var lines = me._options.callbacks.afterBody.apply(me, arguments);
  			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
  		},
  
  		// Get the footer and beforeFooter and afterFooter lines
  		// Args are: (tooltipItem, data)
  		getFooter: function() {
  			var me = this;
  			var callbacks = me._options.callbacks;
  
  			var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
  			var footer = callbacks.footer.apply(me, arguments);
  			var afterFooter = callbacks.afterFooter.apply(me, arguments);
  
  			var lines = [];
  			lines = pushOrConcat(lines, beforeFooter);
  			lines = pushOrConcat(lines, footer);
  			lines = pushOrConcat(lines, afterFooter);
  
  			return lines;
  		},
  
  		update: function(changed) {
  			var me = this;
  			var opts = me._options;
  			var model = me._model;
  			var active = me._active;
  
  			var data = me._data;
  			var chartInstance = me._chartInstance;
  
  			var i, len;
  
  			if (active.length) {
  				model.opacity = 1;
  
  				var labelColors = [],
  					tooltipPosition = getAveragePosition(active);
  
  				var tooltipItems = [];
  				for (i = 0, len = active.length; i < len; ++i) {
  					tooltipItems.push(createTooltipItem(active[i]));
  				}
  
  				// If the user provided a sorting function, use it to modify the tooltip items
  				if (opts.itemSort) {
  					tooltipItems = tooltipItems.sort(opts.itemSort);
  				}
  
  				// If there is more than one item, show color items
  				if (active.length > 1) {
  					helpers.each(tooltipItems, function(tooltipItem) {
  						labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, chartInstance));
  					});
  				}
  
  				// Build the Text Lines
  				helpers.extend(model, {
  					title: me.getTitle(tooltipItems, data),
  					beforeBody: me.getBeforeBody(tooltipItems, data),
  					body: me.getBody(tooltipItems, data),
  					afterBody: me.getAfterBody(tooltipItems, data),
  					footer: me.getFooter(tooltipItems, data),
  					x: Math.round(tooltipPosition.x),
  					y: Math.round(tooltipPosition.y),
  					caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2),
  					labelColors: labelColors
  				});
  
  				// We need to determine alignment of
  				var tooltipSize = me.getTooltipSize(model);
  				me.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas
  
  				helpers.extend(model, me.getBackgroundPoint(model, tooltipSize));
  			} else {
  				me._model.opacity = 0;
  			}
  
  			if (changed && opts.custom) {
  				opts.custom.call(me, model);
  			}
  
  			return me;
  		},
  		getTooltipSize: function getTooltipSize(vm) {
  			var me = this;
  			var ctx = me._chart.ctx;
  
  			var size = {
  				height: vm.yPadding * 2, // Tooltip Padding
  				width: 0
  			};
  
  			// Count of all lines in the body
  			var body = vm.body;
  			var combinedBodyLength = body.reduce(function(count, bodyItem) {
  				return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
  			}, 0);
  			combinedBodyLength += vm.beforeBody.length + vm.afterBody.length;
  
  			var titleLineCount = vm.title.length;
  			var footerLineCount = vm.footer.length;
  			var titleFontSize = vm.titleFontSize,
  				bodyFontSize = vm.bodyFontSize,
  				footerFontSize = vm.footerFontSize;
  
  			size.height += titleLineCount * titleFontSize; // Title Lines
  			size.height += (titleLineCount - 1) * vm.titleSpacing; // Title Line Spacing
  			size.height += titleLineCount ? vm.titleMarginBottom : 0; // Title's bottom Margin
  			size.height += combinedBodyLength * bodyFontSize; // Body Lines
  			size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing
  			size.height += footerLineCount ? vm.footerMarginTop : 0; // Footer Margin
  			size.height += footerLineCount * (footerFontSize); // Footer Lines
  			size.height += footerLineCount ? (footerLineCount - 1) * vm.footerSpacing : 0; // Footer Line Spacing
  
  			// Title width
  			var widthPadding = 0;
  			var maxLineWidth = function(line) {
  				size.width = Math.max(size.width, ctx.measureText(line).width + widthPadding);
  			};
  
  			ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
  			helpers.each(vm.title, maxLineWidth);
  
  			// Body width
  			ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
  			helpers.each(vm.beforeBody.concat(vm.afterBody), maxLineWidth);
  
  			// Body lines may include some extra width due to the color box
  			widthPadding = body.length > 1 ? (bodyFontSize + 2) : 0;
  			helpers.each(body, function(bodyItem) {
  				helpers.each(bodyItem.before, maxLineWidth);
  				helpers.each(bodyItem.lines, maxLineWidth);
  				helpers.each(bodyItem.after, maxLineWidth);
  			});
  
  			// Reset back to 0
  			widthPadding = 0;
  
  			// Footer width
  			ctx.font = helpers.fontString(footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
  			helpers.each(vm.footer, maxLineWidth);
  
  			// Add padding
  			size.width += 2 * vm.xPadding;
  
  			return size;
  		},
  		determineAlignment: function determineAlignment(size) {
  			var me = this;
  			var model = me._model;
  			var chart = me._chart;
  			var chartArea = me._chartInstance.chartArea;
  
  			if (model.y < size.height) {
  				model.yAlign = 'top';
  			} else if (model.y > (chart.height - size.height)) {
  				model.yAlign = 'bottom';
  			}
  
  			var lf, rf; // functions to determine left, right alignment
  			var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
  			var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
  			var midX = (chartArea.left + chartArea.right) / 2;
  			var midY = (chartArea.top + chartArea.bottom) / 2;
  
  			if (model.yAlign === 'center') {
  				lf = function(x) {
  					return x <= midX;
  				};
  				rf = function(x) {
  					return x > midX;
  				};
  			} else {
  				lf = function(x) {
  					return x <= (size.width / 2);
  				};
  				rf = function(x) {
  					return x >= (chart.width - (size.width / 2));
  				};
  			}
  
  			olf = function(x) {
  				return x + size.width > chart.width;
  			};
  			orf = function(x) {
  				return x - size.width < 0;
  			};
  			yf = function(y) {
  				return y <= midY ? 'top' : 'bottom';
  			};
  
  			if (lf(model.x)) {
  				model.xAlign = 'left';
  
  				// Is tooltip too wide and goes over the right side of the chart.?
  				if (olf(model.x)) {
  					model.xAlign = 'center';
  					model.yAlign = yf(model.y);
  				}
  			} else if (rf(model.x)) {
  				model.xAlign = 'right';
  
  				// Is tooltip too wide and goes outside left edge of canvas?
  				if (orf(model.x)) {
  					model.xAlign = 'center';
  					model.yAlign = yf(model.y);
  				}
  			}
  		},
  		getBackgroundPoint: function getBackgroundPoint(vm, size) {
  			// Background Position
  			var pt = {
  				x: vm.x,
  				y: vm.y
  			};
  
  			var caretSize = vm.caretSize,
  				caretPadding = vm.caretPadding,
  				cornerRadius = vm.cornerRadius,
  				xAlign = vm.xAlign,
  				yAlign = vm.yAlign,
  				paddingAndSize = caretSize + caretPadding,
  				radiusAndPadding = cornerRadius + caretPadding;
  
  			if (xAlign === 'right') {
  				pt.x -= size.width;
  			} else if (xAlign === 'center') {
  				pt.x -= (size.width / 2);
  			}
  
  			if (yAlign === 'top') {
  				pt.y += paddingAndSize;
  			} else if (yAlign === 'bottom') {
  				pt.y -= size.height + paddingAndSize;
  			} else {
  				pt.y -= (size.height / 2);
  			}
  
  			if (yAlign === 'center') {
  				if (xAlign === 'left') {
  					pt.x += paddingAndSize;
  				} else if (xAlign === 'right') {
  					pt.x -= paddingAndSize;
  				}
  			} else {
  				if (xAlign === 'left') {
  					pt.x -= radiusAndPadding;
  				} else if (xAlign === 'right') {
  					pt.x += radiusAndPadding;
  				}
  			}
  
  			return pt;
  		},
  		drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) {
  			var me = this;
  			var vm = me._view;
  			var ctx = me._chart.ctx;
  			var x1, x2, x3;
  			var y1, y2, y3;
  			var caretSize = vm.caretSize;
  			var cornerRadius = vm.cornerRadius;
  			var xAlign = vm.xAlign,
  				yAlign = vm.yAlign;
  			var ptX = tooltipPoint.x,
  				ptY = tooltipPoint.y;
  			var width = size.width,
  				height = size.height;
  
  			if (yAlign === 'center') {
  				// Left or right side
  				if (xAlign === 'left') {
  					x1 = ptX;
  					x2 = x1 - caretSize;
  					x3 = x1;
  				} else {
  					x1 = ptX + width;
  					x2 = x1 + caretSize;
  					x3 = x1;
  				}
  
  				y2 = ptY + (height / 2);
  				y1 = y2 - caretSize;
  				y3 = y2 + caretSize;
  			} else {
  				if (xAlign === 'left') {
  					x1 = ptX + cornerRadius;
  					x2 = x1 + caretSize;
  					x3 = x2 + caretSize;
  				} else if (xAlign === 'right') {
  					x1 = ptX + width - cornerRadius;
  					x2 = x1 - caretSize;
  					x3 = x2 - caretSize;
  				} else {
  					x2 = ptX + (width / 2);
  					x1 = x2 - caretSize;
  					x3 = x2 + caretSize;
  				}
  
  				if (yAlign === 'top') {
  					y1 = ptY;
  					y2 = y1 - caretSize;
  					y3 = y1;
  				} else {
  					y1 = ptY + height;
  					y2 = y1 + caretSize;
  					y3 = y1;
  				}
  			}
  
  			var bgColor = helpers.color(vm.backgroundColor);
  			ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
  			ctx.beginPath();
  			ctx.moveTo(x1, y1);
  			ctx.lineTo(x2, y2);
  			ctx.lineTo(x3, y3);
  			ctx.closePath();
  			ctx.fill();
  		},
  		drawTitle: function drawTitle(pt, vm, ctx, opacity) {
  			var title = vm.title;
  
  			if (title.length) {
  				ctx.textAlign = vm._titleAlign;
  				ctx.textBaseline = "top";
  
  				var titleFontSize = vm.titleFontSize,
  					titleSpacing = vm.titleSpacing;
  
  				var titleColor = helpers.color(vm.titleColor);
  				ctx.fillStyle = titleColor.alpha(opacity * titleColor.alpha()).rgbString();
  				ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
  
  				var i, len;
  				for (i = 0, len = title.length; i < len; ++i) {
  					ctx.fillText(title[i], pt.x, pt.y);
  					pt.y += titleFontSize + titleSpacing; // Line Height and spacing
  
  					if (i + 1 === title.length) {
  						pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
  					}
  				}
  			}
  		},
  		drawBody: function drawBody(pt, vm, ctx, opacity) {
  			var me = this;
  			var bodyFontSize = vm.bodyFontSize;
  			var bodySpacing = vm.bodySpacing;
  			var body = vm.body;
  
  			ctx.textAlign = vm._bodyAlign;
  			ctx.textBaseline = "top";
  
  			var bodyColor = helpers.color(vm.bodyColor);
  			var textColor = bodyColor.alpha(opacity * bodyColor.alpha()).rgbString();
  			ctx.fillStyle = textColor;
  			ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
  
  			// Before Body
  			var xLinePadding = 0;
  			var fillLineOfText = function(line) {
  				ctx.fillText(line, pt.x + xLinePadding, pt.y);
  				pt.y += bodyFontSize + bodySpacing;
  			};
  
  			// Before body lines
  			helpers.each(vm.beforeBody, fillLineOfText);
  
  			var drawColorBoxes = body.length > 1;
  			xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
  			
  			// Draw body lines now
  			helpers.each(body, function(bodyItem, i) {
  				helpers.each(bodyItem.before, fillLineOfText);
  
  				helpers.each(bodyItem.lines, function(line) {
  					// Draw Legend-like boxes if needed
  					if (drawColorBoxes) {
  						// 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, bodyFontSize, bodyFontSize);
  
  						// Border
  						ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
  						ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
  
  						// Inner square
  						ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
  						ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
  
  						ctx.fillStyle = textColor;
  					}
  
  					fillLineOfText(line);
  				});
  				
  				helpers.each(bodyItem.after, fillLineOfText);
  			});
  
  			// Reset back to 0 for after body
  			xLinePadding = 0;
  
  			// After body lines
  			helpers.each(vm.afterBody, fillLineOfText);
  			pt.y -= bodySpacing; // Remove last body spacing
  		},
  		drawFooter: function drawFooter(pt, vm, ctx, opacity) {
  			var footer = vm.footer;
  
  			if (footer.length) {
  				pt.y += vm.footerMarginTop;
  
  				ctx.textAlign = vm._footerAlign;
  				ctx.textBaseline = "top";
  
  				var footerColor = helpers.color(vm.footerColor);
  				ctx.fillStyle = footerColor.alpha(opacity * footerColor.alpha()).rgbString();
  				ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
  
  				helpers.each(footer, function(line) {
  					ctx.fillText(line, pt.x, pt.y);
  					pt.y += vm.footerFontSize + vm.footerSpacing;
  				});
  			}
  		},
  		draw: function draw() {
  			var ctx = this._chart.ctx;
  			var vm = this._view;
  
  			if (vm.opacity === 0) {
  				return;
  			}
  
  			var tooltipSize = this.getTooltipSize(vm);
  			var pt = {
  				x: vm.x,
  				y: vm.y
  			};
  
  			// IE11/Edge does not like very small opacities, so snap to 0
  			var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
  
  			if (this._options.enabled) {
  				// Draw Background
  				var bgColor = helpers.color(vm.backgroundColor);
  				ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
  				helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
  				ctx.fill();
  
  				// Draw Caret
  				this.drawCaret(pt, tooltipSize, opacity, vm.caretPadding);
  
  				// Draw Title, Body, and Footer
  				pt.x += vm.xPadding;
  				pt.y += vm.yPadding;
  
  				// Titles
  				this.drawTitle(pt, vm, ctx, opacity);
  
  				// Body
  				this.drawBody(pt, vm, ctx, opacity);
  
  				// Footer
  				this.drawFooter(pt, vm, ctx, opacity);
  			}
  		}
  	});
  };
  