'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; /** * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice', * 'unshift') and notify the listener AFTER the array has been altered. Listeners are * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments. */ function listenArrayEvents(array, listener) { if (array._chartjs) { array._chartjs.listeners.push(listener); return; } Object.defineProperty(array, '_chartjs', { configurable: true, enumerable: false, value: { listeners: [listener] } }); arrayEvents.forEach(function(key) { var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1); var base = array[key]; Object.defineProperty(array, key, { configurable: true, enumerable: false, value: function() { var args = Array.prototype.slice.call(arguments); var res = base.apply(this, args); helpers.each(array._chartjs.listeners, function(object) { if (typeof object[method] === 'function') { object[method].apply(object, args); } }); return res; } }); }); } /** * Removes the given array event listener and cleanup extra attached properties (such as * the _chartjs stub and overridden methods) if array doesn't have any more listeners. */ function unlistenArrayEvents(array, listener) { var stub = array._chartjs; if (!stub) { return; } var listeners = stub.listeners; var index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } if (listeners.length > 0) { return; } arrayEvents.forEach(function(key) { delete array[key]; }); delete array._chartjs; } // Base class for all dataset controllers (line, bar, etc) Chart.DatasetController = function(chart, datasetIndex) { this.initialize(chart, datasetIndex); }; helpers.extend(Chart.DatasetController.prototype, { /** * Element type used to generate a meta dataset (e.g. Chart.element.Line). * @type {Chart.core.element} */ datasetElementType: null, /** * Element type used to generate a meta data (e.g. Chart.element.Point). * @type {Chart.core.element} */ dataElementType: null, initialize: function(chart, datasetIndex) { var me = this; me.chart = chart; me.index = datasetIndex; me.linkScales(); me.addElements(); }, updateIndex: function(datasetIndex) { this.index = datasetIndex; }, linkScales: function() { var me = this; var meta = me.getMeta(); var dataset = me.getDataset(); if (meta.xAxisID === null) { meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id; } if (meta.yAxisID === null) { meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id; } }, getDataset: function() { return this.chart.data.datasets[this.index]; }, getMeta: function() { return this.chart.getDatasetMeta(this.index); }, getScaleForId: function(scaleID) { return this.chart.scales[scaleID]; }, reset: function() { this.update(true); }, /** * @private */ destroy: function() { if (this._data) { unlistenArrayEvents(this._data, this); } }, createMetaDataset: function() { var me = this; var type = me.datasetElementType; return type && new type({ _chart: me.chart.chart, _datasetIndex: me.index }); }, createMetaData: function(index) { var me = this; var type = me.dataElementType; return type && new type({ _chart: me.chart.chart, _datasetIndex: me.index, _index: index }); }, addElements: function() { var me = this; var meta = me.getMeta(); var data = me.getDataset().data || []; var metaData = meta.data; var i, ilen; for (i=0, ilen=data.length; i numMeta) { me.insertElements(numMeta, numData - numMeta); } }, /** * @private */ insertElements: function(start, count) { for (var i=0; i