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) {
- if (tooltipItems[0].xLabel) {
- title = tooltipItems[0].xLabel;
- } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
- title = data.labels[tooltipItems[0].index];
+ var item = tooltipItems[0];
+
+ if (item.xLabel) {
+ title = item.xLabel;
+ } else if (labelCount > 0 && item.index < labelCount) {
+ title = labels[item.index];
}
}
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 = this._options;
+ var tooltipOpts = me._options;
+ var getValueOrDefault = helpers.getValueOrDefault;
- helpers.extend(this, {
+ helpers.extend(me, {
_model: {
// Positioning
xPadding: tooltipOpts.xPadding,
// Body
bodyColor: tooltipOpts.bodyColor,
- _bodyFontFamily: helpers.getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
- _bodyFontStyle: helpers.getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+ _bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+ _bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
_bodyAlign: tooltipOpts.bodyAlign,
- bodyFontSize: helpers.getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+ bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
bodySpacing: tooltipOpts.bodySpacing,
// Title
titleColor: tooltipOpts.titleColor,
- _titleFontFamily: helpers.getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
- _titleFontStyle: helpers.getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
- titleFontSize: helpers.getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+ _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: helpers.getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
- _footerFontStyle: helpers.getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
- footerFontSize: helpers.getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
+ _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,
// Get the title
// Args are: (tooltipItem, data)
getTitle: function() {
- var beforeTitle = this._options.callbacks.beforeTitle.apply(this, arguments),
- title = this._options.callbacks.title.apply(this, arguments),
- afterTitle = this._options.callbacks.afterTitle.apply(this, arguments);
+ 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);
// Args are: (tooltipItem, data)
getBeforeBody: function() {
- var lines = this._options.callbacks.beforeBody.apply(this, arguments);
+ 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) {
lines: [],
after: []
};
- helpers.pushAllIfDefined(this._options.callbacks.beforeLabel.call(this, tooltipItem, data), bodyItem.before);
- helpers.pushAllIfDefined(this._options.callbacks.label.call(this, tooltipItem, data), bodyItem.lines);
- helpers.pushAllIfDefined(this._options.callbacks.afterLabel.call(this, tooltipItem, data), bodyItem.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);
- }, this);
+ });
return bodyItems;
},
// Args are: (tooltipItem, data)
getAfterBody: function() {
- var lines = this._options.callbacks.afterBody.apply(this, arguments);
+ 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 beforeFooter = this._options.callbacks.beforeFooter.apply(this, arguments);
- var footer = this._options.callbacks.footer.apply(this, arguments);
- var afterFooter = this._options.callbacks.afterFooter.apply(this, arguments);
+ 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);
return lines;
},
- getAveragePosition: function(elements) {
-
- if (!elements.length) {
- return false;
- }
-
- var xPositions = [];
- var yPositions = [];
-
- helpers.each(elements, function(el) {
- if (el && el.hasValue()){
- var pos = el.tooltipPosition();
- xPositions.push(pos.x);
- yPositions.push(pos.y);
- }
- });
-
- var x = 0,
- y = 0;
- for (var i = 0; i < xPositions.length; i++) {
- x += xPositions[i];
- y += yPositions[i];
- }
+ 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;
- return {
- x: Math.round(x / xPositions.length),
- y: Math.round(y / xPositions.length)
- };
+ var i, len;
- },
+ if (active.length) {
+ model.opacity = 1;
- update: function(changed) {
- if (this._active.length) {
- this._model.opacity = 1;
-
- var element = this._active[0],
+ var element = active[0],
labelColors = [],
- tooltipPosition;
+ tooltipPosition = tooltipPosition = getAveragePosition(active);
var tooltipItems = [];
+ for (var i = 0, len = active.length; i < len; ++i) {
+ tooltipItems.push(createTooltipItem(active[i]));
+ }
- if (this._options.mode === 'single') {
- var yScale = element._yScale || element._scale; // handle radar || polarArea charts
- tooltipItems.push({
- xLabel: element._xScale ? element._xScale.getLabelForIndex(element._index, element._datasetIndex) : '',
- yLabel: yScale ? yScale.getLabelForIndex(element._index, element._datasetIndex) : '',
- index: element._index,
- datasetIndex: element._datasetIndex
- });
- tooltipPosition = this.getAveragePosition(this._active);
- } else {
- helpers.each(this._data.datasets, function(dataset, datasetIndex) {
- if (!this._chartInstance.isDatasetVisible(datasetIndex)) {
- return;
- }
-
- var meta = this._chartInstance.getDatasetMeta(datasetIndex);
- var currentElement = meta.data[element._index];
- if (currentElement) {
- var yScale = element._yScale || element._scale; // handle radar || polarArea charts
-
- tooltipItems.push({
- xLabel: currentElement._xScale ? currentElement._xScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
- yLabel: yScale ? yScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
- index: element._index,
- datasetIndex: datasetIndex
- });
- }
- }, this);
-
+ // If there is more than one item, show color items
+ if (active.length > 1) {
helpers.each(tooltipItems, function(tooltipItem) {
- labelColors.push(this._options.callbacks.labelColor.call(this, tooltipItem, this._chartInstance));
- }, this);
-
- tooltipPosition = this.getAveragePosition(this._active);
+ labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, chartInstance));
+ });
}
// Build the Text Lines
- helpers.extend(this._model, {
- title: this.getTitle(tooltipItems, this._data),
- beforeBody: this.getBeforeBody(tooltipItems, this._data),
- body: this.getBody(tooltipItems, this._data),
- afterBody: this.getAfterBody(tooltipItems, this._data),
- footer: this.getFooter(tooltipItems, this._data),
+ 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),
});
// We need to determine alignment of
- var tooltipSize = this.getTooltipSize(this._model);
- this.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas
+ var tooltipSize = me.getTooltipSize(model);
+ me.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas
- helpers.extend(this._model, this.getBackgroundPoint(this._model, tooltipSize));
+ helpers.extend(model, me.getBackgroundPoint(model, tooltipSize));
} else {
- this._model.opacity = 0;
+ me._model.opacity = 0;
}
- if (changed && this._options.custom) {
- this._options.custom.call(this, this._model);
+ if (changed && opts.custom) {
+ opts.custom.call(me, model);
}
- return this;
+ return me;
},
getTooltipSize: function getTooltipSize(vm) {
- var ctx = this._chart.ctx;
+ var me = this;
+ var ctx = me._chart.ctx;
var size = {
height: vm.yPadding * 2, // Tooltip Padding
width: 0
};
-
- var combinedBodyLength = vm.body.reduce(function(count, bodyItem) {
+ // 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);
- // Count in before and after body sections
combinedBodyLength += vm.beforeBody.length + vm.afterBody.length;
- 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
+ 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 += 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
- ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
- helpers.each(vm.title, function(line) {
- size.width = Math.max(size.width, ctx.measureText(line).width);
- });
+ 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(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);
- });
+ ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+ helpers.each(vm.title, maxLineWidth);
- var _this = this;
- var maxBodyWidth = function(line) {
- size.width = Math.max(size.width, ctx.measureText(line).width + (_this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
- };
- helpers.each(vm.body, function(bodyItem) {
- helpers.each(bodyItem.before, maxBodyWidth);
- helpers.each(bodyItem.lines, maxBodyWidth);
- helpers.each(bodyItem.after, maxBodyWidth);
- });
+ // Body width
+ ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+ helpers.each(vm.beforeBody.concat(vm.afterBody), maxLineWidth);
- ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
- helpers.each(vm.footer, function(line) {
- size.width = Math.max(size.width, ctx.measureText(line).width);
+ // 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) {
- if (this._model.y < size.height) {
- this._model.yAlign = 'top';
- } else if (this._model.y > (this._chart.height - size.height)) {
- this._model.yAlign = 'bottom';
+ 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 _this = this;
- var midX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
- var midY = (this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2;
+ var midX = (chartArea.left + chartArea.right) / 2;
+ var midY = (chartArea.top + chartArea.bottom) / 2;
- if (this._model.yAlign === 'center') {
+ if (model.yAlign === 'center') {
lf = function(x) {
return x <= midX;
};
return x <= (size.width / 2);
};
rf = function(x) {
- return x >= (_this._chart.width - (size.width / 2));
+ return x >= (chart.width - (size.width / 2));
};
}
olf = function(x) {
- return x + size.width > _this._chart.width;
+ return x + size.width > chart.width;
};
orf = function(x) {
return x - size.width < 0;
return y <= midY ? 'top' : 'bottom';
};
- if (lf(this._model.x)) {
- this._model.xAlign = 'left';
+ if (lf(model.x)) {
+ model.xAlign = 'left';
// Is tooltip too wide and goes over the right side of the chart.?
- if (olf(this._model.x)) {
- this._model.xAlign = 'center';
- this._model.yAlign = yf(this._model.y);
+ if (olf(model.x)) {
+ model.xAlign = 'center';
+ model.yAlign = yf(model.y);
}
- } else if (rf(this._model.x)) {
- this._model.xAlign = 'right';
+ } else if (rf(model.x)) {
+ model.xAlign = 'right';
// Is tooltip too wide and goes outside left edge of canvas?
- if (orf(this._model.x)) {
- this._model.xAlign = 'center';
- this._model.yAlign = yf(this._model.y);
+ if (orf(model.x)) {
+ model.xAlign = 'center';
+ model.yAlign = yf(model.y);
}
}
},
y: vm.y
};
- if (vm.xAlign === 'right') {
+ 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 (vm.xAlign === 'center') {
+ } else if (xAlign === 'center') {
pt.x -= (size.width / 2);
}
- if (vm.yAlign === 'top') {
- pt.y += vm.caretPadding + vm.caretSize;
- } else if (vm.yAlign === 'bottom') {
- pt.y -= size.height + vm.caretPadding + vm.caretSize;
+ if (yAlign === 'top') {
+ pt.y += paddingAndSize;
+ } else if (yAlign === 'bottom') {
+ pt.y -= size.height + paddingAndSize;
} else {
pt.y -= (size.height / 2);
}
- if (vm.yAlign === 'center') {
- if (vm.xAlign === 'left') {
- pt.x += vm.caretPadding + vm.caretSize;
- } else if (vm.xAlign === 'right') {
- pt.x -= vm.caretPadding + vm.caretSize;
+ if (yAlign === 'center') {
+ if (xAlign === 'left') {
+ pt.x += paddingAndSize;
+ } else if (xAlign === 'right') {
+ pt.x -= paddingAndSize;
}
} else {
- if (vm.xAlign === 'left') {
- pt.x -= vm.cornerRadius + vm.caretPadding;
- } else if (vm.xAlign === 'right') {
- pt.x += vm.cornerRadius + vm.caretPadding;
+ if (xAlign === 'left') {
+ pt.x -= radiusAndPadding;
+ } else if (xAlign === 'right') {
+ pt.x += radiusAndPadding;
}
}
return pt;
},
drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) {
- var vm = this._view;
- var ctx = this._chart.ctx;
+ var me = this;
+ var vm = me._view;
+ var ctx = me._chart.ctx;
var x1, x2, x3;
var y1, y2, y3;
-
- if (vm.yAlign === 'center') {
+ 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 (vm.xAlign === 'left') {
- x1 = tooltipPoint.x;
- x2 = x1 - vm.caretSize;
+ if (xAlign === 'left') {
+ x1 = ptX;
+ x2 = x1 - caretSize;
x3 = x1;
} else {
- x1 = tooltipPoint.x + size.width;
- x2 = x1 + vm.caretSize;
+ x1 = ptX + width;
+ x2 = x1 + caretSize;
x3 = x1;
}
- y2 = tooltipPoint.y + (size.height / 2);
- y1 = y2 - vm.caretSize;
- y3 = y2 + vm.caretSize;
+ y2 = ptY + (height / 2);
+ y1 = y2 - caretSize;
+ y3 = y2 + caretSize;
} else {
- if (vm.xAlign === 'left') {
- x1 = tooltipPoint.x + vm.cornerRadius;
- x2 = x1 + vm.caretSize;
- x3 = x2 + vm.caretSize;
- } else if (vm.xAlign === 'right') {
- x1 = tooltipPoint.x + size.width - vm.cornerRadius;
- x2 = x1 - vm.caretSize;
- x3 = x2 - vm.caretSize;
+ 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 = tooltipPoint.x + (size.width / 2);
- x1 = x2 - vm.caretSize;
- x3 = x2 + vm.caretSize;
+ x2 = ptX + (width / 2);
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
}
- if (vm.yAlign === 'top') {
- y1 = tooltipPoint.y;
- y2 = y1 - vm.caretSize;
+ if (yAlign === 'top') {
+ y1 = ptY;
+ y2 = y1 - caretSize;
y3 = y1;
} else {
- y1 = tooltipPoint.y + size.height;
- y2 = y1 + vm.caretSize;
+ y1 = ptY + height;
+ y2 = y1 + caretSize;
y3 = y1;
}
}
ctx.fill();
},
drawTitle: function drawTitle(pt, vm, ctx, opacity) {
- if (vm.title.length) {
+ 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(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+ ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
- helpers.each(vm.title, function(title, i) {
- ctx.fillText(title, pt.x, pt.y);
- pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
+ 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 === vm.title.length) {
- pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove 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);
- ctx.fillStyle = bodyColor.alpha(opacity * bodyColor.alpha()).rgbString();
- ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+ var textColor = bodyColor.alpha(opacity * bodyColor.alpha()).rgbString();
+ ctx.fillStyle = textColor
+ ctx.font = helpers.fontString(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;
- });
+ var xLinePadding = 0;
+ var fillLineOfText = function(line) {
+ ctx.fillText(line, pt.x + xLinePadding, pt.y);
+ pt.y += bodyFontSize + bodySpacing;
+ };
- helpers.each(vm.body, function(bodyItem, i) {
- var _this = this;
- var fillLine = function(line) {
- // Body Line
- ctx.fillText(line, pt.x + (_this._options.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
- pt.y += vm.bodyFontSize + vm.bodySpacing;
- };
+ // Before body lines
+ helpers.each(vm.beforeBody, fillLineOfText);
- helpers.each(bodyItem.before, fillLine);
+ 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 (this._options.mode !== 'single') {
+ 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, vm.bodyFontSize, vm.bodyFontSize);
+ 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, vm.bodyFontSize, vm.bodyFontSize);
+ 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, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
+ ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
- ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
+ ctx.fillStyle = textColor;
}
- fillLine(line);
- }, this);
+ fillLineOfText(line);
+ });
- helpers.each(bodyItem.after, fillLine);
- }, this);
-
- // After Body
- helpers.each(vm.afterBody, function(afterBody) {
- ctx.fillText(afterBody, pt.x, pt.y);
- pt.y += vm.bodyFontSize;
+ helpers.each(bodyItem.after, fillLineOfText);
});
- pt.y -= vm.bodySpacing; // Remove last body spacing
+ // 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) {
- if (vm.footer.length) {
+ var footer = vm.footer;
+
+ if (footer.length) {
pt.y += vm.footerMarginTop;
ctx.textAlign = vm._footerAlign;
ctx.fillStyle = footerColor.alpha(opacity * footerColor.alpha()).rgbString();
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
- helpers.each(vm.footer, function(footer) {
- ctx.fillText(footer, pt.x, pt.y);
+ helpers.each(footer, function(line) {
+ ctx.fillText(line, pt.x, pt.y);
pt.y += vm.footerFontSize + vm.footerSpacing;
});
}
return;
}
- var caretPadding = vm.caretPadding;
var tooltipSize = this.getTooltipSize(vm);
var pt = {
x: vm.x,
ctx.fill();
// Draw Caret
- this.drawCaret(pt, tooltipSize, opacity, caretPadding);
+ this.drawCaret(pt, tooltipSize, opacity, vm.caretPadding);
// Draw Title, Body, and Footer
pt.x += vm.xPadding;