mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-02-01 17:47:09 +00:00
Fix: maximum size and mouse position with styling (#7816)
Fix: maximum size and mouse position with styling
This commit is contained in:
parent
2bb23dfe8c
commit
10f393a58d
@ -380,8 +380,6 @@ The following properties were renamed during v3 development:
|
||||
* `helpers.distanceBetweenPoints` was renamed to `helpers.math.distanceBetweenPoints`
|
||||
* `helpers.drawRoundedRectangle` was renamed to `helpers.canvas.roundedRect`
|
||||
* `helpers.getAngleFromPoint` was renamed to `helpers.math.getAngleFromPoint`
|
||||
* `helpers.getMaximumHeight` was renamed to `helpers.dom.getMaximumHeight`
|
||||
* `helpers.getMaximumWidth` was renamed to `helpers.dom.getMaximumWidth`
|
||||
* `helpers.getRelativePosition` was renamed to `helpers.dom.getRelativePosition`
|
||||
* `helpers.getStyle` was renamed to `helpers.dom.getStyle`
|
||||
* `helpers.getValueOrDefault` was renamed to `helpers.valueOrDefault`
|
||||
@ -477,6 +475,8 @@ The APIs listed in this section have changed in signature or behaviour from vers
|
||||
##### Canvas Helper
|
||||
|
||||
* The second parameter to `drawPoint` is now the full options object, so `style`, `rotation`, and `radius` are no longer passed explicitly
|
||||
* `helpers.getMaximumHeight` was replaced by `helpers.dom.getMaximumSize`
|
||||
* `helpers.getMaximumWidth` was replaced by `helpers.dom.getMaximumSize`
|
||||
|
||||
#### Platform
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import layouts from './core.layouts';
|
||||
import {BasicPlatform, DomPlatform} from '../platform';
|
||||
import PluginService from './core.plugins';
|
||||
import registry from './core.registry';
|
||||
import {getMaximumWidth, getMaximumHeight, retinaScale} from '../helpers/helpers.dom';
|
||||
import {retinaScale} from '../helpers/helpers.dom';
|
||||
import {mergeIf, merge, _merger, each, callback as callCallback, uid, valueOrDefault, _elementsEqual} from '../helpers/helpers.core';
|
||||
import {clear as canvasClear, clipArea, unclipArea, _isPointInArea} from '../helpers/helpers.canvas';
|
||||
// @ts-ignore
|
||||
@ -214,22 +214,6 @@ function getCanvas(item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
function computeNewSize(canvas, width, height, aspectRatio) {
|
||||
if (width === undefined || height === undefined) {
|
||||
width = getMaximumWidth(canvas);
|
||||
height = getMaximumHeight(canvas);
|
||||
}
|
||||
// the canvas render width and height will be casted to integers so make sure that
|
||||
// the canvas display style uses the same integer values to avoid blurring effect.
|
||||
|
||||
// Minimum values set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed
|
||||
width = Math.max(0, Math.floor(width));
|
||||
return {
|
||||
width,
|
||||
height: Math.max(0, Math.floor(aspectRatio ? width / aspectRatio : height))
|
||||
};
|
||||
}
|
||||
|
||||
class Chart {
|
||||
|
||||
// eslint-disable-next-line max-statements
|
||||
@ -355,7 +339,7 @@ class Chart {
|
||||
const options = me.options;
|
||||
const canvas = me.canvas;
|
||||
const aspectRatio = options.maintainAspectRatio && me.aspectRatio;
|
||||
const newSize = computeNewSize(canvas, width, height, aspectRatio);
|
||||
const newSize = me.platform.getMaximumSize(canvas, width, height, aspectRatio);
|
||||
|
||||
// detect devicePixelRation changes
|
||||
const oldRatio = me.currentDevicePixelRatio;
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
/**
|
||||
* Returns if the given value contains an effective constraint.
|
||||
* @private
|
||||
*/
|
||||
function isConstrainedValue(value) {
|
||||
return value !== undefined && value !== null && value !== 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -17,7 +9,10 @@ export function _getParentNode(domNode) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
// Private helper function to convert max-width/max-height values that may be percentages into a number
|
||||
/**
|
||||
* convert max-width/max-height values that may be percentages into a number
|
||||
* @private
|
||||
*/
|
||||
function parseMaxStyle(styleValue, node, parentProperty) {
|
||||
let valueInPixels;
|
||||
if (typeof styleValue === 'string') {
|
||||
@ -34,111 +29,117 @@ function parseMaxStyle(styleValue, node, parentProperty) {
|
||||
return valueInPixels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the max width or height of the given DOM node in a cross-browser compatible fashion
|
||||
* @param {HTMLElement} domNode - the node to check the constraint on
|
||||
* @param {string} maxStyle - the style that defines the maximum for the direction we are using ('max-width' / 'max-height')
|
||||
* @param {string} percentageProperty - property of parent to use when calculating width as a percentage
|
||||
* @return {number=} number or undefined if no constraint
|
||||
* @see {@link https://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser}
|
||||
*/
|
||||
function getConstraintDimension(domNode, maxStyle, percentageProperty) {
|
||||
const view = document.defaultView;
|
||||
const parentNode = _getParentNode(domNode);
|
||||
const constrainedNode = view.getComputedStyle(domNode)[maxStyle];
|
||||
const constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
|
||||
const hasCNode = isConstrainedValue(constrainedNode);
|
||||
const hasCContainer = isConstrainedValue(constrainedContainer);
|
||||
const infinity = Number.POSITIVE_INFINITY;
|
||||
|
||||
if (hasCNode || hasCContainer) {
|
||||
return Math.min(
|
||||
hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
|
||||
hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
|
||||
}
|
||||
}
|
||||
const getComputedStyle = (element) => window.getComputedStyle(element, null);
|
||||
|
||||
export function getStyle(el, property) {
|
||||
return el.currentStyle ?
|
||||
el.currentStyle[property] :
|
||||
document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
|
||||
getComputedStyle(el).getPropertyValue(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function _calculatePadding(container, padding, parentDimension) {
|
||||
padding = getStyle(container, padding);
|
||||
|
||||
// If the padding is not set at all and the node is not in the DOM, this can be an empty string
|
||||
// In that case, we need to handle it as no padding
|
||||
if (padding === '') {
|
||||
return 0;
|
||||
const positions = ['top', 'right', 'bottom', 'left'];
|
||||
function getPositionedStyle(styles, style, suffix) {
|
||||
const result = {};
|
||||
suffix = suffix ? '-' + suffix : '';
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const pos = positions[i];
|
||||
result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
|
||||
}
|
||||
|
||||
return padding.indexOf('%') > -1 ? parentDimension * parseInt(padding, 10) / 100 : parseInt(padding, 10);
|
||||
result.width = result.left + result.right;
|
||||
result.height = result.top + result.bottom;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getRelativePosition(evt, chart) {
|
||||
function getCanvasPosition(evt, canvas) {
|
||||
const e = evt.originalEvent || evt;
|
||||
const touches = e.touches;
|
||||
const source = touches && touches.length ? touches[0] : e;
|
||||
const {offsetX, offsetY} = source;
|
||||
|
||||
let box = false;
|
||||
let x, y;
|
||||
if (offsetX > 0 || offsetY > 0) {
|
||||
return {
|
||||
x: offsetX,
|
||||
y: offsetY
|
||||
};
|
||||
x = offsetX;
|
||||
y = offsetY;
|
||||
} else {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
x = source.clientX - rect.left;
|
||||
y = source.clientY - rect.top;
|
||||
box = true;
|
||||
}
|
||||
|
||||
return calculateRelativePositionFromClientXY(source, chart);
|
||||
return {x, y, box};
|
||||
}
|
||||
|
||||
function calculateRelativePositionFromClientXY(source, chart) {
|
||||
const {clientX: x, clientY: y} = source;
|
||||
export function getRelativePosition(evt, chart) {
|
||||
const {canvas, currentDevicePixelRatio} = chart;
|
||||
const style = getComputedStyle(canvas);
|
||||
const borderBox = style.boxSizing === 'border-box';
|
||||
const paddings = getPositionedStyle(style, 'padding');
|
||||
const borders = getPositionedStyle(style, 'border', 'width');
|
||||
const {x, y, box} = getCanvasPosition(evt, canvas);
|
||||
const xOffset = paddings.left + (box && borders.left);
|
||||
const yOffset = paddings.top + (box && borders.top);
|
||||
|
||||
const canvasElement = chart.canvas;
|
||||
const devicePixelRatio = chart.currentDevicePixelRatio;
|
||||
const boundingRect = canvasElement.getBoundingClientRect();
|
||||
// Scale mouse coordinates into canvas coordinates
|
||||
// by following the pattern laid out by 'jerryj' in the comments of
|
||||
// https://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
|
||||
const paddingLeft = parseFloat(getStyle(canvasElement, 'padding-left'));
|
||||
const paddingTop = parseFloat(getStyle(canvasElement, 'padding-top'));
|
||||
const paddingRight = parseFloat(getStyle(canvasElement, 'padding-right'));
|
||||
const paddingBottom = parseFloat(getStyle(canvasElement, 'padding-bottom'));
|
||||
const width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
|
||||
const height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
|
||||
|
||||
// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
|
||||
// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
|
||||
let {width, height} = chart;
|
||||
if (borderBox) {
|
||||
width -= paddings.width + borders.width;
|
||||
height -= paddings.height + borders.height;
|
||||
}
|
||||
return {
|
||||
x: Math.round((x - boundingRect.left - paddingLeft) / (width) * canvasElement.width / devicePixelRatio),
|
||||
y: Math.round((y - boundingRect.top - paddingTop) / (height) * canvasElement.height / devicePixelRatio)
|
||||
x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
|
||||
y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
|
||||
};
|
||||
}
|
||||
|
||||
function fallbackIfNotValid(measure, fallback) {
|
||||
return typeof measure === 'number' ? measure : fallback;
|
||||
}
|
||||
const infinity = Number.POSITIVE_INFINITY;
|
||||
|
||||
function getMax(domNode, prop, fallback, paddings) {
|
||||
const container = _getParentNode(domNode);
|
||||
if (!container) {
|
||||
return fallbackIfNotValid(domNode[prop], domNode[fallback]);
|
||||
function getContainerSize(canvas, width, height) {
|
||||
let maxWidth, maxHeight;
|
||||
|
||||
if (width === undefined || height === undefined) {
|
||||
const container = _getParentNode(canvas);
|
||||
if (!container) {
|
||||
width = canvas.clientWidth;
|
||||
height = canvas.clientHeight;
|
||||
} else {
|
||||
const rect = container.getBoundingClientRect(); // this is the border box of the container
|
||||
const containerStyle = getComputedStyle(container);
|
||||
const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
|
||||
const contarinerPadding = getPositionedStyle(containerStyle, 'padding');
|
||||
width = rect.width - contarinerPadding.width - containerBorder.width;
|
||||
height = rect.height - contarinerPadding.height - containerBorder.height;
|
||||
maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
|
||||
maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
|
||||
}
|
||||
}
|
||||
|
||||
const value = container[prop];
|
||||
const padding = paddings.reduce((acc, cur) => acc + _calculatePadding(container, 'padding-' + cur, value), 0);
|
||||
|
||||
const v = value - padding;
|
||||
const cv = getConstraintDimension(domNode, 'max-' + fallback, prop);
|
||||
return isNaN(cv) ? v : Math.min(v, cv);
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
maxWidth: maxWidth || infinity,
|
||||
maxHeight: maxHeight || infinity
|
||||
};
|
||||
}
|
||||
|
||||
export const getMaximumWidth = (domNode) => getMax(domNode, 'clientWidth', 'width', ['left', 'right']);
|
||||
export const getMaximumHeight = (domNode) => getMax(domNode, 'clientHeight', 'height', ['top', 'bottom']);
|
||||
export function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
|
||||
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);
|
||||
let {width, height} = containerSize;
|
||||
|
||||
if (style.boxSizing === 'content-box') {
|
||||
const borders = getPositionedStyle(style, 'border', 'width');
|
||||
const paddings = getPositionedStyle(style, 'padding');
|
||||
width -= paddings.width + borders.width;
|
||||
height -= paddings.height + borders.height;
|
||||
}
|
||||
width = Math.max(0, width - margins.width);
|
||||
height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height);
|
||||
return {
|
||||
width: Math.min(width, maxWidth, containerSize.maxWidth),
|
||||
height: Math.min(height, maxHeight, containerSize.maxHeight)
|
||||
};
|
||||
}
|
||||
|
||||
export function retinaScale(chart, forceRatio) {
|
||||
const pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
|
||||
|
||||
@ -49,6 +49,22 @@ export default class BasePlatform {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum size in pixels of given canvas 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;
|
||||
return {
|
||||
width,
|
||||
height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @returns {boolean} true if the canvas is attached to the platform, false if not.
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import BasePlatform from './platform.base';
|
||||
import {_getParentNode, getRelativePosition, supportsEventListenerOptions, readUsedSize} from '../helpers/helpers.dom';
|
||||
import {_getParentNode, getRelativePosition, supportsEventListenerOptions, readUsedSize, getMaximumSize} from '../helpers/helpers.dom';
|
||||
import {throttled} from '../helpers/helpers.extras';
|
||||
import {isNullOrUndef} from '../helpers/helpers.core';
|
||||
|
||||
@ -102,22 +102,18 @@ function removeListener(chart, type, listener) {
|
||||
chart.canvas.removeEventListener(type, listener, eventListenerOptions);
|
||||
}
|
||||
|
||||
function createEvent(type, chart, x, y, nativeEvent) {
|
||||
function fromNativeEvent(event, chart) {
|
||||
const type = EVENT_TYPES[event.type] || event.type;
|
||||
const {x, y} = getRelativePosition(event, chart);
|
||||
return {
|
||||
type,
|
||||
chart,
|
||||
native: nativeEvent || null,
|
||||
native: event,
|
||||
x: x !== undefined ? x : null,
|
||||
y: y !== undefined ? y : null,
|
||||
};
|
||||
}
|
||||
|
||||
function fromNativeEvent(event, chart) {
|
||||
const type = EVENT_TYPES[event.type] || event.type;
|
||||
const pos = getRelativePosition(event, chart);
|
||||
return createEvent(type, chart, pos.x, pos.y, event);
|
||||
}
|
||||
|
||||
function createAttachObserver(chart, type, listener) {
|
||||
const canvas = chart.canvas;
|
||||
const container = canvas && _getParentNode(canvas);
|
||||
@ -371,6 +367,15 @@ export default class DomPlatform extends BasePlatform {
|
||||
return window.devicePixelRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {number} [width] - content width of parent element
|
||||
* @param {number} [height] - content height of parent element
|
||||
* @param {number} [aspectRatio] - aspect ratio to maintain
|
||||
*/
|
||||
getMaximumSize(canvas, width, height, aspectRatio) {
|
||||
return getMaximumSize(canvas, width, height, aspectRatio);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
|
||||
@ -5,7 +5,7 @@ describe('DOM helpers tests', function() {
|
||||
helpers = window.Chart.helpers.dom;
|
||||
});
|
||||
|
||||
it ('should get the maximum width and height for a node', function() {
|
||||
it ('should get the maximum size for a node', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = '200px';
|
||||
@ -17,8 +17,7 @@ describe('DOM helpers tests', function() {
|
||||
var innerDiv = document.createElement('div');
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(200);
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(300);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 200, height: 300}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -42,8 +41,7 @@ describe('DOM helpers tests', function() {
|
||||
var innerDiv = document.createElement('div');
|
||||
shadow.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(200);
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(300);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 200, height: 300}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -61,7 +59,7 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.style.maxWidth = '150px';
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 150}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -79,7 +77,7 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.style.maxHeight = '150px';
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -101,7 +99,7 @@ describe('DOM helpers tests', function() {
|
||||
var innerDiv = document.createElement('div');
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 150}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -124,7 +122,7 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.style.height = '300px'; // make it large
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -142,12 +140,12 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.style.maxWidth = '50%';
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 100}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum height of a node that has a percentage max-height style', function() {
|
||||
it('should get the maximum height of a node that has a percentage max-height style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = '200px';
|
||||
@ -160,7 +158,7 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.style.maxHeight = '50%';
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -182,7 +180,7 @@ describe('DOM helpers tests', function() {
|
||||
var innerDiv = document.createElement('div');
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 100}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -204,7 +202,7 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.style.height = '300px'; // make it large
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -226,15 +224,15 @@ describe('DOM helpers tests', function() {
|
||||
innerDiv.appendChild(canvas);
|
||||
|
||||
// No padding
|
||||
expect(helpers.getMaximumWidth(canvas)).toBe(300);
|
||||
expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 300}));
|
||||
|
||||
// test with percentage
|
||||
innerDiv.style.padding = '5%';
|
||||
expect(helpers.getMaximumWidth(canvas)).toBe(270);
|
||||
expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 270}));
|
||||
|
||||
// test with pixels
|
||||
innerDiv.style.padding = '10px';
|
||||
expect(helpers.getMaximumWidth(canvas)).toBe(280);
|
||||
expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 280}));
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
@ -258,9 +256,51 @@ describe('DOM helpers tests', function() {
|
||||
|
||||
describe('getRelativePosition', function() {
|
||||
it('should use offsetX/Y when available', function() {
|
||||
const event = {offsetX: 0, offsetY: 10};
|
||||
const chart = undefined;
|
||||
expect(helpers.getRelativePosition(event, chart)).toEqual({x: 0, y: 10});
|
||||
const event = {offsetX: 50, offsetY: 100};
|
||||
const chart = window.acquireChart({}, {
|
||||
canvas: {
|
||||
height: 200,
|
||||
width: 200,
|
||||
}
|
||||
});
|
||||
expect(helpers.getRelativePosition(event, chart)).toEqual({x: 50, y: 100});
|
||||
|
||||
const chart2 = window.acquireChart({}, {
|
||||
canvas: {
|
||||
height: 200,
|
||||
width: 200,
|
||||
style: 'padding: 10px'
|
||||
}
|
||||
});
|
||||
expect(helpers.getRelativePosition(event, chart2)).toEqual({
|
||||
x: Math.round((event.offsetX - 10) / 180 * 200),
|
||||
y: Math.round((event.offsetY - 10) / 180 * 200)
|
||||
});
|
||||
|
||||
const chart3 = window.acquireChart({}, {
|
||||
canvas: {
|
||||
height: 200,
|
||||
width: 200,
|
||||
style: 'width: 400px, height: 400px; padding: 10px'
|
||||
}
|
||||
});
|
||||
expect(helpers.getRelativePosition(event, chart3)).toEqual({
|
||||
x: Math.round((event.offsetX - 10) / 360 * 400),
|
||||
y: Math.round((event.offsetY - 10) / 360 * 400)
|
||||
});
|
||||
|
||||
const chart4 = window.acquireChart({}, {
|
||||
canvas: {
|
||||
height: 200,
|
||||
width: 200,
|
||||
style: 'width: 400px, height: 400px; padding: 10px; position: absolute; left: 20, top: 20'
|
||||
}
|
||||
});
|
||||
expect(helpers.getRelativePosition(event, chart4)).toEqual({
|
||||
x: Math.round((event.offsetX - 10) / 360 * 400),
|
||||
y: Math.round((event.offsetY - 10) / 360 * 400)
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should calculate from clientX/Y as fallback', function() {
|
||||
|
||||
3
types/helpers/helpers.dom.d.ts
vendored
3
types/helpers/helpers.dom.d.ts
vendored
@ -1,5 +1,4 @@
|
||||
export function getMaximumHeight(node: HTMLElement): number;
|
||||
export function getMaximumWidth(node: HTMLElement): number;
|
||||
export function getMaximumSize(node: HTMLElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number };
|
||||
export function getRelativePosition(
|
||||
evt: MouseEvent,
|
||||
chart: { readonly canvas: HTMLCanvasElement }
|
||||
|
||||
8
types/platform/index.d.ts
vendored
8
types/platform/index.d.ts
vendored
@ -38,6 +38,14 @@ export class BasePlatform {
|
||||
* @returns {number} the current devicePixelRatio of the device this platform is connected to.
|
||||
*/
|
||||
getDevicePixelRatio(): number;
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas - The canvas for which to calculate the maximum size
|
||||
* @param {number} [width] - Parent element's content width
|
||||
* @param {number} [height] - Parent element's content height
|
||||
* @param {number} [aspectRatio] - The aspect ratio to maintain
|
||||
* @returns { width: number, height: number } the maximum size available.
|
||||
*/
|
||||
getMaximumSize(canvas: HTMLCanvasElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number };
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @returns {boolean} true if the canvas is attached to the platform, false if not.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user