]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Make `Chart.layout(Service)` importable (#5113)
authorSimon Brunel <simonbrunel@users.noreply.github.com>
Sun, 7 Jan 2018 22:38:26 +0000 (23:38 +0100)
committerGitHub <noreply@github.com>
Sun, 7 Jan 2018 22:38:26 +0000 (23:38 +0100)
Rename (and deprecate) `Chart.layoutService` to `Chart.layout` and make it importable.

src/chart.js
src/core/core.controller.js
src/core/core.layout.js [new file with mode: 0644]
src/core/core.layoutService.js [deleted file]
src/core/core.scaleService.js
src/plugins/plugin.legend.js
src/plugins/plugin.title.js
test/specs/global.deprecations.tests.js

index 8bd49761461bad0eea9bd3350fdfdbb38c791ff1..b46e66b9e6fb3f48631904cada2ea149899d086e 100644 (file)
@@ -12,6 +12,7 @@ Chart.defaults = require('./core/core.defaults');
 Chart.Element = require('./core/core.element');
 Chart.elements = require('./elements/index');
 Chart.Interaction = require('./core/core.interaction');
+Chart.layout = require('./core/core.layout');
 Chart.platform = require('./platforms/platform');
 Chart.Ticks = require('./core/core.ticks');
 
@@ -19,7 +20,6 @@ require('./core/core.plugin')(Chart);
 require('./core/core.animation')(Chart);
 require('./core/core.controller')(Chart);
 require('./core/core.datasetController')(Chart);
-require('./core/core.layoutService')(Chart);
 require('./core/core.scaleService')(Chart);
 require('./core/core.scale')(Chart);
 require('./core/core.tooltip')(Chart);
@@ -77,3 +77,12 @@ if (typeof window !== 'undefined') {
  * @private
  */
 Chart.canvasHelpers = Chart.helpers.canvas;
+
+/**
+ * Provided for backward compatibility, use Chart.layout instead.
+ * @namespace Chart.layoutService
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+Chart.layoutService = Chart.layout;
index 6026e8620fb45ff91e695a8bfb847d93885ae487..2d143f6e0093c60f234466bb16db1b593ca08876 100644 (file)
@@ -3,6 +3,7 @@
 var defaults = require('./core.defaults');
 var helpers = require('../helpers/index');
 var Interaction = require('./core.interaction');
+var layout = require('./core.layout');
 var platform = require('../platforms/platform');
 
 module.exports = function(Chart) {
@@ -46,7 +47,7 @@ module.exports = function(Chart) {
                var newOptions = chart.options;
 
                helpers.each(chart.scales, function(scale) {
-                       Chart.layoutService.removeBox(chart, scale);
+                       layout.removeBox(chart, scale);
                });
 
                newOptions = helpers.configMerge(
@@ -435,7 +436,7 @@ module.exports = function(Chart) {
                                return;
                        }
 
-                       Chart.layoutService.update(this, this.width, this.height);
+                       layout.update(this, this.width, this.height);
 
                        /**
                         * Provided for backward compatibility, use `afterLayout` instead.
diff --git a/src/core/core.layout.js b/src/core/core.layout.js
new file mode 100644 (file)
index 0000000..b99612b
--- /dev/null
@@ -0,0 +1,419 @@
+'use strict';
+
+var helpers = require('../helpers/index');
+
+function filterByPosition(array, position) {
+       return helpers.where(array, function(v) {
+               return v.position === position;
+       });
+}
+
+function sortByWeight(array, reverse) {
+       array.forEach(function(v, i) {
+               v._tmpIndex_ = i;
+               return v;
+       });
+       array.sort(function(a, b) {
+               var v0 = reverse ? b : a;
+               var v1 = reverse ? a : b;
+               return v0.weight === v1.weight ?
+                       v0._tmpIndex_ - v1._tmpIndex_ :
+                       v0.weight - v1.weight;
+       });
+       array.forEach(function(v) {
+               delete v._tmpIndex_;
+       });
+}
+
+/**
+ * @interface ILayoutItem
+ * @prop {String} position - The position of the item in the chart layout. Possible values are
+ * 'left', 'top', 'right', 'bottom', and 'chartArea'
+ * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
+ * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
+ * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
+ * @prop {Function} update - Takes two parameters: width and height. Returns size of item
+ * @prop {Function} getPadding -  Returns an object with padding on the edges
+ * @prop {Number} width - Width of item. Must be valid after update()
+ * @prop {Number} height - Height of item. Must be valid after update()
+ * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
+ */
+
+// The layout service is very self explanatory.  It's responsible for the layout within a chart.
+// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
+// It is this service's responsibility of carrying out that layout.
+module.exports = {
+       defaults: {},
+
+       /**
+        * Register a box to a chart.
+        * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
+        * @param {Chart} chart - the chart to use
+        * @param {ILayoutItem} item - the item to add to be layed out
+        */
+       addBox: function(chart, item) {
+               if (!chart.boxes) {
+                       chart.boxes = [];
+               }
+
+               // initialize item with default values
+               item.fullWidth = item.fullWidth || false;
+               item.position = item.position || 'top';
+               item.weight = item.weight || 0;
+
+               chart.boxes.push(item);
+       },
+
+       /**
+        * Remove a layoutItem from a chart
+        * @param {Chart} chart - the chart to remove the box from
+        * @param {Object} layoutItem - the item to remove from the layout
+        */
+       removeBox: function(chart, layoutItem) {
+               var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
+               if (index !== -1) {
+                       chart.boxes.splice(index, 1);
+               }
+       },
+
+       /**
+        * Sets (or updates) options on the given `item`.
+        * @param {Chart} chart - the chart in which the item lives (or will be added to)
+        * @param {Object} item - the item to configure with the given options
+        * @param {Object} options - the new item options.
+        */
+       configure: function(chart, item, options) {
+               var props = ['fullWidth', 'position', 'weight'];
+               var ilen = props.length;
+               var i = 0;
+               var prop;
+
+               for (; i < ilen; ++i) {
+                       prop = props[i];
+                       if (options.hasOwnProperty(prop)) {
+                               item[prop] = options[prop];
+                       }
+               }
+       },
+
+       /**
+        * Fits boxes of the given chart into the given size by having each box measure itself
+        * then running a fitting algorithm
+        * @param {Chart} chart - the chart
+        * @param {Number} width - the width to fit into
+        * @param {Number} height - the height to fit into
+        */
+       update: function(chart, width, height) {
+               if (!chart) {
+                       return;
+               }
+
+               var layoutOptions = chart.options.layout || {};
+               var padding = helpers.options.toPadding(layoutOptions.padding);
+               var leftPadding = padding.left;
+               var rightPadding = padding.right;
+               var topPadding = padding.top;
+               var bottomPadding = padding.bottom;
+
+               var leftBoxes = filterByPosition(chart.boxes, 'left');
+               var rightBoxes = filterByPosition(chart.boxes, 'right');
+               var topBoxes = filterByPosition(chart.boxes, 'top');
+               var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
+               var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
+
+               // Sort boxes by weight. A higher weight is further away from the chart area
+               sortByWeight(leftBoxes, true);
+               sortByWeight(rightBoxes, false);
+               sortByWeight(topBoxes, true);
+               sortByWeight(bottomBoxes, false);
+
+               // Essentially we now have any number of boxes on each of the 4 sides.
+               // Our canvas looks like the following.
+               // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
+               // B1 is the bottom axis
+               // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
+               // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
+               // an error will be thrown.
+               //
+               // |----------------------------------------------------|
+               // |                  T1 (Full Width)                   |
+               // |----------------------------------------------------|
+               // |    |    |                 T2                  |    |
+               // |    |----|-------------------------------------|----|
+               // |    |    | C1 |                           | C2 |    |
+               // |    |    |----|                           |----|    |
+               // |    |    |                                     |    |
+               // | L1 | L2 |           ChartArea (C0)            | R1 |
+               // |    |    |                                     |    |
+               // |    |    |----|                           |----|    |
+               // |    |    | C3 |                           | C4 |    |
+               // |    |----|-------------------------------------|----|
+               // |    |    |                 B1                  |    |
+               // |----------------------------------------------------|
+               // |                  B2 (Full Width)                   |
+               // |----------------------------------------------------|
+               //
+               // What we do to find the best sizing, we do the following
+               // 1. Determine the minimum size of the chart area.
+               // 2. Split the remaining width equally between each vertical axis
+               // 3. Split the remaining height equally between each horizontal axis
+               // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
+               // 5. Adjust the sizes of each axis based on it's minimum reported size.
+               // 6. Refit each axis
+               // 7. Position each axis in the final location
+               // 8. Tell the chart the final location of the chart area
+               // 9. Tell any axes that overlay the chart area the positions of the chart area
+
+               // Step 1
+               var chartWidth = width - leftPadding - rightPadding;
+               var chartHeight = height - topPadding - bottomPadding;
+               var chartAreaWidth = chartWidth / 2; // min 50%
+               var chartAreaHeight = chartHeight / 2; // min 50%
+
+               // Step 2
+               var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
+
+               // Step 3
+               var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
+
+               // Step 4
+               var maxChartAreaWidth = chartWidth;
+               var maxChartAreaHeight = chartHeight;
+               var minBoxSizes = [];
+
+               function getMinimumBoxSize(box) {
+                       var minSize;
+                       var isHorizontal = box.isHorizontal();
+
+                       if (isHorizontal) {
+                               minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
+                               maxChartAreaHeight -= minSize.height;
+                       } else {
+                               minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
+                               maxChartAreaWidth -= minSize.width;
+                       }
+
+                       minBoxSizes.push({
+                               horizontal: isHorizontal,
+                               minSize: minSize,
+                               box: box,
+                       });
+               }
+
+               helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
+
+               // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
+               var maxHorizontalLeftPadding = 0;
+               var maxHorizontalRightPadding = 0;
+               var maxVerticalTopPadding = 0;
+               var maxVerticalBottomPadding = 0;
+
+               helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
+                       if (horizontalBox.getPadding) {
+                               var boxPadding = horizontalBox.getPadding();
+                               maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
+                               maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
+                       }
+               });
+
+               helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
+                       if (verticalBox.getPadding) {
+                               var boxPadding = verticalBox.getPadding();
+                               maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
+                               maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
+                       }
+               });
+
+               // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
+               // be if the axes are drawn at their minimum sizes.
+               // Steps 5 & 6
+               var totalLeftBoxesWidth = leftPadding;
+               var totalRightBoxesWidth = rightPadding;
+               var totalTopBoxesHeight = topPadding;
+               var totalBottomBoxesHeight = bottomPadding;
+
+               // Function to fit a box
+               function fitBox(box) {
+                       var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
+                               return minBox.box === box;
+                       });
+
+                       if (minBoxSize) {
+                               if (box.isHorizontal()) {
+                                       var scaleMargin = {
+                                               left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
+                                               right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
+                                               top: 0,
+                                               bottom: 0
+                                       };
+
+                                       // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
+                                       // on the margin. Sometimes they need to increase in size slightly
+                                       box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
+                               } else {
+                                       box.update(minBoxSize.minSize.width, maxChartAreaHeight);
+                               }
+                       }
+               }
+
+               // Update, and calculate the left and right margins for the horizontal boxes
+               helpers.each(leftBoxes.concat(rightBoxes), fitBox);
+
+               helpers.each(leftBoxes, function(box) {
+                       totalLeftBoxesWidth += box.width;
+               });
+
+               helpers.each(rightBoxes, function(box) {
+                       totalRightBoxesWidth += box.width;
+               });
+
+               // Set the Left and Right margins for the horizontal boxes
+               helpers.each(topBoxes.concat(bottomBoxes), fitBox);
+
+               // Figure out how much margin is on the top and bottom of the vertical boxes
+               helpers.each(topBoxes, function(box) {
+                       totalTopBoxesHeight += box.height;
+               });
+
+               helpers.each(bottomBoxes, function(box) {
+                       totalBottomBoxesHeight += box.height;
+               });
+
+               function finalFitVerticalBox(box) {
+                       var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
+                               return minSize.box === box;
+                       });
+
+                       var scaleMargin = {
+                               left: 0,
+                               right: 0,
+                               top: totalTopBoxesHeight,
+                               bottom: totalBottomBoxesHeight
+                       };
+
+                       if (minBoxSize) {
+                               box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
+                       }
+               }
+
+               // Let the left layout know the final margin
+               helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
+
+               // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
+               totalLeftBoxesWidth = leftPadding;
+               totalRightBoxesWidth = rightPadding;
+               totalTopBoxesHeight = topPadding;
+               totalBottomBoxesHeight = bottomPadding;
+
+               helpers.each(leftBoxes, function(box) {
+                       totalLeftBoxesWidth += box.width;
+               });
+
+               helpers.each(rightBoxes, function(box) {
+                       totalRightBoxesWidth += box.width;
+               });
+
+               helpers.each(topBoxes, function(box) {
+                       totalTopBoxesHeight += box.height;
+               });
+               helpers.each(bottomBoxes, function(box) {
+                       totalBottomBoxesHeight += box.height;
+               });
+
+               // We may be adding some padding to account for rotated x axis labels
+               var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
+               totalLeftBoxesWidth += leftPaddingAddition;
+               totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
+
+               var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
+               totalTopBoxesHeight += topPaddingAddition;
+               totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
+
+               // Figure out if our chart area changed. This would occur if the dataset layout label rotation
+               // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
+               // without calling `fit` again
+               var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
+               var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
+
+               if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
+                       helpers.each(leftBoxes, function(box) {
+                               box.height = newMaxChartAreaHeight;
+                       });
+
+                       helpers.each(rightBoxes, function(box) {
+                               box.height = newMaxChartAreaHeight;
+                       });
+
+                       helpers.each(topBoxes, function(box) {
+                               if (!box.fullWidth) {
+                                       box.width = newMaxChartAreaWidth;
+                               }
+                       });
+
+                       helpers.each(bottomBoxes, function(box) {
+                               if (!box.fullWidth) {
+                                       box.width = newMaxChartAreaWidth;
+                               }
+                       });
+
+                       maxChartAreaHeight = newMaxChartAreaHeight;
+                       maxChartAreaWidth = newMaxChartAreaWidth;
+               }
+
+               // Step 7 - Position the boxes
+               var left = leftPadding + leftPaddingAddition;
+               var top = topPadding + topPaddingAddition;
+
+               function placeBox(box) {
+                       if (box.isHorizontal()) {
+                               box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
+                               box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
+                               box.top = top;
+                               box.bottom = top + box.height;
+
+                               // Move to next point
+                               top = box.bottom;
+
+                       } else {
+
+                               box.left = left;
+                               box.right = left + box.width;
+                               box.top = totalTopBoxesHeight;
+                               box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
+
+                               // Move to next point
+                               left = box.right;
+                       }
+               }
+
+               helpers.each(leftBoxes.concat(topBoxes), placeBox);
+
+               // Account for chart width and height
+               left += maxChartAreaWidth;
+               top += maxChartAreaHeight;
+
+               helpers.each(rightBoxes, placeBox);
+               helpers.each(bottomBoxes, placeBox);
+
+               // Step 8
+               chart.chartArea = {
+                       left: totalLeftBoxesWidth,
+                       top: totalTopBoxesHeight,
+                       right: totalLeftBoxesWidth + maxChartAreaWidth,
+                       bottom: totalTopBoxesHeight + maxChartAreaHeight
+               };
+
+               // Step 9
+               helpers.each(chartAreaBoxes, function(box) {
+                       box.left = chart.chartArea.left;
+                       box.top = chart.chartArea.top;
+                       box.right = chart.chartArea.right;
+                       box.bottom = chart.chartArea.bottom;
+
+                       box.update(maxChartAreaWidth, maxChartAreaHeight);
+               });
+       }
+};
diff --git a/src/core/core.layoutService.js b/src/core/core.layoutService.js
deleted file mode 100644 (file)
index df28f97..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-'use strict';
-
-var helpers = require('../helpers/index');
-
-module.exports = function(Chart) {
-
-       function filterByPosition(array, position) {
-               return helpers.where(array, function(v) {
-                       return v.position === position;
-               });
-       }
-
-       function sortByWeight(array, reverse) {
-               array.forEach(function(v, i) {
-                       v._tmpIndex_ = i;
-                       return v;
-               });
-               array.sort(function(a, b) {
-                       var v0 = reverse ? b : a;
-                       var v1 = reverse ? a : b;
-                       return v0.weight === v1.weight ?
-                               v0._tmpIndex_ - v1._tmpIndex_ :
-                               v0.weight - v1.weight;
-               });
-               array.forEach(function(v) {
-                       delete v._tmpIndex_;
-               });
-       }
-
-       /**
-        * @interface ILayoutItem
-        * @prop {String} position - The position of the item in the chart layout. Possible values are
-        * 'left', 'top', 'right', 'bottom', and 'chartArea'
-        * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
-        * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
-        * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
-        * @prop {Function} update - Takes two parameters: width and height. Returns size of item
-        * @prop {Function} getPadding -  Returns an object with padding on the edges
-        * @prop {Number} width - Width of item. Must be valid after update()
-        * @prop {Number} height - Height of item. Must be valid after update()
-        * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
-        * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
-        * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
-        * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
-        */
-
-       // The layout service is very self explanatory.  It's responsible for the layout within a chart.
-       // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
-       // It is this service's responsibility of carrying out that layout.
-       Chart.layoutService = {
-               defaults: {},
-
-               /**
-                * Register a box to a chart.
-                * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
-                * @param {Chart} chart - the chart to use
-                * @param {ILayoutItem} item - the item to add to be layed out
-                */
-               addBox: function(chart, item) {
-                       if (!chart.boxes) {
-                               chart.boxes = [];
-                       }
-
-                       // initialize item with default values
-                       item.fullWidth = item.fullWidth || false;
-                       item.position = item.position || 'top';
-                       item.weight = item.weight || 0;
-
-                       chart.boxes.push(item);
-               },
-
-               /**
-                * Remove a layoutItem from a chart
-                * @param {Chart} chart - the chart to remove the box from
-                * @param {Object} layoutItem - the item to remove from the layout
-                */
-               removeBox: function(chart, layoutItem) {
-                       var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
-                       if (index !== -1) {
-                               chart.boxes.splice(index, 1);
-                       }
-               },
-
-               /**
-                * Sets (or updates) options on the given `item`.
-                * @param {Chart} chart - the chart in which the item lives (or will be added to)
-                * @param {Object} item - the item to configure with the given options
-                * @param {Object} options - the new item options.
-                */
-               configure: function(chart, item, options) {
-                       var props = ['fullWidth', 'position', 'weight'];
-                       var ilen = props.length;
-                       var i = 0;
-                       var prop;
-
-                       for (; i < ilen; ++i) {
-                               prop = props[i];
-                               if (options.hasOwnProperty(prop)) {
-                                       item[prop] = options[prop];
-                               }
-                       }
-               },
-
-               /**
-                * Fits boxes of the given chart into the given size by having each box measure itself
-                * then running a fitting algorithm
-                * @param {Chart} chart - the chart
-                * @param {Number} width - the width to fit into
-                * @param {Number} height - the height to fit into
-                */
-               update: function(chart, width, height) {
-                       if (!chart) {
-                               return;
-                       }
-
-                       var layoutOptions = chart.options.layout || {};
-                       var padding = helpers.options.toPadding(layoutOptions.padding);
-                       var leftPadding = padding.left;
-                       var rightPadding = padding.right;
-                       var topPadding = padding.top;
-                       var bottomPadding = padding.bottom;
-
-                       var leftBoxes = filterByPosition(chart.boxes, 'left');
-                       var rightBoxes = filterByPosition(chart.boxes, 'right');
-                       var topBoxes = filterByPosition(chart.boxes, 'top');
-                       var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
-                       var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
-
-                       // Sort boxes by weight. A higher weight is further away from the chart area
-                       sortByWeight(leftBoxes, true);
-                       sortByWeight(rightBoxes, false);
-                       sortByWeight(topBoxes, true);
-                       sortByWeight(bottomBoxes, false);
-
-                       // Essentially we now have any number of boxes on each of the 4 sides.
-                       // Our canvas looks like the following.
-                       // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
-                       // B1 is the bottom axis
-                       // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
-                       // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
-                       // an error will be thrown.
-                       //
-                       // |----------------------------------------------------|
-                       // |                  T1 (Full Width)                   |
-                       // |----------------------------------------------------|
-                       // |    |    |                 T2                  |    |
-                       // |    |----|-------------------------------------|----|
-                       // |    |    | C1 |                           | C2 |    |
-                       // |    |    |----|                           |----|    |
-                       // |    |    |                                     |    |
-                       // | L1 | L2 |           ChartArea (C0)            | R1 |
-                       // |    |    |                                     |    |
-                       // |    |    |----|                           |----|    |
-                       // |    |    | C3 |                           | C4 |    |
-                       // |    |----|-------------------------------------|----|
-                       // |    |    |                 B1                  |    |
-                       // |----------------------------------------------------|
-                       // |                  B2 (Full Width)                   |
-                       // |----------------------------------------------------|
-                       //
-                       // What we do to find the best sizing, we do the following
-                       // 1. Determine the minimum size of the chart area.
-                       // 2. Split the remaining width equally between each vertical axis
-                       // 3. Split the remaining height equally between each horizontal axis
-                       // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
-                       // 5. Adjust the sizes of each axis based on it's minimum reported size.
-                       // 6. Refit each axis
-                       // 7. Position each axis in the final location
-                       // 8. Tell the chart the final location of the chart area
-                       // 9. Tell any axes that overlay the chart area the positions of the chart area
-
-                       // Step 1
-                       var chartWidth = width - leftPadding - rightPadding;
-                       var chartHeight = height - topPadding - bottomPadding;
-                       var chartAreaWidth = chartWidth / 2; // min 50%
-                       var chartAreaHeight = chartHeight / 2; // min 50%
-
-                       // Step 2
-                       var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
-
-                       // Step 3
-                       var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
-
-                       // Step 4
-                       var maxChartAreaWidth = chartWidth;
-                       var maxChartAreaHeight = chartHeight;
-                       var minBoxSizes = [];
-
-                       function getMinimumBoxSize(box) {
-                               var minSize;
-                               var isHorizontal = box.isHorizontal();
-
-                               if (isHorizontal) {
-                                       minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
-                                       maxChartAreaHeight -= minSize.height;
-                               } else {
-                                       minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
-                                       maxChartAreaWidth -= minSize.width;
-                               }
-
-                               minBoxSizes.push({
-                                       horizontal: isHorizontal,
-                                       minSize: minSize,
-                                       box: box,
-                               });
-                       }
-
-                       helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
-
-                       // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
-                       var maxHorizontalLeftPadding = 0;
-                       var maxHorizontalRightPadding = 0;
-                       var maxVerticalTopPadding = 0;
-                       var maxVerticalBottomPadding = 0;
-
-                       helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
-                               if (horizontalBox.getPadding) {
-                                       var boxPadding = horizontalBox.getPadding();
-                                       maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
-                                       maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
-                               }
-                       });
-
-                       helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
-                               if (verticalBox.getPadding) {
-                                       var boxPadding = verticalBox.getPadding();
-                                       maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
-                                       maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
-                               }
-                       });
-
-                       // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
-                       // be if the axes are drawn at their minimum sizes.
-                       // Steps 5 & 6
-                       var totalLeftBoxesWidth = leftPadding;
-                       var totalRightBoxesWidth = rightPadding;
-                       var totalTopBoxesHeight = topPadding;
-                       var totalBottomBoxesHeight = bottomPadding;
-
-                       // Function to fit a box
-                       function fitBox(box) {
-                               var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
-                                       return minBox.box === box;
-                               });
-
-                               if (minBoxSize) {
-                                       if (box.isHorizontal()) {
-                                               var scaleMargin = {
-                                                       left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
-                                                       right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
-                                                       top: 0,
-                                                       bottom: 0
-                                               };
-
-                                               // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
-                                               // on the margin. Sometimes they need to increase in size slightly
-                                               box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
-                                       } else {
-                                               box.update(minBoxSize.minSize.width, maxChartAreaHeight);
-                                       }
-                               }
-                       }
-
-                       // Update, and calculate the left and right margins for the horizontal boxes
-                       helpers.each(leftBoxes.concat(rightBoxes), fitBox);
-
-                       helpers.each(leftBoxes, function(box) {
-                               totalLeftBoxesWidth += box.width;
-                       });
-
-                       helpers.each(rightBoxes, function(box) {
-                               totalRightBoxesWidth += box.width;
-                       });
-
-                       // Set the Left and Right margins for the horizontal boxes
-                       helpers.each(topBoxes.concat(bottomBoxes), fitBox);
-
-                       // Figure out how much margin is on the top and bottom of the vertical boxes
-                       helpers.each(topBoxes, function(box) {
-                               totalTopBoxesHeight += box.height;
-                       });
-
-                       helpers.each(bottomBoxes, function(box) {
-                               totalBottomBoxesHeight += box.height;
-                       });
-
-                       function finalFitVerticalBox(box) {
-                               var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
-                                       return minSize.box === box;
-                               });
-
-                               var scaleMargin = {
-                                       left: 0,
-                                       right: 0,
-                                       top: totalTopBoxesHeight,
-                                       bottom: totalBottomBoxesHeight
-                               };
-
-                               if (minBoxSize) {
-                                       box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
-                               }
-                       }
-
-                       // Let the left layout know the final margin
-                       helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
-
-                       // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
-                       totalLeftBoxesWidth = leftPadding;
-                       totalRightBoxesWidth = rightPadding;
-                       totalTopBoxesHeight = topPadding;
-                       totalBottomBoxesHeight = bottomPadding;
-
-                       helpers.each(leftBoxes, function(box) {
-                               totalLeftBoxesWidth += box.width;
-                       });
-
-                       helpers.each(rightBoxes, function(box) {
-                               totalRightBoxesWidth += box.width;
-                       });
-
-                       helpers.each(topBoxes, function(box) {
-                               totalTopBoxesHeight += box.height;
-                       });
-                       helpers.each(bottomBoxes, function(box) {
-                               totalBottomBoxesHeight += box.height;
-                       });
-
-                       // We may be adding some padding to account for rotated x axis labels
-                       var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
-                       totalLeftBoxesWidth += leftPaddingAddition;
-                       totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
-
-                       var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
-                       totalTopBoxesHeight += topPaddingAddition;
-                       totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
-
-                       // Figure out if our chart area changed. This would occur if the dataset layout label rotation
-                       // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
-                       // without calling `fit` again
-                       var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
-                       var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
-
-                       if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
-                               helpers.each(leftBoxes, function(box) {
-                                       box.height = newMaxChartAreaHeight;
-                               });
-
-                               helpers.each(rightBoxes, function(box) {
-                                       box.height = newMaxChartAreaHeight;
-                               });
-
-                               helpers.each(topBoxes, function(box) {
-                                       if (!box.fullWidth) {
-                                               box.width = newMaxChartAreaWidth;
-                                       }
-                               });
-
-                               helpers.each(bottomBoxes, function(box) {
-                                       if (!box.fullWidth) {
-                                               box.width = newMaxChartAreaWidth;
-                                       }
-                               });
-
-                               maxChartAreaHeight = newMaxChartAreaHeight;
-                               maxChartAreaWidth = newMaxChartAreaWidth;
-                       }
-
-                       // Step 7 - Position the boxes
-                       var left = leftPadding + leftPaddingAddition;
-                       var top = topPadding + topPaddingAddition;
-
-                       function placeBox(box) {
-                               if (box.isHorizontal()) {
-                                       box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
-                                       box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
-                                       box.top = top;
-                                       box.bottom = top + box.height;
-
-                                       // Move to next point
-                                       top = box.bottom;
-
-                               } else {
-
-                                       box.left = left;
-                                       box.right = left + box.width;
-                                       box.top = totalTopBoxesHeight;
-                                       box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
-
-                                       // Move to next point
-                                       left = box.right;
-                               }
-                       }
-
-                       helpers.each(leftBoxes.concat(topBoxes), placeBox);
-
-                       // Account for chart width and height
-                       left += maxChartAreaWidth;
-                       top += maxChartAreaHeight;
-
-                       helpers.each(rightBoxes, placeBox);
-                       helpers.each(bottomBoxes, placeBox);
-
-                       // Step 8
-                       chart.chartArea = {
-                               left: totalLeftBoxesWidth,
-                               top: totalTopBoxesHeight,
-                               right: totalLeftBoxesWidth + maxChartAreaWidth,
-                               bottom: totalTopBoxesHeight + maxChartAreaHeight
-                       };
-
-                       // Step 9
-                       helpers.each(chartAreaBoxes, function(box) {
-                               box.left = chart.chartArea.left;
-                               box.top = chart.chartArea.top;
-                               box.right = chart.chartArea.right;
-                               box.bottom = chart.chartArea.bottom;
-
-                               box.update(maxChartAreaWidth, maxChartAreaHeight);
-                       });
-               }
-       };
-};
index 23cabe610d26f39874cc2ac0e5a98e6cf9c1d624..bfbf832094a2ad7a34a829900f4eeee70fd5b328 100644 (file)
@@ -2,6 +2,7 @@
 
 var defaults = require('./core.defaults');
 var helpers = require('../helpers/index');
+var layout = require('./core.layout');
 
 module.exports = function(Chart) {
 
@@ -38,7 +39,7 @@ module.exports = function(Chart) {
                                scale.fullWidth = scale.options.fullWidth;
                                scale.position = scale.options.position;
                                scale.weight = scale.options.weight;
-                               Chart.layoutService.addBox(chart, scale);
+                               layout.addBox(chart, scale);
                        });
                }
        };
index 71e0e4110e45713cef514b5366046a7ff789eb63..7e0e429d0ceac5b7978b592ac1d4066049afab5f 100644 (file)
@@ -3,6 +3,7 @@
 var defaults = require('../core/core.defaults');
 var Element = require('../core/core.element');
 var helpers = require('../helpers/index');
+var layout = require('../core/core.layout');
 
 defaults._set('global', {
        legend: {
@@ -81,7 +82,6 @@ defaults._set('global', {
 
 module.exports = function(Chart) {
 
-       var layout = Chart.layoutService;
        var noop = helpers.noop;
 
        /**
index ebefed294fff130b040d9c020f54e2f3dd2b421f..8eac103f542f3805009cc886a5c7b3fbf2447a85 100644 (file)
@@ -3,6 +3,7 @@
 var defaults = require('../core/core.defaults');
 var Element = require('../core/core.element');
 var helpers = require('../helpers/index');
+var layout = require('../core/core.layout');
 
 defaults._set('global', {
        title: {
@@ -19,7 +20,6 @@ defaults._set('global', {
 
 module.exports = function(Chart) {
 
-       var layout = Chart.layoutService;
        var noop = helpers.noop;
 
        Chart.Title = Element.extend({
@@ -235,7 +235,7 @@ module.exports = function(Chart) {
                                        createNewTitleBlockAndAttach(chart, titleOpts);
                                }
                        } else if (titleBlock) {
-                               Chart.layoutService.removeBox(chart, titleBlock);
+                               layout.removeBox(chart, titleBlock);
                                delete chart.titleBlock;
                        }
                }
index f1091464d1efaba1dda3e6c95792d824493188a1..fee37288df9a5c1663a28173c6958180a4e634e6 100644 (file)
@@ -1,4 +1,13 @@
 describe('Deprecations', function() {
+       describe('Version 2.8.0', function() {
+               describe('Chart.layoutService', function() {
+                       it('should be defined and an alias of Chart.layout', function() {
+                               expect(Chart.layoutService).toBeDefined();
+                               expect(Chart.layoutService).toBe(Chart.layout);
+                       });
+               });
+       });
+
        describe('Version 2.7.0', function() {
                describe('Chart.Controller.update(duration, lazy)', function() {
                        it('should add an animation with the provided options', function() {
@@ -302,8 +311,8 @@ describe('Deprecations', function() {
                                        'afterLayout'
                                ];
 
-                               var override = Chart.layoutService.update;
-                               Chart.layoutService.update = function() {
+                               var override = Chart.layout.update;
+                               Chart.layout.update = function() {
                                        sequence.push('layoutUpdate');
                                        override.apply(this, arguments);
                                };