this.ensureScalesHaveIDs();
this.buildOrUpdateControllers();
this.buildScales();
- this.buildLegends();
+ this.buildSurroundingItems();
this.updateLayout();
this.resetElements();
this.initToolTip();
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() {
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,
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
// 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
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,
};
// 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';
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();
-
- }
-
}
}
},
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;
}
--- /dev/null
+(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);