"use strict"; module.exports = function(Chart) { var helpers = Chart.helpers; Chart.defaults.global.title = { display: false, position: 'top', fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes) fontStyle: 'bold', padding: 10, // actual title text: '' }; var noop = helpers.noop; Chart.Title = Chart.Element.extend({ initialize: function(config) { var me = this; helpers.extend(me, config); me.options = helpers.configMerge(Chart.defaults.global.title, config.options); // Contains hit boxes for each dataset (in dataset order) me.legendHitBoxes = []; }, // These methods are ordered by lifecyle. Utilities then follow. beforeUpdate: function () { var chartOpts = this.chart.options; if (chartOpts && chartOpts.title) { this.options = helpers.configMerge(Chart.defaults.global.title, chartOpts.title); } }, update: function(maxWidth, maxHeight, margins) { var me = this; // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) me.beforeUpdate(); // Absorb the master measurements me.maxWidth = maxWidth; me.maxHeight = maxHeight; me.margins = margins; // Dimensions me.beforeSetDimensions(); me.setDimensions(); me.afterSetDimensions(); // Labels me.beforeBuildLabels(); me.buildLabels(); me.afterBuildLabels(); // Fit me.beforeFit(); me.fit(); me.afterFit(); // me.afterUpdate(); return me.minSize; }, afterUpdate: noop, // beforeSetDimensions: noop, setDimensions: function() { var me = this; // Set the unconstrained dimension before label rotation if (me.isHorizontal()) { // Reset position before calculating rotation me.width = me.maxWidth; me.left = 0; me.right = me.width; } else { me.height = me.maxHeight; // Reset position before calculating rotation me.top = 0; me.bottom = me.height; } // Reset padding me.paddingLeft = 0; me.paddingTop = 0; me.paddingRight = 0; me.paddingBottom = 0; // Reset minSize me.minSize = { width: 0, height: 0 }; }, afterSetDimensions: noop, // beforeBuildLabels: noop, buildLabels: noop, afterBuildLabels: noop, // beforeFit: noop, fit: function() { var me = this, ctx = me.ctx, valueOrDefault = helpers.getValueOrDefault, opts = me.options, globalDefaults = Chart.defaults.global, display = opts.display, fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize), minSize = me.minSize; if (me.isHorizontal()) { minSize.width = me.maxWidth; // fill all the width minSize.height = display ? fontSize + (opts.padding * 2) : 0; } else { minSize.width = display ? fontSize + (opts.padding * 2) : 0; minSize.height = me.maxHeight; // fill all the height } me.width = minSize.width; me.height = minSize.height; }, afterFit: noop, // Shared Methods isHorizontal: function() { var pos = this.options.position; return pos === "top" || pos === "bottom"; }, // Actualy draw the title block on the canvas draw: function() { var me = this, ctx = me.ctx, valueOrDefault = helpers.getValueOrDefault, opts = me.options, globalDefaults = Chart.defaults.global; if (opts.display) { var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize), fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle), fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily), titleFont = helpers.fontString(fontSize, fontStyle, fontFamily), rotation = 0, titleX, titleY, top = me.top, left = me.left, bottom = me.bottom, right = me.right; ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour ctx.font = titleFont; // Horizontal if (me.isHorizontal()) { titleX = left + ((right - left) / 2); // midpoint of the width titleY = top + ((bottom - top) / 2); // midpoint of the height } else { titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2); titleY = top + ((bottom - top) / 2); rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5); } ctx.save(); ctx.translate(titleX, titleY); ctx.rotate(rotation); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(opts.text, 0, 0); ctx.restore(); } } }); // Register the title plugin Chart.pluginService.register({ beforeInit: function(chartInstance) { var opts = chartInstance.options; var titleOpts = opts.title; if (titleOpts) { chartInstance.titleBlock = new Chart.Title({ ctx: chartInstance.chart.ctx, options: titleOpts, chart: chartInstance }); Chart.layoutService.addBox(chartInstance, chartInstance.titleBlock); } } }); };