From 61c728953a69d1e922b38e056d3d3dde54a7b4d6 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Sat, 2 Feb 2019 10:46:27 +0200 Subject: [PATCH] Fix padding of horizontal axes when labels are rotated (#6021) --- src/core/core.layouts.js | 177 ++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 104 deletions(-) diff --git a/src/core/core.layouts.js b/src/core/core.layouts.js index d212731f7ef..96887770b51 100644 --- a/src/core/core.layouts.js +++ b/src/core/core.layouts.js @@ -26,6 +26,34 @@ function sortByWeight(array, reverse) { }); } +function findMaxPadding(boxes) { + var top = 0; + var left = 0; + var bottom = 0; + var right = 0; + helpers.each(boxes, function(box) { + if (box.getPadding) { + var boxPadding = box.getPadding(); + top = Math.max(top, boxPadding.top); + left = Math.max(left, boxPadding.left); + bottom = Math.max(bottom, boxPadding.bottom); + right = Math.max(right, boxPadding.right); + } + }); + return { + top: top, + left: left, + bottom: bottom, + right: right + }; +} + +function addSizeByPosition(boxes, size) { + helpers.each(boxes, function(box) { + size[box.position] += box.isHorizontal() ? box.height : box.width; + }); +} + defaults._set('global', { layout: { padding: { @@ -142,6 +170,10 @@ module.exports = { sortByWeight(topBoxes, true); sortByWeight(bottomBoxes, false); + var verticalBoxes = leftBoxes.concat(rightBoxes); + var horizontalBoxes = topBoxes.concat(bottomBoxes); + var outerBoxes = verticalBoxes.concat(horizontalBoxes); + // 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 @@ -183,25 +215,27 @@ module.exports = { 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); + var verticalBoxWidth = (width - chartAreaWidth) / verticalBoxes.length; // Step 3 - var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length); + // TODO re-limit horizontal axis height (this limit has affected only padding calculation since PR 1837) + // var horizontalBoxHeight = (height - chartAreaHeight) / horizontalBoxes.length; // Step 4 var maxChartAreaWidth = chartWidth; var maxChartAreaHeight = chartHeight; + var outerBoxSizes = {top: topPadding, left: leftPadding, bottom: bottomPadding, right: rightPadding}; var minBoxSizes = []; + var maxPadding; function getMinimumBoxSize(box) { var minSize; var isHorizontal = box.isHorizontal(); if (isHorizontal) { - minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight); + minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2); maxChartAreaHeight -= minSize.height; } else { minSize = box.update(verticalBoxWidth, maxChartAreaHeight); @@ -210,42 +244,19 @@ module.exports = { minBoxSizes.push({ horizontal: isHorizontal, - minSize: minSize, + width: minSize.width, box: box, }); } - helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize); + helpers.each(outerBoxes, 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); - } - }); + maxPadding = findMaxPadding(outerBoxes); // 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) { @@ -254,10 +265,10 @@ module.exports = { }); if (minBoxSize) { - if (box.isHorizontal()) { + if (minBoxSize.horizontal) { var scaleMargin = { - left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding), - right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding), + left: Math.max(outerBoxSizes.left, maxPadding.left), + right: Math.max(outerBoxSizes.right, maxPadding.right), top: 0, bottom: 0 }; @@ -266,33 +277,18 @@ module.exports = { // 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); + box.update(minBoxSize.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; - }); + helpers.each(verticalBoxes, fitBox); + addSizeByPosition(verticalBoxes, outerBoxSizes); // 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; - }); + helpers.each(horizontalBoxes, fitBox); + addSizeByPosition(horizontalBoxes, outerBoxSizes); function finalFitVerticalBox(box) { var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) { @@ -302,70 +298,43 @@ module.exports = { var scaleMargin = { left: 0, right: 0, - top: totalTopBoxesHeight, - bottom: totalBottomBoxesHeight + top: outerBoxSizes.top, + bottom: outerBoxSizes.bottom }; if (minBoxSize) { - box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin); + box.update(minBoxSize.width, maxChartAreaHeight, scaleMargin); } } // Let the left layout know the final margin - helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox); + helpers.each(verticalBoxes, 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; - }); + outerBoxSizes = {top: topPadding, left: leftPadding, bottom: bottomPadding, right: rightPadding}; + addSizeByPosition(outerBoxes, outerBoxSizes); // 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 leftPaddingAddition = Math.max(maxPadding.left - outerBoxSizes.left, 0); + outerBoxSizes.left += leftPaddingAddition; + outerBoxSizes.right += Math.max(maxPadding.right - outerBoxSizes.right, 0); - var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0); - totalTopBoxesHeight += topPaddingAddition; - totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0); + var topPaddingAddition = Math.max(maxPadding.top - outerBoxSizes.top, 0); + outerBoxSizes.top += topPaddingAddition; + outerBoxSizes.bottom += Math.max(maxPadding.bottom - outerBoxSizes.bottom, 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; + var newMaxChartAreaHeight = height - outerBoxSizes.top - outerBoxSizes.bottom; + var newMaxChartAreaWidth = width - outerBoxSizes.left - outerBoxSizes.right; if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) { - helpers.each(leftBoxes, function(box) { + helpers.each(verticalBoxes, 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) { + helpers.each(horizontalBoxes, function(box) { if (!box.fullWidth) { box.width = newMaxChartAreaWidth; } @@ -381,8 +350,8 @@ module.exports = { function placeBox(box) { if (box.isHorizontal()) { - box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth; - box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth; + box.left = box.fullWidth ? leftPadding : outerBoxSizes.left; + box.right = box.fullWidth ? width - rightPadding : outerBoxSizes.left + maxChartAreaWidth; box.top = top; box.bottom = top + box.height; @@ -393,8 +362,8 @@ module.exports = { box.left = left; box.right = left + box.width; - box.top = totalTopBoxesHeight; - box.bottom = totalTopBoxesHeight + maxChartAreaHeight; + box.top = outerBoxSizes.top; + box.bottom = outerBoxSizes.top + maxChartAreaHeight; // Move to next point left = box.right; @@ -412,10 +381,10 @@ module.exports = { // Step 8 chart.chartArea = { - left: totalLeftBoxesWidth, - top: totalTopBoxesHeight, - right: totalLeftBoxesWidth + maxChartAreaWidth, - bottom: totalTopBoxesHeight + maxChartAreaHeight + left: outerBoxSizes.left, + top: outerBoxSizes.top, + right: outerBoxSizes.left + maxChartAreaWidth, + bottom: outerBoxSizes.top + maxChartAreaHeight }; // Step 9