]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Make Chart.controllers.* importable (#5871)
authorSimon Brunel <simonbrunel@users.noreply.github.com>
Thu, 29 Nov 2018 20:06:34 +0000 (21:06 +0100)
committerGitHub <noreply@github.com>
Thu, 29 Nov 2018 20:06:34 +0000 (21:06 +0100)
`controllers.*.js` and `core.datasetController.js` are now importable (no more function export), that's why there is so many changes mainly due to one indentation level removed. Split code for `bar/horizontalBar` and `doughnut/pie` in separate files, added a global controllers import (`src/controllers/index.js`) and add tests to check that all dataset controllers are correctly registered under `chart.controllers.{type}`.

20 files changed:
src/chart.js
src/controllers/controller.bar.js
src/controllers/controller.bubble.js
src/controllers/controller.doughnut.js
src/controllers/controller.horizontalBar.js [new file with mode: 0644]
src/controllers/controller.line.js
src/controllers/controller.pie.js [new file with mode: 0644]
src/controllers/controller.polarArea.js
src/controllers/controller.radar.js
src/controllers/controller.scatter.js
src/controllers/index.js [new file with mode: 0644]
src/core/core.controller.js
src/core/core.datasetController.js
test/specs/controller.bar.tests.js
test/specs/controller.bubble.tests.js
test/specs/controller.doughnut.tests.js
test/specs/controller.line.tests.js
test/specs/controller.polarArea.tests.js
test/specs/controller.radar.tests.js
test/specs/controller.scatter.test.js

index 7b393e6b069e4cc114a3232c1dc22a55a5dcfd99..acb57862c5083d9f1db31b9c60ca213e50b11b76 100644 (file)
@@ -10,6 +10,8 @@ require('./core/core.helpers')(Chart);
 
 Chart.Animation = require('./core/core.animation');
 Chart.animationService = require('./core/core.animations');
+Chart.controllers = require('./controllers/index');
+Chart.DatasetController = require('./core/core.datasetController');
 Chart.defaults = require('./core/core.defaults');
 Chart.Element = require('./core/core.element');
 Chart.elements = require('./elements/index');
@@ -23,7 +25,6 @@ Chart.Ticks = require('./core/core.ticks');
 Chart.Tooltip = require('./core/core.tooltip');
 
 require('./core/core.controller')(Chart);
-require('./core/core.datasetController')(Chart);
 
 require('./scales/scale.linearbase')(Chart);
 require('./scales/scale.category')(Chart);
@@ -32,16 +33,6 @@ require('./scales/scale.logarithmic')(Chart);
 require('./scales/scale.radialLinear')(Chart);
 require('./scales/scale.time')(Chart);
 
-// Controllers must be loaded after elements
-// See Chart.core.datasetController.dataElementType
-require('./controllers/controller.bar')(Chart);
-require('./controllers/controller.bubble')(Chart);
-require('./controllers/controller.doughnut')(Chart);
-require('./controllers/controller.line')(Chart);
-require('./controllers/controller.polarArea')(Chart);
-require('./controllers/controller.radar')(Chart);
-require('./controllers/controller.scatter')(Chart);
-
 // Loading built-in plugins
 var plugins = require('./plugins');
 for (var k in plugins) {
index 36f7c7e6e3749b713a5f11513f3e656e59a47af3..760fd8887efc40a4635443fe04a67e74e4cb5490 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var DatasetController = require('../core/core.datasetController');
 var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
@@ -12,15 +13,9 @@ defaults._set('bar', {
        scales: {
                xAxes: [{
                        type: 'category',
-
-                       // Specific to Bar Controller
                        categoryPercentage: 0.8,
                        barPercentage: 0.9,
-
-                       // offset settings
                        offset: true,
-
-                       // grid line settings
                        gridLines: {
                                offsetGridLines: true
                        }
@@ -32,69 +27,6 @@ defaults._set('bar', {
        }
 });
 
-defaults._set('horizontalBar', {
-       hover: {
-               mode: 'index',
-               axis: 'y'
-       },
-
-       scales: {
-               xAxes: [{
-                       type: 'linear',
-                       position: 'bottom'
-               }],
-
-               yAxes: [{
-                       position: 'left',
-                       type: 'category',
-
-                       // Specific to Horizontal Bar Controller
-                       categoryPercentage: 0.8,
-                       barPercentage: 0.9,
-
-                       // offset settings
-                       offset: true,
-
-                       // grid line settings
-                       gridLines: {
-                               offsetGridLines: true
-                       }
-               }]
-       },
-
-       elements: {
-               rectangle: {
-                       borderSkipped: 'left'
-               }
-       },
-
-       tooltips: {
-               callbacks: {
-                       title: function(item, data) {
-                               // Pick first xLabel for now
-                               var title = '';
-
-                               if (item.length > 0) {
-                                       if (item[0].yLabel) {
-                                               title = item[0].yLabel;
-                                       } else if (data.labels.length > 0 && item[0].index < data.labels.length) {
-                                               title = data.labels[item[0].index];
-                                       }
-                               }
-
-                               return title;
-                       },
-
-                       label: function(item, data) {
-                               var datasetLabel = data.datasets[item.datasetIndex].label || '';
-                               return datasetLabel + ': ' + item.xLabel;
-                       }
-               },
-               mode: 'index',
-               axis: 'y'
-       }
-});
-
 /**
  * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
  * @private
@@ -182,349 +114,330 @@ function computeFlexCategoryTraits(index, ruler, options) {
        };
 }
 
-module.exports = function(Chart) {
+module.exports = DatasetController.extend({
 
-       Chart.controllers.bar = Chart.DatasetController.extend({
+       dataElementType: elements.Rectangle,
 
-               dataElementType: elements.Rectangle,
+       initialize: function() {
+               var me = this;
+               var meta;
 
-               initialize: function() {
-                       var me = this;
-                       var meta;
+               DatasetController.prototype.initialize.apply(me, arguments);
 
-                       Chart.DatasetController.prototype.initialize.apply(me, arguments);
+               meta = me.getMeta();
+               meta.stack = me.getDataset().stack;
+               meta.bar = true;
+       },
 
-                       meta = me.getMeta();
-                       meta.stack = me.getDataset().stack;
-                       meta.bar = true;
-               },
+       update: function(reset) {
+               var me = this;
+               var rects = me.getMeta().data;
+               var i, ilen;
 
-               update: function(reset) {
-                       var me = this;
-                       var rects = me.getMeta().data;
-                       var i, ilen;
+               me._ruler = me.getRuler();
 
-                       me._ruler = me.getRuler();
+               for (i = 0, ilen = rects.length; i < ilen; ++i) {
+                       me.updateElement(rects[i], i, reset);
+               }
+       },
 
-                       for (i = 0, ilen = rects.length; i < ilen; ++i) {
-                               me.updateElement(rects[i], i, reset);
-                       }
-               },
-
-               updateElement: function(rectangle, index, reset) {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var dataset = me.getDataset();
-                       var options = me._resolveElementOptions(rectangle, index);
-
-                       rectangle._xScale = me.getScaleForId(meta.xAxisID);
-                       rectangle._yScale = me.getScaleForId(meta.yAxisID);
-                       rectangle._datasetIndex = me.index;
-                       rectangle._index = index;
-                       rectangle._model = {
-                               backgroundColor: options.backgroundColor,
-                               borderColor: options.borderColor,
-                               borderSkipped: options.borderSkipped,
-                               borderWidth: options.borderWidth,
-                               datasetLabel: dataset.label,
-                               label: me.chart.data.labels[index]
-                       };
-
-                       me._updateElementGeometry(rectangle, index, reset);
-
-                       rectangle.pivot();
-               },
-
-               /**
-                * @private
-                */
-               _updateElementGeometry: function(rectangle, index, reset) {
-                       var me = this;
-                       var model = rectangle._model;
-                       var vscale = me.getValueScale();
-                       var base = vscale.getBasePixel();
-                       var horizontal = vscale.isHorizontal();
-                       var ruler = me._ruler || me.getRuler();
-                       var vpixels = me.calculateBarValuePixels(me.index, index);
-                       var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
-
-                       model.horizontal = horizontal;
-                       model.base = reset ? base : vpixels.base;
-                       model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
-                       model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
-                       model.height = horizontal ? ipixels.size : undefined;
-                       model.width = horizontal ? undefined : ipixels.size;
-               },
-
-               /**
-                * @private
-                */
-               getValueScaleId: function() {
-                       return this.getMeta().yAxisID;
-               },
-
-               /**
-                * @private
-                */
-               getIndexScaleId: function() {
-                       return this.getMeta().xAxisID;
-               },
-
-               /**
-                * @private
-                */
-               getValueScale: function() {
-                       return this.getScaleForId(this.getValueScaleId());
-               },
-
-               /**
-                * @private
-                */
-               getIndexScale: function() {
-                       return this.getScaleForId(this.getIndexScaleId());
-               },
-
-               /**
-                * Returns the stacks based on groups and bar visibility.
-                * @param {Number} [last] - The dataset index
-                * @returns {Array} The stack list
-                * @private
-                */
-               _getStacks: function(last) {
-                       var me = this;
-                       var chart = me.chart;
-                       var scale = me.getIndexScale();
-                       var stacked = scale.options.stacked;
-                       var ilen = last === undefined ? chart.data.datasets.length : last + 1;
-                       var stacks = [];
-                       var i, meta;
-
-                       for (i = 0; i < ilen; ++i) {
-                               meta = chart.getDatasetMeta(i);
-                               if (meta.bar && chart.isDatasetVisible(i) &&
-                                       (stacked === false ||
-                                       (stacked === true && stacks.indexOf(meta.stack) === -1) ||
-                                       (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
-                                       stacks.push(meta.stack);
-                               }
-                       }
+       updateElement: function(rectangle, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = me.getDataset();
+               var options = me._resolveElementOptions(rectangle, index);
+
+               rectangle._xScale = me.getScaleForId(meta.xAxisID);
+               rectangle._yScale = me.getScaleForId(meta.yAxisID);
+               rectangle._datasetIndex = me.index;
+               rectangle._index = index;
+               rectangle._model = {
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderSkipped: options.borderSkipped,
+                       borderWidth: options.borderWidth,
+                       datasetLabel: dataset.label,
+                       label: me.chart.data.labels[index]
+               };
+
+               me._updateElementGeometry(rectangle, index, reset);
+
+               rectangle.pivot();
+       },
+
+       /**
+        * @private
+        */
+       _updateElementGeometry: function(rectangle, index, reset) {
+               var me = this;
+               var model = rectangle._model;
+               var vscale = me.getValueScale();
+               var base = vscale.getBasePixel();
+               var horizontal = vscale.isHorizontal();
+               var ruler = me._ruler || me.getRuler();
+               var vpixels = me.calculateBarValuePixels(me.index, index);
+               var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
+
+               model.horizontal = horizontal;
+               model.base = reset ? base : vpixels.base;
+               model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
+               model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
+               model.height = horizontal ? ipixels.size : undefined;
+               model.width = horizontal ? undefined : ipixels.size;
+       },
+
+       /**
+        * @private
+        */
+       getValueScaleId: function() {
+               return this.getMeta().yAxisID;
+       },
+
+       /**
+        * @private
+        */
+       getIndexScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       getValueScale: function() {
+               return this.getScaleForId(this.getValueScaleId());
+       },
 
-                       return stacks;
-               },
-
-               /**
-                * Returns the effective number of stacks based on groups and bar visibility.
-                * @private
-                */
-               getStackCount: function() {
-                       return this._getStacks().length;
-               },
-
-               /**
-                * Returns the stack index for the given dataset based on groups and bar visibility.
-                * @param {Number} [datasetIndex] - The dataset index
-                * @param {String} [name] - The stack name to find
-                * @returns {Number} The stack index
-                * @private
-                */
-               getStackIndex: function(datasetIndex, name) {
-                       var stacks = this._getStacks(datasetIndex);
-                       var index = (name !== undefined)
-                               ? stacks.indexOf(name)
-                               : -1; // indexOf returns -1 if element is not present
-
-                       return (index === -1)
-                               ? stacks.length - 1
-                               : index;
-               },
-
-               /**
-                * @private
-                */
-               getRuler: function() {
-                       var me = this;
-                       var scale = me.getIndexScale();
-                       var stackCount = me.getStackCount();
-                       var datasetIndex = me.index;
-                       var isHorizontal = scale.isHorizontal();
-                       var start = isHorizontal ? scale.left : scale.top;
-                       var end = start + (isHorizontal ? scale.width : scale.height);
-                       var pixels = [];
-                       var i, ilen, min;
-
-                       for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
-                               pixels.push(scale.getPixelForValue(null, i, datasetIndex));
+       /**
+        * @private
+        */
+       getIndexScale: function() {
+               return this.getScaleForId(this.getIndexScaleId());
+       },
+
+       /**
+        * Returns the stacks based on groups and bar visibility.
+        * @param {Number} [last] - The dataset index
+        * @returns {Array} The stack list
+        * @private
+        */
+       _getStacks: function(last) {
+               var me = this;
+               var chart = me.chart;
+               var scale = me.getIndexScale();
+               var stacked = scale.options.stacked;
+               var ilen = last === undefined ? chart.data.datasets.length : last + 1;
+               var stacks = [];
+               var i, meta;
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = chart.getDatasetMeta(i);
+                       if (meta.bar && chart.isDatasetVisible(i) &&
+                               (stacked === false ||
+                               (stacked === true && stacks.indexOf(meta.stack) === -1) ||
+                               (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
+                               stacks.push(meta.stack);
                        }
+               }
+
+               return stacks;
+       },
+
+       /**
+        * Returns the effective number of stacks based on groups and bar visibility.
+        * @private
+        */
+       getStackCount: function() {
+               return this._getStacks().length;
+       },
+
+       /**
+        * Returns the stack index for the given dataset based on groups and bar visibility.
+        * @param {Number} [datasetIndex] - The dataset index
+        * @param {String} [name] - The stack name to find
+        * @returns {Number} The stack index
+        * @private
+        */
+       getStackIndex: function(datasetIndex, name) {
+               var stacks = this._getStacks(datasetIndex);
+               var index = (name !== undefined)
+                       ? stacks.indexOf(name)
+                       : -1; // indexOf returns -1 if element is not present
+
+               return (index === -1)
+                       ? stacks.length - 1
+                       : index;
+       },
+
+       /**
+        * @private
+        */
+       getRuler: function() {
+               var me = this;
+               var scale = me.getIndexScale();
+               var stackCount = me.getStackCount();
+               var datasetIndex = me.index;
+               var isHorizontal = scale.isHorizontal();
+               var start = isHorizontal ? scale.left : scale.top;
+               var end = start + (isHorizontal ? scale.width : scale.height);
+               var pixels = [];
+               var i, ilen, min;
+
+               for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
+                       pixels.push(scale.getPixelForValue(null, i, datasetIndex));
+               }
+
+               min = helpers.isNullOrUndef(scale.options.barThickness)
+                       ? computeMinSampleSize(scale, pixels)
+                       : -1;
+
+               return {
+                       min: min,
+                       pixels: pixels,
+                       start: start,
+                       end: end,
+                       stackCount: stackCount,
+                       scale: scale
+               };
+       },
 
-                       min = helpers.isNullOrUndef(scale.options.barThickness)
-                               ? computeMinSampleSize(scale, pixels)
-                               : -1;
-
-                       return {
-                               min: min,
-                               pixels: pixels,
-                               start: start,
-                               end: end,
-                               stackCount: stackCount,
-                               scale: scale
-                       };
-               },
-
-               /**
-                * Note: pixel values are not clamped to the scale area.
-                * @private
-                */
-               calculateBarValuePixels: function(datasetIndex, index) {
-                       var me = this;
-                       var chart = me.chart;
-                       var meta = me.getMeta();
-                       var scale = me.getValueScale();
-                       var isHorizontal = scale.isHorizontal();
-                       var datasets = chart.data.datasets;
-                       var value = scale.getRightValue(datasets[datasetIndex].data[index]);
-                       var minBarLength = scale.options.minBarLength;
-                       var stacked = scale.options.stacked;
-                       var stack = meta.stack;
-                       var start = 0;
-                       var i, imeta, ivalue, base, head, size;
-
-                       if (stacked || (stacked === undefined && stack !== undefined)) {
-                               for (i = 0; i < datasetIndex; ++i) {
-                                       imeta = chart.getDatasetMeta(i);
-
-                                       if (imeta.bar &&
-                                               imeta.stack === stack &&
-                                               imeta.controller.getValueScaleId() === scale.id &&
-                                               chart.isDatasetVisible(i)) {
-
-                                               ivalue = scale.getRightValue(datasets[i].data[index]);
-                                               if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
-                                                       start += ivalue;
-                                               }
+       /**
+        * Note: pixel values are not clamped to the scale area.
+        * @private
+        */
+       calculateBarValuePixels: function(datasetIndex, index) {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var scale = me.getValueScale();
+               var isHorizontal = scale.isHorizontal();
+               var datasets = chart.data.datasets;
+               var value = scale.getRightValue(datasets[datasetIndex].data[index]);
+               var minBarLength = scale.options.minBarLength;
+               var stacked = scale.options.stacked;
+               var stack = meta.stack;
+               var start = 0;
+               var i, imeta, ivalue, base, head, size;
+
+               if (stacked || (stacked === undefined && stack !== undefined)) {
+                       for (i = 0; i < datasetIndex; ++i) {
+                               imeta = chart.getDatasetMeta(i);
+
+                               if (imeta.bar &&
+                                       imeta.stack === stack &&
+                                       imeta.controller.getValueScaleId() === scale.id &&
+                                       chart.isDatasetVisible(i)) {
+
+                                       ivalue = scale.getRightValue(datasets[i].data[index]);
+                                       if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
+                                               start += ivalue;
                                        }
                                }
                        }
+               }
 
-                       base = scale.getPixelForValue(start);
-                       head = scale.getPixelForValue(start + value);
-                       size = (head - base) / 2;
+               base = scale.getPixelForValue(start);
+               head = scale.getPixelForValue(start + value);
+               size = (head - base) / 2;
 
-                       if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
-                               size = minBarLength;
-                               if (value >= 0 && !isHorizontal || value < 0 && isHorizontal) {
-                                       head = base - minBarLength;
-                               } else {
-                                       head = base + minBarLength;
-                               }
+               if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
+                       size = minBarLength;
+                       if (value >= 0 && !isHorizontal || value < 0 && isHorizontal) {
+                               head = base - minBarLength;
+                       } else {
+                               head = base + minBarLength;
                        }
+               }
 
-                       return {
-                               size: size,
-                               base: base,
-                               head: head,
-                               center: head + size / 2
-                       };
-               },
-
-               /**
-                * @private
-                */
-               calculateBarIndexPixels: function(datasetIndex, index, ruler) {
-                       var me = this;
-                       var options = ruler.scale.options;
-                       var range = options.barThickness === 'flex'
-                               ? computeFlexCategoryTraits(index, ruler, options)
-                               : computeFitCategoryTraits(index, ruler, options);
-
-                       var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
-                       var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
-                       var size = Math.min(
-                               helpers.valueOrDefault(options.maxBarThickness, Infinity),
-                               range.chunk * range.ratio);
-
-                       return {
-                               base: center - size / 2,
-                               head: center + size / 2,
-                               center: center,
-                               size: size
-                       };
-               },
-
-               draw: function() {
-                       var me = this;
-                       var chart = me.chart;
-                       var scale = me.getValueScale();
-                       var rects = me.getMeta().data;
-                       var dataset = me.getDataset();
-                       var ilen = rects.length;
-                       var i = 0;
-
-                       helpers.canvas.clipArea(chart.ctx, chart.chartArea);
-
-                       for (; i < ilen; ++i) {
-                               if (!isNaN(scale.getRightValue(dataset.data[i]))) {
-                                       rects[i].draw();
-                               }
-                       }
+               return {
+                       size: size,
+                       base: base,
+                       head: head,
+                       center: head + size / 2
+               };
+       },
 
-                       helpers.canvas.unclipArea(chart.ctx);
-               },
-
-               /**
-                * @private
-                */
-               _resolveElementOptions: function(rectangle, index) {
-                       var me = this;
-                       var chart = me.chart;
-                       var datasets = chart.data.datasets;
-                       var dataset = datasets[me.index];
-                       var custom = rectangle.custom || {};
-                       var options = chart.options.elements.rectangle;
-                       var resolve = helpers.options.resolve;
-                       var values = {};
-                       var i, ilen, key;
-
-                       // Scriptable options
-                       var context = {
-                               chart: chart,
-                               dataIndex: index,
-                               dataset: dataset,
-                               datasetIndex: me.index
-                       };
-
-                       var keys = [
-                               'backgroundColor',
-                               'borderColor',
-                               'borderSkipped',
-                               'borderWidth'
-                       ];
-
-                       for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                               key = keys[i];
-                               values[key] = resolve([
-                                       custom[key],
-                                       dataset[key],
-                                       options[key]
-                               ], context, index);
-                       }
+       /**
+        * @private
+        */
+       calculateBarIndexPixels: function(datasetIndex, index, ruler) {
+               var me = this;
+               var options = ruler.scale.options;
+               var range = options.barThickness === 'flex'
+                       ? computeFlexCategoryTraits(index, ruler, options)
+                       : computeFitCategoryTraits(index, ruler, options);
+
+               var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
+               var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
+               var size = Math.min(
+                       helpers.valueOrDefault(options.maxBarThickness, Infinity),
+                       range.chunk * range.ratio);
+
+               return {
+                       base: center - size / 2,
+                       head: center + size / 2,
+                       center: center,
+                       size: size
+               };
+       },
+
+       draw: function() {
+               var me = this;
+               var chart = me.chart;
+               var scale = me.getValueScale();
+               var rects = me.getMeta().data;
+               var dataset = me.getDataset();
+               var ilen = rects.length;
+               var i = 0;
+
+               helpers.canvas.clipArea(chart.ctx, chart.chartArea);
 
-                       return values;
+               for (; i < ilen; ++i) {
+                       if (!isNaN(scale.getRightValue(dataset.data[i]))) {
+                               rects[i].draw();
+                       }
                }
-       });
-
-       Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
-               /**
-                * @private
-                */
-               getValueScaleId: function() {
-                       return this.getMeta().xAxisID;
-               },
-
-               /**
-                * @private
-                */
-               getIndexScaleId: function() {
-                       return this.getMeta().yAxisID;
+
+               helpers.canvas.unclipArea(chart.ctx);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(rectangle, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var dataset = datasets[me.index];
+               var custom = rectangle.custom || {};
+               var options = chart.options.elements.rectangle;
+               var resolve = helpers.options.resolve;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderSkipped',
+                       'borderWidth'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
                }
-       });
-};
+
+               return values;
+       }
+});
index ed1e2045c71416648a027001bf984a66e79e80cd..77956c9dc7b146f05ceef89ae79edd2d6c2d3567 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var DatasetController = require('../core/core.datasetController');
 var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
@@ -37,140 +38,136 @@ defaults._set('bubble', {
        }
 });
 
+module.exports = DatasetController.extend({
+       /**
+        * @protected
+        */
+       dataElementType: elements.Point,
+
+       /**
+        * @protected
+        */
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var points = meta.data;
+
+               // Update Points
+               helpers.each(points, function(point, index) {
+                       me.updateElement(point, index, reset);
+               });
+       },
 
-module.exports = function(Chart) {
-
-       Chart.controllers.bubble = Chart.DatasetController.extend({
-               /**
-                * @protected
-                */
-               dataElementType: elements.Point,
-
-               /**
-                * @protected
-                */
-               update: function(reset) {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var points = meta.data;
-
-                       // Update Points
-                       helpers.each(points, function(point, index) {
-                               me.updateElement(point, index, reset);
-                       });
-               },
-
-               /**
-                * @protected
-                */
-               updateElement: function(point, index, reset) {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var custom = point.custom || {};
-                       var xScale = me.getScaleForId(meta.xAxisID);
-                       var yScale = me.getScaleForId(meta.yAxisID);
-                       var options = me._resolveElementOptions(point, index);
-                       var data = me.getDataset().data[index];
-                       var dsIndex = me.index;
-
-                       var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
-                       var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
-
-                       point._xScale = xScale;
-                       point._yScale = yScale;
-                       point._options = options;
-                       point._datasetIndex = dsIndex;
-                       point._index = index;
-                       point._model = {
-                               backgroundColor: options.backgroundColor,
-                               borderColor: options.borderColor,
-                               borderWidth: options.borderWidth,
-                               hitRadius: options.hitRadius,
-                               pointStyle: options.pointStyle,
-                               rotation: options.rotation,
-                               radius: reset ? 0 : options.radius,
-                               skip: custom.skip || isNaN(x) || isNaN(y),
-                               x: x,
-                               y: y,
-                       };
-
-                       point.pivot();
-               },
-
-               /**
-                * @protected
-                */
-               setHoverStyle: function(point) {
-                       var model = point._model;
-                       var options = point._options;
-
-                       point.$previousStyle = {
-                               backgroundColor: model.backgroundColor,
-                               borderColor: model.borderColor,
-                               borderWidth: model.borderWidth,
-                               radius: model.radius
-                       };
-
-                       model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor));
-                       model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
-                       model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
-                       model.radius = options.radius + options.hoverRadius;
-               },
-
-               /**
-                * @private
-                */
-               _resolveElementOptions: function(point, index) {
-                       var me = this;
-                       var chart = me.chart;
-                       var datasets = chart.data.datasets;
-                       var dataset = datasets[me.index];
-                       var custom = point.custom || {};
-                       var options = chart.options.elements.point;
-                       var resolve = helpers.options.resolve;
-                       var data = dataset.data[index];
-                       var values = {};
-                       var i, ilen, key;
-
-                       // Scriptable options
-                       var context = {
-                               chart: chart,
-                               dataIndex: index,
-                               dataset: dataset,
-                               datasetIndex: me.index
-                       };
-
-                       var keys = [
-                               'backgroundColor',
-                               'borderColor',
-                               'borderWidth',
-                               'hoverBackgroundColor',
-                               'hoverBorderColor',
-                               'hoverBorderWidth',
-                               'hoverRadius',
-                               'hitRadius',
-                               'pointStyle',
-                               'rotation'
-                       ];
-
-                       for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                               key = keys[i];
-                               values[key] = resolve([
-                                       custom[key],
-                                       dataset[key],
-                                       options[key]
-                               ], context, index);
-                       }
+       /**
+        * @protected
+        */
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var custom = point.custom || {};
+               var xScale = me.getScaleForId(meta.xAxisID);
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var options = me._resolveElementOptions(point, index);
+               var data = me.getDataset().data[index];
+               var dsIndex = me.index;
+
+               var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
+               var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
+
+               point._xScale = xScale;
+               point._yScale = yScale;
+               point._options = options;
+               point._datasetIndex = dsIndex;
+               point._index = index;
+               point._model = {
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       hitRadius: options.hitRadius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       radius: reset ? 0 : options.radius,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       x: x,
+                       y: y,
+               };
+
+               point.pivot();
+       },
 
-                       // Custom radius resolution
-                       values.radius = resolve([
-                               custom.radius,
-                               data ? data.r : undefined,
-                               dataset.radius,
-                               options.radius
-                       ], context, index);
+       /**
+        * @protected
+        */
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor));
+               model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
+               model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
+               model.radius = options.radius + options.hoverRadius;
+       },
 
-                       return values;
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(point, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var dataset = datasets[me.index];
+               var custom = point.custom || {};
+               var options = chart.options.elements.point;
+               var resolve = helpers.options.resolve;
+               var data = dataset.data[index];
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+                       'hoverRadius',
+                       'hitRadius',
+                       'pointStyle',
+                       'rotation'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
                }
-       });
-};
+
+               // Custom radius resolution
+               values.radius = resolve([
+                       custom.radius,
+                       data ? data.r : undefined,
+                       dataset.radius,
+                       options.radius
+               ], context, index);
+
+               return values;
+       }
+});
index eb759fe60b85b22a5da3e3826ccee1abf025fdfc..b24a7a00e9f6f56154c39433867b130d95c258f7 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var DatasetController = require('../core/core.datasetController');
 var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
@@ -118,184 +119,176 @@ defaults._set('doughnut', {
        }
 });
 
-defaults._set('pie', helpers.clone(defaults.doughnut));
-defaults._set('pie', {
-       cutoutPercentage: 0
-});
-
-module.exports = function(Chart) {
+module.exports = DatasetController.extend({
 
-       Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
+       dataElementType: elements.Arc,
 
-               dataElementType: elements.Arc,
+       linkScales: helpers.noop,
 
-               linkScales: helpers.noop,
+       // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
+       getRingIndex: function(datasetIndex) {
+               var ringIndex = 0;
 
-               // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
-               getRingIndex: function(datasetIndex) {
-                       var ringIndex = 0;
-
-                       for (var j = 0; j < datasetIndex; ++j) {
-                               if (this.chart.isDatasetVisible(j)) {
-                                       ++ringIndex;
-                               }
+               for (var j = 0; j < datasetIndex; ++j) {
+                       if (this.chart.isDatasetVisible(j)) {
+                               ++ringIndex;
                        }
+               }
 
-                       return ringIndex;
-               },
-
-               update: function(reset) {
-                       var me = this;
-                       var chart = me.chart;
-                       var chartArea = chart.chartArea;
-                       var opts = chart.options;
-                       var arcOpts = opts.elements.arc;
-                       var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
-                       var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
-                       var minSize = Math.min(availableWidth, availableHeight);
-                       var offset = {x: 0, y: 0};
-                       var meta = me.getMeta();
-                       var cutoutPercentage = opts.cutoutPercentage;
-                       var circumference = opts.circumference;
-
-                       // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
-                       if (circumference < Math.PI * 2.0) {
-                               var startAngle = opts.rotation % (Math.PI * 2.0);
-                               startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
-                               var endAngle = startAngle + circumference;
-                               var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
-                               var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
-                               var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
-                               var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
-                               var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
-                               var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
-                               var cutout = cutoutPercentage / 100.0;
-                               var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
-                               var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
-                               var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
-                               minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
-                               offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
-                       }
+               return ringIndex;
+       },
 
-                       chart.borderWidth = me.getMaxBorderWidth(meta.data);
-                       chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
-                       chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
-                       chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
-                       chart.offsetX = offset.x * chart.outerRadius;
-                       chart.offsetY = offset.y * chart.outerRadius;
+       update: function(reset) {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var arcOpts = opts.elements.arc;
+               var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
+               var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
+               var minSize = Math.min(availableWidth, availableHeight);
+               var offset = {x: 0, y: 0};
+               var meta = me.getMeta();
+               var cutoutPercentage = opts.cutoutPercentage;
+               var circumference = opts.circumference;
+
+               // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
+               if (circumference < Math.PI * 2.0) {
+                       var startAngle = opts.rotation % (Math.PI * 2.0);
+                       startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
+                       var endAngle = startAngle + circumference;
+                       var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
+                       var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
+                       var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
+                       var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
+                       var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
+                       var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
+                       var cutout = cutoutPercentage / 100.0;
+                       var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
+                       var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
+                       var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
+                       minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
+                       offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
+               }
 
-                       meta.total = me.calculateTotal();
+               chart.borderWidth = me.getMaxBorderWidth(meta.data);
+               chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
+               chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
+               chart.offsetX = offset.x * chart.outerRadius;
+               chart.offsetY = offset.y * chart.outerRadius;
 
-                       me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
-                       me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
+               meta.total = me.calculateTotal();
 
-                       helpers.each(meta.data, function(arc, index) {
-                               me.updateElement(arc, index, reset);
-                       });
-               },
+               me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
+               me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
 
-               updateElement: function(arc, index, reset) {
-                       var me = this;
-                       var chart = me.chart;
-                       var chartArea = chart.chartArea;
-                       var opts = chart.options;
-                       var animationOpts = opts.animation;
-                       var centerX = (chartArea.left + chartArea.right) / 2;
-                       var centerY = (chartArea.top + chartArea.bottom) / 2;
-                       var startAngle = opts.rotation; // non reset case handled later
-                       var endAngle = opts.rotation; // non reset case handled later
-                       var dataset = me.getDataset();
-                       var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
-                       var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
-                       var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
-                       var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
-
-                       helpers.extend(arc, {
-                               // Utility
-                               _datasetIndex: me.index,
-                               _index: index,
-
-                               // Desired view properties
-                               _model: {
-                                       x: centerX + chart.offsetX,
-                                       y: centerY + chart.offsetY,
-                                       startAngle: startAngle,
-                                       endAngle: endAngle,
-                                       circumference: circumference,
-                                       outerRadius: outerRadius,
-                                       innerRadius: innerRadius,
-                                       label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
-                               }
-                       });
-
-                       var model = arc._model;
-
-                       // Resets the visual styles
-                       var custom = arc.custom || {};
-                       var valueOrDefault = helpers.valueAtIndexOrDefault;
-                       var elementOpts = this.chart.options.elements.arc;
-                       model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
-                       model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
-                       model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
-
-                       // Set correct angles if not resetting
-                       if (!reset || !animationOpts.animateRotate) {
-                               if (index === 0) {
-                                       model.startAngle = opts.rotation;
-                               } else {
-                                       model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
-                               }
+               helpers.each(meta.data, function(arc, index) {
+                       me.updateElement(arc, index, reset);
+               });
+       },
 
-                               model.endAngle = model.startAngle + model.circumference;
+       updateElement: function(arc, index, reset) {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var animationOpts = opts.animation;
+               var centerX = (chartArea.left + chartArea.right) / 2;
+               var centerY = (chartArea.top + chartArea.bottom) / 2;
+               var startAngle = opts.rotation; // non reset case handled later
+               var endAngle = opts.rotation; // non reset case handled later
+               var dataset = me.getDataset();
+               var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
+               var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
+               var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
+               var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
+
+               helpers.extend(arc, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+
+                       // Desired view properties
+                       _model: {
+                               x: centerX + chart.offsetX,
+                               y: centerY + chart.offsetY,
+                               startAngle: startAngle,
+                               endAngle: endAngle,
+                               circumference: circumference,
+                               outerRadius: outerRadius,
+                               innerRadius: innerRadius,
+                               label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
+                       }
+               });
+
+               var model = arc._model;
+
+               // Resets the visual styles
+               var custom = arc.custom || {};
+               var valueOrDefault = helpers.valueAtIndexOrDefault;
+               var elementOpts = this.chart.options.elements.arc;
+               model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
+               model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
+               model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
+
+               // Set correct angles if not resetting
+               if (!reset || !animationOpts.animateRotate) {
+                       if (index === 0) {
+                               model.startAngle = opts.rotation;
+                       } else {
+                               model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
                        }
 
-                       arc.pivot();
-               },
+                       model.endAngle = model.startAngle + model.circumference;
+               }
 
-               calculateTotal: function() {
-                       var dataset = this.getDataset();
-                       var meta = this.getMeta();
-                       var total = 0;
-                       var value;
+               arc.pivot();
+       },
 
-                       helpers.each(meta.data, function(element, index) {
-                               value = dataset.data[index];
-                               if (!isNaN(value) && !element.hidden) {
-                                       total += Math.abs(value);
-                               }
-                       });
+       calculateTotal: function() {
+               var dataset = this.getDataset();
+               var meta = this.getMeta();
+               var total = 0;
+               var value;
 
-                       /* if (total === 0) {
-                               total = NaN;
-                       }*/
+               helpers.each(meta.data, function(element, index) {
+                       value = dataset.data[index];
+                       if (!isNaN(value) && !element.hidden) {
+                               total += Math.abs(value);
+                       }
+               });
 
-                       return total;
-               },
+               /* if (total === 0) {
+                       total = NaN;
+               }*/
 
-               calculateCircumference: function(value) {
-                       var total = this.getMeta().total;
-                       if (total > 0 && !isNaN(value)) {
-                               return (Math.PI * 2.0) * (Math.abs(value) / total);
-                       }
-                       return 0;
-               },
+               return total;
+       },
 
-               // gets the max border or hover width to properly scale pie charts
-               getMaxBorderWidth: function(arcs) {
-                       var max = 0;
-                       var index = this.index;
-                       var length = arcs.length;
-                       var borderWidth;
-                       var hoverWidth;
+       calculateCircumference: function(value) {
+               var total = this.getMeta().total;
+               if (total > 0 && !isNaN(value)) {
+                       return (Math.PI * 2.0) * (Math.abs(value) / total);
+               }
+               return 0;
+       },
 
-                       for (var i = 0; i < length; i++) {
-                               borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
-                               hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
+       // gets the max border or hover width to properly scale pie charts
+       getMaxBorderWidth: function(arcs) {
+               var max = 0;
+               var index = this.index;
+               var length = arcs.length;
+               var borderWidth;
+               var hoverWidth;
 
-                               max = borderWidth > max ? borderWidth : max;
-                               max = hoverWidth > max ? hoverWidth : max;
-                       }
-                       return max;
+               for (var i = 0; i < length; i++) {
+                       borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
+                       hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
+
+                       max = borderWidth > max ? borderWidth : max;
+                       max = hoverWidth > max ? hoverWidth : max;
                }
-       });
-};
+               return max;
+       }
+});
diff --git a/src/controllers/controller.horizontalBar.js b/src/controllers/controller.horizontalBar.js
new file mode 100644 (file)
index 0000000..b761c34
--- /dev/null
@@ -0,0 +1,79 @@
+
+'use strict';
+
+var BarController = require('./controller.bar');
+var defaults = require('../core/core.defaults');
+
+defaults._set('horizontalBar', {
+       hover: {
+               mode: 'index',
+               axis: 'y'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'linear',
+                       position: 'bottom'
+               }],
+
+               yAxes: [{
+                       type: 'category',
+                       position: 'left',
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9,
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }]
+       },
+
+       elements: {
+               rectangle: {
+                       borderSkipped: 'left'
+               }
+       },
+
+       tooltips: {
+               callbacks: {
+                       title: function(item, data) {
+                               // Pick first xLabel for now
+                               var title = '';
+
+                               if (item.length > 0) {
+                                       if (item[0].yLabel) {
+                                               title = item[0].yLabel;
+                                       } else if (data.labels.length > 0 && item[0].index < data.labels.length) {
+                                               title = data.labels[item[0].index];
+                                       }
+                               }
+
+                               return title;
+                       },
+
+                       label: function(item, data) {
+                               var datasetLabel = data.datasets[item.datasetIndex].label || '';
+                               return datasetLabel + ': ' + item.xLabel;
+                       }
+               },
+               mode: 'index',
+               axis: 'y'
+       }
+});
+
+module.exports = BarController.extend({
+       /**
+        * @private
+        */
+       getValueScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       getIndexScaleId: function() {
+               return this.getMeta().yAxisID;
+       }
+});
+
index 4a18bdadb3c4de952379fe5ca4c0ff3cf5b0a5d7..fffb1ce55d255854a1e08a9ac4ca8d75fbaa8e59 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var DatasetController = require('../core/core.datasetController');
 var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
@@ -24,321 +25,318 @@ defaults._set('line', {
        }
 });
 
-module.exports = function(Chart) {
+function lineEnabled(dataset, options) {
+       return helpers.valueOrDefault(dataset.showLine, options.showLines);
+}
 
-       function lineEnabled(dataset, options) {
-               return helpers.valueOrDefault(dataset.showLine, options.showLines);
-       }
+module.exports = DatasetController.extend({
 
-       Chart.controllers.line = Chart.DatasetController.extend({
+       datasetElementType: elements.Line,
 
-               datasetElementType: elements.Line,
+       dataElementType: elements.Point,
 
-               dataElementType: elements.Point,
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var options = me.chart.options;
+               var lineElementOptions = options.elements.line;
+               var scale = me.getScaleForId(meta.yAxisID);
+               var i, ilen, custom;
+               var dataset = me.getDataset();
+               var showLine = lineEnabled(dataset, options);
 
-               update: function(reset) {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var line = meta.dataset;
-                       var points = meta.data || [];
-                       var options = me.chart.options;
-                       var lineElementOptions = options.elements.line;
-                       var scale = me.getScaleForId(meta.yAxisID);
-                       var i, ilen, custom;
-                       var dataset = me.getDataset();
-                       var showLine = lineEnabled(dataset, options);
+               // Update Line
+               if (showLine) {
+                       custom = line.custom || {};
 
-                       // Update Line
-                       if (showLine) {
-                               custom = line.custom || {};
+                       // Compatibility: If the properties are defined with only the old name, use those values
+                       if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+                               dataset.lineTension = dataset.tension;
+                       }
 
-                               // Compatibility: If the properties are defined with only the old name, use those values
-                               if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
-                                       dataset.lineTension = dataset.tension;
-                               }
+                       // Utility
+                       line._scale = scale;
+                       line._datasetIndex = me.index;
+                       // Data
+                       line._children = points;
+                       // Model
+                       line._model = {
+                               // Appearance
+                               // The default behavior of lines is to break at null values, according
+                               // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
+                               // This option gives lines the ability to span gaps
+                               spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
+                               tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
+                               backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
+                               borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
+                               borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
+                               borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
+                               borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
+                               borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
+                               borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
+                               fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
+                               steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
+                               cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
+                       };
 
-                               // Utility
-                               line._scale = scale;
-                               line._datasetIndex = me.index;
-                               // Data
-                               line._children = points;
-                               // Model
-                               line._model = {
-                                       // Appearance
-                                       // The default behavior of lines is to break at null values, according
-                                       // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
-                                       // This option gives lines the ability to span gaps
-                                       spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
-                                       tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
-                                       backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
-                                       borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
-                                       borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
-                                       borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
-                                       borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
-                                       borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
-                                       borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
-                                       fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
-                                       steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
-                                       cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
-                               };
-
-                               line.pivot();
-                       }
+                       line.pivot();
+               }
 
-                       // Update Points
-                       for (i = 0, ilen = points.length; i < ilen; ++i) {
-                               me.updateElement(points[i], i, reset);
-                       }
+               // Update Points
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       me.updateElement(points[i], i, reset);
+               }
 
-                       if (showLine && line._model.tension !== 0) {
-                               me.updateBezierControlPoints();
-                       }
+               if (showLine && line._model.tension !== 0) {
+                       me.updateBezierControlPoints();
+               }
 
-                       // Now pivot the point for animation
-                       for (i = 0, ilen = points.length; i < ilen; ++i) {
-                               points[i].pivot();
-                       }
-               },
-
-               getPointBackgroundColor: function(point, index) {
-                       var backgroundColor = this.chart.options.elements.point.backgroundColor;
-                       var dataset = this.getDataset();
-                       var custom = point.custom || {};
-
-                       if (custom.backgroundColor) {
-                               backgroundColor = custom.backgroundColor;
-                       } else if (dataset.pointBackgroundColor) {
-                               backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
-                       } else if (dataset.backgroundColor) {
-                               backgroundColor = dataset.backgroundColor;
-                       }
+               // Now pivot the point for animation
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       points[i].pivot();
+               }
+       },
 
-                       return backgroundColor;
-               },
+       getPointBackgroundColor: function(point, index) {
+               var backgroundColor = this.chart.options.elements.point.backgroundColor;
+               var dataset = this.getDataset();
+               var custom = point.custom || {};
 
-               getPointBorderColor: function(point, index) {
-                       var borderColor = this.chart.options.elements.point.borderColor;
-                       var dataset = this.getDataset();
-                       var custom = point.custom || {};
+               if (custom.backgroundColor) {
+                       backgroundColor = custom.backgroundColor;
+               } else if (dataset.pointBackgroundColor) {
+                       backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
+               } else if (dataset.backgroundColor) {
+                       backgroundColor = dataset.backgroundColor;
+               }
 
-                       if (custom.borderColor) {
-                               borderColor = custom.borderColor;
-                       } else if (dataset.pointBorderColor) {
-                               borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
-                       } else if (dataset.borderColor) {
-                               borderColor = dataset.borderColor;
-                       }
+               return backgroundColor;
+       },
 
-                       return borderColor;
-               },
+       getPointBorderColor: function(point, index) {
+               var borderColor = this.chart.options.elements.point.borderColor;
+               var dataset = this.getDataset();
+               var custom = point.custom || {};
 
-               getPointBorderWidth: function(point, index) {
-                       var borderWidth = this.chart.options.elements.point.borderWidth;
-                       var dataset = this.getDataset();
-                       var custom = point.custom || {};
+               if (custom.borderColor) {
+                       borderColor = custom.borderColor;
+               } else if (dataset.pointBorderColor) {
+                       borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
+               } else if (dataset.borderColor) {
+                       borderColor = dataset.borderColor;
+               }
 
-                       if (!isNaN(custom.borderWidth)) {
-                               borderWidth = custom.borderWidth;
-                       } else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) {
-                               borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
-                       } else if (!isNaN(dataset.borderWidth)) {
-                               borderWidth = dataset.borderWidth;
-                       }
+               return borderColor;
+       },
 
-                       return borderWidth;
-               },
+       getPointBorderWidth: function(point, index) {
+               var borderWidth = this.chart.options.elements.point.borderWidth;
+               var dataset = this.getDataset();
+               var custom = point.custom || {};
 
-               getPointRotation: function(point, index) {
-                       var pointRotation = this.chart.options.elements.point.rotation;
-                       var dataset = this.getDataset();
-                       var custom = point.custom || {};
+               if (!isNaN(custom.borderWidth)) {
+                       borderWidth = custom.borderWidth;
+               } else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) {
+                       borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
+               } else if (!isNaN(dataset.borderWidth)) {
+                       borderWidth = dataset.borderWidth;
+               }
 
-                       if (!isNaN(custom.rotation)) {
-                               pointRotation = custom.rotation;
-                       } else if (!isNaN(dataset.pointRotation) || helpers.isArray(dataset.pointRotation)) {
-                               pointRotation = helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointRotation);
-                       }
-                       return pointRotation;
-               },
-
-               updateElement: function(point, index, reset) {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var custom = point.custom || {};
-                       var dataset = me.getDataset();
-                       var datasetIndex = me.index;
-                       var value = dataset.data[index];
-                       var yScale = me.getScaleForId(meta.yAxisID);
-                       var xScale = me.getScaleForId(meta.xAxisID);
-                       var pointOptions = me.chart.options.elements.point;
-                       var x, y;
+               return borderWidth;
+       },
 
-                       // Compatibility: If the properties are defined with only the old name, use those values
-                       if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
-                               dataset.pointRadius = dataset.radius;
-                       }
-                       if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
-                               dataset.pointHitRadius = dataset.hitRadius;
-                       }
+       getPointRotation: function(point, index) {
+               var pointRotation = this.chart.options.elements.point.rotation;
+               var dataset = this.getDataset();
+               var custom = point.custom || {};
+
+               if (!isNaN(custom.rotation)) {
+                       pointRotation = custom.rotation;
+               } else if (!isNaN(dataset.pointRotation) || helpers.isArray(dataset.pointRotation)) {
+                       pointRotation = helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointRotation);
+               }
+               return pointRotation;
+       },
 
-                       x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
-                       y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var custom = point.custom || {};
+               var dataset = me.getDataset();
+               var datasetIndex = me.index;
+               var value = dataset.data[index];
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var xScale = me.getScaleForId(meta.xAxisID);
+               var pointOptions = me.chart.options.elements.point;
+               var x, y;
+
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
+                       dataset.pointRadius = dataset.radius;
+               }
+               if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
+                       dataset.pointHitRadius = dataset.hitRadius;
+               }
+
+               x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
+               y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
+
+               // Utility
+               point._xScale = xScale;
+               point._yScale = yScale;
+               point._datasetIndex = datasetIndex;
+               point._index = index;
+
+               // Desired view properties
+               point._model = {
+                       x: x,
+                       y: y,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       // Appearance
+                       radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
+                       pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
+                       rotation: me.getPointRotation(point, index),
+                       backgroundColor: me.getPointBackgroundColor(point, index),
+                       borderColor: me.getPointBorderColor(point, index),
+                       borderWidth: me.getPointBorderWidth(point, index),
+                       tension: meta.dataset._model ? meta.dataset._model.tension : 0,
+                       steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
+                       // Tooltip
+                       hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
+               };
+       },
 
-                       // Utility
-                       point._xScale = xScale;
-                       point._yScale = yScale;
-                       point._datasetIndex = datasetIndex;
-                       point._index = index;
-
-                       // Desired view properties
-                       point._model = {
-                               x: x,
-                               y: y,
-                               skip: custom.skip || isNaN(x) || isNaN(y),
-                               // Appearance
-                               radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
-                               pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
-                               rotation: me.getPointRotation(point, index),
-                               backgroundColor: me.getPointBackgroundColor(point, index),
-                               borderColor: me.getPointBorderColor(point, index),
-                               borderWidth: me.getPointBorderWidth(point, index),
-                               tension: meta.dataset._model ? meta.dataset._model.tension : 0,
-                               steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
-                               // Tooltip
-                               hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
-                       };
-               },
-
-               calculatePointY: function(value, index, datasetIndex) {
-                       var me = this;
-                       var chart = me.chart;
-                       var meta = me.getMeta();
-                       var yScale = me.getScaleForId(meta.yAxisID);
-                       var sumPos = 0;
-                       var sumNeg = 0;
-                       var i, ds, dsMeta;
-
-                       if (yScale.options.stacked) {
-                               for (i = 0; i < datasetIndex; i++) {
-                                       ds = chart.data.datasets[i];
-                                       dsMeta = chart.getDatasetMeta(i);
-                                       if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
-                                               var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
-                                               if (stackedRightValue < 0) {
-                                                       sumNeg += stackedRightValue || 0;
-                                               } else {
-                                                       sumPos += stackedRightValue || 0;
-                                               }
+       calculatePointY: function(value, index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var sumPos = 0;
+               var sumNeg = 0;
+               var i, ds, dsMeta;
+
+               if (yScale.options.stacked) {
+                       for (i = 0; i < datasetIndex; i++) {
+                               ds = chart.data.datasets[i];
+                               dsMeta = chart.getDatasetMeta(i);
+                               if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
+                                       var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
+                                       if (stackedRightValue < 0) {
+                                               sumNeg += stackedRightValue || 0;
+                                       } else {
+                                               sumPos += stackedRightValue || 0;
                                        }
                                }
-
-                               var rightValue = Number(yScale.getRightValue(value));
-                               if (rightValue < 0) {
-                                       return yScale.getPixelForValue(sumNeg + rightValue);
-                               }
-                               return yScale.getPixelForValue(sumPos + rightValue);
                        }
 
-                       return yScale.getPixelForValue(value);
-               },
-
-               updateBezierControlPoints: function() {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var area = me.chart.chartArea;
-                       var points = (meta.data || []);
-                       var i, ilen, point, model, controlPoints;
-
-                       // Only consider points that are drawn in case the spanGaps option is used
-                       if (meta.dataset._model.spanGaps) {
-                               points = points.filter(function(pt) {
-                                       return !pt._model.skip;
-                               });
+                       var rightValue = Number(yScale.getRightValue(value));
+                       if (rightValue < 0) {
+                               return yScale.getPixelForValue(sumNeg + rightValue);
                        }
+                       return yScale.getPixelForValue(sumPos + rightValue);
+               }
 
-                       function capControlPoint(pt, min, max) {
-                               return Math.max(Math.min(pt, max), min);
-                       }
+               return yScale.getPixelForValue(value);
+       },
 
-                       if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
-                               helpers.splineCurveMonotone(points);
-                       } else {
-                               for (i = 0, ilen = points.length; i < ilen; ++i) {
-                                       point = points[i];
-                                       model = point._model;
-                                       controlPoints = helpers.splineCurve(
-                                               helpers.previousItem(points, i)._model,
-                                               model,
-                                               helpers.nextItem(points, i)._model,
-                                               meta.dataset._model.tension
-                                       );
-                                       model.controlPointPreviousX = controlPoints.previous.x;
-                                       model.controlPointPreviousY = controlPoints.previous.y;
-                                       model.controlPointNextX = controlPoints.next.x;
-                                       model.controlPointNextY = controlPoints.next.y;
-                               }
+       updateBezierControlPoints: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var area = me.chart.chartArea;
+               var points = (meta.data || []);
+               var i, ilen, point, model, controlPoints;
+
+               // Only consider points that are drawn in case the spanGaps option is used
+               if (meta.dataset._model.spanGaps) {
+                       points = points.filter(function(pt) {
+                               return !pt._model.skip;
+                       });
+               }
+
+               function capControlPoint(pt, min, max) {
+                       return Math.max(Math.min(pt, max), min);
+               }
+
+               if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
+                       helpers.splineCurveMonotone(points);
+               } else {
+                       for (i = 0, ilen = points.length; i < ilen; ++i) {
+                               point = points[i];
+                               model = point._model;
+                               controlPoints = helpers.splineCurve(
+                                       helpers.previousItem(points, i)._model,
+                                       model,
+                                       helpers.nextItem(points, i)._model,
+                                       meta.dataset._model.tension
+                               );
+                               model.controlPointPreviousX = controlPoints.previous.x;
+                               model.controlPointPreviousY = controlPoints.previous.y;
+                               model.controlPointNextX = controlPoints.next.x;
+                               model.controlPointNextY = controlPoints.next.y;
                        }
+               }
 
-                       if (me.chart.options.elements.line.capBezierPoints) {
-                               for (i = 0, ilen = points.length; i < ilen; ++i) {
-                                       model = points[i]._model;
-                                       model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
-                                       model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
-                                       model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
-                                       model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
-                               }
-                       }
-               },
-
-               draw: function() {
-                       var me = this;
-                       var chart = me.chart;
-                       var meta = me.getMeta();
-                       var points = meta.data || [];
-                       var area = chart.chartArea;
-                       var ilen = points.length;
-                       var halfBorderWidth;
-                       var i = 0;
-
-                       if (lineEnabled(me.getDataset(), chart.options)) {
-                               halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
-
-                               helpers.canvas.clipArea(chart.ctx, {
-                                       left: area.left,
-                                       right: area.right,
-                                       top: area.top - halfBorderWidth,
-                                       bottom: area.bottom + halfBorderWidth
-                               });
-
-                               meta.dataset.draw();
-
-                               helpers.canvas.unclipArea(chart.ctx);
+               if (me.chart.options.elements.line.capBezierPoints) {
+                       for (i = 0, ilen = points.length; i < ilen; ++i) {
+                               model = points[i]._model;
+                               model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
+                               model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
+                               model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
+                               model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
                        }
+               }
+       },
 
-                       // Draw the points
-                       for (; i < ilen; ++i) {
-                               points[i].draw(area);
-                       }
-               },
-
-               setHoverStyle: function(element) {
-                       // Point
-                       var dataset = this.chart.data.datasets[element._datasetIndex];
-                       var index = element._index;
-                       var custom = element.custom || {};
-                       var model = element._model;
-
-                       element.$previousStyle = {
-                               backgroundColor: model.backgroundColor,
-                               borderColor: model.borderColor,
-                               borderWidth: model.borderWidth,
-                               radius: model.radius
-                       };
+       draw: function() {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var points = meta.data || [];
+               var area = chart.chartArea;
+               var ilen = points.length;
+               var halfBorderWidth;
+               var i = 0;
+
+               if (lineEnabled(me.getDataset(), chart.options)) {
+                       halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
+
+                       helpers.canvas.clipArea(chart.ctx, {
+                               left: area.left,
+                               right: area.right,
+                               top: area.top - halfBorderWidth,
+                               bottom: area.bottom + halfBorderWidth
+                       });
+
+                       meta.dataset.draw();
+
+                       helpers.canvas.unclipArea(chart.ctx);
+               }
+
+               // Draw the points
+               for (; i < ilen; ++i) {
+                       points[i].draw(area);
+               }
+       },
 
-                       model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
-                       model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
-                       model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
-                       model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
-               },
-       });
-};
+       setHoverStyle: function(element) {
+               // Point
+               var dataset = this.chart.data.datasets[element._datasetIndex];
+               var index = element._index;
+               var custom = element.custom || {};
+               var model = element._model;
+
+               element.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
+               model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
+               model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
+               model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
+       }
+});
diff --git a/src/controllers/controller.pie.js b/src/controllers/controller.pie.js
new file mode 100644 (file)
index 0000000..2f50c9d
--- /dev/null
@@ -0,0 +1,13 @@
+'use strict';
+
+var DoughnutController = require('./controller.doughnut');
+var defaults = require('../core/core.defaults');
+var helpers = require('../helpers/index');
+
+defaults._set('pie', helpers.clone(defaults.doughnut));
+defaults._set('pie', {
+       cutoutPercentage: 0
+});
+
+// Pie charts are Doughnut chart with different defaults
+module.exports = DoughnutController;
index 663a9534d554c2166160798917ef587623a5c658..fb045e302717058d955a49754a82343446e266ce 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var DatasetController = require('../core/core.datasetController');
 var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
@@ -108,148 +109,145 @@ defaults._set('polarArea', {
        }
 });
 
-module.exports = function(Chart) {
+module.exports = DatasetController.extend({
 
-       Chart.controllers.polarArea = Chart.DatasetController.extend({
+       dataElementType: elements.Arc,
 
-               dataElementType: elements.Arc,
+       linkScales: helpers.noop,
 
-               linkScales: helpers.noop,
+       update: function(reset) {
+               var me = this;
+               var dataset = me.getDataset();
+               var meta = me.getMeta();
+               var start = me.chart.options.startAngle || 0;
+               var starts = me._starts = [];
+               var angles = me._angles = [];
+               var i, ilen, angle;
 
-               update: function(reset) {
-                       var me = this;
-                       var dataset = me.getDataset();
-                       var meta = me.getMeta();
-                       var start = me.chart.options.startAngle || 0;
-                       var starts = me._starts = [];
-                       var angles = me._angles = [];
-                       var i, ilen, angle;
+               me._updateRadius();
 
-                       me._updateRadius();
+               meta.count = me.countVisibleElements();
 
-                       meta.count = me.countVisibleElements();
-
-                       for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
-                               starts[i] = start;
-                               angle = me._computeAngle(i);
-                               angles[i] = angle;
-                               start += angle;
-                       }
-
-                       helpers.each(meta.data, function(arc, index) {
-                               me.updateElement(arc, index, reset);
-                       });
-               },
-
-               /**
-                * @private
-                */
-               _updateRadius: function() {
-                       var me = this;
-                       var chart = me.chart;
-                       var chartArea = chart.chartArea;
-                       var opts = chart.options;
-                       var arcOpts = opts.elements.arc;
-                       var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
-
-                       chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
-                       chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
-                       chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
-
-                       me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
-                       me.innerRadius = me.outerRadius - chart.radiusLength;
-               },
+               for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
+                       starts[i] = start;
+                       angle = me._computeAngle(i);
+                       angles[i] = angle;
+                       start += angle;
+               }
 
-               updateElement: function(arc, index, reset) {
-                       var me = this;
-                       var chart = me.chart;
-                       var dataset = me.getDataset();
-                       var opts = chart.options;
-                       var animationOpts = opts.animation;
-                       var scale = chart.scale;
-                       var labels = chart.data.labels;
-
-                       var centerX = scale.xCenter;
-                       var centerY = scale.yCenter;
-
-                       // var negHalfPI = -0.5 * Math.PI;
-                       var datasetStartAngle = opts.startAngle;
-                       var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
-                       var startAngle = me._starts[index];
-                       var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);
-
-                       var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
-
-                       helpers.extend(arc, {
-                               // Utility
-                               _datasetIndex: me.index,
-                               _index: index,
-                               _scale: scale,
-
-                               // Desired view properties
-                               _model: {
-                                       x: centerX,
-                                       y: centerY,
-                                       innerRadius: 0,
-                                       outerRadius: reset ? resetRadius : distance,
-                                       startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
-                                       endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
-                                       label: helpers.valueAtIndexOrDefault(labels, index, labels[index])
-                               }
-                       });
+               helpers.each(meta.data, function(arc, index) {
+                       me.updateElement(arc, index, reset);
+               });
+       },
 
-                       // Apply border and fill style
-                       var elementOpts = this.chart.options.elements.arc;
-                       var custom = arc.custom || {};
-                       var valueOrDefault = helpers.valueAtIndexOrDefault;
-                       var model = arc._model;
+       /**
+        * @private
+        */
+       _updateRadius: function() {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var arcOpts = opts.elements.arc;
+               var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+
+               chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
+               chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
+
+               me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
+               me.innerRadius = me.outerRadius - chart.radiusLength;
+       },
 
-                       model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
-                       model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
-                       model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
+       updateElement: function(arc, index, reset) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var opts = chart.options;
+               var animationOpts = opts.animation;
+               var scale = chart.scale;
+               var labels = chart.data.labels;
+
+               var centerX = scale.xCenter;
+               var centerY = scale.yCenter;
+
+               // var negHalfPI = -0.5 * Math.PI;
+               var datasetStartAngle = opts.startAngle;
+               var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+               var startAngle = me._starts[index];
+               var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);
+
+               var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+
+               helpers.extend(arc, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+                       _scale: scale,
+
+                       // Desired view properties
+                       _model: {
+                               x: centerX,
+                               y: centerY,
+                               innerRadius: 0,
+                               outerRadius: reset ? resetRadius : distance,
+                               startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
+                               endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
+                               label: helpers.valueAtIndexOrDefault(labels, index, labels[index])
+                       }
+               });
 
-                       arc.pivot();
-               },
+               // Apply border and fill style
+               var elementOpts = this.chart.options.elements.arc;
+               var custom = arc.custom || {};
+               var valueOrDefault = helpers.valueAtIndexOrDefault;
+               var model = arc._model;
 
-               countVisibleElements: function() {
-                       var dataset = this.getDataset();
-                       var meta = this.getMeta();
-                       var count = 0;
+               model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
+               model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
+               model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
 
-                       helpers.each(meta.data, function(element, index) {
-                               if (!isNaN(dataset.data[index]) && !element.hidden) {
-                                       count++;
-                               }
-                       });
+               arc.pivot();
+       },
 
-                       return count;
-               },
+       countVisibleElements: function() {
+               var dataset = this.getDataset();
+               var meta = this.getMeta();
+               var count = 0;
 
-               /**
-                * @private
-                */
-               _computeAngle: function(index) {
-                       var me = this;
-                       var count = this.getMeta().count;
-                       var dataset = me.getDataset();
-                       var meta = me.getMeta();
-
-                       if (isNaN(dataset.data[index]) || meta.data[index].hidden) {
-                               return 0;
+               helpers.each(meta.data, function(element, index) {
+                       if (!isNaN(dataset.data[index]) && !element.hidden) {
+                               count++;
                        }
+               });
 
-                       // Scriptable options
-                       var context = {
-                               chart: me.chart,
-                               dataIndex: index,
-                               dataset: dataset,
-                               datasetIndex: me.index
-                       };
-
-                       return helpers.options.resolve([
-                               me.chart.options.elements.arc.angle,
-                               (2 * Math.PI) / count
-                       ], context, index);
+               return count;
+       },
+
+       /**
+        * @private
+        */
+       _computeAngle: function(index) {
+               var me = this;
+               var count = this.getMeta().count;
+               var dataset = me.getDataset();
+               var meta = me.getMeta();
+
+               if (isNaN(dataset.data[index]) || meta.data[index].hidden) {
+                       return 0;
                }
-       });
-};
+
+               // Scriptable options
+               var context = {
+                       chart: me.chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               return helpers.options.resolve([
+                       me.chart.options.elements.arc.angle,
+                       (2 * Math.PI) / count
+               ], context, index);
+       }
+});
index dc2b86c617bc3e3b6fd332dab39c60fc1c3fcbd2..4d69928d87be8452af2f2c42b577b7005c060820 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var DatasetController = require('../core/core.datasetController');
 var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
@@ -15,158 +16,157 @@ defaults._set('radar', {
        }
 });
 
-module.exports = function(Chart) {
+module.exports = DatasetController.extend({
 
-       Chart.controllers.radar = Chart.DatasetController.extend({
+       datasetElementType: elements.Line,
 
-               datasetElementType: elements.Line,
+       dataElementType: elements.Point,
 
-               dataElementType: elements.Point,
+       linkScales: helpers.noop,
 
-               linkScales: helpers.noop,
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var custom = line.custom || {};
+               var dataset = me.getDataset();
+               var lineElementOptions = me.chart.options.elements.line;
+               var scale = me.chart.scale;
+               var i, ilen;
 
-               update: function(reset) {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var line = meta.dataset;
-                       var points = meta.data || [];
-                       var custom = line.custom || {};
-                       var dataset = me.getDataset();
-                       var lineElementOptions = me.chart.options.elements.line;
-                       var scale = me.chart.scale;
-                       var i, ilen;
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+                       dataset.lineTension = dataset.tension;
+               }
 
-                       // Compatibility: If the properties are defined with only the old name, use those values
-                       if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
-                               dataset.lineTension = dataset.tension;
+               helpers.extend(meta.dataset, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _scale: scale,
+                       // Data
+                       _children: points,
+                       _loop: true,
+                       // Model
+                       _model: {
+                               // Appearance
+                               tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
+                               backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
+                               borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
+                               borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
+                               fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
+                               borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
+                               borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
+                               borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
+                               borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
                        }
+               });
 
-                       helpers.extend(meta.dataset, {
-                               // Utility
-                               _datasetIndex: me.index,
-                               _scale: scale,
-                               // Data
-                               _children: points,
-                               _loop: true,
-                               // Model
-                               _model: {
-                                       // Appearance
-                                       tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
-                                       backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
-                                       borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
-                                       borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
-                                       fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
-                                       borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
-                                       borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
-                                       borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
-                                       borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
-                               }
-                       });
-
-                       meta.dataset.pivot();
-
-                       // Update Points
-                       for (i = 0, ilen = points.length; i < ilen; i++) {
-                               me.updateElement(points[i], i, reset);
-                       }
+               meta.dataset.pivot();
 
-                       // Update bezier control points
-                       me.updateBezierControlPoints();
+               // Update Points
+               for (i = 0, ilen = points.length; i < ilen; i++) {
+                       me.updateElement(points[i], i, reset);
+               }
 
-                       // Now pivot the point for animation
-                       for (i = 0, ilen = points.length; i < ilen; i++) {
-                               points[i].pivot();
-                       }
-               },
-               updateElement: function(point, index, reset) {
-                       var me = this;
-                       var custom = point.custom || {};
-                       var dataset = me.getDataset();
-                       var scale = me.chart.scale;
-                       var pointElementOptions = me.chart.options.elements.point;
-                       var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
-
-                       // Compatibility: If the properties are defined with only the old name, use those values
-                       if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
-                               dataset.pointRadius = dataset.radius;
-                       }
-                       if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
-                               dataset.pointHitRadius = dataset.hitRadius;
-                       }
+               // Update bezier control points
+               me.updateBezierControlPoints();
 
-                       helpers.extend(point, {
-                               // Utility
-                               _datasetIndex: me.index,
-                               _index: index,
-                               _scale: scale,
-
-                               // Desired view properties
-                               _model: {
-                                       x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
-                                       y: reset ? scale.yCenter : pointPosition.y,
-
-                                       // Appearance
-                                       tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
-                                       radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
-                                       backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
-                                       borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
-                                       borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
-                                       pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
-                                       rotation: custom.rotation ? custom.rotation : helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointElementOptions.rotation),
-
-                                       // Tooltip
-                                       hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
-                               }
-                       });
-
-                       point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
-               },
-               updateBezierControlPoints: function() {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var area = me.chart.chartArea;
-                       var points = meta.data || [];
-                       var i, ilen, model, controlPoints;
-
-                       function capControlPoint(pt, min, max) {
-                               return Math.max(Math.min(pt, max), min);
-                       }
+               // Now pivot the point for animation
+               for (i = 0, ilen = points.length; i < ilen; i++) {
+                       points[i].pivot();
+               }
+       },
+
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var custom = point.custom || {};
+               var dataset = me.getDataset();
+               var scale = me.chart.scale;
+               var pointElementOptions = me.chart.options.elements.point;
+               var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
+
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
+                       dataset.pointRadius = dataset.radius;
+               }
+               if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
+                       dataset.pointHitRadius = dataset.hitRadius;
+               }
 
-                       for (i = 0, ilen = points.length; i < ilen; i++) {
-                               model = points[i]._model;
-                               controlPoints = helpers.splineCurve(
-                                       helpers.previousItem(points, i, true)._model,
-                                       model,
-                                       helpers.nextItem(points, i, true)._model,
-                                       model.tension
-                               );
-
-                               // Prevent the bezier going outside of the bounds of the graph
-                               model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);
-                               model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);
-                               model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);
-                               model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);
+               helpers.extend(point, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+                       _scale: scale,
+
+                       // Desired view properties
+                       _model: {
+                               x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
+                               y: reset ? scale.yCenter : pointPosition.y,
+
+                               // Appearance
+                               tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
+                               radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
+                               backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
+                               borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
+                               borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
+                               pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
+                               rotation: custom.rotation ? custom.rotation : helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointElementOptions.rotation),
+
+                               // Tooltip
+                               hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
                        }
-               },
-
-               setHoverStyle: function(point) {
-                       // Point
-                       var dataset = this.chart.data.datasets[point._datasetIndex];
-                       var custom = point.custom || {};
-                       var index = point._index;
-                       var model = point._model;
-
-                       point.$previousStyle = {
-                               backgroundColor: model.backgroundColor,
-                               borderColor: model.borderColor,
-                               borderWidth: model.borderWidth,
-                               radius: model.radius
-                       };
-
-                       model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
-                       model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
-                       model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
-                       model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
-               },
-       });
-};
+               });
+
+               point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
+       },
+
+       updateBezierControlPoints: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var area = me.chart.chartArea;
+               var points = meta.data || [];
+               var i, ilen, model, controlPoints;
+
+               function capControlPoint(pt, min, max) {
+                       return Math.max(Math.min(pt, max), min);
+               }
+
+               for (i = 0, ilen = points.length; i < ilen; i++) {
+                       model = points[i]._model;
+                       controlPoints = helpers.splineCurve(
+                               helpers.previousItem(points, i, true)._model,
+                               model,
+                               helpers.nextItem(points, i, true)._model,
+                               model.tension
+                       );
+
+                       // Prevent the bezier going outside of the bounds of the graph
+                       model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);
+                       model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);
+                       model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);
+                       model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);
+               }
+       },
+
+       setHoverStyle: function(point) {
+               // Point
+               var dataset = this.chart.data.datasets[point._datasetIndex];
+               var custom = point.custom || {};
+               var index = point._index;
+               var model = point._model;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
+               model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
+               model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
+               model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
+       }
+});
index b2e2cf1f7e1bb52176be560d058925464ec22ed2..319296d33ba804336ab7c6a26dd776a182a6caa3 100644 (file)
@@ -1,5 +1,6 @@
 'use strict';
 
+var LineController = require('./controller.line');
 var defaults = require('../core/core.defaults');
 
 defaults._set('scatter', {
@@ -34,9 +35,5 @@ defaults._set('scatter', {
        }
 });
 
-module.exports = function(Chart) {
-
-       // Scatter charts use line controllers
-       Chart.controllers.scatter = Chart.controllers.line;
-
-};
+// Scatter charts use line controllers
+module.exports = LineController;
diff --git a/src/controllers/index.js b/src/controllers/index.js
new file mode 100644 (file)
index 0000000..d2fa6c9
--- /dev/null
@@ -0,0 +1,18 @@
+'use strict';
+
+// NOTE export a map in which the key represents the controller type, not
+// the class, and so must be CamelCase in order to be correctly retrieved
+// by the controller in core.controller.js (`controllers[meta.type]`).
+
+/* eslint-disable global-require */
+module.exports = {
+       bar: require('./controller.bar'),
+       bubble: require('./controller.bubble'),
+       doughnut: require('./controller.doughnut'),
+       horizontalBar: require('./controller.horizontalBar'),
+       line: require('./controller.line'),
+       polarArea: require('./controller.polarArea'),
+       pie: require('./controller.pie'),
+       radar: require('./controller.radar'),
+       scatter: require('./controller.scatter')
+};
index 48365fb224d085d3188332880bf32daaf0f59eb5..117a6d576eaac74af1ff68c9f31514b1f7f54b6c 100644 (file)
@@ -2,6 +2,7 @@
 
 var Animation = require('./core.animation');
 var animations = require('./core.animations');
+var controllers = require('../controllers/index');
 var defaults = require('./core.defaults');
 var helpers = require('../helpers/index');
 var Interaction = require('./core.interaction');
@@ -20,9 +21,6 @@ module.exports = function(Chart) {
        // Destroy method on the chart will remove the instance of the chart from this reference.
        Chart.instances = {};
 
-       // Controllers available for dataset visualization eg. bar, line, slice, etc.
-       Chart.controllers = {};
-
        /**
         * Initializes the given config with global and chart default values.
         */
@@ -337,7 +335,7 @@ module.exports = function(Chart) {
                                        meta.controller.updateIndex(datasetIndex);
                                        meta.controller.linkScales();
                                } else {
-                                       var ControllerClass = Chart.controllers[meta.type];
+                                       var ControllerClass = controllers[meta.type];
                                        if (ControllerClass === undefined) {
                                                throw new Error('"' + meta.type + '" is not a chart type.');
                                        }
index 4928f98913ee1117d16b0578eec8dfb50cf1fd12..8d2de1a1aaf22e304ff242d95321b9a240f91d63 100644 (file)
 
 var helpers = require('../helpers/index');
 
-module.exports = function(Chart) {
-
-       var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
+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;
+       }
 
-       /**
-        * 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]
                }
+       });
 
-               Object.defineProperty(array, '_chartjs', {
+       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: {
-                               listeners: [listener]
+                       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;
+       }
 
-               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;
-                               }
-                       });
-               });
+       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)
+var DatasetController = module.exports = function(chart, datasetIndex) {
+       this.initialize(chart, datasetIndex);
+};
+
+helpers.extend(DatasetController.prototype, {
+
        /**
-        * 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.
+        * Element type used to generate a meta dataset (e.g. Chart.element.Line).
+        * @type {Chart.core.element}
         */
-       function unlistenArrayEvents(array, listener) {
-               var stub = array._chartjs;
-               if (!stub) {
-                       return;
-               }
+       datasetElementType: null,
 
-               var listeners = stub.listeners;
-               var index = listeners.indexOf(listener);
-               if (index !== -1) {
-                       listeners.splice(index, 1);
+       /**
+        * 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 in me.chart.scales)) {
+                       meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
                }
-
-               if (listeners.length > 0) {
-                       return;
+               if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
+                       meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
                }
+       },
+
+       getDataset: function() {
+               return this.chart.data.datasets[this.index];
+       },
 
-               arrayEvents.forEach(function(key) {
-                       delete array[key];
+       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,
+                       _datasetIndex: me.index
+               });
+       },
+
+       createMetaData: function(index) {
+               var me = this;
+               var type = me.dataElementType;
+               return type && new type({
+                       _chart: me.chart,
+                       _datasetIndex: me.index,
+                       _index: index
                });
+       },
 
-               delete array._chartjs;
-       }
+       addElements: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var data = me.getDataset().data || [];
+               var metaData = meta.data;
+               var i, ilen;
 
-       // 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 in me.chart.scales)) {
-                               meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
-                       }
-                       if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
-                               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,
-                               _datasetIndex: me.index
-                       });
-               },
-
-               createMetaData: function(index) {
-                       var me = this;
-                       var type = me.dataElementType;
-                       return type && new type({
-                               _chart: me.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 < ilen; ++i) {
-                               metaData[i] = metaData[i] || me.createMetaData(i);
-                       }
+               for (i = 0, ilen = data.length; i < ilen; ++i) {
+                       metaData[i] = metaData[i] || me.createMetaData(i);
+               }
 
-                       meta.dataset = meta.dataset || me.createMetaDataset();
-               },
-
-               addElementAndReset: function(index) {
-                       var element = this.createMetaData(index);
-                       this.getMeta().data.splice(index, 0, element);
-                       this.updateElement(element, index, true);
-               },
-
-               buildOrUpdateElements: function() {
-                       var me = this;
-                       var dataset = me.getDataset();
-                       var data = dataset.data || (dataset.data = []);
-
-                       // In order to correctly handle data addition/deletion animation (an thus simulate
-                       // real-time charts), we need to monitor these data modifications and synchronize
-                       // the internal meta data accordingly.
-                       if (me._data !== data) {
-                               if (me._data) {
-                                       // This case happens when the user replaced the data array instance.
-                                       unlistenArrayEvents(me._data, me);
-                               }
-
-                               listenArrayEvents(data, me);
-                               me._data = data;
+               meta.dataset = meta.dataset || me.createMetaDataset();
+       },
+
+       addElementAndReset: function(index) {
+               var element = this.createMetaData(index);
+               this.getMeta().data.splice(index, 0, element);
+               this.updateElement(element, index, true);
+       },
+
+       buildOrUpdateElements: function() {
+               var me = this;
+               var dataset = me.getDataset();
+               var data = dataset.data || (dataset.data = []);
+
+               // In order to correctly handle data addition/deletion animation (an thus simulate
+               // real-time charts), we need to monitor these data modifications and synchronize
+               // the internal meta data accordingly.
+               if (me._data !== data) {
+                       if (me._data) {
+                               // This case happens when the user replaced the data array instance.
+                               unlistenArrayEvents(me._data, me);
                        }
 
-                       // Re-sync meta data in case the user replaced the data array or if we missed
-                       // any updates and so make sure that we handle number of datapoints changing.
-                       me.resyncElements();
-               },
+                       listenArrayEvents(data, me);
+                       me._data = data;
+               }
 
-               update: helpers.noop,
+               // Re-sync meta data in case the user replaced the data array or if we missed
+               // any updates and so make sure that we handle number of datapoints changing.
+               me.resyncElements();
+       },
 
-               transition: function(easingValue) {
-                       var meta = this.getMeta();
-                       var elements = meta.data || [];
-                       var ilen = elements.length;
-                       var i = 0;
+       update: helpers.noop,
 
-                       for (; i < ilen; ++i) {
-                               elements[i].transition(easingValue);
-                       }
+       transition: function(easingValue) {
+               var meta = this.getMeta();
+               var elements = meta.data || [];
+               var ilen = elements.length;
+               var i = 0;
 
-                       if (meta.dataset) {
-                               meta.dataset.transition(easingValue);
-                       }
-               },
+               for (; i < ilen; ++i) {
+                       elements[i].transition(easingValue);
+               }
 
-               draw: function() {
-                       var meta = this.getMeta();
-                       var elements = meta.data || [];
-                       var ilen = elements.length;
-                       var i = 0;
+               if (meta.dataset) {
+                       meta.dataset.transition(easingValue);
+               }
+       },
 
-                       if (meta.dataset) {
-                               meta.dataset.draw();
-                       }
+       draw: function() {
+               var meta = this.getMeta();
+               var elements = meta.data || [];
+               var ilen = elements.length;
+               var i = 0;
 
-                       for (; i < ilen; ++i) {
-                               elements[i].draw();
-                       }
-               },
-
-               removeHoverStyle: function(element) {
-                       helpers.merge(element._model, element.$previousStyle || {});
-                       delete element.$previousStyle;
-               },
-
-               setHoverStyle: function(element) {
-                       var dataset = this.chart.data.datasets[element._datasetIndex];
-                       var index = element._index;
-                       var custom = element.custom || {};
-                       var valueOrDefault = helpers.valueAtIndexOrDefault;
-                       var getHoverColor = helpers.getHoverColor;
-                       var model = element._model;
-
-                       element.$previousStyle = {
-                               backgroundColor: model.backgroundColor,
-                               borderColor: model.borderColor,
-                               borderWidth: model.borderWidth
-                       };
-
-                       model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
-                       model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
-                       model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
-               },
-
-               /**
-                * @private
-                */
-               resyncElements: function() {
-                       var me = this;
-                       var meta = me.getMeta();
-                       var data = me.getDataset().data;
-                       var numMeta = meta.data.length;
-                       var numData = data.length;
-
-                       if (numData < numMeta) {
-                               meta.data.splice(numData, numMeta - numData);
-                       } else if (numData > numMeta) {
-                               me.insertElements(numMeta, numData - numMeta);
-                       }
-               },
-
-               /**
-                * @private
-                */
-               insertElements: function(start, count) {
-                       for (var i = 0; i < count; ++i) {
-                               this.addElementAndReset(start + i);
-                       }
-               },
-
-               /**
-                * @private
-                */
-               onDataPush: function() {
-                       this.insertElements(this.getDataset().data.length - 1, arguments.length);
-               },
-
-               /**
-                * @private
-                */
-               onDataPop: function() {
-                       this.getMeta().data.pop();
-               },
-
-               /**
-                * @private
-                */
-               onDataShift: function() {
-                       this.getMeta().data.shift();
-               },
-
-               /**
-                * @private
-                */
-               onDataSplice: function(start, count) {
-                       this.getMeta().data.splice(start, count);
-                       this.insertElements(start, arguments.length - 2);
-               },
-
-               /**
-                * @private
-                */
-               onDataUnshift: function() {
-                       this.insertElements(0, arguments.length);
+               if (meta.dataset) {
+                       meta.dataset.draw();
                }
-       });
 
-       Chart.DatasetController.extend = helpers.inherits;
-};
+               for (; i < ilen; ++i) {
+                       elements[i].draw();
+               }
+       },
+
+       removeHoverStyle: function(element) {
+               helpers.merge(element._model, element.$previousStyle || {});
+               delete element.$previousStyle;
+       },
+
+       setHoverStyle: function(element) {
+               var dataset = this.chart.data.datasets[element._datasetIndex];
+               var index = element._index;
+               var custom = element.custom || {};
+               var valueOrDefault = helpers.valueAtIndexOrDefault;
+               var getHoverColor = helpers.getHoverColor;
+               var model = element._model;
+
+               element.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth
+               };
+
+               model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
+               model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
+               model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
+       },
+
+       /**
+        * @private
+        */
+       resyncElements: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var data = me.getDataset().data;
+               var numMeta = meta.data.length;
+               var numData = data.length;
+
+               if (numData < numMeta) {
+                       meta.data.splice(numData, numMeta - numData);
+               } else if (numData > numMeta) {
+                       me.insertElements(numMeta, numData - numMeta);
+               }
+       },
+
+       /**
+        * @private
+        */
+       insertElements: function(start, count) {
+               for (var i = 0; i < count; ++i) {
+                       this.addElementAndReset(start + i);
+               }
+       },
+
+       /**
+        * @private
+        */
+       onDataPush: function() {
+               this.insertElements(this.getDataset().data.length - 1, arguments.length);
+       },
+
+       /**
+        * @private
+        */
+       onDataPop: function() {
+               this.getMeta().data.pop();
+       },
+
+       /**
+        * @private
+        */
+       onDataShift: function() {
+               this.getMeta().data.shift();
+       },
+
+       /**
+        * @private
+        */
+       onDataSplice: function(start, count) {
+               this.getMeta().data.splice(start, count);
+               this.insertElements(start, arguments.length - 2);
+       },
+
+       /**
+        * @private
+        */
+       onDataUnshift: function() {
+               this.insertElements(0, arguments.length);
+       }
+});
+
+DatasetController.extend = helpers.inherits;
index 0e843e1435fa3697dfc8eff20ae1716aca122efa..62ab0acd87a82a9b92e8769a739504a3f478ae3f 100644 (file)
@@ -1,6 +1,11 @@
 describe('Chart.controllers.bar', function() {
        describe('auto', jasmine.fixture.specs('controller.bar'));
 
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.bar).toBe('function');
+               expect(typeof Chart.controllers.horizontalBar).toBe('function');
+       });
+
        it('should be constructed', function() {
                var chart = window.acquireChart({
                        type: 'bar',
index a5f5b89a5de3af5f0689050be9e67e25fa245a42..9591e65973ceb1e3707abd7a82f23ac0d5d95efd 100644 (file)
@@ -1,6 +1,10 @@
 describe('Chart.controllers.bubble', function() {
        describe('auto', jasmine.fixture.specs('controller.bubble'));
 
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.bubble).toBe('function');
+       });
+
        it('should be constructed', function() {
                var chart = window.acquireChart({
                        type: 'bubble',
index 2f9602bda736968367c1499ba3ae99fd5842fd49..e7bc951fd5702d9fcc02969694d3e1b8ba1b8565 100644 (file)
@@ -1,4 +1,9 @@
 describe('Chart.controllers.doughnut', function() {
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.doughnut).toBe('function');
+               expect(Chart.controllers.doughnut).toBe(Chart.controllers.pie);
+       });
+
        it('should be constructed', function() {
                var chart = window.acquireChart({
                        type: 'doughnut',
index 25a9ed6b0f5a276305bea71e308a164b9cb86d00..f3a3351de9cb867e728b0088890d53eb5987835a 100644 (file)
@@ -1,6 +1,10 @@
 describe('Chart.controllers.line', function() {
        describe('auto', jasmine.fixture.specs('controller.line'));
 
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.line).toBe('function');
+       });
+
        it('should be constructed', function() {
                var chart = window.acquireChart({
                        type: 'line',
index 1023bf0789bc48ffec0940ff336492aaec692652..1feda5134b86946a077d9619609be38ae6afe4c9 100644 (file)
@@ -1,6 +1,10 @@
-describe('auto', jasmine.fixture.specs('controller.polarArea'));
-
 describe('Chart.controllers.polarArea', function() {
+       describe('auto', jasmine.fixture.specs('controller.polarArea'));
+
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.polarArea).toBe('function');
+       });
+
        it('should be constructed', function() {
                var chart = window.acquireChart({
                        type: 'polarArea',
index 6a447a1ccdb9698f5578f832745a2d85fd1fa493..a013274bb78eefed358d3dcce012221e77d0c897 100644 (file)
@@ -1,6 +1,10 @@
 describe('Chart.controllers.radar', function() {
        describe('auto', jasmine.fixture.specs('controller.radar'));
 
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.radar).toBe('function');
+       });
+
        it('Should be constructed', function() {
                var chart = window.acquireChart({
                        type: 'radar',
index 435750928d9bc115624fb703656b4355f1802a7f..6063caed7661ff3d634c5cb6ffc641dc7af016c0 100644 (file)
@@ -1,4 +1,8 @@
 describe('Chart.controllers.scatter', function() {
+       it('should be registered as dataset controller', function() {
+               expect(typeof Chart.controllers.scatter).toBe('function');
+       });
+
        describe('showLines option', function() {
                it('should not draw a line if undefined', function() {
                        var chart = window.acquireChart({