]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Better default tick rotation and tick autoskip settings (#2258)
authorTanner Linsley <tannerlinsley@gmail.com>
Sat, 16 Apr 2016 22:38:03 +0000 (17:38 -0500)
committerTanner Linsley <tannerlinsley@gmail.com>
Sat, 16 Apr 2016 22:38:03 +0000 (17:38 -0500)
* Better default tick rotation and tick autoskip settings

* scale.time: Use ctx to measure label, and <= instead of < for unit fitting

* Test Changes

* Passing Tests with new defaults

src/core/core.scale.js
src/scales/scale.time.js
test/controller.bar.tests.js
test/controller.line.tests.js
test/core.helpers.tests.js
test/core.layoutService.tests.js
test/scale.category.tests.js
test/scale.linear.tests.js
test/scale.logarithmic.tests.js
test/scale.radialLinear.tests.js
test/scale.time.tests.js

index 538263290f3f9c28fa9f9331caebdd79f95cda6b..18c201eea31caa9d9dc1c8c021aef9e333960033 100644 (file)
@@ -31,13 +31,13 @@ module.exports = function(Chart) {
                // label settings
                ticks: {
                        beginAtZero: false,
-                       maxRotation: 90,
+                       maxRotation: 50,
                        mirror: false,
                        padding: 10,
                        reverse: false,
                        display: true,
                        autoSkip: true,
-                       autoSkipPadding: 20,
+                       autoSkipPadding: 0,
                        callback: function(value) {
                                return '' + value;
                        }
@@ -682,4 +682,4 @@ module.exports = function(Chart) {
                        }
                }
        });
-};
\ No newline at end of file
+};
index 7e5b7c387597e542dbd844fab949210e2027f6d3..2dbb4ba6d4d067e2a24b5772d6517072b0737a53 100644 (file)
@@ -62,7 +62,7 @@ module.exports = function(Chart) {
                        }
                },
                ticks: {
-                       autoSkip: false,
+                       autoSkip: false
                }
        };
 
@@ -137,6 +137,13 @@ module.exports = function(Chart) {
                },
                buildTicks: function(index) {
 
+                       this.ctx.save();
+                       var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
+                       var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
+                       var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
+                       var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
+                       this.ctx.font = tickLabelFont;
+
                        this.ticks = [];
                        this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
                        this.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc)
@@ -149,16 +156,15 @@ module.exports = function(Chart) {
                                this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, 1);
                        } else {
                                // Determine the smallest needed unit of the time
-                               var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
                                var innerWidth = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
-                               
+
                                // Crude approximation of what the label length might be
                                var tempFirstLabel = this.tickFormatFunction(this.firstTick, 0, []);
-                               var tickLabelWidth = tempFirstLabel.length * tickFontSize;
+                               var tickLabelWidth = this.ctx.measureText(tempFirstLabel).width;
                                var cosRotation = Math.cos(helpers.toRadians(this.options.ticks.maxRotation));
                                var sinRotation = Math.sin(helpers.toRadians(this.options.ticks.maxRotation));
                                tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
-                               var labelCapacity = innerWidth / (tickLabelWidth + 10);
+                               var labelCapacity = innerWidth / (tickLabelWidth);
 
                                // Start as small as possible
                                this.tickUnit = 'millisecond';
@@ -176,7 +182,7 @@ module.exports = function(Chart) {
                                        if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) {
                                                // Use one of the prefedined steps
                                                for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
-                                                       if (unitDefinition.steps[idx] > Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
+                                                       if (unitDefinition.steps[idx] >= Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
                                                                this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, unitDefinition.steps[idx]);
                                                                break;
                                                        }
@@ -257,6 +263,7 @@ module.exports = function(Chart) {
                                        this.lastTick = this.ticks[this.ticks.length - 1].clone();
                                }
                        }
+                       this.ctx.restore();
                },
                // Get tooltip label
                getLabelForIndex: function(index, datasetIndex) {
@@ -335,4 +342,4 @@ module.exports = function(Chart) {
        });
        Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig);
 
-};
\ No newline at end of file
+};
index 869836b42fe85973e4ce6b13f7805436f4900d7e..2564258a6b7f1d1930b83e283dd4f611fb461a2b 100644 (file)
 // Test the bar controller
 describe('Bar controller tests', function() {
-       it('Should be constructed', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-
-                               }, {
-                                       xAxisID: 'myXAxis',
-                                       yAxisID: 'myYAxis',
-                                       data: []
-                               }]
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-               expect(controller).not.toBe(undefined);
-               expect(controller.index).toBe(1);
-               expect(chart.data.datasets[1].metaData).toEqual([]);
-
-               controller.updateIndex(0);
-               expect(controller.index).toBe(0);
-       });
-
-       it('Should use the first scale IDs if the dataset does not specify them', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-
-                               }, {
-                                       data: []
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-               expect(chart.data.datasets[1].xAxisID).toBe('firstXScaleID');
-               expect(chart.data.datasets[1].yAxisID).toBe('firstYScaleID');
-       });
-
-       it('should correctly count the number of bar datasets', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                               }, {
-                                       bar: true
-                               }, {
-                                       bar: true
-                               }]
-                       },
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-               expect(controller.getBarCount()).toBe(2);
-       });
-
-       it('should correctly get the bar index accounting for hidden datasets', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                                       bar: true,
-                               }, {
-                                       bar: true,
-                                       hidden: true
-                               }, {
-                               }, {
-                                       bar: true,
-                               }]
-                       },
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-               expect(controller.getBarIndex(0)).toBe(0);
-               expect(controller.getBarIndex(3)).toBe(1);
-       });
-
-       it('Should create rectangle elements for each data item during initialization', function() {
-               var chart = {
-                       data: {
-                               datasets: [{}, {
-                                       data: [10, 15, 0, -4]
-                               }]
-                       },
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-
-               expect(chart.data.datasets[1].metaData.length).toBe(4); // 4 rectangles created
-               expect(chart.data.datasets[1].metaData[0] instanceof Chart.elements.Rectangle).toBe(true);
-               expect(chart.data.datasets[1].metaData[1] instanceof Chart.elements.Rectangle).toBe(true);
-               expect(chart.data.datasets[1].metaData[2] instanceof Chart.elements.Rectangle).toBe(true);
-               expect(chart.data.datasets[1].metaData[3] instanceof Chart.elements.Rectangle).toBe(true);
-       });
-
-       it('should update elements', function() {
-               var data = {
-                       datasets: [{
-                               data: [1, 2],
-                               label: 'dataset1',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               bar: true
-                       }, {
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-               var chart = {
-                       data: data,
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               elements: {
-                                       rectangle: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderSkipped: 'top',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-
-               chart.data.datasets[1].data = [1, 2]; // remove 2 items
-               controller.buildOrUpdateElements();
-               controller.update();
-
-               expect(chart.data.datasets[1].metaData.length).toBe(2);
-               
-               var bar1 = chart.data.datasets[1].metaData[0];
-               var bar2 = chart.data.datasets[1].metaData[1];
-
-               expect(bar1._datasetIndex).toBe(1);
-               expect(bar1._index).toBe(0);
-               expect(bar1._xScale).toBe(chart.scales.firstXScaleID);
-               expect(bar1._yScale).toBe(chart.scales.firstYScaleID);
-               expect(bar1._model).toEqual({
-                       x: 113.60000000000001,
-                       y: 194,
-                       label: 'label1',
-                       datasetLabel: 'dataset2',
-
-                       base: 194,
-                       width: 13.680000000000001,
-                       backgroundColor: 'rgb(255, 0, 0)',
-                       borderSkipped: 'top',
-                       borderColor: 'rgb(0, 0, 255)',
-                       borderWidth: 2,
-               });
-
-               expect(bar2._datasetIndex).toBe(1);
-               expect(bar2._index).toBe(1);
-               expect(bar2._xScale).toBe(chart.scales.firstXScaleID);
-               expect(bar2._yScale).toBe(chart.scales.firstYScaleID);
-               expect(bar2._model).toEqual({
-                       x: 151.60000000000002,
-                       y: 6,
-                       label: 'label2',
-                       datasetLabel: 'dataset2',
-
-                       base: 194,
-                       width: 13.680000000000001,
-                       backgroundColor: 'rgb(255, 0, 0)',
-                       borderSkipped: 'top',
-                       borderColor: 'rgb(0, 0, 255)',
-                       borderWidth: 2,
-               });
-
-               chart.data.datasets[1].data = [1, 2, 3];
-               controller.buildOrUpdateElements();
-               controller.update();
-
-               expect(chart.data.datasets[1].metaData.length).toBe(3); // should add a new meta data item
-       });
-
-       it ('should get the correct bar points when datasets of different types exist', function() {
-               var data = {
-                       datasets: [{
-                               data: [1, 2],
-                               label: 'dataset1',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               bar: true,
-                       }, {
-                               data: [10, 15],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                       }, {
-                               data: [30, 25],
-                               label: 'dataset3',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               bar: true
-                       }],
-                       labels: ['label1', 'label2']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-               var chart = {
-                       data: data,
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               elements: {
-                                       rectangle: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 2);
-               controller.buildOrUpdateElements();
-               controller.update();
-
-               var bar1 = chart.data.datasets[2].metaData[0];
-               var bar2 = chart.data.datasets[2].metaData[1];
-
-               expect(bar1._model.x).toBe(119.9);
-               expect(bar1._model.y).toBe(6);
-               expect(bar2._model.x).toBe(186.9);
-               expect(bar2._model.y).toBe(37);
-       });
-
-       it('should update elements when the scales are stacked', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, -10, 10, -10],
-                               label: 'dataset1',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               bar: true
-                       }, {
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               bar: true
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
-               verticalScaleConfig.stacked = true;
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
-               horizontalScaleConfig.stacked = true;
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-               var chart = {
-                       data: data,
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               elements: {
-                                       rectangle: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller0 = new Chart.controllers.bar(chart, 0);
-               var controller1 = new Chart.controllers.bar(chart, 1);
-
-               controller0.buildOrUpdateElements();
-               controller0.update();
-               controller1.buildOrUpdateElements();
-               controller1.update();
-
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual(jasmine.objectContaining({
-                       x: 106,
-                       y: 60,
-                       base: 113,
-                       width: 30.400000000000002
-               }));
-               expect(chart.data.datasets[0].metaData[1]._model).toEqual(jasmine.objectContaining({
-                       x: 144,
-                       y: 167,
-                       base: 113,
-                       width: 30.400000000000002
-               }));
-               expect(chart.data.datasets[0].metaData[2]._model).toEqual(jasmine.objectContaining({
-                       x: 183,
-                       y: 60,
-                       base: 113,
-                       width: 30.400000000000002
-               }));
-               expect(chart.data.datasets[0].metaData[3]._model).toEqual(jasmine.objectContaining({
-                       x: 222,
-                       y: 167,
-                       base: 113,
-                       width: 30.400000000000002
-               }));
-
-               expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
-                       x: 106,
-                       y: 6,
-                       base: 60,
-                       width: 30.400000000000002
-               }));
-               expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
-                       x: 144,
-                       y: 33,
-                       base: 113,
-                       width: 30.400000000000002
-               }));
-               expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
-                       x: 183,
-                       y: 60,
-                       base: 60,
-                       width: 30.400000000000002
-               }));
-               expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
-                       x: 222,
-                       y: 189,
-                       base: 167,
-                       width: 30.400000000000002
-               }));
-       });
-
-       it ('should draw all bars', function() {
-               var data = {
-                       datasets: [{}, {
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       data: data,
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-
-               spyOn(chart.data.datasets[1].metaData[0], 'draw');
-               spyOn(chart.data.datasets[1].metaData[1], 'draw');
-               spyOn(chart.data.datasets[1].metaData[2], 'draw');
-               spyOn(chart.data.datasets[1].metaData[3], 'draw');
-
-               controller.draw();
-
-               expect(chart.data.datasets[1].metaData[0].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[1].metaData[1].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[1].metaData[2].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[1].metaData[3].draw.calls.count()).toBe(1);
-       });
-
-       it ('should set hover styles on rectangles', function() {
-               var data = {
-                       datasets: [{}, {
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       data: data,
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               elements: {
-                                       rectangle: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-               controller.update();
-               var bar = chart.data.datasets[1].metaData[0];
-               controller.setHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(230, 0, 0)');
-               expect(bar._model.borderColor).toBe('rgb(0, 0, 230)');
-               expect(bar._model.borderWidth).toBe(2);
-
-               // Set a dataset style
-               chart.data.datasets[1].hoverBackgroundColor = 'rgb(128, 128, 128)';
-               chart.data.datasets[1].hoverBorderColor = 'rgb(0, 0, 0)';
-               chart.data.datasets[1].hoverBorderWidth = 5;
-
-               controller.setHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
-               expect(bar._model.borderColor).toBe('rgb(0, 0, 0)');
-               expect(bar._model.borderWidth).toBe(5);
-
-               // Should work with array styles so that we can set per bar
-               chart.data.datasets[1].hoverBackgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
-               chart.data.datasets[1].hoverBorderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
-               chart.data.datasets[1].hoverBorderWidth = [2.5, 5];
-
-               controller.setHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
-               expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
-               expect(bar._model.borderWidth).toBe(2.5);
-
-               // Should allow a custom style
-               bar.custom = {
-                       hoverBackgroundColor: 'rgb(255, 0, 0)',
-                       hoverBorderColor: 'rgb(0, 255, 0)',
-                       hoverBorderWidth: 1.5
-               };
-
-               controller.setHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(255, 0, 0)');
-               expect(bar._model.borderColor).toBe('rgb(0, 255, 0)');
-               expect(bar._model.borderWidth).toBe(1.5);
-       });
-
-       it ('should remove a hover style from a bar', function() {
-               var data = {
-                       datasets: [{}, {
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       data: data,
-                       config: {
-                               type: 'bar'
-                       },
-                       options: {
-                               elements: {
-                                       rectangle: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.bar(chart, 1);
-               controller.update();
-               var bar = chart.data.datasets[1].metaData[0];
-
-               // Change default
-               chart.options.elements.rectangle.backgroundColor = 'rgb(128, 128, 128)';
-               chart.options.elements.rectangle.borderColor = 'rgb(15, 15, 15)';
-               chart.options.elements.rectangle.borderWidth = 3.14;
-
-               // Remove to defaults
-               controller.removeHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
-               expect(bar._model.borderColor).toBe('rgb(15, 15, 15)');
-               expect(bar._model.borderWidth).toBe(3.14);
-
-               // Should work with array styles so that we can set per bar
-               chart.data.datasets[1].backgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
-               chart.data.datasets[1].borderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
-               chart.data.datasets[1].borderWidth = [2.5, 5];
-
-               controller.removeHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
-               expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
-               expect(bar._model.borderWidth).toBe(2.5);
-
-               // Should allow a custom style
-               bar.custom = {
-                       backgroundColor: 'rgb(255, 0, 0)',
-                       borderColor: 'rgb(0, 255, 0)',
-                       borderWidth: 1.5
-               };
-
-               controller.removeHoverStyle(bar);
-
-               expect(bar._model.backgroundColor).toBe('rgb(255, 0, 0)');
-               expect(bar._model.borderColor).toBe('rgb(0, 255, 0)');
-               expect(bar._model.borderWidth).toBe(1.5);
-       });     
-});
\ No newline at end of file
+  it('Should be constructed', function() {
+    var chart = {
+      data: {
+        datasets: [{
+
+        }, {
+          xAxisID: 'myXAxis',
+          yAxisID: 'myYAxis',
+          data: []
+        }]
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+    expect(controller).not.toBe(undefined);
+    expect(controller.index).toBe(1);
+    expect(chart.data.datasets[1].metaData).toEqual([]);
+
+    controller.updateIndex(0);
+    expect(controller.index).toBe(0);
+  });
+
+  it('Should use the first scale IDs if the dataset does not specify them', function() {
+    var chart = {
+      data: {
+        datasets: [{
+
+        }, {
+          data: []
+        }]
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+    expect(chart.data.datasets[1].xAxisID).toBe('firstXScaleID');
+    expect(chart.data.datasets[1].yAxisID).toBe('firstYScaleID');
+  });
+
+  it('should correctly count the number of bar datasets', function() {
+    var chart = {
+      data: {
+        datasets: [{}, {
+          bar: true
+        }, {
+          bar: true
+        }]
+      },
+      config: {
+        type: 'bar'
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+    expect(controller.getBarCount()).toBe(2);
+  });
+
+  it('should correctly get the bar index accounting for hidden datasets', function() {
+    var chart = {
+      data: {
+        datasets: [{
+          bar: true,
+        }, {
+          bar: true,
+          hidden: true
+        }, {}, {
+          bar: true,
+        }]
+      },
+      config: {
+        type: 'bar'
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+    expect(controller.getBarIndex(0)).toBe(0);
+    expect(controller.getBarIndex(3)).toBe(1);
+  });
+
+  it('Should create rectangle elements for each data item during initialization', function() {
+    var chart = {
+      data: {
+        datasets: [{}, {
+          data: [10, 15, 0, -4]
+        }]
+      },
+      config: {
+        type: 'bar'
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+
+    expect(chart.data.datasets[1].metaData.length).toBe(4); // 4 rectangles created
+    expect(chart.data.datasets[1].metaData[0] instanceof Chart.elements.Rectangle).toBe(true);
+    expect(chart.data.datasets[1].metaData[1] instanceof Chart.elements.Rectangle).toBe(true);
+    expect(chart.data.datasets[1].metaData[2] instanceof Chart.elements.Rectangle).toBe(true);
+    expect(chart.data.datasets[1].metaData[3] instanceof Chart.elements.Rectangle).toBe(true);
+  });
+
+  it('should update elements', function() {
+    var data = {
+      datasets: [{
+        data: [1, 2],
+        label: 'dataset1',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        bar: true
+      }, {
+        data: [10, 15, 0, -4],
+        label: 'dataset2'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+    var chart = {
+      data: data,
+      config: {
+        type: 'bar'
+      },
+      options: {
+        elements: {
+          rectangle: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderSkipped: 'top',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+
+    chart.data.datasets[1].data = [1, 2]; // remove 2 items
+    controller.buildOrUpdateElements();
+    controller.update();
+
+    expect(chart.data.datasets[1].metaData.length).toBe(2);
+
+    var bar1 = chart.data.datasets[1].metaData[0];
+    var bar2 = chart.data.datasets[1].metaData[1];
+
+    expect(bar1._datasetIndex).toBe(1);
+    expect(bar1._index).toBe(0);
+    expect(bar1._xScale).toBe(chart.scales.firstXScaleID);
+    expect(bar1._yScale).toBe(chart.scales.firstYScaleID);
+    expect(bar1._model).toEqual({
+      x: 117.9,
+      y: 194,
+      label: 'label1',
+      datasetLabel: 'dataset2',
+      base: 194,
+      width: 13.32,
+      backgroundColor: 'rgb(255, 0, 0)',
+      borderSkipped: 'top',
+      borderColor: 'rgb(0, 0, 255)',
+      borderWidth: 2
+    });
+
+    expect(bar2._datasetIndex).toBe(1);
+    expect(bar2._index).toBe(1);
+    expect(bar2._xScale).toBe(chart.scales.firstXScaleID);
+    expect(bar2._yScale).toBe(chart.scales.firstYScaleID);
+    expect(bar2._model).toEqual({
+      x: 154.89999999999998,
+      y: 6,
+      label: 'label2',
+      datasetLabel: 'dataset2',
+      base: 194,
+      width: 13.32,
+      backgroundColor: 'rgb(255, 0, 0)',
+      borderSkipped: 'top',
+      borderColor: 'rgb(0, 0, 255)',
+      borderWidth: 2
+    });
+
+    chart.data.datasets[1].data = [1, 2, 3];
+    controller.buildOrUpdateElements();
+    controller.update();
+
+    expect(chart.data.datasets[1].metaData.length).toBe(3); // should add a new meta data item
+  });
+
+  it('should get the correct bar points when datasets of different types exist', function() {
+    var data = {
+      datasets: [{
+        data: [1, 2],
+        label: 'dataset1',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        bar: true,
+      }, {
+        data: [10, 15],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+      }, {
+        data: [30, 25],
+        label: 'dataset3',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        bar: true
+      }],
+      labels: ['label1', 'label2']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+    var chart = {
+      data: data,
+      config: {
+        type: 'bar'
+      },
+      options: {
+        elements: {
+          rectangle: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 2);
+    controller.buildOrUpdateElements();
+    controller.update();
+
+    var bar1 = chart.data.datasets[2].metaData[0];
+    var bar2 = chart.data.datasets[2].metaData[1];
+
+    expect(bar1._model.x).toBe(119.9);
+    expect(bar1._model.y).toBe(6);
+    expect(bar2._model.x).toBe(186.9);
+    expect(bar2._model.y).toBe(37);
+  });
+
+  it('should update elements when the scales are stacked', function() {
+    var data = {
+      datasets: [{
+        data: [10, -10, 10, -10],
+        label: 'dataset1',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        bar: true
+      }, {
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        bar: true
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
+    verticalScaleConfig.stacked = true;
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
+    horizontalScaleConfig.stacked = true;
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+    var chart = {
+      data: data,
+      config: {
+        type: 'bar'
+      },
+      options: {
+        elements: {
+          rectangle: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller0 = new Chart.controllers.bar(chart, 0);
+    var controller1 = new Chart.controllers.bar(chart, 1);
+
+    controller0.buildOrUpdateElements();
+    controller0.update();
+    controller1.buildOrUpdateElements();
+    controller1.update();
+
+    expect(chart.data.datasets[0].metaData[0]._model).toEqual(jasmine.objectContaining({
+      x: 110.5,
+      y: 60,
+      base: 113,
+      width: 29.6
+    }));
+    expect(chart.data.datasets[0].metaData[1]._model).toEqual(jasmine.objectContaining({
+      x: 147.5,
+      y: 167,
+      base: 113,
+      width: 29.6
+    }));
+    expect(chart.data.datasets[0].metaData[2]._model).toEqual(jasmine.objectContaining({
+      x: 185.5,
+      y: 60,
+      base: 113,
+      width: 29.6
+    }));
+    expect(chart.data.datasets[0].metaData[3]._model).toEqual(jasmine.objectContaining({
+      x: 223.5,
+      y: 167,
+      base: 113,
+      width: 29.6
+    }));
+
+    expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
+      x: 110.5,
+      y: 6,
+      base: 60,
+      width: 29.6
+    }));
+    expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
+      x: 147.5,
+      y: 33,
+      base: 113,
+      width: 29.6
+    }));
+    expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
+      x: 185.5,
+      y: 60,
+      base: 60,
+      width: 29.6
+    }));
+    expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
+      x: 223.5,
+      y: 189,
+      base: 167,
+      width: 29.6
+    }));
+  });
+
+  it('should draw all bars', function() {
+    var data = {
+      datasets: [{}, {
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      data: data,
+      config: {
+        type: 'bar'
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+
+    spyOn(chart.data.datasets[1].metaData[0], 'draw');
+    spyOn(chart.data.datasets[1].metaData[1], 'draw');
+    spyOn(chart.data.datasets[1].metaData[2], 'draw');
+    spyOn(chart.data.datasets[1].metaData[3], 'draw');
+
+    controller.draw();
+
+    expect(chart.data.datasets[1].metaData[0].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[1].metaData[1].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[1].metaData[2].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[1].metaData[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should set hover styles on rectangles', function() {
+    var data = {
+      datasets: [{}, {
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      data: data,
+      config: {
+        type: 'bar'
+      },
+      options: {
+        elements: {
+          rectangle: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+    controller.update();
+    var bar = chart.data.datasets[1].metaData[0];
+    controller.setHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(230, 0, 0)');
+    expect(bar._model.borderColor).toBe('rgb(0, 0, 230)');
+    expect(bar._model.borderWidth).toBe(2);
+
+    // Set a dataset style
+    chart.data.datasets[1].hoverBackgroundColor = 'rgb(128, 128, 128)';
+    chart.data.datasets[1].hoverBorderColor = 'rgb(0, 0, 0)';
+    chart.data.datasets[1].hoverBorderWidth = 5;
+
+    controller.setHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
+    expect(bar._model.borderColor).toBe('rgb(0, 0, 0)');
+    expect(bar._model.borderWidth).toBe(5);
+
+    // Should work with array styles so that we can set per bar
+    chart.data.datasets[1].hoverBackgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
+    chart.data.datasets[1].hoverBorderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
+    chart.data.datasets[1].hoverBorderWidth = [2.5, 5];
+
+    controller.setHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
+    expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
+    expect(bar._model.borderWidth).toBe(2.5);
+
+    // Should allow a custom style
+    bar.custom = {
+      hoverBackgroundColor: 'rgb(255, 0, 0)',
+      hoverBorderColor: 'rgb(0, 255, 0)',
+      hoverBorderWidth: 1.5
+    };
+
+    controller.setHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(255, 0, 0)');
+    expect(bar._model.borderColor).toBe('rgb(0, 255, 0)');
+    expect(bar._model.borderWidth).toBe(1.5);
+  });
+
+  it('should remove a hover style from a bar', function() {
+    var data = {
+      datasets: [{}, {
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      data: data,
+      config: {
+        type: 'bar'
+      },
+      options: {
+        elements: {
+          rectangle: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.bar(chart, 1);
+    controller.update();
+    var bar = chart.data.datasets[1].metaData[0];
+
+    // Change default
+    chart.options.elements.rectangle.backgroundColor = 'rgb(128, 128, 128)';
+    chart.options.elements.rectangle.borderColor = 'rgb(15, 15, 15)';
+    chart.options.elements.rectangle.borderWidth = 3.14;
+
+    // Remove to defaults
+    controller.removeHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
+    expect(bar._model.borderColor).toBe('rgb(15, 15, 15)');
+    expect(bar._model.borderWidth).toBe(3.14);
+
+    // Should work with array styles so that we can set per bar
+    chart.data.datasets[1].backgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
+    chart.data.datasets[1].borderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
+    chart.data.datasets[1].borderWidth = [2.5, 5];
+
+    controller.removeHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
+    expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
+    expect(bar._model.borderWidth).toBe(2.5);
+
+    // Should allow a custom style
+    bar.custom = {
+      backgroundColor: 'rgb(255, 0, 0)',
+      borderColor: 'rgb(0, 255, 0)',
+      borderWidth: 1.5
+    };
+
+    controller.removeHoverStyle(bar);
+
+    expect(bar._model.backgroundColor).toBe('rgb(255, 0, 0)');
+    expect(bar._model.borderColor).toBe('rgb(0, 255, 0)');
+    expect(bar._model.borderWidth).toBe(1.5);
+  });
+});
index 0b8cc79218d783ba13c2026c7708c6b0034807eb..a4d12bdb35fd779e6c82c37aa63880fa8d5e7248 100644 (file)
 // Test the line controller
 describe('Line controller tests', function() {
-       it('Should be constructed', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'myXAxis',
-                                       yAxisID: 'myYAxis',
-                                       data: []
-                               }]
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               expect(controller).not.toBe(undefined);
-               expect(controller.index).toBe(0);
-               expect(chart.data.datasets[0].metaData).toEqual([]);
-
-               controller.updateIndex(1);
-               expect(controller.index).toBe(1);
-       });
-
-       it('Should use the first scale IDs if the dataset does not specify them', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               expect(chart.data.datasets[0].xAxisID).toBe('firstXScaleID');
-               expect(chart.data.datasets[0].yAxisID).toBe('firstYScaleID');
-       });
-
-       it('Should create line elements and point elements for each data item during initialization', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4]
-                               }]
-                       },
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-
-               expect(chart.data.datasets[0].metaData.length).toBe(4); // 4 points created
-               expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaDataset instanceof Chart.elements.Line).toBe(true); // 1 line element
-       });
-
-       it('should draw all elements', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4]
-                               }]
-                       },
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               showLines: true,
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-
-               spyOn(chart.data.datasets[0].metaDataset, 'draw');
-               spyOn(chart.data.datasets[0].metaData[0], 'draw');
-               spyOn(chart.data.datasets[0].metaData[1], 'draw');
-               spyOn(chart.data.datasets[0].metaData[2], 'draw');
-               spyOn(chart.data.datasets[0].metaData[3], 'draw');
-
-               controller.draw();
-
-               expect(chart.data.datasets[0].metaDataset.draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should draw all elements except lines', function() {
-               var chart = {
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4]
-                               }]
-                       },
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               showLines: false,
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-
-               spyOn(chart.data.datasets[0].metaDataset, 'draw');
-               spyOn(chart.data.datasets[0].metaData[0], 'draw');
-               spyOn(chart.data.datasets[0].metaData[1], 'draw');
-               spyOn(chart.data.datasets[0].metaData[2], 'draw');
-               spyOn(chart.data.datasets[0].metaData[3], 'draw');
-
-               controller.draw();
-
-               expect(chart.data.datasets[0].metaDataset.draw.calls.count()).toBe(0);
-               expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
-               expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should update elements', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: xScale.left + 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               showLines: true,
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0.1,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.global.defaultColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.global.defaultColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                               pointStyle: 'circle'
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               controller.update();
-
-               // Line element
-               expect(chart.data.datasets[0].metaDataset._model).toEqual({
-                       backgroundColor: 'rgb(255, 0, 0)',
-                       borderCapStyle: 'round',
-                       borderColor: 'rgb(0, 255, 0)',
-                       borderDash: [],
-                       borderDashOffset: 0.1,
-                       borderJoinStyle: 'bevel',
-                       borderWidth: 1.2,
-                       fill: true,
-                       tension: 0.1,
-
-                       scaleTop: 0,
-                       scaleBottom: 200,
-                       scaleZero: 156,
-               });
-
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual({
-                       backgroundColor: Chart.defaults.global.defaultColor,
-                       borderWidth: 1,
-                       borderColor: Chart.defaults.global.defaultColor,
-                       hitRadius: 1,
-                       radius: 3,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0.1,
-
-                       // Point
-                       x: 81,
-                       y: 62,
-
-                       // Control points
-                       controlPointPreviousX: 81,
-                       controlPointPreviousY: 62,
-                       controlPointNextX: 86,
-                       controlPointNextY: 57.3,
-               });
-
-               expect(chart.data.datasets[0].metaData[1]._model).toEqual({
-                       backgroundColor: Chart.defaults.global.defaultColor,
-                       borderWidth: 1,
-                       borderColor: Chart.defaults.global.defaultColor,
-                       hitRadius: 1,
-                       radius: 3,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0.1,
-
-                       // Point
-                       x: 131,
-                       y: 15,
-
-                       // Control points
-                       controlPointPreviousX: 127.82889384189087,
-                       controlPointPreviousY: 12.04867347661131,
-                       controlPointNextX: 137.92889384189088,
-                       controlPointNextY: 21.44867347661131,
-               });
-
-               expect(chart.data.datasets[0].metaData[2]._model).toEqual({
-                       backgroundColor: Chart.defaults.global.defaultColor,
-                       borderWidth: 1,
-                       borderColor: Chart.defaults.global.defaultColor,
-                       hitRadius: 1,
-                       radius: 3,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0.1,
-
-                       // Point
-                       x: 182,
-                       y: 156,
-
-                       // Control points
-                       controlPointPreviousX: 174.8815225337256,
-                       controlPointPreviousY: 143.38408449046415,
-                       controlPointNextX: 184.98152253372558,
-                       controlPointNextY: 161.28408449046415,
-               });
-
-               expect(chart.data.datasets[0].metaData[3]._model).toEqual({
-                       backgroundColor: Chart.defaults.global.defaultColor,
-                       borderWidth: 1,
-                       borderColor: Chart.defaults.global.defaultColor,
-                       hitRadius: 1,
-                       radius: 3,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0.1,
-
-                       // Point
-                       x: 232,
-                       y: 194,
-
-                       // Control points
-                       controlPointPreviousX: 227,
-                       controlPointPreviousY: 190.2,
-                       controlPointNextX: 232,
-                       controlPointNextY: 194,
-               });
-
-               // Use dataset level styles for lines & points
-               chart.data.datasets[0].tension = 0;
-               chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
-               chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
-               chart.data.datasets[0].borderWidth = 0.55;
-               chart.data.datasets[0].borderCapStyle = 'butt';
-               chart.data.datasets[0].borderDash = [2, 3];
-               chart.data.datasets[0].borderDashOffset = 7;
-               chart.data.datasets[0].borderJoinStyle = 'miter';
-               chart.data.datasets[0].fill = false;
-
-               // point styles
-               chart.data.datasets[0].radius = 22;
-               chart.data.datasets[0].hitRadius = 3.3;
-               chart.data.datasets[0].pointBackgroundColor = 'rgb(128, 129, 130)';
-               chart.data.datasets[0].pointBorderColor = 'rgb(56, 57, 58)';
-               chart.data.datasets[0].pointBorderWidth = 1.123;
-
-               controller.update();
-
-               expect(chart.data.datasets[0].metaDataset._model).toEqual({
-                       backgroundColor: 'rgb(98, 98, 98)',
-                       borderCapStyle: 'butt',
-                       borderColor: 'rgb(8, 8, 8)',
-                       borderDash: [2, 3],
-                       borderDashOffset: 7,
-                       borderJoinStyle: 'miter',
-                       borderWidth: 0.55,
-                       fill: false,
-                       tension: 0,
-
-                       scaleTop: 0,
-                       scaleBottom: 200,
-                       scaleZero: 156,
-               });
-
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual({
-                       backgroundColor: 'rgb(128, 129, 130)',
-                       borderWidth: 1.123,
-                       borderColor: 'rgb(56, 57, 58)',
-                       hitRadius: 3.3,
-                       radius: 22,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0,
-
-                       // Point
-                       x: 81,
-                       y: 62,
-
-                       // Control points
-                       controlPointPreviousX: 81,
-                       controlPointPreviousY: 62,
-                       controlPointNextX: 81,
-                       controlPointNextY: 62,
-               });
-
-               expect(chart.data.datasets[0].metaData[1]._model).toEqual({
-                       backgroundColor: 'rgb(128, 129, 130)',
-                       borderWidth: 1.123,
-                       borderColor: 'rgb(56, 57, 58)',
-                       hitRadius: 3.3,
-                       radius: 22,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0,
-
-                       // Point
-                       x: 131,
-                       y: 15,
-
-                       // Control points
-                       controlPointPreviousX: 131,
-                       controlPointPreviousY: 15,
-                       controlPointNextX: 131,
-                       controlPointNextY: 15,
-               });
-
-               expect(chart.data.datasets[0].metaData[2]._model).toEqual({
-                       backgroundColor: 'rgb(128, 129, 130)',
-                       borderWidth: 1.123,
-                       borderColor: 'rgb(56, 57, 58)',
-                       hitRadius: 3.3,
-                       radius: 22,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0,
-
-                       // Point
-                       x: 182,
-                       y: 156,
-
-                       // Control points
-                       controlPointPreviousX: 182,
-                       controlPointPreviousY: 156,
-                       controlPointNextX: 182,
-                       controlPointNextY: 156,
-               });
-
-               expect(chart.data.datasets[0].metaData[3]._model).toEqual({
-                       backgroundColor: 'rgb(128, 129, 130)',
-                       borderWidth: 1.123,
-                       borderColor: 'rgb(56, 57, 58)',
-                       hitRadius: 3.3,
-                       radius: 22,
-                       pointStyle: 'circle',
-                       skip: false,
-                       tension: 0,
-
-                       // Point
-                       x: 232,
-                       y: 194,
-
-                       // Control points
-                       controlPointPreviousX: 232,
-                       controlPointPreviousY: 194,
-                       controlPointNextX: 232,
-                       controlPointNextY: 194,
-               });
-
-               // Use custom styles for lines & first point
-               chart.data.datasets[0].metaDataset.custom = {
-                       tension: 0.25,
-                       backgroundColor: 'rgb(55, 55, 54)',
-                       borderColor: 'rgb(8, 7, 6)',
-                       borderWidth: 0.3,
-                       borderCapStyle: 'square',
-                       borderDash: [4, 3],
-                       borderDashOffset: 4.4,
-                       borderJoinStyle: 'round',
-                       fill: true,
-               };
-
-               // point styles
-               chart.data.datasets[0].metaData[0].custom = {
-                       radius: 2.2,
-                       backgroundColor: 'rgb(0, 1, 3)',
-                       borderColor: 'rgb(4, 6, 8)',
-                       borderWidth: 0.787,
-                       tension: 0.15,
-                       skip: true,
-                       hitRadius: 5,
-               };
-
-               controller.update();
-
-               expect(chart.data.datasets[0].metaDataset._model).toEqual({
-                       backgroundColor: 'rgb(55, 55, 54)',
-                       borderCapStyle: 'square',
-                       borderColor: 'rgb(8, 7, 6)',
-                       borderDash: [4, 3],
-                       borderDashOffset: 4.4,
-                       borderJoinStyle: 'round',
-                       borderWidth: 0.3,
-                       fill: true,
-                       tension: 0.25,
-
-                       scaleTop: 0,
-                       scaleBottom: 200,
-                       scaleZero: 156,
-               });
-
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual({
-                       backgroundColor: 'rgb(0, 1, 3)',
-                       borderWidth: 0.787,
-                       borderColor: 'rgb(4, 6, 8)',
-                       hitRadius: 5,
-                       radius: 2.2,
-                       pointStyle: 'circle',
-                       skip: true,
-                       tension: 0.15,
-
-                       // Point
-                       x: 81,
-                       y: 62,
-
-                       // Control points
-                       controlPointPreviousX: 81,
-                       controlPointPreviousY: 62,
-                       controlPointNextX: 88.5,
-                       controlPointNextY: 54.95,
-               });
-       });
-
-       it('should update elements when the y scale is stacked', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, 15, -4, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               type: 'line'
-                       }, {
-                               data: [20, 20, 30, -30],
-                               label: 'dataset1',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               type: 'line'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               verticalScaleConfig.stacked = true;
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: xScale.left + 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               showLines: true,
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.global.defaultColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.global.defaultColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                               pointStyle: 'circle'
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               var controller2 = new Chart.controllers.line(chart, 1);
-               controller.update();
-               controller2.update();
-
-               // Line element
-               expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
-                       scaleTop: 0,
-                       scaleBottom: 200,
-                       scaleZero: 100,
-               }));
-
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 91,
-                       y: 77,
-               }));
-
-               expect(chart.data.datasets[0].metaData[1]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 141,
-                       y: 65,
-               }));
-
-               expect(chart.data.datasets[0].metaData[2]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 192,
-                       y: 109,
-               }));
-
-               expect(chart.data.datasets[0].metaData[3]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 242,
-                       y: 109,
-               }));
-
-               expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 91,
-                       y: 30,
-               }));
-
-               expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 141,
-                       y: 18,
-               }));
-
-               expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 192,
-                       y: 30,
-               }));
-
-               expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
-                       // Point
-                       x: 242,
-                       y: 180,
-               }));
-
-
-       });
-
-       it('should find the correct scale zero when the data is all positive', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, 15, 20, 20],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               type: 'line'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               verticalScaleConfig.stacked = true;
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: xScale.left + 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               showLines: true,
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.global.defaultColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.global.defaultColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                               pointStyle: 'circle'
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               controller.update();
-
-               // Line element
-               expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
-                       scaleTop: 0,
-                       scaleBottom: 200,
-                       scaleZero: 194, // yScale.min is the 0 point
-               }));
-       });
-
-       it('should find the correct scale zero when the data is all negative', function() {
-               var data = {
-                       datasets: [{
-                               data: [-10, -15, -20, -20],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-                               type: 'line'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               verticalScaleConfig.stacked = true;
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: xScale.left + 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               showLines: true,
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.global.defaultColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.global.defaultColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                               pointStyle: 'circle'
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               controller.update();
-
-               // Line element
-               expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
-                       scaleTop: 0,
-                       scaleBottom: 200,
-                       scaleZero: 6, // yScale.max is the zero point
-               }));
-       });
-
-       it ('should fall back to the line styles for points', function() {
-               var data = {
-                       datasets: [{
-                               data: [0, 0],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID',
-
-                               // line styles
-                               backgroundColor: 'rgb(98, 98, 98)',
-                               borderColor: 'rgb(8, 8, 8)',
-                               borderWidth: 0.55,
-                       }],
-                       labels: ['label1', 'label2']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0.1,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.global.defaultColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.global.defaultColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               controller.update();
-
-               expect(chart.data.datasets[0].metaData[0]._model.backgroundColor).toBe('rgb(98, 98, 98)');
-               expect(chart.data.datasets[0].metaData[0]._model.borderColor).toBe('rgb(8, 8, 8)');
-               expect(chart.data.datasets[0].metaData[0]._model.borderWidth).toBe(0.55);
-       });
-
-       it('should handle number of data point changes in update', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0.1,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.global.defaultColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.global.defaultColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               chart.data.datasets[0].data = [1, 2]; // remove 2 items
-               controller.buildOrUpdateElements();
-               controller.update();
-               expect(chart.data.datasets[0].metaData.length).toBe(2);
-               expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
-
-               chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items
-               controller.buildOrUpdateElements();
-               controller.update();
-               expect(chart.data.datasets[0].metaData.length).toBe(5);
-               expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
-               expect(chart.data.datasets[0].metaData[4] instanceof Chart.elements.Point).toBe(true);
-       });
-
-       it('should set point hover styles', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               skipNull: true,
-                                               tension: 0.1,
-                                       },
-                                       point: {
-                                               backgroundColor: 'rgb(255, 255, 0)',
-                                               borderWidth: 1,
-                                               borderColor: 'rgb(255, 255, 255)',
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               controller.update();
-               var point = chart.data.datasets[0].metaData[0];
-
-               controller.setHoverStyle(point);
-               expect(point._model.backgroundColor).toBe('rgb(229, 230, 0)');
-               expect(point._model.borderColor).toBe('rgb(230, 230, 230)');
-               expect(point._model.borderWidth).toBe(1);
-               expect(point._model.radius).toBe(4);
-
-               // Can set hover style per dataset
-               chart.data.datasets[0].pointHoverRadius = 3.3;
-               chart.data.datasets[0].pointHoverBackgroundColor = 'rgb(77, 79, 81)';
-               chart.data.datasets[0].pointHoverBorderColor = 'rgb(123, 125, 127)';
-               chart.data.datasets[0].pointHoverBorderWidth = 2.1;
-
-               controller.setHoverStyle(point);
-               expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
-               expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
-               expect(point._model.borderWidth).toBe(2.1);
-               expect(point._model.radius).toBe(3.3);
-
-               // Custom style
-               point.custom = {
-                       hoverRadius: 4.4,
-                       hoverBorderWidth: 5.5,
-                       hoverBackgroundColor: 'rgb(0, 0, 0)',
-                       hoverBorderColor: 'rgb(10, 10, 10)'
-               };
-
-               controller.setHoverStyle(point);
-               expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
-               expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
-               expect(point._model.borderWidth).toBe(5.5);
-               expect(point._model.radius).toBe(4.4);
-       });
-
-       it('should remove hover styles', function() {
-               var data = {
-                       datasets: [{
-                               data: [10, 15, 0, -4],
-                               label: 'dataset2',
-                               xAxisID: 'firstXScaleID',
-                               yAxisID: 'firstYScaleID'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               };
-               var mockContext = window.createMockContext();
-
-               var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
-               var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
-               verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
-               var yScale = new VerticalScaleConstructor({
-                       ctx: mockContext,
-                       options: verticalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstYScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var verticalSize = yScale.update(50, 200);
-               yScale.top = 0;
-               yScale.left = 0;
-               yScale.right = verticalSize.width;
-               yScale.bottom = verticalSize.height;
-
-               var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
-               var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
-               horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
-               var xScale = new HorizontalScaleConstructor({
-                       ctx: mockContext,
-                       options: horizontalScaleConfig,
-                       chart: {
-                               data: data
-                       },
-                       id: 'firstXScaleID'
-               });
-
-               // Update ticks & set physical dimensions
-               var horizontalSize = xScale.update(200, 50);
-               xScale.left = yScale.right;
-               xScale.top = yScale.bottom;
-               xScale.right = horizontalSize.width + xScale.left;
-               xScale.bottom = horizontalSize.height + xScale.top;
-
-
-               var chart = {
-                       chartArea: {
-                               bottom: 200,
-                               left: xScale.left,
-                               right: 200,
-                               top: 0
-                       },
-                       data: data,
-                       config: {
-                               type: 'line'
-                       },
-                       options: {
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0.1,
-                                       },
-                                       point: {
-                                               backgroundColor: 'rgb(255, 255, 0)',
-                                               borderWidth: 1,
-                                               borderColor: 'rgb(255, 255, 255)',
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                       }
-                               },
-                               scales: {
-                                       xAxes: [{
-                                               id: 'firstXScaleID'
-                                       }],
-                                       yAxes: [{
-                                               id: 'firstYScaleID'
-                                       }]
-                               }
-                       },
-                       scales: {
-                               firstXScaleID: xScale,
-                               firstYScaleID: yScale,
-                       }
-               };
-
-               var controller = new Chart.controllers.line(chart, 0);
-               controller.update();
-               var point = chart.data.datasets[0].metaData[0];
-
-               chart.options.elements.point.backgroundColor = 'rgb(45, 46, 47)';
-               chart.options.elements.point.borderColor = 'rgb(50, 51, 52)';
-               chart.options.elements.point.borderWidth = 10.1;
-               chart.options.elements.point.radius = 1.01;
-
-               controller.removeHoverStyle(point);
-               expect(point._model.backgroundColor).toBe('rgb(45, 46, 47)');
-               expect(point._model.borderColor).toBe('rgb(50, 51, 52)');
-               expect(point._model.borderWidth).toBe(10.1);
-               expect(point._model.radius).toBe(1.01);
-
-               // Can set hover style per dataset
-               chart.data.datasets[0].radius = 3.3;
-               chart.data.datasets[0].pointBackgroundColor = 'rgb(77, 79, 81)';
-               chart.data.datasets[0].pointBorderColor = 'rgb(123, 125, 127)';
-               chart.data.datasets[0].pointBorderWidth = 2.1;
-
-               controller.removeHoverStyle(point);
-               expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
-               expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
-               expect(point._model.borderWidth).toBe(2.1);
-               expect(point._model.radius).toBe(3.3);
-
-               // Custom style
-               point.custom = {
-                       radius: 4.4,
-                       borderWidth: 5.5,
-                       backgroundColor: 'rgb(0, 0, 0)',
-                       borderColor: 'rgb(10, 10, 10)'
-               };
-
-               controller.removeHoverStyle(point);
-               expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
-               expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
-               expect(point._model.borderWidth).toBe(5.5);
-               expect(point._model.radius).toBe(4.4);
-       });
+  it('Should be constructed', function() {
+    var chart = {
+      data: {
+        datasets: [{
+          xAxisID: 'myXAxis',
+          yAxisID: 'myYAxis',
+          data: []
+        }]
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    expect(controller).not.toBe(undefined);
+    expect(controller.index).toBe(0);
+    expect(chart.data.datasets[0].metaData).toEqual([]);
+
+    controller.updateIndex(1);
+    expect(controller.index).toBe(1);
+  });
+
+  it('Should use the first scale IDs if the dataset does not specify them', function() {
+    var chart = {
+      data: {
+        datasets: [{
+          data: []
+        }]
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    expect(chart.data.datasets[0].xAxisID).toBe('firstXScaleID');
+    expect(chart.data.datasets[0].yAxisID).toBe('firstYScaleID');
+  });
+
+  it('Should create line elements and point elements for each data item during initialization', function() {
+    var chart = {
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4]
+        }]
+      },
+      config: {
+        type: 'line'
+      },
+      options: {
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+
+    expect(chart.data.datasets[0].metaData.length).toBe(4); // 4 points created
+    expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaDataset instanceof Chart.elements.Line).toBe(true); // 1 line element
+  });
+
+  it('should draw all elements', function() {
+    var chart = {
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4]
+        }]
+      },
+      config: {
+        type: 'line'
+      },
+      options: {
+        showLines: true,
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+
+    spyOn(chart.data.datasets[0].metaDataset, 'draw');
+    spyOn(chart.data.datasets[0].metaData[0], 'draw');
+    spyOn(chart.data.datasets[0].metaData[1], 'draw');
+    spyOn(chart.data.datasets[0].metaData[2], 'draw');
+    spyOn(chart.data.datasets[0].metaData[3], 'draw');
+
+    controller.draw();
+
+    expect(chart.data.datasets[0].metaDataset.draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should draw all elements except lines', function() {
+    var chart = {
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4]
+        }]
+      },
+      config: {
+        type: 'line'
+      },
+      options: {
+        showLines: false,
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+
+    spyOn(chart.data.datasets[0].metaDataset, 'draw');
+    spyOn(chart.data.datasets[0].metaData[0], 'draw');
+    spyOn(chart.data.datasets[0].metaData[1], 'draw');
+    spyOn(chart.data.datasets[0].metaData[2], 'draw');
+    spyOn(chart.data.datasets[0].metaData[3], 'draw');
+
+    controller.draw();
+
+    expect(chart.data.datasets[0].metaDataset.draw.calls.count()).toBe(0);
+    expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
+    expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should update elements', function() {
+    var data = {
+      datasets: [{
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: xScale.left + 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        showLines: true,
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0.1,
+          },
+          point: {
+            backgroundColor: Chart.defaults.global.defaultColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.global.defaultColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+            pointStyle: 'circle'
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    controller.update();
+
+    // Line element
+    expect(chart.data.datasets[0].metaDataset._model).toEqual({
+      backgroundColor: 'rgb(255, 0, 0)',
+      borderCapStyle: 'round',
+      borderColor: 'rgb(0, 255, 0)',
+      borderDash: [],
+      borderDashOffset: 0.1,
+      borderJoinStyle: 'bevel',
+      borderWidth: 1.2,
+      fill: true,
+      tension: 0.1,
+
+      scaleTop: 0,
+      scaleBottom: 200,
+      scaleZero: 156,
+    });
+
+    expect(chart.data.datasets[0].metaData[0]._model).toEqual({
+      backgroundColor: Chart.defaults.global.defaultColor,
+      borderWidth: 1,
+      borderColor: Chart.defaults.global.defaultColor,
+      hitRadius: 1,
+      radius: 3,
+      pointStyle: 'circle',
+      skip: false,
+      tension: 0.1,
+
+      // Point
+      x: 82,
+      y: 62,
+
+      // Control points
+      controlPointPreviousX: 82,
+      controlPointPreviousY: 62,
+      controlPointNextX: 87,
+      controlPointNextY: 57.3
+    });
+
+    expect(chart.data.datasets[0].metaData[1]._model).toEqual({
+      x: 132,
+      y: 15,
+      tension: 0.1,
+      radius: 3,
+      pointStyle: 'circle',
+      backgroundColor: 'rgba(0,0,0,0.1)',
+      borderColor: 'rgba(0,0,0,0.1)',
+      borderWidth: 1,
+      hitRadius: 1,
+      skip: false,
+      controlPointPreviousX: 128.85543975158012,
+      controlPointPreviousY: 12.044113366485313,
+      controlPointNextX: 138.85543975158012,
+      controlPointNextY: 21.444113366485315
+    });
+
+    expect(chart.data.datasets[0].metaData[2]._model).toEqual({
+      x: 182,
+      y: 156,
+      tension: 0.1,
+      radius: 3,
+      pointStyle: 'circle',
+      backgroundColor: 'rgba(0,0,0,0.1)',
+      borderColor: 'rgba(0,0,0,0.1)',
+      borderWidth: 1,
+      hitRadius: 1,
+      skip: false,
+      controlPointPreviousX: 174.95668866051852,
+      controlPointPreviousY: 143.39247270232818,
+      controlPointNextX: 184.95668866051852,
+      controlPointNextY: 161.29247270232815
+    });
+
+    expect(chart.data.datasets[0].metaData[3]._model).toEqual({
+      backgroundColor: Chart.defaults.global.defaultColor,
+      borderWidth: 1,
+      borderColor: Chart.defaults.global.defaultColor,
+      hitRadius: 1,
+      radius: 3,
+      pointStyle: 'circle',
+      skip: false,
+      tension: 0.1,
+
+      // Point
+      x: 232,
+      y: 194,
+
+      // Control points
+      controlPointPreviousX: 227,
+      controlPointPreviousY: 190.2,
+      controlPointNextX: 232,
+      controlPointNextY: 194,
+    });
+
+    // Use dataset level styles for lines & points
+    chart.data.datasets[0].tension = 0;
+    chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
+    chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
+    chart.data.datasets[0].borderWidth = 0.55;
+    chart.data.datasets[0].borderCapStyle = 'butt';
+    chart.data.datasets[0].borderDash = [2, 3];
+    chart.data.datasets[0].borderDashOffset = 7;
+    chart.data.datasets[0].borderJoinStyle = 'miter';
+    chart.data.datasets[0].fill = false;
+
+    // point styles
+    chart.data.datasets[0].radius = 22;
+    chart.data.datasets[0].hitRadius = 3.3;
+    chart.data.datasets[0].pointBackgroundColor = 'rgb(128, 129, 130)';
+    chart.data.datasets[0].pointBorderColor = 'rgb(56, 57, 58)';
+    chart.data.datasets[0].pointBorderWidth = 1.123;
+
+    controller.update();
+
+    expect(chart.data.datasets[0].metaDataset._model).toEqual({
+      backgroundColor: 'rgb(98, 98, 98)',
+      borderCapStyle: 'butt',
+      borderColor: 'rgb(8, 8, 8)',
+      borderDash: [2, 3],
+      borderDashOffset: 7,
+      borderJoinStyle: 'miter',
+      borderWidth: 0.55,
+      fill: false,
+      tension: 0,
+
+      scaleTop: 0,
+      scaleBottom: 200,
+      scaleZero: 156,
+    });
+
+    expect(chart.data.datasets[0].metaData[0]._model).toEqual({
+      x: 82,
+      y: 62,
+      tension: 0,
+      radius: 22,
+      pointStyle: 'circle',
+      backgroundColor: 'rgb(128, 129, 130)',
+      borderColor: 'rgb(56, 57, 58)',
+      borderWidth: 1.123,
+      hitRadius: 3.3,
+      skip: false,
+      controlPointPreviousX: 82,
+      controlPointPreviousY: 62,
+      controlPointNextX: 82,
+      controlPointNextY: 62
+    });
+
+    expect(chart.data.datasets[0].metaData[1]._model).toEqual({
+      x: 132,
+      y: 15,
+      tension: 0,
+      radius: 22,
+      pointStyle: 'circle',
+      backgroundColor: 'rgb(128, 129, 130)',
+      borderColor: 'rgb(56, 57, 58)',
+      borderWidth: 1.123,
+      hitRadius: 3.3,
+      skip: false,
+      controlPointPreviousX: 132,
+      controlPointPreviousY: 15,
+      controlPointNextX: 132,
+      controlPointNextY: 15
+    });
+
+    expect(chart.data.datasets[0].metaData[2]._model).toEqual({
+      backgroundColor: 'rgb(128, 129, 130)',
+      borderWidth: 1.123,
+      borderColor: 'rgb(56, 57, 58)',
+      hitRadius: 3.3,
+      radius: 22,
+      pointStyle: 'circle',
+      skip: false,
+      tension: 0,
+
+      // Point
+      x: 182,
+      y: 156,
+
+      // Control points
+      controlPointPreviousX: 182,
+      controlPointPreviousY: 156,
+      controlPointNextX: 182,
+      controlPointNextY: 156,
+    });
+
+    expect(chart.data.datasets[0].metaData[3]._model).toEqual({
+      backgroundColor: 'rgb(128, 129, 130)',
+      borderWidth: 1.123,
+      borderColor: 'rgb(56, 57, 58)',
+      hitRadius: 3.3,
+      radius: 22,
+      pointStyle: 'circle',
+      skip: false,
+      tension: 0,
+
+      // Point
+      x: 232,
+      y: 194,
+
+      // Control points
+      controlPointPreviousX: 232,
+      controlPointPreviousY: 194,
+      controlPointNextX: 232,
+      controlPointNextY: 194,
+    });
+
+    // Use custom styles for lines & first point
+    chart.data.datasets[0].metaDataset.custom = {
+      tension: 0.25,
+      backgroundColor: 'rgb(55, 55, 54)',
+      borderColor: 'rgb(8, 7, 6)',
+      borderWidth: 0.3,
+      borderCapStyle: 'square',
+      borderDash: [4, 3],
+      borderDashOffset: 4.4,
+      borderJoinStyle: 'round',
+      fill: true,
+    };
+
+    // point styles
+    chart.data.datasets[0].metaData[0].custom = {
+      radius: 2.2,
+      backgroundColor: 'rgb(0, 1, 3)',
+      borderColor: 'rgb(4, 6, 8)',
+      borderWidth: 0.787,
+      tension: 0.15,
+      skip: true,
+      hitRadius: 5,
+    };
+
+    controller.update();
+
+    expect(chart.data.datasets[0].metaDataset._model).toEqual({
+      backgroundColor: 'rgb(55, 55, 54)',
+      borderCapStyle: 'square',
+      borderColor: 'rgb(8, 7, 6)',
+      borderDash: [4, 3],
+      borderDashOffset: 4.4,
+      borderJoinStyle: 'round',
+      borderWidth: 0.3,
+      fill: true,
+      tension: 0.25,
+
+      scaleTop: 0,
+      scaleBottom: 200,
+      scaleZero: 156,
+    });
+
+    expect(chart.data.datasets[0].metaData[0]._model).toEqual({
+      x: 82,
+      y: 62,
+      tension: 0.15,
+      radius: 2.2,
+      pointStyle: 'circle',
+      backgroundColor: 'rgb(0, 1, 3)',
+      borderColor: 'rgb(4, 6, 8)',
+      borderWidth: 0.787,
+      hitRadius: 5,
+      skip: true,
+      controlPointPreviousX: 82,
+      controlPointPreviousY: 62,
+      controlPointNextX: 89.5,
+      controlPointNextY: 54.95
+    });
+  });
+
+  it('should update elements when the y scale is stacked', function() {
+    var data = {
+      datasets: [{
+        data: [10, 15, -4, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        type: 'line'
+      }, {
+        data: [20, 20, 30, -30],
+        label: 'dataset1',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        type: 'line'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    verticalScaleConfig.stacked = true;
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: xScale.left + 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        showLines: true,
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0,
+          },
+          point: {
+            backgroundColor: Chart.defaults.global.defaultColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.global.defaultColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+            pointStyle: 'circle'
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    var controller2 = new Chart.controllers.line(chart, 1);
+    controller.update();
+    controller2.update();
+
+    // Line element
+    expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
+      scaleTop: 0,
+      scaleBottom: 200,
+      scaleZero: 100
+    }));
+
+    expect(chart.data.datasets[0].metaData[0]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 92,
+      y: 77
+    }));
+
+    expect(chart.data.datasets[0].metaData[1]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 142,
+      y: 65
+    }));
+
+    expect(chart.data.datasets[0].metaData[2]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 192,
+      y: 109
+    }));
+
+    expect(chart.data.datasets[0].metaData[3]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 242,
+      y: 109
+    }));
+
+    expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 92,
+      y: 30
+    }));
+
+    expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 142,
+      y: 18
+    }));
+
+    expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 192,
+      y: 30
+    }));
+
+    expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
+      // Point
+      x: 242,
+      y: 180
+    }));
+
+
+  });
+
+  it('should find the correct scale zero when the data is all positive', function() {
+    var data = {
+      datasets: [{
+        data: [10, 15, 20, 20],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        type: 'line'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    verticalScaleConfig.stacked = true;
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: xScale.left + 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        showLines: true,
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0,
+          },
+          point: {
+            backgroundColor: Chart.defaults.global.defaultColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.global.defaultColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+            pointStyle: 'circle'
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    controller.update();
+
+    // Line element
+    expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
+      scaleTop: 0,
+      scaleBottom: 200,
+      scaleZero: 194, // yScale.min is the 0 point
+    }));
+  });
+
+  it('should find the correct scale zero when the data is all negative', function() {
+    var data = {
+      datasets: [{
+        data: [-10, -15, -20, -20],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+        type: 'line'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    verticalScaleConfig.stacked = true;
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: xScale.left + 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        showLines: true,
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0,
+          },
+          point: {
+            backgroundColor: Chart.defaults.global.defaultColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.global.defaultColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+            pointStyle: 'circle'
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    controller.update();
+
+    // Line element
+    expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
+      scaleTop: 0,
+      scaleBottom: 200,
+      scaleZero: 6, // yScale.max is the zero point
+    }));
+  });
+
+  it('should fall back to the line styles for points', function() {
+    var data = {
+      datasets: [{
+        data: [0, 0],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID',
+
+        // line styles
+        backgroundColor: 'rgb(98, 98, 98)',
+        borderColor: 'rgb(8, 8, 8)',
+        borderWidth: 0.55,
+      }],
+      labels: ['label1', 'label2']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0.1,
+          },
+          point: {
+            backgroundColor: Chart.defaults.global.defaultColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.global.defaultColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    controller.update();
+
+    expect(chart.data.datasets[0].metaData[0]._model.backgroundColor).toBe('rgb(98, 98, 98)');
+    expect(chart.data.datasets[0].metaData[0]._model.borderColor).toBe('rgb(8, 8, 8)');
+    expect(chart.data.datasets[0].metaData[0]._model.borderWidth).toBe(0.55);
+  });
+
+  it('should handle number of data point changes in update', function() {
+    var data = {
+      datasets: [{
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0.1,
+          },
+          point: {
+            backgroundColor: Chart.defaults.global.defaultColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.global.defaultColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    chart.data.datasets[0].data = [1, 2]; // remove 2 items
+    controller.buildOrUpdateElements();
+    controller.update();
+    expect(chart.data.datasets[0].metaData.length).toBe(2);
+    expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
+
+    chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items
+    controller.buildOrUpdateElements();
+    controller.update();
+    expect(chart.data.datasets[0].metaData.length).toBe(5);
+    expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
+    expect(chart.data.datasets[0].metaData[4] instanceof Chart.elements.Point).toBe(true);
+  });
+
+  it('should set point hover styles', function() {
+    var data = {
+      datasets: [{
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            skipNull: true,
+            tension: 0.1,
+          },
+          point: {
+            backgroundColor: 'rgb(255, 255, 0)',
+            borderWidth: 1,
+            borderColor: 'rgb(255, 255, 255)',
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    controller.update();
+    var point = chart.data.datasets[0].metaData[0];
+
+    controller.setHoverStyle(point);
+    expect(point._model.backgroundColor).toBe('rgb(229, 230, 0)');
+    expect(point._model.borderColor).toBe('rgb(230, 230, 230)');
+    expect(point._model.borderWidth).toBe(1);
+    expect(point._model.radius).toBe(4);
+
+    // Can set hover style per dataset
+    chart.data.datasets[0].pointHoverRadius = 3.3;
+    chart.data.datasets[0].pointHoverBackgroundColor = 'rgb(77, 79, 81)';
+    chart.data.datasets[0].pointHoverBorderColor = 'rgb(123, 125, 127)';
+    chart.data.datasets[0].pointHoverBorderWidth = 2.1;
+
+    controller.setHoverStyle(point);
+    expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
+    expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
+    expect(point._model.borderWidth).toBe(2.1);
+    expect(point._model.radius).toBe(3.3);
+
+    // Custom style
+    point.custom = {
+      hoverRadius: 4.4,
+      hoverBorderWidth: 5.5,
+      hoverBackgroundColor: 'rgb(0, 0, 0)',
+      hoverBorderColor: 'rgb(10, 10, 10)'
+    };
+
+    controller.setHoverStyle(point);
+    expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
+    expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
+    expect(point._model.borderWidth).toBe(5.5);
+    expect(point._model.radius).toBe(4.4);
+  });
+
+  it('should remove hover styles', function() {
+    var data = {
+      datasets: [{
+        data: [10, 15, 0, -4],
+        label: 'dataset2',
+        xAxisID: 'firstXScaleID',
+        yAxisID: 'firstYScaleID'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    };
+    var mockContext = window.createMockContext();
+
+    var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
+    var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
+    verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
+    var yScale = new VerticalScaleConstructor({
+      ctx: mockContext,
+      options: verticalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstYScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var verticalSize = yScale.update(50, 200);
+    yScale.top = 0;
+    yScale.left = 0;
+    yScale.right = verticalSize.width;
+    yScale.bottom = verticalSize.height;
+
+    var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
+    var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+    horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
+    var xScale = new HorizontalScaleConstructor({
+      ctx: mockContext,
+      options: horizontalScaleConfig,
+      chart: {
+        data: data
+      },
+      id: 'firstXScaleID'
+    });
+
+    // Update ticks & set physical dimensions
+    var horizontalSize = xScale.update(200, 50);
+    xScale.left = yScale.right;
+    xScale.top = yScale.bottom;
+    xScale.right = horizontalSize.width + xScale.left;
+    xScale.bottom = horizontalSize.height + xScale.top;
+
+
+    var chart = {
+      chartArea: {
+        bottom: 200,
+        left: xScale.left,
+        right: 200,
+        top: 0
+      },
+      data: data,
+      config: {
+        type: 'line'
+      },
+      options: {
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0.1,
+          },
+          point: {
+            backgroundColor: 'rgb(255, 255, 0)',
+            borderWidth: 1,
+            borderColor: 'rgb(255, 255, 255)',
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+          }
+        },
+        scales: {
+          xAxes: [{
+            id: 'firstXScaleID'
+          }],
+          yAxes: [{
+            id: 'firstYScaleID'
+          }]
+        }
+      },
+      scales: {
+        firstXScaleID: xScale,
+        firstYScaleID: yScale,
+      }
+    };
+
+    var controller = new Chart.controllers.line(chart, 0);
+    controller.update();
+    var point = chart.data.datasets[0].metaData[0];
+
+    chart.options.elements.point.backgroundColor = 'rgb(45, 46, 47)';
+    chart.options.elements.point.borderColor = 'rgb(50, 51, 52)';
+    chart.options.elements.point.borderWidth = 10.1;
+    chart.options.elements.point.radius = 1.01;
+
+    controller.removeHoverStyle(point);
+    expect(point._model.backgroundColor).toBe('rgb(45, 46, 47)');
+    expect(point._model.borderColor).toBe('rgb(50, 51, 52)');
+    expect(point._model.borderWidth).toBe(10.1);
+    expect(point._model.radius).toBe(1.01);
+
+    // Can set hover style per dataset
+    chart.data.datasets[0].radius = 3.3;
+    chart.data.datasets[0].pointBackgroundColor = 'rgb(77, 79, 81)';
+    chart.data.datasets[0].pointBorderColor = 'rgb(123, 125, 127)';
+    chart.data.datasets[0].pointBorderWidth = 2.1;
+
+    controller.removeHoverStyle(point);
+    expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
+    expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
+    expect(point._model.borderWidth).toBe(2.1);
+    expect(point._model.radius).toBe(3.3);
+
+    // Custom style
+    point.custom = {
+      radius: 4.4,
+      borderWidth: 5.5,
+      backgroundColor: 'rgb(0, 0, 0)',
+      borderColor: 'rgb(10, 10, 10)'
+    };
+
+    controller.removeHoverStyle(point);
+    expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
+    expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
+    expect(point._model.borderWidth).toBe(5.5);
+    expect(point._model.radius).toBe(4.4);
+  });
 });
index b0fa09555f7868ed7c6b7434a0e698a7902f95f5..3721e3b413f6fe09664f11393082cfa7c58ebe4a 100644 (file)
@@ -230,14 +230,14 @@ describe('Core helper tests', function() {
                                        },
                                        ticks: {
                                                beginAtZero: false,
-                                               maxRotation: 90,
+                                               maxRotation: 50,
                                                mirror: false,
                                                padding: 10,
                                                reverse: false,
                                                display: true,
                                                callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
                                                autoSkip: true,
-                                               autoSkipPadding: 20
+                                               autoSkipPadding: 0
                                        },
                                        type: 'linear'
                                }, {
@@ -260,14 +260,14 @@ describe('Core helper tests', function() {
                                        },
                                        ticks: {
                                                beginAtZero: false,
-                                               maxRotation: 90,
+                                               maxRotation: 50,
                                                mirror: false,
                                                padding: 10,
                                                reverse: false,
                                                display: true,
                                                callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
                                                autoSkip: true,
-                                               autoSkipPadding: 20
+                                               autoSkipPadding: 0
                                        },
                                        type: 'linear'
                                }]
index da0e4c1e54a3143c4433de8ef08145f2620165df..4a0f6cdb9b59aecb5534597cd64aedbded2c0093 100644 (file)
@@ -49,21 +49,21 @@ describe('Test the layout service', function() {
                        left: 50,
                        right: 250,
                        top: 0,
-                       bottom: 81.0423977855504,
+                       bottom: 83.6977778440511,
                });
 
                // Is xScale at the right spot
                expect(xScale.left).toBe(50);
                expect(xScale.right).toBe(250);
-               expect(xScale.top).toBe(81.0423977855504);
+               expect(xScale.top).toBe(83.6977778440511);
                expect(xScale.bottom).toBe(150);
-               expect(xScale.labelRotation).toBe(55);
+               expect(xScale.labelRotation).toBe(50);
 
                // Is yScale at the right spot
                expect(yScale.left).toBe(0);
                expect(yScale.right).toBe(50);
                expect(yScale.top).toBe(0);
-               expect(yScale.bottom).toBe(81.0423977855504);
+               expect(yScale.bottom).toBe(83.6977778440511);
        });
 
        it('should fit scales that are in the top and right positions', function() {
@@ -116,7 +116,7 @@ describe('Test the layout service', function() {
                expect(chartInstance.chartArea).toEqual({
                        left: 0,
                        right: 200,
-                       top: 68.9576022144496,
+                       top: 66.3022221559489,
                        bottom: 150,
                });
 
@@ -124,13 +124,13 @@ describe('Test the layout service', function() {
                expect(xScale.left).toBe(0);
                expect(xScale.right).toBe(200);
                expect(xScale.top).toBe(0);
-               expect(xScale.bottom).toBe(68.9576022144496);
-               expect(xScale.labelRotation).toBe(55);
+               expect(xScale.bottom).toBe(66.3022221559489);
+               expect(xScale.labelRotation).toBe(50);
 
                // Is yScale at the right spot
                expect(yScale.left).toBe(200);
                expect(yScale.right).toBe(250);
-               expect(yScale.top).toBe(68.9576022144496);
+               expect(yScale.top).toBe(66.3022221559489);
                expect(yScale.bottom).toBe(150);
        });
 
@@ -196,30 +196,30 @@ describe('Test the layout service', function() {
                        left: 110,
                        right: 250,
                        top: 0,
-                       bottom: 75,
+                       bottom: 83.6977778440511,
                });
 
                // Is xScale at the right spot
                expect(xScale.left).toBe(110);
                expect(xScale.right).toBe(250);
-               expect(xScale.top).toBe(75);
+               expect(xScale.top).toBe(83.6977778440511);
                expect(xScale.bottom).toBe(150);
 
                // Are yScales at the right spot
                expect(yScale1.left).toBe(0);
                expect(yScale1.right).toBe(50);
                expect(yScale1.top).toBe(0);
-               expect(yScale1.bottom).toBe(75);
+               expect(yScale1.bottom).toBe(83.6977778440511);
 
                expect(yScale2.left).toBe(50);
                expect(yScale2.right).toBe(110);
                expect(yScale2.top).toBe(0);
-               expect(yScale2.bottom).toBe(75);
+               expect(yScale2.bottom).toBe(83.6977778440511);
        });
 
        // This is an oddball case. What happens is, when the scales are fit the first time they must fit within the assigned size. In this case,
-       // the labels on the xScale need to rotate to fit. However, when the scales are fit again after the width of the left axis is determined, 
-       // the labels do not need to rotate. Previously, the chart was too small because the chartArea did not expand to take up the space freed up 
+       // the labels on the xScale need to rotate to fit. However, when the scales are fit again after the width of the left axis is determined,
+       // the labels do not need to rotate. Previously, the chart was too small because the chartArea did not expand to take up the space freed up
        // due to the lack of label rotation
        it('should fit scales that overlap the chart area', function() {
                var chartInstance = {
@@ -337,13 +337,13 @@ describe('Test the layout service', function() {
                        left: 60,
                        right: 250,
                        top: 54.495963211660246,
-                       bottom: 80.0664716027288,
+                       bottom: 83.6977778440511
                });
 
                // Are xScales at the right spot
                expect(xScale1.left).toBe(60);
                expect(xScale1.right).toBe(250);
-               expect(xScale1.top).toBeCloseTo(80.06, 1e-3);
+               expect(xScale1.top).toBeCloseTo(83.69, 1e-3);
                expect(xScale1.bottom).toBe(150);
 
                expect(xScale2.left).toBe(0);
@@ -355,6 +355,6 @@ describe('Test the layout service', function() {
                expect(yScale.left).toBe(0);
                expect(yScale.right).toBe(60);
                expect(yScale.top).toBeCloseTo(54.49, 1e-3);
-               expect(yScale.bottom).toBeCloseTo(80.06, 1e-3);
+               expect(yScale.bottom).toBeCloseTo(83.69, 1e-3);
        });
-});
\ No newline at end of file
+});
index c59504a8b7d719432f415fc03812f404cf680290..47645fe2391842feacf857d18894036d9a09b1c5 100644 (file)
@@ -20,23 +20,23 @@ describe('Category scale tests', function() {
                                offsetGridLines: false,
                                display: true,
                                zeroLineColor: "rgba(0,0,0,0.25)",
-                               zeroLineWidth: 1,
+                               zeroLineWidth: 1
                        },
                        position: "bottom",
                        scaleLabel: {
                                labelString: '',
-                               display: false,
+                               display: false
                        },
                        ticks: {
                                beginAtZero: false,
-                               maxRotation: 90,
+                               maxRotation: 50,
                                mirror: false,
                                padding: 10,
                                reverse: false,
                                display: true,
                                callback: defaultConfig.ticks.callback,  // make this nicer, then check explicitly below
                                autoSkip: true,
-                               autoSkipPadding: 20
+                               autoSkipPadding: 0
                        }
                });
 
@@ -93,7 +93,7 @@ describe('Category scale tests', function() {
                });
 
                scale.buildTicks();
-               
+
                expect(scale.getLabelForIndex(1)).toBe('tick2');
        });
 
@@ -340,4 +340,4 @@ describe('Category scale tests', function() {
                expect(scale.getPixelForValue(0, 3, 0, false)).toBe(199);
                expect(scale.getPixelForValue(0, 3, 0, true)).toBe(199);
        });
-});
\ No newline at end of file
+});
index 85d076bf68e7d8127a361cfd0eed3aa0cdbec267..1de340d4ed2e456452497e07c0b9c4dfb338a07d 100644 (file)
@@ -28,14 +28,14 @@ describe('Linear Scale', function() {
                        },
                        ticks: {
                                beginAtZero: false,
-                               maxRotation: 90,
+                               maxRotation: 50,
                                mirror: false,
                                padding: 10,
                                reverse: false,
                                display: true,
                                callback: defaultConfig.ticks.callback, // make this work nicer, then check below
                                autoSkip: true,
-                               autoSkipPadding: 20
+                               autoSkipPadding: 0
                        }
                });
 
@@ -2049,4 +2049,4 @@ describe('Linear Scale', function() {
                        "args": []
                }])
        });
-});
\ No newline at end of file
+});
index 2d315e9da934d7f8784d3a6785d8dba9323ac4f2..6f286623779397772eabce718b907fe4db690260 100644 (file)
@@ -27,14 +27,14 @@ describe('Logarithmic Scale tests', function() {
                        },
                        ticks: {
                                beginAtZero: false,
-                               maxRotation: 90,
+                               maxRotation: 50,
                                mirror: false,
                                padding: 10,
                                reverse: false,
                                display: true,
                                callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
                                autoSkip: true,
-                               autoSkipPadding: 20
+                               autoSkipPadding: 0
                        },
                });
 
@@ -626,4 +626,4 @@ describe('Logarithmic Scale tests', function() {
                expect(horizontalScale.getPixelForValue(10, 0, 0)).toBeCloseTo(57.5, 1e-4); // halfway
                expect(horizontalScale.getPixelForValue(0, 0, 0)).toBe(5); // 0 is invalid, put it on the left.
        });
-});
\ No newline at end of file
+});
index cd0386a0941d72786318cc764dd5fb9ec0631d1e..566e61b6aae373ba602bbe5ac3e64fd831d44f41 100644 (file)
@@ -41,7 +41,7 @@ describe('Test the radial linear scale', function() {
                                backdropPaddingY: 2,
                                backdropPaddingX: 2,
                                beginAtZero: false,
-                               maxRotation: 90,
+                               maxRotation: 50,
                                mirror: false,
                                padding: 10,
                                reverse: false,
@@ -49,7 +49,7 @@ describe('Test the radial linear scale', function() {
                                display: true,
                                callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
                                autoSkip: true,
-                               autoSkipPadding: 20
+                               autoSkipPadding: 0
                        },
                });
 
index 72619c6dd4cb97cb34b91e290fadcf11c9c77bcf..244daff636944d5627042b51c57d2a6ac3ee1bc9 100644 (file)
@@ -44,23 +44,23 @@ describe('Time scale tests', function() {
                                offsetGridLines: false,
                                display: true,
                                zeroLineColor: "rgba(0,0,0,0.25)",
-                               zeroLineWidth: 1,
+                               zeroLineWidth: 1
                        },
                        position: "bottom",
                        scaleLabel: {
                                labelString: '',
-                               display: false,
+                               display: false
                        },
                        ticks: {
                                beginAtZero: false,
-                               maxRotation: 90,
+                               maxRotation: 50,
                                mirror: false,
                                padding: 10,
                                reverse: false,
                                display: true,
                                callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below,
                                autoSkip: false,
-                               autoSkipPadding: 20
+                               autoSkipPadding: 0
                        },
                        time: {
                                parser: false,
@@ -77,8 +77,8 @@ describe('Time scale tests', function() {
                                        'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
                                        'month': 'MMM YYYY', // Sept 2015
                                        'quarter': '[Q]Q - YYYY', // Q3
-                                       'year': 'YYYY', // 2015
-                               },
+                                       'year': 'YYYY' // 2015
+                               }
                        }
                });
 
@@ -108,7 +108,7 @@ describe('Time scale tests', function() {
                scale.update(400, 50);
 
                // Counts down because the lines are drawn top to bottom
-               expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
+               expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 6, 2015', 'Jan 11, 2015' ]);
        });
 
        it('should build ticks using date objects', function() {
@@ -136,7 +136,7 @@ describe('Time scale tests', function() {
                scale.update(400, 50);
 
                // Counts down because the lines are drawn top to bottom
-               expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
+               expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 6, 2015', 'Jan 11, 2015' ]);
        });
 
        it('should build ticks when the data is xy points', function() {
@@ -187,7 +187,7 @@ describe('Time scale tests', function() {
                scale.update(400, 50);
 
                // Counts down because the lines are drawn top to bottom
-               expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
+               expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 6, 2015', 'Jan 11, 2015' ]);
        });
 
        it('should allow custom time parsers', function() {
@@ -302,7 +302,7 @@ describe('Time scale tests', function() {
                });
 
                scale.update(400, 50);
-               expect(scale.ticks).toEqual(['Jan 1, 4AM', 'Jan 1, 4PM', 'Jan 2, 4AM', 'Jan 2, 4PM', 'Jan 3, 4AM', 'Jan 3, 4PM', 'Jan 4, 4AM', 'Jan 4, 4PM', 'Jan 5, 4AM', 'Jan 5, 6AM']);
+               expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015' ]);
        });
 
        it('should get the correct pixel for a value', function() {
@@ -329,14 +329,14 @@ describe('Time scale tests', function() {
                scale.update(400, 50);
 
                expect(scale.width).toBe(400);
-               expect(scale.height).toBe(50);
+               expect(scale.height).toBe(28);
                scale.left = 0;
                scale.right = 400;
                scale.top = 10;
                scale.bottom = 38;
 
-               expect(scale.getPixelForValue('', 0, 0)).toBe(128);
-               expect(scale.getPixelForValue('', 6, 0)).toBe(380);
+               expect(scale.getPixelForValue('', 0, 0)).toBe(81);
+               expect(scale.getPixelForValue('', 6, 0)).toBe(323);
 
                var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
                verticalScaleConfig.position = "left";
@@ -385,7 +385,7 @@ describe('Time scale tests', function() {
                scale.update(400, 50);
 
                expect(scale.width).toBe(400);
-               expect(scale.height).toBe(50);
+               expect(scale.height).toBe(28);
                scale.left = 0;
                scale.right = 400;
                scale.top = 10;