question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

chart is out of the canvas

See original GitHub issue

When hide both xAxes and yAxes together

xAxes: [{ display: false }],
yAxes: [{ display: false }]

the chart is out of the canvas. jsfiddle image

I tried to adding padding using CSS, but it does not work.

You can check it by Chrome’s Developer Tools: image

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:11 (2 by maintainers)

github_iconTop GitHub Comments

3reactions
carlesnunezcommented, Sep 19, 2016

Hello all.

I’ve been investigated how to make a hotfix to solve that. I saw three strange behaviors:

1- The data breaks if have heavy changes, for example:

[0, 10, 70, 30, 20, 12, 50, 200, 200, 200, 200, 200]

2- The ‘error’ is always the half of the height of our borderWidth.

3- That error may was introduced when we changed the line 36 of core.layoutService.js on the next COMMIT

In second place I saw two strange padding vars inside the function ‘update’ of the core.layoutService:

Around the line 29 we have the function and on lines 35 and 36 we have the strange vars.

// The most important function
        update: function(chartInstance, width, height) {
            if (!chartInstance) {
                return;
            }

            var xPadding = 0;
            var yPadding = 0;

I have been seen what the function does with that vars, specially with yPadding. I couldn’t se any useful calc done with yPadding. In my opinion here is the problem. We always maintain the yPadding to 0 and IMHO it was an error applied in another version of that file HERE .

The solution is that follows and I developed that because is the demand behind the developer of that commit deleted the line.

THAT’S A HOTFIX, I WILL MAKE A PR AND IF IT IS APPROVED IT WILL BE THE SOLUTION

If you apply that code you will can set your padding on the styles config of the chart, also, if you don’t apply any config he will take a default based on the chart height.

Config prop example:

padding: {
  x: 5,
  y: 4
},

Once we have loaded the ChartJS lib, overwrite the method doing the next:

        Chart.layoutService.update = function(chartInstance, width, height) {
//PATCH to have helpers here
    var helpers = Chart.helpers;
            if (!chartInstance) {
                return;
            }
             var paddingX = chartInstance.config.options.padding ? chartInstance.config.options.padding.x : 0,
           paddingY = chartInstance.config.options.padding ? chartInstance.config.options.padding.y : 0,
           validYConfigPadding = paddingY < height / 2 && (paddingY > 0),
           validXConfigPadding = paddingX < width / 2 && (paddingX > 0),
           xPadding = (validXConfigPadding ? paddingX : (height > 30 ? 5 : 2)),
                 yPadding = (validYConfigPadding ? paddingY : (height > 30 ? 5 : 2));

            var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
                return box.options.position === "left";
            });
            var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
                return box.options.position === "right";
            });
            var topBoxes = helpers.where(chartInstance.boxes, function(box) {
                return box.options.position === "top";
            });
            var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
                return box.options.position === "bottom";
            });

            // Boxes that overlay the chart area such as the radialLinear scale
            var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
                return box.options.position === "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);
            });

            // 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 - (2 * xPadding);
            var chartHeight = height - (2 * yPadding);
            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 = [];

            helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);

            function getMinimumBoxSize(box) {
                var minSize;
                var isHorizontal = box.isHorizontal();

                if (isHorizontal) {
                    minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
                    maxChartAreaHeight -= minSize.height;
                } else {
                    minSize = box.update(verticalBoxWidth, chartAreaHeight);
                    maxChartAreaWidth -= minSize.width;
                }

                minBoxSizes.push({
                    horizontal: isHorizontal,
                    minSize: minSize,
                    box: box
                });
            }

            // 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 = xPadding;
            var totalRightBoxesWidth = xPadding;
            var totalTopBoxesHeight = yPadding;
            var totalBottomBoxesHeight = yPadding;

            // 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);

            // Function to fit a box
            function fitBox(box) {
                var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
                    return minBoxSize.box === box;
                });

                if (minBoxSize) {
                    if (box.isHorizontal()) {
                        var scaleMargin = {
                            left: totalLeftBoxesWidth,
                            right: totalRightBoxesWidth,
                            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.options.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
                    } else {
                        box.update(minBoxSize.minSize.width, maxChartAreaHeight);
                    }
                }
            }

            // 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;
            });

            // Let the left layout know the final margin
            helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);

            function finalFitVerticalBox(box) {
                var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
                    return minBoxSize.box === box;
                });

                var scaleMargin = {
                    left: 0,
                    right: 0,
                    top: totalTopBoxesHeight,
                    bottom: totalBottomBoxesHeight
                };

                if (minBoxSize) {
                    box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
                }
            }

            // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
            totalLeftBoxesWidth = xPadding;
            totalRightBoxesWidth = xPadding;
            totalTopBoxesHeight = yPadding;
            totalBottomBoxesHeight = yPadding;

            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;
            });

            // 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.options.fullWidth) {
                        box.width = newMaxChartAreaWidth;
                    }
                });

                helpers.each(bottomBoxes, function(box) {
                    if (!box.options.fullWidth) {
                        box.width = newMaxChartAreaWidth;
                    }
                });

                maxChartAreaHeight = newMaxChartAreaHeight;
                maxChartAreaWidth = newMaxChartAreaWidth;
            }

            // Step 7 - Position the boxes
            var left = xPadding;
            var top = yPadding;
            var right = 0;
            var bottom = 0;

            helpers.each(leftBoxes.concat(topBoxes), placeBox);

            // Account for chart width and height
            left += maxChartAreaWidth;
            top += maxChartAreaHeight;

            helpers.each(rightBoxes, placeBox);
            helpers.each(bottomBoxes, placeBox);

            function placeBox(box) {
                if (box.isHorizontal()) {
                    box.left = box.options.fullWidth ? xPadding : totalLeftBoxesWidth;
                    box.right = box.options.fullWidth ? width - xPadding : 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;
                }
            }

            // Step 8
            chartInstance.chartArea = {
                left: totalLeftBoxesWidth,
                top: totalTopBoxesHeight,
                right: totalLeftBoxesWidth + maxChartAreaWidth,
                bottom: totalTopBoxesHeight + maxChartAreaHeight
            };

            // Step 9
            helpers.each(chartAreaBoxes, function(box) {
                box.left = chartInstance.chartArea.left;
                box.top = chartInstance.chartArea.top;
                box.right = chartInstance.chartArea.right;
                box.bottom = chartInstance.chartArea.bottom;

                box.update(maxChartAreaWidth, maxChartAreaHeight);
            });
        }
1reaction
etimbergcommented, Oct 17, 2016

Fixed in #3476

Read more comments on GitHub >

github_iconTop Results From Across the Web

Google Chart Bar chart is rendered outside of the chart canvas
When there is a high value like one million, the bar chart is not rendered. If you inspect the element is with a...
Read more >
Responsive Charts - Chart.js
Chart.js provides a few options to enable responsiveness and control the resize behavior of charts by detecting when the canvas display size ...
Read more >
Amazon.com: Animals Growth Chart for Kids, Baby Height ...
Amazon.com: Animals Growth Chart for Kids, Baby Height Chart, Canvas Height Measuring ... ASIN: B08JYSJHPY; Customer Reviews: 4.6 out of 5 stars 565Reviews....
Read more >
Heart of the Adirondacks Canvas Wall Chart
Shop this Heart of the Adirondacks Canvas Wall Chart reproduction of an 1800s Verplank Colvin Adirondack survey and ... This item is currently...
Read more >
Canvas Growth Chart - Etsy
Check out our canvas growth chart selection for the very best in unique or custom, handmade pieces from our wall decor shops.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found