From: Evert Timberg Date: Sun, 6 Dec 2015 15:20:38 +0000 (-0500) Subject: Split legend and title block functionality into 2 separate blocks. This allows the... X-Git-Tag: 2.0.0-beta2~25^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=792ee587ae0e18e66990692eaec74163222976ec;p=thirdparty%2FChart.js.git Split legend and title block functionality into 2 separate blocks. This allows the title to be on the top of the chart while the legend is on the bottom --- diff --git a/samples/bar.html b/samples/bar.html index 004e0738f..d12765700 100644 --- a/samples/bar.html +++ b/samples/bar.html @@ -72,11 +72,11 @@ responsive: true, legend: { position: 'top', - title: { - display: true, - text: 'Our 3 Favorite Datasets' - } }, + title: { + display: true, + text: 'Our 3 Favorite Datasets' + } } }); diff --git a/samples/doughnut.html b/samples/doughnut.html index 0a6be617a..f0ebd5129 100644 --- a/samples/doughnut.html +++ b/samples/doughnut.html @@ -107,11 +107,11 @@ responsive: true, legend: { position: 'top', - title: { - display: true, - text: 'Our Favorite Datasets' - } }, + title: { + display: true, + text: 'Our Favorite Datasets' + } } }; diff --git a/samples/line-legend.html b/samples/line-legend.html index 98ffc18f3..ea345c21b 100644 --- a/samples/line-legend.html +++ b/samples/line-legend.html @@ -61,11 +61,7 @@ options: { responsive: true, legend: { - position: 'top', - title: { - display: true, - text: 'Our 4 Favorite Datasets' - } + position: 'bottom', }, hover: { mode: 'label' @@ -85,6 +81,10 @@ labelString: 'Value' } }] + }, + title: { + display: true, + text: 'Our 4 Favorite Datasets' } } }; diff --git a/samples/polar-area.html b/samples/polar-area.html index 58f9d57f1..8d9bc9c64 100644 --- a/samples/polar-area.html +++ b/samples/polar-area.html @@ -62,10 +62,10 @@ responsive: true, legend: { position: 'top', - title: { - display: true, - text: 'Our Favorite Dataset' - } + }, + title: { + display: true, + text: 'Our Favorite Dataset' }, scale: { ticks: { diff --git a/samples/radar.html b/samples/radar.html index 867605275..e294cee18 100644 --- a/samples/radar.html +++ b/samples/radar.html @@ -58,13 +58,13 @@ options: { legend: { position: 'top', - title: { - display: true, - text: 'Our 3 Favorite Datasets' - } + }, + title: { + display: true, + text: 'Our 3 Favorite Datasets' }, scale: { - reverse: true, + reverse: false, ticks: { beginAtZero: true } diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 47884b732..88bf11a83 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -59,7 +59,7 @@ this.ensureScalesHaveIDs(); this.buildOrUpdateControllers(); this.buildScales(); - this.buildLegends(); + this.buildSurroundingItems(); this.updateLayout(); this.resetElements(); this.initToolTip(); @@ -170,18 +170,26 @@ Chart.scaleService.addScalesToLayout(this); }, - buildLegends: function() { - if (!this.options.legend) { - return; + buildSurroundingItems: function() { + if (this.options.title) { + this.titleBlock = new Chart.Title({ + ctx: this.chart.ctx, + options: this.options.title, + chart: this + }); + + Chart.layoutService.addBox(this, this.titleBlock); } - this.legend = new Chart.Legend({ - ctx: this.chart.ctx, - options: this.options.legend, - chart: this, - }); + if (this.options.legend) { + this.legend = new Chart.Legend({ + ctx: this.chart.ctx, + options: this.options.legend, + chart: this, + }); - Chart.layoutService.addBox(this, this.legend); + Chart.layoutService.addBox(this, this.legend); + } }, updateLayout: function() { diff --git a/src/core/core.legend.js b/src/core/core.legend.js index fb3776d27..14e1c6b4e 100644 --- a/src/core/core.legend.js +++ b/src/core/core.legend.js @@ -12,21 +12,6 @@ fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes) onClick: false, // a callback will override the default behavior of toggling the datasets - title: { - position: 'top', - fontColor: '#666', - fontFamily: 'Helvetica Neue', - fontSize: 12, - fontStyle: 'bold', - padding: 10, - - // actual title - text: '', - - // display property - display: false, - }, - labels: { boxWidth: 40, fontSize: 12, @@ -136,7 +121,6 @@ fit: function() { var ctx = this.ctx; - var titleFont = helpers.fontString(this.options.title.fontSize, this.options.title.fontStyle, this.options.title.fontFamily); var labelFont = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily); // Reset hit boxes @@ -158,12 +142,6 @@ // Increase sizes here if (this.isHorizontal()) { - - // Title - if (this.options.title.display) { - this.minSize.height += this.options.title.fontSize + (this.options.title.padding * 2); - } - // Labels // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one @@ -215,7 +193,7 @@ var ctx = this.ctx; var cursor = { x: this.left + ((this.width - this.lineWidths[0]) / 2), - y: this.top, + y: this.top + this.options.labels.padding, line: 0, }; @@ -223,17 +201,6 @@ // Horizontal if (this.isHorizontal()) { - - // Title Spacing if on top - if (this.options.title.display) { - if (this.options.title.position === 'top') { - cursor.y += this.options.title.fontSize + (this.options.title.padding * 2); - } else { - // bottom - cursor.y += this.options.labels.padding; - } - } - // Labels ctx.textAlign = "left"; ctx.textBaseline = 'top'; @@ -299,49 +266,8 @@ cursor.x += width + (this.options.labels.padding); }, this); - - // Title Spacing if on bottom - if (this.options.title.display && this.options.title.position === 'bottom') { - cursor.y += this.options.title.fontSize + (this.options.title.padding * 2); - } - - // Title - if (this.options.title.display) { - - ctx.textAlign = "center"; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.options.title.fontColor; // render in correct colour - ctx.font = helpers.fontString(this.options.title.fontSize, this.options.title.fontStyle, this.options.title.fontFamily); - - var titleX = this.left + ((this.right - this.left) / 2); // midpoint of the width - var titleY = this.options.title.position == 'bottom' ? this.bottom - (this.options.title.fontSize / 2) - this.options.title.padding : this.top + (this.options.title.fontSize / 2) + this.options.title.padding; - - ctx.fillText(this.options.title.text, titleX, titleY); - } - - } else { - // Title - if (this.options.title.display) { - - // Draw the legend label - titleX = this.options.position == 'left' ? this.left + (this.options.title.fontSize / 2) : this.right - (this.options.title.fontSize / 2); - titleY = this.top + ((this.bottom - this.top) / 2); - var rotation = this.options.position == 'left' ? -0.5 * Math.PI : 0.5 * Math.PI; - - ctx.save(); - ctx.translate(titleX, titleY); - ctx.rotate(rotation); - ctx.textAlign = "center"; - ctx.fillStyle = this.options.title.fontColor; // render in correct colour - ctx.font = helpers.fontString(this.options.title.fontSize, this.options.title.fontStyle, this.options.title.fontFamily); - ctx.textBaseline = 'middle'; - ctx.fillText(this.options.title.text, 0, 0); - ctx.restore(); - - } - } } }, @@ -363,7 +289,6 @@ this.chart.data.datasets[i].hidden = !this.chart.data.datasets[i].hidden; // We hid a dataset ... rerender the chart - //this.chart.render(); this.chart.update(); break; } diff --git a/src/core/core.title.js b/src/core/core.title.js new file mode 100644 index 000000000..7758fd337 --- /dev/null +++ b/src/core/core.title.js @@ -0,0 +1,196 @@ +(function() { + "use strict"; + + var root = this, + Chart = root.Chart, + helpers = Chart.helpers; + + Chart.defaults.title = { + + display: true, + position: 'top', + fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes) + + fontColor: '#666', + fontFamily: 'Helvetica Neue', + fontSize: 12, + fontStyle: 'bold', + padding: 10, + + // actual title + text: '', + }; + + Chart.Title = Chart.Element.extend({ + + initialize: function(config) { + helpers.extend(this, config); + this.options = helpers.configMerge(Chart.defaults.title, config.options); + + // Contains hit boxes for each dataset (in dataset order) + this.legendHitBoxes = []; + }, + + // These methods are ordered by lifecyle. Utilities then follow. + + beforeUpdate: helpers.noop, + update: function(maxWidth, maxHeight, margins) { + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + this.beforeUpdate(); + + // Absorb the master measurements + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.margins = margins; + + // Dimensions + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + // Labels + this.beforeBuildLabels(); + this.buildLabels(); + this.afterBuildLabels(); + + // Fit + this.beforeFit(); + this.fit(); + this.afterFit(); + // + this.afterUpdate(); + + return this.minSize; + + }, + afterUpdate: helpers.noop, + + // + + beforeSetDimensions: helpers.noop, + setDimensions: function() { + // Set the unconstrained dimension before label rotation + if (this.isHorizontal()) { + // Reset position before calculating rotation + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + + // Reset position before calculating rotation + this.top = 0; + this.bottom = this.height; + } + + // Reset padding + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + + // Reset minSize + this.minSize = { + width: 0, + height: 0, + }; + }, + afterSetDimensions: helpers.noop, + + // + + beforeBuildLabels: helpers.noop, + buildLabels: helpers.noop, + afterBuildLabels: helpers.noop, + + // + + beforeFit: helpers.noop, + fit: function() { + + var ctx = this.ctx; + var titleFont = helpers.fontString(this.options.fontSize, this.options.fontStyle, this.options.fontFamily); + + // Width + if (this.isHorizontal()) { + this.minSize.width = this.maxWidth; // fill all the width + } else { + this.minSize.width = 0; + } + + // height + if (this.isHorizontal()) { + this.minSize.height = 0; + } else { + this.minSize.height = this.maxHeight; // fill all the height + } + + // Increase sizes here + if (this.isHorizontal()) { + + // Title + if (this.options.display) { + this.minSize.height += this.options.fontSize + (this.options.padding * 2); + } + } else { + // TODO vertical + } + + this.width = this.minSize.width; + this.height = this.minSize.height; + + }, + afterFit: helpers.noop, + + // Shared Methods + isHorizontal: function() { + return this.options.position == "top" || this.options.position == "bottom"; + }, + + // Actualy draw the title block on the canvas + draw: function() { + if (this.options.display) { + var ctx = this.ctx; + var titleX, titleY; + + // Horizontal + if (this.isHorizontal()) { + // Title + if (this.options.display) { + + ctx.textAlign = "center"; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.options.fontColor; // render in correct colour + ctx.font = helpers.fontString(this.options.fontSize, this.options.fontStyle, this.options.fontFamily); + + titleX = this.left + ((this.right - this.left) / 2); // midpoint of the width + titleY = this.top + ((this.bottom - this.top) / 2); // midpoint of the height + + ctx.fillText(this.options.text, titleX, titleY); + } + } else { + + // Title + if (this.options.display) { + titleX = this.options.position == 'left' ? this.left + (this.options.fontSize / 2) : this.right - (this.options.fontSize / 2); + titleY = this.top + ((this.bottom - this.top) / 2); + var rotation = this.options.position == 'left' ? -0.5 * Math.PI : 0.5 * Math.PI; + + ctx.save(); + ctx.translate(titleX, titleY); + ctx.rotate(rotation); + ctx.textAlign = "center"; + ctx.fillStyle = this.options.fontColor; // render in correct colour + ctx.font = helpers.fontString(this.options.fontSize, this.options.fontStyle, this.options.fontFamily); + ctx.textBaseline = 'middle'; + ctx.fillText(this.options.text, 0, 0); + ctx.restore(); + + } + + } + } + } + }); + +}).call(this);