]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Layout service supports a new order setting to configure how boxes are ordered on...
authoretimberg <evert.timberg@gmail.com>
Fri, 20 Jan 2017 22:29:31 +0000 (17:29 -0500)
committerEvert Timberg <evert.timberg+github@gmail.com>
Sat, 25 Feb 2017 17:10:27 +0000 (12:10 -0500)
src/core/core.layoutService.js
src/core/core.legend.js
src/core/core.scaleService.js
src/core/core.title.js

index bd82e4780e971c4308e41515a63a4c98824a1ea7..9d40a2e407fa0a0737fadc06b7e8d52c409902e9 100644 (file)
@@ -4,30 +4,90 @@ module.exports = function(Chart) {
 
        var helpers = Chart.helpers;
 
+       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, Plugins.
-               addBox: function(chart, box) {
+               /**
+                * 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} layoutItem - the item to add to be layed out
+                */
+               addBox: function(chart, layoutItem) {
                        if (!chart.boxes) {
                                chart.boxes = [];
                        }
-                       chart.boxes.push(box);
+
+                       // Ensure that all layout items have a weight
+                       if (!layoutItem.weight) {
+                               layoutItem.weight = 0;
+                       }
+                       chart.boxes.push(layoutItem);
                },
 
-               removeBox: function(chart, box) {
+               /**
+                * 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) {
                        if (!chart.boxes) {
                                return;
                        }
-                       chart.boxes.splice(chart.boxes.indexOf(box), 1);
+                       chart.boxes.splice(chart.boxes.indexOf(layoutItem), 1);
                },
 
-               // The most important function
+               /**
+                * 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;
                        }
@@ -53,31 +113,17 @@ module.exports = function(Chart) {
                                bottomPadding = padding.bottom || 0;
                        }
 
-                       var leftBoxes = helpers.where(chart.boxes, function(box) {
-                               return box.options.position === 'left';
-                       });
-                       var rightBoxes = helpers.where(chart.boxes, function(box) {
-                               return box.options.position === 'right';
-                       });
-                       var topBoxes = helpers.where(chart.boxes, function(box) {
-                               return box.options.position === 'top';
-                       });
-                       var bottomBoxes = helpers.where(chart.boxes, function(box) {
-                               return box.options.position === 'bottom';
-                       });
-
-                       // Boxes that overlay the chartarea such as the radialLinear scale
-                       var chartAreaBoxes = helpers.where(chart.boxes, function(box) {
-                               return box.options.position === 'chartArea';
-                       });
+                       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');
 
-                       // Ensure that full width boxes are at the very top / bottom
-                       topBoxes.sort(function(a, b) {
-                               return (b.options.fullWidth ? 1 : 0) - (a.options.fullWidth ? 1 : 0);
-                       });
-                       bottomBoxes.sort(function(a, b) {
-                               return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
-                       });
+                       // 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.
@@ -138,7 +184,7 @@ module.exports = function(Chart) {
                                var isHorizontal = box.isHorizontal();
 
                                if (isHorizontal) {
-                                       minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
+                                       minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
                                        maxChartAreaHeight -= minSize.height;
                                } else {
                                        minSize = box.update(verticalBoxWidth, chartAreaHeight);
@@ -201,7 +247,7 @@ module.exports = function(Chart) {
 
                                                // 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.options.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
+                                               box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
                                        } else {
                                                box.update(minBoxSize.minSize.width, maxChartAreaHeight);
                                        }
@@ -297,13 +343,13 @@ module.exports = function(Chart) {
                                });
 
                                helpers.each(topBoxes, function(box) {
-                                       if (!box.options.fullWidth) {
+                                       if (!box.fullWidth) {
                                                box.width = newMaxChartAreaWidth;
                                        }
                                });
 
                                helpers.each(bottomBoxes, function(box) {
-                                       if (!box.options.fullWidth) {
+                                       if (!box.fullWidth) {
                                                box.width = newMaxChartAreaWidth;
                                        }
                                });
@@ -318,8 +364,8 @@ module.exports = function(Chart) {
 
                        function placeBox(box) {
                                if (box.isHorizontal()) {
-                                       box.left = box.options.fullWidth ? leftPadding : totalLeftBoxesWidth;
-                                       box.right = box.options.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
+                                       box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
+                                       box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
                                        box.top = top;
                                        box.bottom = top + box.height;
 
index 9e181193208a6ac6d242c0d79dda5b4e44ba3227..aace498bfe1f538e4a3aab7c63724180f3ba7fb7 100644 (file)
@@ -495,7 +495,13 @@ module.exports = function(Chart) {
                var legend = new Chart.Legend({
                        ctx: chart.ctx,
                        options: legendOpts,
-                       chart: chart
+                       chart: chart,
+
+                       // ILayoutItem parameters for layout service
+                       // pick a large number to ensure we are on the outside after any axes
+                       weight: 1000,
+                       position: legendOpts.position,
+                       fullWidth: legendOpts.fullWidth,
                });
                chart.legend = legend;
                Chart.layoutService.addBox(chart, legend);
index 4f3dea242cb53ad2e0dc2d46630ad02b390297c4..9923bc922af1e775898c5ce9ba91485c09078efb 100644 (file)
@@ -33,6 +33,9 @@ module.exports = function(Chart) {
                addScalesToLayout: function(chart) {
                        // Adds each scale to the chart.boxes array to be sized accordingly
                        helpers.each(chart.scales, function(scale) {
+                               // Set ILayoutItem parameters for backwards compatibility
+                               scale.fullWidth = scale.options.fullWidth;
+                               scale.position = scale.options.position;
                                Chart.layoutService.addBox(chart, scale);
                        });
                }
index a1a3c8f430917035b1d24010fac1f7662eef38c5..fe7674d4ae19e7f10a6ab307cb778a59682f701c 100644 (file)
@@ -185,7 +185,12 @@ module.exports = function(Chart) {
                var title = new Chart.Title({
                        ctx: chart.ctx,
                        options: titleOpts,
-                       chart: chart
+                       chart: chart,
+
+                       // ILayoutItem parameters
+                       weight: 2000, // greater than legend to be above
+                       position: titleOpts.position,
+                       fullWidth: titleOpts.fullWidth,
                });
                chart.titleBlock = title;
                Chart.layoutService.addBox(chart, title);