module.exports = function(Chart) {
var helpers = Chart.helpers;
+ var noop = helpers.noop;
Chart.defaults.global.legend = {
// a callback that will handle
onClick: function(e, legendItem) {
var index = legendItem.datasetIndex;
- var meta = this.chart.getDatasetMeta(index);
+ var ci = this.chart;
+ var meta = ci.getDatasetMeta(index);
// See controller.isDatasetVisible comment
- meta.hidden = meta.hidden === null? !this.chart.data.datasets[index].hidden : null;
+ meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
// We hid a dataset ... rerender the chart
- this.chart.update();
+ ci.update();
},
labels: {
// Any function defined here is inherited by all legend types.
// Any function can be extended by the legend type
- beforeUpdate: helpers.noop,
+ beforeUpdate: noop,
update: function(maxWidth, maxHeight, margins) {
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
return this.minSize;
},
- afterUpdate: helpers.noop,
+ afterUpdate: noop,
//
- beforeSetDimensions: helpers.noop,
+ beforeSetDimensions: noop,
setDimensions: function() {
// Set the unconstrained dimension before label rotation
if (this.isHorizontal()) {
height: 0
};
},
- afterSetDimensions: helpers.noop,
+ afterSetDimensions: noop,
//
- beforeBuildLabels: helpers.noop,
+ beforeBuildLabels: noop,
buildLabels: function() {
this.legendItems = this.options.labels.generateLabels.call(this, this.chart);
if(this.options.reverse){
this.legendItems.reverse();
}
},
- afterBuildLabels: helpers.noop,
+ afterBuildLabels: noop,
//
- beforeFit: helpers.noop,
+ beforeFit: noop,
fit: function() {
+ var opts = this.options;
+ var labelOpts = opts.labels;
+ var display = opts.display;
var ctx = this.ctx;
- var fontSize = helpers.getValueOrDefault(this.options.labels.fontSize, Chart.defaults.global.defaultFontSize);
- var fontStyle = helpers.getValueOrDefault(this.options.labels.fontStyle, Chart.defaults.global.defaultFontStyle);
- var fontFamily = helpers.getValueOrDefault(this.options.labels.fontFamily, Chart.defaults.global.defaultFontFamily);
- var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
+
+ var globalDefault = Chart.defaults.global,
+ itemOrDefault = helpers.getValueOrDefault,
+ fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
+ fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
+ fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
+ labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
// Reset hit boxes
- this.legendHitBoxes = [];
+ var hitboxes = this.legendHitBoxes = [];
- // Width
- if (this.isHorizontal()) {
- this.minSize.width = this.maxWidth; // fill all the width
- } else {
- this.minSize.width = this.options.display ? 10 : 0;
- }
+ var minSize = this.minSize;
+ var isHorizontal = this.isHorizontal();
- // height
- if (this.isHorizontal()) {
- this.minSize.height = this.options.display ? 10 : 0;
+ if (isHorizontal) {
+ minSize.width = this.maxWidth; // fill all the width
+ minSize.height = display ? 10 : 0;
} else {
- this.minSize.height = this.maxHeight; // fill all the height
+ minSize.width = display ? 10 : 0;
+ minSize.height = this.maxHeight; // fill all the height
}
// Increase sizes here
- if (this.options.display) {
- if (this.isHorizontal()) {
+ if (display) {
+ if (isHorizontal) {
// Labels
// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
- this.lineWidths = [0];
- var totalHeight = this.legendItems.length ? fontSize + (this.options.labels.padding) : 0;
+ var lineWidths = this.lineWidths = [0];
+ var totalHeight = this.legendItems.length ? fontSize + (labelOpts.padding) : 0;
ctx.textAlign = "left";
ctx.textBaseline = 'top';
ctx.font = labelFont;
helpers.each(this.legendItems, function(legendItem, i) {
- var width = this.options.labels.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
- if (this.lineWidths[this.lineWidths.length - 1] + width + this.options.labels.padding >= this.width) {
- totalHeight += fontSize + (this.options.labels.padding);
- this.lineWidths[this.lineWidths.length] = this.left;
+ var width = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+ if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= this.width) {
+ totalHeight += fontSize + (labelOpts.padding);
+ lineWidths[lineWidths.length] = this.left;
}
// Store the hitbox width and height here. Final position will be updated in `draw`
- this.legendHitBoxes[i] = {
+ hitboxes[i] = {
left: 0,
top: 0,
width: width,
height: fontSize
};
- this.lineWidths[this.lineWidths.length - 1] += width + this.options.labels.padding;
+ lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
}, this);
- this.minSize.height += totalHeight;
+ minSize.height += totalHeight;
} else {
// TODO vertical
}
}
- this.width = this.minSize.width;
- this.height = this.minSize.height;
-
+ this.width = minSize.width;
+ this.height = minSize.height;
},
- afterFit: helpers.noop,
+ afterFit: noop,
// Shared Methods
isHorizontal: function() {
// Actualy draw the legend on the canvas
draw: function() {
- if (this.options.display) {
- var ctx = this.ctx;
- var cursor = {
- x: this.left + ((this.width - this.lineWidths[0]) / 2),
- y: this.top + this.options.labels.padding,
- line: 0
- };
-
- var fontColor = helpers.getValueOrDefault(this.options.labels.fontColor, Chart.defaults.global.defaultFontColor);
- var fontSize = helpers.getValueOrDefault(this.options.labels.fontSize, Chart.defaults.global.defaultFontSize);
- var fontStyle = helpers.getValueOrDefault(this.options.labels.fontStyle, Chart.defaults.global.defaultFontStyle);
- var fontFamily = helpers.getValueOrDefault(this.options.labels.fontFamily, Chart.defaults.global.defaultFontFamily);
- var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
+ var opts = this.options;
+ var labelOpts = opts.labels;
+ var globalDefault = Chart.defaults.global,
+ lineDefault = globalDefault.elements.line,
+ legendWidth = this.width,
+ lineWidths = this.lineWidths;
+
+ if (opts.display) {
+ var ctx = this.ctx,
+ cursor = {
+ x: this.left + ((legendWidth - lineWidths[0]) / 2),
+ y: this.top + labelOpts.padding,
+ line: 0
+ },
+ itemOrDefault = helpers.getValueOrDefault,
+ fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
+ fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
+ fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
+ fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
+ labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
// Horizontal
if (this.isHorizontal()) {
ctx.fillStyle = fontColor; // render in correct colour
ctx.font = labelFont;
+ var boxWidth = labelOpts.boxWidth,
+ hitboxes = this.legendHitBoxes;
+
helpers.each(this.legendItems, function(legendItem, i) {
- var textWidth = ctx.measureText(legendItem.text).width;
- var width = this.options.labels.boxWidth + (fontSize / 2) + textWidth;
+ var textWidth = ctx.measureText(legendItem.text).width,
+ width = boxWidth + (fontSize / 2) + textWidth,
+ x = cursor.x,
+ y = cursor.y;
- if (cursor.x + width >= this.width) {
- cursor.y += fontSize + (this.options.labels.padding);
+ if (x + width >= legendWidth) {
+ cursor.y += fontSize + (labelOpts.padding);
cursor.line++;
- cursor.x = this.left + ((this.width - this.lineWidths[cursor.line]) / 2);
+ cursor.x = this.left + ((legendWidth - lineWidths[cursor.line]) / 2);
}
// Set the ctx for the box
ctx.save();
- var itemOrDefault = function(item, defaulVal) {
- return item !== undefined ? item : defaulVal;
- };
-
- ctx.fillStyle = itemOrDefault(legendItem.fillStyle, Chart.defaults.global.defaultColor);
- ctx.lineCap = itemOrDefault(legendItem.lineCap, Chart.defaults.global.elements.line.borderCapStyle);
- ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, Chart.defaults.global.elements.line.borderDashOffset);
- ctx.lineJoin = itemOrDefault(legendItem.lineJoin, Chart.defaults.global.elements.line.borderJoinStyle);
- ctx.lineWidth = itemOrDefault(legendItem.lineWidth, Chart.defaults.global.elements.line.borderWidth);
- ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, Chart.defaults.global.defaultColor);
+ ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
+ ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
+ ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+ ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
+ ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
+ ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
if (ctx.setLineDash) {
// IE 9 and 10 do not support line dash
- ctx.setLineDash(itemOrDefault(legendItem.lineDash, Chart.defaults.global.elements.line.borderDash));
+ ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
}
// Draw the box
- ctx.strokeRect(cursor.x, cursor.y, this.options.labels.boxWidth, fontSize);
- ctx.fillRect(cursor.x, cursor.y, this.options.labels.boxWidth, fontSize);
+ ctx.strokeRect(x, y, boxWidth, fontSize);
+ ctx.fillRect(x, y, boxWidth, fontSize);
ctx.restore();
- this.legendHitBoxes[i].left = cursor.x;
- this.legendHitBoxes[i].top = cursor.y;
+ hitboxes[i].left = x;
+ hitboxes[i].top = y;
// Fill the actual label
- ctx.fillText(legendItem.text, this.options.labels.boxWidth + (fontSize / 2) + cursor.x, cursor.y);
+ ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);
if (legendItem.hidden) {
// Strikethrough the text if hidden
ctx.beginPath();
ctx.lineWidth = 2;
- ctx.moveTo(this.options.labels.boxWidth + (fontSize / 2) + cursor.x, cursor.y + (fontSize / 2));
- ctx.lineTo(this.options.labels.boxWidth + (fontSize / 2) + cursor.x + textWidth, cursor.y + (fontSize / 2));
+ ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
+ ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
ctx.stroke();
}
- cursor.x += width + (this.options.labels.padding);
+ cursor.x += width + (labelOpts.padding);
}, this);
} else {
// Handle an event
handleEvent: function(e) {
- var position = helpers.getRelativePosition(e, this.chart.chart);
+ var position = helpers.getRelativePosition(e, this.chart.chart),
+ x = position.x,
+ y = position.y,
+ opts = this.options;
- if (position.x >= this.left && position.x <= this.right && position.y >= this.top && position.y <= this.bottom) {
+ if (x >= this.left && x <= this.right && y >= this.top && y <= this.bottom) {
// See if we are touching one of the dataset boxes
- for (var i = 0; i < this.legendHitBoxes.length; ++i) {
- var hitBox = this.legendHitBoxes[i];
+ var lh = this.legendHitBoxes;
+ for (var i = 0; i < lh.length; ++i) {
+ var hitBox = lh[i];
- if (position.x >= hitBox.left && position.x <= hitBox.left + hitBox.width && position.y >= hitBox.top && position.y <= hitBox.top + hitBox.height) {
+ if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
// Touching an element
- if (this.options.onClick) {
- this.options.onClick.call(this, e, this.legendItems[i]);
+ if (opts.onClick) {
+ opts.onClick.call(this, e, this.legendItems[i]);
}
break;
}