From 953000a9a5c4d7b339e03a09f907fa54adb4d468 Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Tue, 8 Jan 2019 16:57:49 +0100 Subject: [PATCH 1/2] Make the main controller importable Merge `core/core.js` in `core/core.controller.js`, split defaults options next to their associated code and deprecate `Chart.type` (not sure what it was for). --- src/chart.js | 4 +- src/core/core.controller.js | 1572 ++++++++++++----------- src/core/core.defaults.js | 14 +- src/core/core.js | 50 - src/core/core.layouts.js | 12 + test/specs/global.deprecations.tests.js | 15 +- 6 files changed, 834 insertions(+), 833 deletions(-) delete mode 100644 src/core/core.js diff --git a/src/chart.js b/src/chart.js index b60129f2cf5..d74a6d82efb 100644 --- a/src/chart.js +++ b/src/chart.js @@ -1,7 +1,7 @@ /** * @namespace Chart */ -var Chart = require('./core/core')(); +var Chart = require('./core/core.controller'); Chart.helpers = require('./helpers/index'); @@ -24,8 +24,6 @@ Chart.scaleService = require('./core/core.scaleService'); Chart.Ticks = require('./core/core.ticks'); Chart.Tooltip = require('./core/core.tooltip'); -require('./core/core.controller')(Chart); - // Register built-in scales var scales = require('./scales'); Chart.helpers.each(scales, function(scale, type) { diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 0a97f6aada5..f3b62e2eee4 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -14,947 +14,977 @@ var Tooltip = require('./core.tooltip'); var valueOrDefault = helpers.valueOrDefault; -module.exports = function(Chart) { - - // Create a dictionary of chart types, to allow for extension of existing types - Chart.types = {}; +defaults._set('global', { + elements: {}, + events: [ + 'mousemove', + 'mouseout', + 'click', + 'touchstart', + 'touchmove' + ], + hover: { + onHover: null, + mode: 'nearest', + intersect: true, + animationDuration: 400 + }, + onClick: null, + maintainAspectRatio: true, + responsive: true, + responsiveAnimationDuration: 0 +}); + +function initConfig(config) { + config = config || {}; + + // Do NOT use configMerge() for the data object because this method merges arrays + // and so would change references to labels and datasets, preventing data updates. + var data = config.data = config.data || {}; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + + config.options = helpers.configMerge( + defaults.global, + defaults[config.type], + config.options || {}); + + return config; +} + +function updateConfig(chart) { + var newOptions = chart.options; + + helpers.each(chart.scales, function(scale) { + layouts.removeBox(chart, scale); + }); - // Store a reference to each instance - allowing us to globally resize chart instances on window resize. - // Destroy method on the chart will remove the instance of the chart from this reference. - Chart.instances = {}; + newOptions = helpers.configMerge( + defaults.global, + defaults[chart.config.type], + newOptions); - /** - * Initializes the given config with global and chart default values. - */ - function initConfig(config) { - config = config || {}; + chart.options = chart.config.options = newOptions; + chart.ensureScalesHaveIDs(); + chart.buildOrUpdateScales(); - // Do NOT use configMerge() for the data object because this method merges arrays - // and so would change references to labels and datasets, preventing data updates. - var data = config.data = config.data || {}; - data.datasets = data.datasets || []; - data.labels = data.labels || []; + // Tooltip + chart.tooltip._options = newOptions.tooltips; + chart.tooltip.initialize(); +} - config.options = helpers.configMerge( - defaults.global, - defaults[config.type], - config.options || {}); +function positionIsHorizontal(position) { + return position === 'top' || position === 'bottom'; +} - return config; - } +var Chart = function(item, config) { + this.construct(item, config); + return this; +}; +helpers.extend(Chart.prototype, /** @lends Chart */ { /** - * Updates the config of the chart - * @param chart {Chart} chart to update the options for + * @private */ - function updateConfig(chart) { - var newOptions = chart.options; - - helpers.each(chart.scales, function(scale) { - layouts.removeBox(chart, scale); - }); - - newOptions = helpers.configMerge( - Chart.defaults.global, - Chart.defaults[chart.config.type], - newOptions); - - chart.options = chart.config.options = newOptions; - chart.ensureScalesHaveIDs(); - chart.buildOrUpdateScales(); - // Tooltip - chart.tooltip._options = newOptions.tooltips; - chart.tooltip.initialize(); - } - - function positionIsHorizontal(position) { - return position === 'top' || position === 'bottom'; - } + construct: function(item, config) { + var me = this; + + config = initConfig(config); + + var context = platform.acquireContext(item, config); + var canvas = context && context.canvas; + var height = canvas && canvas.height; + var width = canvas && canvas.width; + + me.id = helpers.uid(); + me.ctx = context; + me.canvas = canvas; + me.config = config; + me.width = width; + me.height = height; + me.aspectRatio = height ? width / height : null; + me.options = config.options; + me._bufferedRender = false; - helpers.extend(Chart.prototype, /** @lends Chart */ { /** + * Provided for backward compatibility, Chart and Chart.Controller have been merged, + * the "instance" still need to be defined since it might be called from plugins. + * @prop Chart#chart + * @deprecated since version 2.6.0 + * @todo remove at version 3 * @private */ - construct: function(item, config) { - var me = this; - - config = initConfig(config); - - var context = platform.acquireContext(item, config); - var canvas = context && context.canvas; - var height = canvas && canvas.height; - var width = canvas && canvas.width; - - me.id = helpers.uid(); - me.ctx = context; - me.canvas = canvas; - me.config = config; - me.width = width; - me.height = height; - me.aspectRatio = height ? width / height : null; - me.options = config.options; - me._bufferedRender = false; - - /** - * Provided for backward compatibility, Chart and Chart.Controller have been merged, - * the "instance" still need to be defined since it might be called from plugins. - * @prop Chart#chart - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ - me.chart = me; - me.controller = me; // chart.chart.controller #inception - - // Add the chart instance to the global namespace - Chart.instances[me.id] = me; - - // Define alias to the config data: `chart.data === chart.config.data` - Object.defineProperty(me, 'data', { - get: function() { - return me.config.data; - }, - set: function(value) { - me.config.data = value; - } - }); + me.chart = me; + me.controller = me; // chart.chart.controller #inception - if (!context || !canvas) { - // The given item is not a compatible context2d element, let's return before finalizing - // the chart initialization but after setting basic chart / controller properties that - // can help to figure out that the chart is not valid (e.g chart.canvas !== null); - // https://github.com/chartjs/Chart.js/issues/2807 - console.error("Failed to create chart: can't acquire context from the given item"); - return; + // Add the chart instance to the global namespace + Chart.instances[me.id] = me; + + // Define alias to the config data: `chart.data === chart.config.data` + Object.defineProperty(me, 'data', { + get: function() { + return me.config.data; + }, + set: function(value) { + me.config.data = value; } + }); - me.initialize(); - me.update(); - }, + if (!context || !canvas) { + // The given item is not a compatible context2d element, let's return before finalizing + // the chart initialization but after setting basic chart / controller properties that + // can help to figure out that the chart is not valid (e.g chart.canvas !== null); + // https://github.com/chartjs/Chart.js/issues/2807 + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } - /** - * @private - */ - initialize: function() { - var me = this; + me.initialize(); + me.update(); + }, - // Before init plugin notification - plugins.notify(me, 'beforeInit'); + /** + * @private + */ + initialize: function() { + var me = this; - helpers.retinaScale(me, me.options.devicePixelRatio); + // Before init plugin notification + plugins.notify(me, 'beforeInit'); - me.bindEvents(); + helpers.retinaScale(me, me.options.devicePixelRatio); - if (me.options.responsive) { - // Initial resize before chart draws (must be silent to preserve initial animations). - me.resize(true); - } + me.bindEvents(); - // Make sure scales have IDs and are built before we build any controllers. - me.ensureScalesHaveIDs(); - me.buildOrUpdateScales(); - me.initToolTip(); + if (me.options.responsive) { + // Initial resize before chart draws (must be silent to preserve initial animations). + me.resize(true); + } - // After init plugin notification - plugins.notify(me, 'afterInit'); + // Make sure scales have IDs and are built before we build any controllers. + me.ensureScalesHaveIDs(); + me.buildOrUpdateScales(); + me.initToolTip(); - return me; - }, + // After init plugin notification + plugins.notify(me, 'afterInit'); - clear: function() { - helpers.canvas.clear(this); - return this; - }, + return me; + }, - stop: function() { - // Stops any current animation loop occurring - animations.cancelAnimation(this); - return this; - }, + clear: function() { + helpers.canvas.clear(this); + return this; + }, - resize: function(silent) { - var me = this; - var options = me.options; - var canvas = me.canvas; - var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null; + stop: function() { + // Stops any current animation loop occurring + animations.cancelAnimation(this); + return this; + }, - // the canvas render width and height will be casted to integers so make sure that - // the canvas display style uses the same integer values to avoid blurring effect. + resize: function(silent) { + var me = this; + var options = me.options; + var canvas = me.canvas; + var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null; - // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed - var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas))); - var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas))); + // the canvas render width and height will be casted to integers so make sure that + // the canvas display style uses the same integer values to avoid blurring effect. - if (me.width === newWidth && me.height === newHeight) { - return; - } + // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed + var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas))); + var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas))); - canvas.width = me.width = newWidth; - canvas.height = me.height = newHeight; - canvas.style.width = newWidth + 'px'; - canvas.style.height = newHeight + 'px'; + if (me.width === newWidth && me.height === newHeight) { + return; + } - helpers.retinaScale(me, options.devicePixelRatio); + canvas.width = me.width = newWidth; + canvas.height = me.height = newHeight; + canvas.style.width = newWidth + 'px'; + canvas.style.height = newHeight + 'px'; - if (!silent) { - // Notify any plugins about the resize - var newSize = {width: newWidth, height: newHeight}; - plugins.notify(me, 'resize', [newSize]); + helpers.retinaScale(me, options.devicePixelRatio); - // Notify of resize - if (me.options.onResize) { - me.options.onResize(me, newSize); - } + if (!silent) { + // Notify any plugins about the resize + var newSize = {width: newWidth, height: newHeight}; + plugins.notify(me, 'resize', [newSize]); - me.stop(); - me.update({ - duration: me.options.responsiveAnimationDuration - }); + // Notify of resize + if (me.options.onResize) { + me.options.onResize(me, newSize); } - }, - - ensureScalesHaveIDs: function() { - var options = this.options; - var scalesOptions = options.scales || {}; - var scaleOptions = options.scale; - helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) { - xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index); + me.stop(); + me.update({ + duration: me.options.responsiveAnimationDuration }); + } + }, - helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) { - yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index); - }); + ensureScalesHaveIDs: function() { + var options = this.options; + var scalesOptions = options.scales || {}; + var scaleOptions = options.scale; - if (scaleOptions) { - scaleOptions.id = scaleOptions.id || 'scale'; - } - }, + helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) { + xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index); + }); - /** - * Builds a map of scale ID to scale object for future lookup. - */ - buildOrUpdateScales: function() { - var me = this; - var options = me.options; - var scales = me.scales || {}; - var items = []; - var updated = Object.keys(scales).reduce(function(obj, id) { - obj[id] = false; - return obj; - }, {}); - - if (options.scales) { - items = items.concat( - (options.scales.xAxes || []).map(function(xAxisOptions) { - return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'}; - }), - (options.scales.yAxes || []).map(function(yAxisOptions) { - return {options: yAxisOptions, dtype: 'linear', dposition: 'left'}; - }) - ); - } + helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) { + yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index); + }); - if (options.scale) { - items.push({ - options: options.scale, - dtype: 'radialLinear', - isDefault: true, - dposition: 'chartArea' - }); - } + if (scaleOptions) { + scaleOptions.id = scaleOptions.id || 'scale'; + } + }, - helpers.each(items, function(item) { - var scaleOptions = item.options; - var id = scaleOptions.id; - var scaleType = valueOrDefault(scaleOptions.type, item.dtype); + /** + * Builds a map of scale ID to scale object for future lookup. + */ + buildOrUpdateScales: function() { + var me = this; + var options = me.options; + var scales = me.scales || {}; + var items = []; + var updated = Object.keys(scales).reduce(function(obj, id) { + obj[id] = false; + return obj; + }, {}); + + if (options.scales) { + items = items.concat( + (options.scales.xAxes || []).map(function(xAxisOptions) { + return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'}; + }), + (options.scales.yAxes || []).map(function(yAxisOptions) { + return {options: yAxisOptions, dtype: 'linear', dposition: 'left'}; + }) + ); + } - if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) { - scaleOptions.position = item.dposition; - } + if (options.scale) { + items.push({ + options: options.scale, + dtype: 'radialLinear', + isDefault: true, + dposition: 'chartArea' + }); + } - updated[id] = true; - var scale = null; - if (id in scales && scales[id].type === scaleType) { - scale = scales[id]; - scale.options = scaleOptions; - scale.ctx = me.ctx; - scale.chart = me; - } else { - var scaleClass = scaleService.getScaleConstructor(scaleType); - if (!scaleClass) { - return; - } - scale = new scaleClass({ - id: id, - type: scaleType, - options: scaleOptions, - ctx: me.ctx, - chart: me - }); - scales[scale.id] = scale; - } + helpers.each(items, function(item) { + var scaleOptions = item.options; + var id = scaleOptions.id; + var scaleType = valueOrDefault(scaleOptions.type, item.dtype); - scale.mergeTicksOptions(); + if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } - // TODO(SB): I think we should be able to remove this custom case (options.scale) - // and consider it as a regular scale part of the "scales"" map only! This would - // make the logic easier and remove some useless? custom code. - if (item.isDefault) { - me.scale = scale; - } - }); - // clear up discarded scales - helpers.each(updated, function(hasUpdated, id) { - if (!hasUpdated) { - delete scales[id]; + updated[id] = true; + var scale = null; + if (id in scales && scales[id].type === scaleType) { + scale = scales[id]; + scale.options = scaleOptions; + scale.ctx = me.ctx; + scale.chart = me; + } else { + var scaleClass = scaleService.getScaleConstructor(scaleType); + if (!scaleClass) { + return; } - }); + scale = new scaleClass({ + id: id, + type: scaleType, + options: scaleOptions, + ctx: me.ctx, + chart: me + }); + scales[scale.id] = scale; + } - me.scales = scales; + scale.mergeTicksOptions(); - scaleService.addScalesToLayout(this); - }, + // TODO(SB): I think we should be able to remove this custom case (options.scale) + // and consider it as a regular scale part of the "scales"" map only! This would + // make the logic easier and remove some useless? custom code. + if (item.isDefault) { + me.scale = scale; + } + }); + // clear up discarded scales + helpers.each(updated, function(hasUpdated, id) { + if (!hasUpdated) { + delete scales[id]; + } + }); - buildOrUpdateControllers: function() { - var me = this; - var types = []; - var newControllers = []; + me.scales = scales; - helpers.each(me.data.datasets, function(dataset, datasetIndex) { - var meta = me.getDatasetMeta(datasetIndex); - var type = dataset.type || me.config.type; + scaleService.addScalesToLayout(this); + }, - if (meta.type && meta.type !== type) { - me.destroyDatasetMeta(datasetIndex); - meta = me.getDatasetMeta(datasetIndex); - } - meta.type = type; + buildOrUpdateControllers: function() { + var me = this; + var types = []; + var newControllers = []; - types.push(meta.type); + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + var meta = me.getDatasetMeta(datasetIndex); + var type = dataset.type || me.config.type; - if (meta.controller) { - meta.controller.updateIndex(datasetIndex); - meta.controller.linkScales(); - } else { - var ControllerClass = controllers[meta.type]; - if (ControllerClass === undefined) { - throw new Error('"' + meta.type + '" is not a chart type.'); - } + if (meta.type && meta.type !== type) { + me.destroyDatasetMeta(datasetIndex); + meta = me.getDatasetMeta(datasetIndex); + } + meta.type = type; - meta.controller = new ControllerClass(me, datasetIndex); - newControllers.push(meta.controller); + types.push(meta.type); + + if (meta.controller) { + meta.controller.updateIndex(datasetIndex); + meta.controller.linkScales(); + } else { + var ControllerClass = controllers[meta.type]; + if (ControllerClass === undefined) { + throw new Error('"' + meta.type + '" is not a chart type.'); } - }, me); - return newControllers; - }, + meta.controller = new ControllerClass(me, datasetIndex); + newControllers.push(meta.controller); + } + }, me); - /** - * Reset the elements of all datasets - * @private - */ - resetElements: function() { - var me = this; - helpers.each(me.data.datasets, function(dataset, datasetIndex) { - me.getDatasetMeta(datasetIndex).controller.reset(); - }, me); - }, + return newControllers; + }, - /** - * Resets the chart back to it's state before the initial animation - */ - reset: function() { - this.resetElements(); - this.tooltip.initialize(); - }, - - update: function(config) { - var me = this; - - if (!config || typeof config !== 'object') { - // backwards compatibility - config = { - duration: config, - lazy: arguments[1] - }; - } + /** + * Reset the elements of all datasets + * @private + */ + resetElements: function() { + var me = this; + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.reset(); + }, me); + }, - updateConfig(me); + /** + * Resets the chart back to it's state before the initial animation + */ + reset: function() { + this.resetElements(); + this.tooltip.initialize(); + }, + + update: function(config) { + var me = this; + + if (!config || typeof config !== 'object') { + // backwards compatibility + config = { + duration: config, + lazy: arguments[1] + }; + } - // plugins options references might have change, let's invalidate the cache - // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167 - plugins._invalidate(me); + updateConfig(me); - if (plugins.notify(me, 'beforeUpdate') === false) { - return; - } + // plugins options references might have change, let's invalidate the cache + // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167 + plugins._invalidate(me); - // In case the entire data object changed - me.tooltip._data = me.data; + if (plugins.notify(me, 'beforeUpdate') === false) { + return; + } - // Make sure dataset controllers are updated and new controllers are reset - var newControllers = me.buildOrUpdateControllers(); + // In case the entire data object changed + me.tooltip._data = me.data; - // Make sure all dataset controllers have correct meta data counts - helpers.each(me.data.datasets, function(dataset, datasetIndex) { - me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); - }, me); + // Make sure dataset controllers are updated and new controllers are reset + var newControllers = me.buildOrUpdateControllers(); - me.updateLayout(); + // Make sure all dataset controllers have correct meta data counts + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); + }, me); - // Can only reset the new controllers after the scales have been updated - if (me.options.animation && me.options.animation.duration) { - helpers.each(newControllers, function(controller) { - controller.reset(); - }); - } + me.updateLayout(); - me.updateDatasets(); + // Can only reset the new controllers after the scales have been updated + if (me.options.animation && me.options.animation.duration) { + helpers.each(newControllers, function(controller) { + controller.reset(); + }); + } - // Need to reset tooltip in case it is displayed with elements that are removed - // after update. - me.tooltip.initialize(); + me.updateDatasets(); - // Last active contains items that were previously in the tooltip. - // When we reset the tooltip, we need to clear it - me.lastActive = []; + // Need to reset tooltip in case it is displayed with elements that are removed + // after update. + me.tooltip.initialize(); - // Do this before render so that any plugins that need final scale updates can use it - plugins.notify(me, 'afterUpdate'); + // Last active contains items that were previously in the tooltip. + // When we reset the tooltip, we need to clear it + me.lastActive = []; - if (me._bufferedRender) { - me._bufferedRequest = { - duration: config.duration, - easing: config.easing, - lazy: config.lazy - }; - } else { - me.render(config); - } - }, + // Do this before render so that any plugins that need final scale updates can use it + plugins.notify(me, 'afterUpdate'); - /** - * Updates the chart layout unless a plugin returns `false` to the `beforeLayout` - * hook, in which case, plugins will not be called on `afterLayout`. - * @private - */ - updateLayout: function() { - var me = this; + if (me._bufferedRender) { + me._bufferedRequest = { + duration: config.duration, + easing: config.easing, + lazy: config.lazy + }; + } else { + me.render(config); + } + }, - if (plugins.notify(me, 'beforeLayout') === false) { - return; - } + /** + * Updates the chart layout unless a plugin returns `false` to the `beforeLayout` + * hook, in which case, plugins will not be called on `afterLayout`. + * @private + */ + updateLayout: function() { + var me = this; - layouts.update(this, this.width, this.height); + if (plugins.notify(me, 'beforeLayout') === false) { + return; + } - /** - * Provided for backward compatibility, use `afterLayout` instead. - * @method IPlugin#afterScaleUpdate - * @deprecated since version 2.5.0 - * @todo remove at version 3 - * @private - */ - plugins.notify(me, 'afterScaleUpdate'); - plugins.notify(me, 'afterLayout'); - }, + layouts.update(this, this.width, this.height); /** - * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate` - * hook, in which case, plugins will not be called on `afterDatasetsUpdate`. + * Provided for backward compatibility, use `afterLayout` instead. + * @method IPlugin#afterScaleUpdate + * @deprecated since version 2.5.0 + * @todo remove at version 3 * @private */ - updateDatasets: function() { - var me = this; + plugins.notify(me, 'afterScaleUpdate'); + plugins.notify(me, 'afterLayout'); + }, - if (plugins.notify(me, 'beforeDatasetsUpdate') === false) { - return; - } + /** + * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate` + * hook, in which case, plugins will not be called on `afterDatasetsUpdate`. + * @private + */ + updateDatasets: function() { + var me = this; - for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { - me.updateDataset(i); - } + if (plugins.notify(me, 'beforeDatasetsUpdate') === false) { + return; + } - plugins.notify(me, 'afterDatasetsUpdate'); - }, + for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me.updateDataset(i); + } - /** - * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate` - * hook, in which case, plugins will not be called on `afterDatasetUpdate`. - * @private - */ - updateDataset: function(index) { - var me = this; - var meta = me.getDatasetMeta(index); - var args = { - meta: meta, - index: index - }; + plugins.notify(me, 'afterDatasetsUpdate'); + }, - if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) { - return; - } + /** + * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate` + * hook, in which case, plugins will not be called on `afterDatasetUpdate`. + * @private + */ + updateDataset: function(index) { + var me = this; + var meta = me.getDatasetMeta(index); + var args = { + meta: meta, + index: index + }; + + if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) { + return; + } - meta.controller.update(); + meta.controller.update(); - plugins.notify(me, 'afterDatasetUpdate', [args]); - }, + plugins.notify(me, 'afterDatasetUpdate', [args]); + }, - render: function(config) { - var me = this; + render: function(config) { + var me = this; - if (!config || typeof config !== 'object') { - // backwards compatibility - config = { - duration: config, - lazy: arguments[1] - }; - } + if (!config || typeof config !== 'object') { + // backwards compatibility + config = { + duration: config, + lazy: arguments[1] + }; + } - var animationOptions = me.options.animation; - var duration = valueOrDefault(config.duration, animationOptions && animationOptions.duration); - var lazy = config.lazy; + var animationOptions = me.options.animation; + var duration = valueOrDefault(config.duration, animationOptions && animationOptions.duration); + var lazy = config.lazy; - if (plugins.notify(me, 'beforeRender') === false) { - return; - } + if (plugins.notify(me, 'beforeRender') === false) { + return; + } - var onComplete = function(animation) { - plugins.notify(me, 'afterRender'); - helpers.callback(animationOptions && animationOptions.onComplete, [animation], me); - }; + var onComplete = function(animation) { + plugins.notify(me, 'afterRender'); + helpers.callback(animationOptions && animationOptions.onComplete, [animation], me); + }; - if (animationOptions && duration) { - var animation = new Animation({ - numSteps: duration / 16.66, // 60 fps - easing: config.easing || animationOptions.easing, + if (animationOptions && duration) { + var animation = new Animation({ + numSteps: duration / 16.66, // 60 fps + easing: config.easing || animationOptions.easing, - render: function(chart, animationObject) { - var easingFunction = helpers.easing.effects[animationObject.easing]; - var currentStep = animationObject.currentStep; - var stepDecimal = currentStep / animationObject.numSteps; + render: function(chart, animationObject) { + var easingFunction = helpers.easing.effects[animationObject.easing]; + var currentStep = animationObject.currentStep; + var stepDecimal = currentStep / animationObject.numSteps; - chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep); - }, + chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep); + }, - onAnimationProgress: animationOptions.onProgress, - onAnimationComplete: onComplete - }); + onAnimationProgress: animationOptions.onProgress, + onAnimationComplete: onComplete + }); - animations.addAnimation(me, animation, duration, lazy); - } else { - me.draw(); + animations.addAnimation(me, animation, duration, lazy); + } else { + me.draw(); - // See https://github.com/chartjs/Chart.js/issues/3781 - onComplete(new Animation({numSteps: 0, chart: me})); - } + // See https://github.com/chartjs/Chart.js/issues/3781 + onComplete(new Animation({numSteps: 0, chart: me})); + } - return me; - }, + return me; + }, - draw: function(easingValue) { - var me = this; + draw: function(easingValue) { + var me = this; - me.clear(); + me.clear(); - if (helpers.isNullOrUndef(easingValue)) { - easingValue = 1; - } + if (helpers.isNullOrUndef(easingValue)) { + easingValue = 1; + } - me.transition(easingValue); + me.transition(easingValue); - if (me.width <= 0 || me.height <= 0) { - return; - } + if (me.width <= 0 || me.height <= 0) { + return; + } - if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) { - return; - } + if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) { + return; + } - // Draw all the scales - helpers.each(me.boxes, function(box) { - box.draw(me.chartArea); - }, me); + // Draw all the scales + helpers.each(me.boxes, function(box) { + box.draw(me.chartArea); + }, me); - if (me.scale) { - me.scale.draw(); - } + if (me.scale) { + me.scale.draw(); + } - me.drawDatasets(easingValue); - me._drawTooltip(easingValue); + me.drawDatasets(easingValue); + me._drawTooltip(easingValue); - plugins.notify(me, 'afterDraw', [easingValue]); - }, + plugins.notify(me, 'afterDraw', [easingValue]); + }, - /** - * @private - */ - transition: function(easingValue) { - var me = this; + /** + * @private + */ + transition: function(easingValue) { + var me = this; - for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) { - if (me.isDatasetVisible(i)) { - me.getDatasetMeta(i).controller.transition(easingValue); - } + for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) { + if (me.isDatasetVisible(i)) { + me.getDatasetMeta(i).controller.transition(easingValue); } + } - me.tooltip.transition(easingValue); - }, + me.tooltip.transition(easingValue); + }, - /** - * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw` - * hook, in which case, plugins will not be called on `afterDatasetsDraw`. - * @private - */ - drawDatasets: function(easingValue) { - var me = this; + /** + * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw` + * hook, in which case, plugins will not be called on `afterDatasetsDraw`. + * @private + */ + drawDatasets: function(easingValue) { + var me = this; - if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) { - return; - } + if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) { + return; + } - // Draw datasets reversed to support proper line stacking - for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) { - if (me.isDatasetVisible(i)) { - me.drawDataset(i, easingValue); - } + // Draw datasets reversed to support proper line stacking + for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) { + if (me.isDatasetVisible(i)) { + me.drawDataset(i, easingValue); } + } - plugins.notify(me, 'afterDatasetsDraw', [easingValue]); - }, + plugins.notify(me, 'afterDatasetsDraw', [easingValue]); + }, - /** - * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw` - * hook, in which case, plugins will not be called on `afterDatasetDraw`. - * @private - */ - drawDataset: function(index, easingValue) { - var me = this; - var meta = me.getDatasetMeta(index); - var args = { - meta: meta, - index: index, - easingValue: easingValue - }; + /** + * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw` + * hook, in which case, plugins will not be called on `afterDatasetDraw`. + * @private + */ + drawDataset: function(index, easingValue) { + var me = this; + var meta = me.getDatasetMeta(index); + var args = { + meta: meta, + index: index, + easingValue: easingValue + }; + + if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) { + return; + } - if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) { - return; - } + meta.controller.draw(easingValue); - meta.controller.draw(easingValue); + plugins.notify(me, 'afterDatasetDraw', [args]); + }, - plugins.notify(me, 'afterDatasetDraw', [args]); - }, + /** + * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw` + * hook, in which case, plugins will not be called on `afterTooltipDraw`. + * @private + */ + _drawTooltip: function(easingValue) { + var me = this; + var tooltip = me.tooltip; + var args = { + tooltip: tooltip, + easingValue: easingValue + }; + + if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) { + return; + } - /** - * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw` - * hook, in which case, plugins will not be called on `afterTooltipDraw`. - * @private - */ - _drawTooltip: function(easingValue) { - var me = this; - var tooltip = me.tooltip; - var args = { - tooltip: tooltip, - easingValue: easingValue - }; + tooltip.draw(); - if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) { - return; - } + plugins.notify(me, 'afterTooltipDraw', [args]); + }, - tooltip.draw(); + // Get the single element that was clicked on + // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw + getElementAtEvent: function(e) { + return Interaction.modes.single(this, e); + }, - plugins.notify(me, 'afterTooltipDraw', [args]); - }, + getElementsAtEvent: function(e) { + return Interaction.modes.label(this, e, {intersect: true}); + }, - // Get the single element that was clicked on - // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw - getElementAtEvent: function(e) { - return Interaction.modes.single(this, e); - }, + getElementsAtXAxis: function(e) { + return Interaction.modes['x-axis'](this, e, {intersect: true}); + }, - getElementsAtEvent: function(e) { - return Interaction.modes.label(this, e, {intersect: true}); - }, + getElementsAtEventForMode: function(e, mode, options) { + var method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options); + } - getElementsAtXAxis: function(e) { - return Interaction.modes['x-axis'](this, e, {intersect: true}); - }, + return []; + }, - getElementsAtEventForMode: function(e, mode, options) { - var method = Interaction.modes[mode]; - if (typeof method === 'function') { - return method(this, e, options); - } + getDatasetAtEvent: function(e) { + return Interaction.modes.dataset(this, e, {intersect: true}); + }, - return []; - }, + getDatasetMeta: function(datasetIndex) { + var me = this; + var dataset = me.data.datasets[datasetIndex]; + if (!dataset._meta) { + dataset._meta = {}; + } - getDatasetAtEvent: function(e) { - return Interaction.modes.dataset(this, e, {intersect: true}); - }, + var meta = dataset._meta[me.id]; + if (!meta) { + meta = dataset._meta[me.id] = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, // See isDatasetVisible() comment + xAxisID: null, + yAxisID: null + }; + } - getDatasetMeta: function(datasetIndex) { - var me = this; - var dataset = me.data.datasets[datasetIndex]; - if (!dataset._meta) { - dataset._meta = {}; - } + return meta; + }, - var meta = dataset._meta[me.id]; - if (!meta) { - meta = dataset._meta[me.id] = { - type: null, - data: [], - dataset: null, - controller: null, - hidden: null, // See isDatasetVisible() comment - xAxisID: null, - yAxisID: null - }; + getVisibleDatasetCount: function() { + var count = 0; + for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + if (this.isDatasetVisible(i)) { + count++; } + } + return count; + }, - return meta; - }, - - getVisibleDatasetCount: function() { - var count = 0; - for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - if (this.isDatasetVisible(i)) { - count++; - } - } - return count; - }, + isDatasetVisible: function(datasetIndex) { + var meta = this.getDatasetMeta(datasetIndex); - isDatasetVisible: function(datasetIndex) { - var meta = this.getDatasetMeta(datasetIndex); + // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false, + // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned. + return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden; + }, - // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false, - // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned. - return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden; - }, + generateLegend: function() { + return this.options.legendCallback(this); + }, - generateLegend: function() { - return this.options.legendCallback(this); - }, + /** + * @private + */ + destroyDatasetMeta: function(datasetIndex) { + var id = this.id; + var dataset = this.data.datasets[datasetIndex]; + var meta = dataset._meta && dataset._meta[id]; + + if (meta) { + meta.controller.destroy(); + delete dataset._meta[id]; + } + }, - /** - * @private - */ - destroyDatasetMeta: function(datasetIndex) { - var id = this.id; - var dataset = this.data.datasets[datasetIndex]; - var meta = dataset._meta && dataset._meta[id]; - - if (meta) { - meta.controller.destroy(); - delete dataset._meta[id]; - } - }, + destroy: function() { + var me = this; + var canvas = me.canvas; + var i, ilen; - destroy: function() { - var me = this; - var canvas = me.canvas; - var i, ilen; + me.stop(); - me.stop(); + // dataset controllers need to cleanup associated data + for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me.destroyDatasetMeta(i); + } - // dataset controllers need to cleanup associated data - for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { - me.destroyDatasetMeta(i); - } + if (canvas) { + me.unbindEvents(); + helpers.canvas.clear(me); + platform.releaseContext(me.ctx); + me.canvas = null; + me.ctx = null; + } - if (canvas) { - me.unbindEvents(); - helpers.canvas.clear(me); - platform.releaseContext(me.ctx); - me.canvas = null; - me.ctx = null; - } + plugins.notify(me, 'destroy'); - plugins.notify(me, 'destroy'); + delete Chart.instances[me.id]; + }, - delete Chart.instances[me.id]; - }, + toBase64Image: function() { + return this.canvas.toDataURL.apply(this.canvas, arguments); + }, - toBase64Image: function() { - return this.canvas.toDataURL.apply(this.canvas, arguments); - }, + initToolTip: function() { + var me = this; + me.tooltip = new Tooltip({ + _chart: me, + _chartInstance: me, // deprecated, backward compatibility + _data: me.data, + _options: me.options.tooltips + }, me); + }, - initToolTip: function() { - var me = this; - me.tooltip = new Tooltip({ - _chart: me, - _chartInstance: me, // deprecated, backward compatibility - _data: me.data, - _options: me.options.tooltips - }, me); - }, + /** + * @private + */ + bindEvents: function() { + var me = this; + var listeners = me._listeners = {}; + var listener = function() { + me.eventHandler.apply(me, arguments); + }; + + helpers.each(me.options.events, function(type) { + platform.addEventListener(me, type, listener); + listeners[type] = listener; + }); - /** - * @private - */ - bindEvents: function() { - var me = this; - var listeners = me._listeners = {}; - var listener = function() { - me.eventHandler.apply(me, arguments); + // Elements used to detect size change should not be injected for non responsive charts. + // See https://github.com/chartjs/Chart.js/issues/2210 + if (me.options.responsive) { + listener = function() { + me.resize(); }; - helpers.each(me.options.events, function(type) { - platform.addEventListener(me, type, listener); - listeners[type] = listener; - }); - - // Elements used to detect size change should not be injected for non responsive charts. - // See https://github.com/chartjs/Chart.js/issues/2210 - if (me.options.responsive) { - listener = function() { - me.resize(); - }; - - platform.addEventListener(me, 'resize', listener); - listeners.resize = listener; - } - }, + platform.addEventListener(me, 'resize', listener); + listeners.resize = listener; + } + }, - /** - * @private - */ - unbindEvents: function() { - var me = this; - var listeners = me._listeners; - if (!listeners) { - return; - } + /** + * @private + */ + unbindEvents: function() { + var me = this; + var listeners = me._listeners; + if (!listeners) { + return; + } - delete me._listeners; - helpers.each(listeners, function(listener, type) { - platform.removeEventListener(me, type, listener); - }); - }, + delete me._listeners; + helpers.each(listeners, function(listener, type) { + platform.removeEventListener(me, type, listener); + }); + }, - updateHoverStyle: function(elements, mode, enabled) { - var method = enabled ? 'setHoverStyle' : 'removeHoverStyle'; - var element, i, ilen; + updateHoverStyle: function(elements, mode, enabled) { + var method = enabled ? 'setHoverStyle' : 'removeHoverStyle'; + var element, i, ilen; - for (i = 0, ilen = elements.length; i < ilen; ++i) { - element = elements[i]; - if (element) { - this.getDatasetMeta(element._datasetIndex).controller[method](element); - } + for (i = 0, ilen = elements.length; i < ilen; ++i) { + element = elements[i]; + if (element) { + this.getDatasetMeta(element._datasetIndex).controller[method](element); } - }, - - /** - * @private - */ - eventHandler: function(e) { - var me = this; - var tooltip = me.tooltip; + } + }, - if (plugins.notify(me, 'beforeEvent', [e]) === false) { - return; - } + /** + * @private + */ + eventHandler: function(e) { + var me = this; + var tooltip = me.tooltip; - // Buffer any update calls so that renders do not occur - me._bufferedRender = true; - me._bufferedRequest = null; - - var changed = me.handleEvent(e); - // for smooth tooltip animations issue #4989 - // the tooltip should be the source of change - // Animation check workaround: - // tooltip._start will be null when tooltip isn't animating - if (tooltip) { - changed = tooltip._start - ? tooltip.handleEvent(e) - : changed | tooltip.handleEvent(e); - } + if (plugins.notify(me, 'beforeEvent', [e]) === false) { + return; + } - plugins.notify(me, 'afterEvent', [e]); - - var bufferedRequest = me._bufferedRequest; - if (bufferedRequest) { - // If we have an update that was triggered, we need to do a normal render - me.render(bufferedRequest); - } else if (changed && !me.animating) { - // If entering, leaving, or changing elements, animate the change via pivot - me.stop(); - - // We only need to render at this point. Updating will cause scales to be - // recomputed generating flicker & using more memory than necessary. - me.render({ - duration: me.options.hover.animationDuration, - lazy: true - }); - } + // Buffer any update calls so that renders do not occur + me._bufferedRender = true; + me._bufferedRequest = null; + + var changed = me.handleEvent(e); + // for smooth tooltip animations issue #4989 + // the tooltip should be the source of change + // Animation check workaround: + // tooltip._start will be null when tooltip isn't animating + if (tooltip) { + changed = tooltip._start + ? tooltip.handleEvent(e) + : changed | tooltip.handleEvent(e); + } - me._bufferedRender = false; - me._bufferedRequest = null; + plugins.notify(me, 'afterEvent', [e]); - return me; - }, + var bufferedRequest = me._bufferedRequest; + if (bufferedRequest) { + // If we have an update that was triggered, we need to do a normal render + me.render(bufferedRequest); + } else if (changed && !me.animating) { + // If entering, leaving, or changing elements, animate the change via pivot + me.stop(); - /** - * Handle an event - * @private - * @param {IEvent} event the event to handle - * @return {Boolean} true if the chart needs to re-render - */ - handleEvent: function(e) { - var me = this; - var options = me.options || {}; - var hoverOptions = options.hover; - var changed = false; + // We only need to render at this point. Updating will cause scales to be + // recomputed generating flicker & using more memory than necessary. + me.render({ + duration: me.options.hover.animationDuration, + lazy: true + }); + } - me.lastActive = me.lastActive || []; + me._bufferedRender = false; + me._bufferedRequest = null; - // Find Active Elements for hover and tooltips - if (e.type === 'mouseout') { - me.active = []; - } else { - me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions); - } + return me; + }, - // Invoke onHover hook - // Need to call with native event here to not break backwards compatibility - helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me); + /** + * Handle an event + * @private + * @param {IEvent} event the event to handle + * @return {Boolean} true if the chart needs to re-render + */ + handleEvent: function(e) { + var me = this; + var options = me.options || {}; + var hoverOptions = options.hover; + var changed = false; + + me.lastActive = me.lastActive || []; + + // Find Active Elements for hover and tooltips + if (e.type === 'mouseout') { + me.active = []; + } else { + me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions); + } - if (e.type === 'mouseup' || e.type === 'click') { - if (options.onClick) { - // Use e.native here for backwards compatibility - options.onClick.call(me, e.native, me.active); - } - } + // Invoke onHover hook + // Need to call with native event here to not break backwards compatibility + helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me); - // Remove styling for last active (even if it may still be active) - if (me.lastActive.length) { - me.updateHoverStyle(me.lastActive, hoverOptions.mode, false); + if (e.type === 'mouseup' || e.type === 'click') { + if (options.onClick) { + // Use e.native here for backwards compatibility + options.onClick.call(me, e.native, me.active); } + } - // Built in hover styling - if (me.active.length && hoverOptions.mode) { - me.updateHoverStyle(me.active, hoverOptions.mode, true); - } + // Remove styling for last active (even if it may still be active) + if (me.lastActive.length) { + me.updateHoverStyle(me.lastActive, hoverOptions.mode, false); + } - changed = !helpers.arrayEquals(me.active, me.lastActive); + // Built in hover styling + if (me.active.length && hoverOptions.mode) { + me.updateHoverStyle(me.active, hoverOptions.mode, true); + } - // Remember Last Actives - me.lastActive = me.active; + changed = !helpers.arrayEquals(me.active, me.lastActive); - return changed; - } - }); + // Remember Last Actives + me.lastActive = me.active; - /** - * Provided for backward compatibility, use Chart instead. - * @class Chart.Controller - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ - Chart.Controller = Chart; -}; + return changed; + } +}); + +/** + * NOTE(SB) We actually don't use this container anymore but we need to keep it + * for backward compatibility. Though, it can still be useful for plugins that + * would need to work on multiple charts?! + */ +Chart.instances = {}; + +module.exports = Chart; + +// DEPRECATIONS + +/** + * Provided for backward compatibility, use Chart instead. + * @class Chart.Controller + * @deprecated since version 2.6 + * @todo remove at version 3 + * @private + */ +Chart.Controller = Chart; + +/** + * Provided for backward compatibility, not available anymore. + * @namespace Chart + * @deprecated since version 2.8 + * @todo remove at version 3 + * @private + */ +Chart.types = {}; diff --git a/src/core/core.defaults.js b/src/core/core.defaults.js index 4a2bb8e1b40..279491debae 100644 --- a/src/core/core.defaults.js +++ b/src/core/core.defaults.js @@ -2,7 +2,7 @@ var helpers = require('../helpers/helpers.core'); -module.exports = { +var defaults = { /** * @private */ @@ -10,3 +10,15 @@ module.exports = { return helpers.merge(this[scope] || (this[scope] = {}), values); } }; + +defaults._set('global', { + defaultColor: 'rgba(0,0,0,0.1)', + defaultFontColor: '#666', + defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + defaultFontSize: 12, + defaultFontStyle: 'normal', + defaultLineHeight: 1.2, + showLines: true +}); + +module.exports = defaults; diff --git a/src/core/core.js b/src/core/core.js deleted file mode 100644 index 8860b9bbcf4..00000000000 --- a/src/core/core.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; - -var defaults = require('./core.defaults'); - -defaults._set('global', { - responsive: true, - responsiveAnimationDuration: 0, - maintainAspectRatio: true, - events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], - hover: { - onHover: null, - mode: 'nearest', - intersect: true, - animationDuration: 400 - }, - onClick: null, - defaultColor: 'rgba(0,0,0,0.1)', - defaultFontColor: '#666', - defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - defaultFontSize: 12, - defaultFontStyle: 'normal', - defaultLineHeight: 1.2, - showLines: true, - - // Element defaults defined in element extensions - elements: {}, - - // Layout options such as padding - layout: { - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } - } -}); - -module.exports = function() { - - // Occupy the global variable of Chart, and create a simple base class - var Chart = function(item, config) { - this.construct(item, config); - return this; - }; - - Chart.Chart = Chart; - - return Chart; -}; diff --git a/src/core/core.layouts.js b/src/core/core.layouts.js index b99612bbebd..d212731f7ef 100644 --- a/src/core/core.layouts.js +++ b/src/core/core.layouts.js @@ -1,5 +1,6 @@ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); function filterByPosition(array, position) { @@ -25,6 +26,17 @@ function sortByWeight(array, reverse) { }); } +defaults._set('global', { + layout: { + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } + } +}); + /** * @interface ILayoutItem * @prop {String} position - The position of the item in the chart layout. Possible values are diff --git a/test/specs/global.deprecations.tests.js b/test/specs/global.deprecations.tests.js index 822b234b417..d358742a594 100644 --- a/test/specs/global.deprecations.tests.js +++ b/test/specs/global.deprecations.tests.js @@ -14,7 +14,6 @@ describe('Deprecations', function() { describe('Chart.' + klass, function() { it('should be defined as a function', function() { - expect(Chart[klass]).toBeDefined(); expect(typeof Chart[klass]).toBe('function'); }); it('should create a chart of type "' + type + '"', function() { @@ -26,19 +25,23 @@ describe('Deprecations', function() { }); describe('Chart.helpers.aliasPixel', function() { - it('should be defined and a function', function() { - expect(Chart.helpers.aliasPixel).toBeDefined(); + it('should be defined as a function', function() { expect(typeof Chart.helpers.aliasPixel).toBe('function'); }); }); describe('Chart.LinearScaleBase', function() { it('should be defined and inherit from Chart.Scale', function() { - expect(Chart.LinearScaleBase).toBeDefined(); expect(typeof Chart.LinearScaleBase).toBe('function'); expect(Chart.LinearScaleBase.prototype instanceof Chart.Scale).toBeTruthy(); }); }); + + describe('Chart.types', function() { + it('should be defined as an empty object', function() { + expect(Chart.types).toEqual({}); + }); + }); }); describe('Version 2.7.3', function() { @@ -103,7 +106,6 @@ describe('Deprecations', function() { describe('Chart.helpers.indexOf', function() { it('should be defined and a function', function() { - expect(Chart.helpers.indexOf).toBeDefined(); expect(typeof Chart.helpers.indexOf).toBe('function'); }); it('should returns the correct index', function() { @@ -144,7 +146,6 @@ describe('Deprecations', function() { describe('Chart.helpers.drawRoundedRectangle', function() { it('should be defined and a function', function() { - expect(Chart.helpers.drawRoundedRectangle).toBeDefined(); expect(typeof Chart.helpers.drawRoundedRectangle).toBe('function'); }); it('should call Chart.helpers.canvas.roundedRect', function() { @@ -161,7 +162,6 @@ describe('Deprecations', function() { describe('Chart.helpers.addEvent', function() { it('should be defined and a function', function() { - expect(Chart.helpers.addEvent).toBeDefined(); expect(typeof Chart.helpers.addEvent).toBe('function'); }); it('should correctly add event listener', function() { @@ -174,7 +174,6 @@ describe('Deprecations', function() { describe('Chart.helpers.removeEvent', function() { it('should be defined and a function', function() { - expect(Chart.helpers.removeEvent).toBeDefined(); expect(typeof Chart.helpers.removeEvent).toBe('function'); }); it('should correctly remove event listener', function() { From 40f371f12aaeddbc104a4ae3649867963100a98c Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Wed, 9 Jan 2019 11:27:53 +0100 Subject: [PATCH 2/2] Remove useless local `types` usage --- src/core/core.controller.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/core.controller.js b/src/core/core.controller.js index f3b62e2eee4..b0175e8a67f 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -329,7 +329,6 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { buildOrUpdateControllers: function() { var me = this; - var types = []; var newControllers = []; helpers.each(me.data.datasets, function(dataset, datasetIndex) { @@ -342,8 +341,6 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { } meta.type = type; - types.push(meta.type); - if (meta.controller) { meta.controller.updateIndex(datasetIndex); meta.controller.linkScales();