Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ensure getComputedStyle always has a valid canvas provided #11809

Closed
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
2 changes: 2 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ rules:
es/no-regexp-s-flag: "error"
es/no-regexp-unicode-property-escapes: "error"
es/no-dynamic-import: "off"
es/no-optional-chaining: "off"
es/no-nullish-coalescing-operators: "off"

overrides:
- files: ['**/*.ts']
Expand Down
31 changes: 21 additions & 10 deletions src/helpers/helpers.dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ function parseMaxStyle(styleValue: string | number, node: HTMLElement, parentPro
const getComputedStyle = (element: HTMLElement): CSSStyleDeclaration =>
element.ownerDocument.defaultView.getComputedStyle(element, null);

export function getStyle(el: HTMLElement, property: string): string {
export function getStyle(property: string, el?: HTMLElement): string {
if (!el) {
return '';
}

return getComputedStyle(el).getPropertyValue(property);
}

Expand Down Expand Up @@ -105,20 +109,22 @@ function getCanvasPosition(

/**
* Gets an event's x, y coordinates, relative to the chart area
* @param event
* @param chart
Comment on lines -108 to -109
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that this was not meant to be?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was removed since it didn't provide any additional information than the function signature already provided (not even variable types). If you still want this, I can revert this change.

* @returns x and y coordinates of the event
*/

export function getRelativePosition(
event: Event | ChartEvent | TouchEvent | MouseEvent,
chart: Chart
chart?: Chart
): { x: number; y: number } {
if ('native' in event) {
return event;
}

const {canvas, currentDevicePixelRatio} = chart;
if (!canvas) {
return {x: 0, y: 0};
}

const style = getComputedStyle(canvas);
const borderBox = style.boxSizing === 'border-box';
const paddings = getPositionedStyle(style, 'padding');
Expand All @@ -138,19 +144,20 @@ export function getRelativePosition(
};
}

function getContainerSize(canvas: HTMLCanvasElement, width: number, height: number): Partial<Scale> {
function getContainerSize(width: number, height: number, canvas?: HTMLCanvasElement): Partial<Scale> {
let maxWidth: number, maxHeight: number;

if (width === undefined || height === undefined) {
const container = canvas && _getParentNode(canvas);
if (!container) {
width = canvas.clientWidth;
height = canvas.clientHeight;
width = canvas?.clientWidth ?? 0;
height = canvas?.clientHeight ?? 0;
} else {
const rect = container.getBoundingClientRect(); // this is the border box of the container
const containerStyle = getComputedStyle(container);
const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
const containerPadding = getPositionedStyle(containerStyle, 'padding');

width = rect.width - containerPadding.width - containerBorder.width;
height = rect.height - containerPadding.height - containerBorder.height;
maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
Expand All @@ -169,16 +176,20 @@ const round1 = (v: number) => Math.round(v * 10) / 10;

// eslint-disable-next-line complexity
export function getMaximumSize(
canvas: HTMLCanvasElement,
canvas?: HTMLCanvasElement,
bbWidth?: number,
bbHeight?: number,
aspectRatio?: number
): { width: number; height: number } {
if (!canvas) {
return {width: 0, height: 0};
}

const style = getComputedStyle(canvas);
const margins = getPositionedStyle(style, 'margin');
const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
const containerSize = getContainerSize(bbWidth, bbHeight, canvas);
let {width, height} = containerSize;

if (style.boxSizing === 'content-box') {
Expand Down Expand Up @@ -286,7 +297,7 @@ export function readUsedSize(
element: HTMLElement,
property: 'width' | 'height'
): number | undefined {
const value = getStyle(element, property);
const value = getStyle(property, element);
const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
return matches ? +matches[1] : undefined;
}
7 changes: 4 additions & 3 deletions src/platform/platform.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ export default class BasePlatform {

/**
* Returns the maximum size in pixels of given canvas element.
* @param {HTMLCanvasElement} element
* @param {HTMLCanvasElement} [element]
* @param {number} [width] - content width of parent element
* @param {number} [height] - content height of parent element
* @param {number} [aspectRatio] - aspect ratio to maintain
*/
getMaximumSize(element, width, height, aspectRatio) {
width = Math.max(0, width || element.width);
height = height || element.height;
width = Math.max(0, width || (element?.width ?? 0));
height = height || (element?.height ?? 0);

return {
width,
height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
Expand Down
Loading