From: Evert Timberg Date: Wed, 4 May 2016 23:28:22 +0000 (-0400) Subject: Reduce size of on-canvas legend X-Git-Tag: v2.1.1~4^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eeae8a6a16649be2d2b16a4e09ffc5d6cc0439b2;p=thirdparty%2FChart.js.git Reduce size of on-canvas legend --- diff --git a/src/core/core.legend.js b/src/core/core.legend.js index 62287ab70..a7ef76c68 100644 --- a/src/core/core.legend.js +++ b/src/core/core.legend.js @@ -3,6 +3,7 @@ module.exports = function(Chart) { var helpers = Chart.helpers; + var noop = helpers.noop; Chart.defaults.global.legend = { @@ -14,13 +15,14 @@ module.exports = function(Chart) { // 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: { @@ -75,7 +77,7 @@ module.exports = function(Chart) { // 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 ;) @@ -104,11 +106,11 @@ module.exports = function(Chart) { 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()) { @@ -136,90 +138,92 @@ module.exports = function(Chart) { 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() { @@ -228,19 +232,26 @@ module.exports = function(Chart) { // 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()) { @@ -252,57 +263,58 @@ module.exports = function(Chart) { 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 { @@ -312,17 +324,21 @@ module.exports = function(Chart) { // 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; }