Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src/helpers/helpers.dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,36 @@ function getContainerSize(canvas: HTMLCanvasElement, width: number, height: numb

const round1 = (v: number) => Math.round(v * 10) / 10;

/**
* Determine whether the container's height is defined independently of the
* canvas, by measuring the container with the canvas removed from the layout.
* When the container's height is derived from the canvas itself (e.g. a plain
* block wrapper with no explicit height), the current canvas height must not
* be used as a constraint, because doing so prevents the chart from ever
* growing (see #11005).
*/
function _isContainerHeightIndependent(canvas: HTMLCanvasElement, containerHeight: number): boolean {
const container = _getParentNode(canvas);
if (!container) {
return false;
}
const style = canvas.style;
const prevValue = style.getPropertyValue('display');
const prevPriority = style.getPropertyPriority('display');
style.setProperty('display', 'none', 'important');
const rect = container.getBoundingClientRect();
const containerStyle = getComputedStyle(container);
const heightWithoutCanvas = rect.height
- getPositionedStyle(containerStyle, 'padding').height
- getPositionedStyle(containerStyle, 'border', 'width').height;
if (prevValue) {
style.setProperty('display', prevValue, prevPriority);
} else {
style.removeProperty('display');
}
return heightWithoutCanvas >= containerHeight - 0.5;
}

// eslint-disable-next-line complexity
export function getMaximumSize(
canvas: HTMLCanvasElement,
Expand Down Expand Up @@ -191,7 +221,8 @@ export function getMaximumSize(

const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;

if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height
&& _isContainerHeightIndependent(canvas, containerSize.height)) {
height = containerSize.height;
width = round1(Math.floor(height * aspectRatio));
}
Expand Down
39 changes: 39 additions & 0 deletions test/specs/helpers.dom.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,45 @@ describe('DOM helpers tests', function() {
document.body.removeChild(container);
});

it('should not limit growth by a container height that is derived from the canvas itself', () => {
// https://github.com/chartjs/Chart.js/issues/11005
// The container has no explicit height, so its height comes from the
// target (canvas) itself. That height must not act as a constraint,
// otherwise the chart can shrink but never grow back.
const container = document.createElement('div');
container.style.width = '900px';

document.body.appendChild(container);

const target = document.createElement('div');
target.style.width = '600px';
target.style.height = '300px';
container.appendChild(target);

expect(helpers.getMaximumSize(target, 900, 300, 2)).toEqual(jasmine.objectContaining({width: 900, height: 450}));

document.body.removeChild(container);
});

it('should still restore the display style of the canvas after measuring', () => {
const container = document.createElement('div');
container.style.width = '900px';

document.body.appendChild(container);

const target = document.createElement('div');
target.style.width = '600px';
target.style.height = '300px';
target.style.setProperty('display', 'block', 'important');
container.appendChild(target);

helpers.getMaximumSize(target, 900, 300, 2);
expect(target.style.getPropertyValue('display')).toBe('block');
expect(target.style.getPropertyPriority('display')).toBe('important');

document.body.removeChild(container);
});

it('should respect aspect ratio and skip container height', () => {
const container = document.createElement('div');
container.style.width = '500px';
Expand Down