@mui/x-charts
Version:
The community edition of MUI X Charts components.
197 lines (195 loc) • 7.29 kB
JavaScript
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useChartDimensions = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
var _ownerWindow = _interopRequireDefault(require("@mui/utils/ownerWindow"));
var _useSelector = require("../../../store/useSelector");
var _constants = require("../../../../constants");
var _useChartDimensions = require("./useChartDimensions.selectors");
var _defaultizeMargin = require("../../../defaultizeMargin");
const MAX_COMPUTE_RUN = 10;
const useChartDimensions = ({
params,
store,
svgRef
}) => {
const hasInSize = params.width !== undefined && params.height !== undefined;
const stateRef = React.useRef({
displayError: false,
initialCompute: true,
computeRun: 0
});
// States only used for the initialization of the size.
const [innerWidth, setInnerWidth] = React.useState(0);
const [innerHeight, setInnerHeight] = React.useState(0);
const computeSize = React.useCallback(() => {
const mainEl = svgRef?.current;
if (!mainEl) {
return {};
}
const win = (0, _ownerWindow.default)(mainEl);
const computedStyle = win.getComputedStyle(mainEl);
const newHeight = Math.floor(parseFloat(computedStyle.height)) || 0;
const newWidth = Math.floor(parseFloat(computedStyle.width)) || 0;
store.update(prev => {
if (prev.dimensions.width === newWidth && prev.dimensions.height === newHeight) {
return prev;
}
return (0, _extends2.default)({}, prev, {
dimensions: {
margin: {
top: params.margin.top,
right: params.margin.right,
bottom: params.margin.bottom,
left: params.margin.left
},
width: params.width ?? newWidth,
height: params.height ?? newHeight,
propsWidth: params.width,
propsHeight: params.height
}
});
});
return {
height: newHeight,
width: newWidth
};
}, [store, svgRef, params.height, params.width,
// Margin is an object, so we need to include all the properties to prevent infinite loops.
params.margin.left, params.margin.right, params.margin.top, params.margin.bottom]);
React.useEffect(() => {
store.update(prev => {
const width = params.width ?? prev.dimensions.width;
const height = params.height ?? prev.dimensions.height;
return (0, _extends2.default)({}, prev, {
dimensions: {
margin: {
top: params.margin.top,
right: params.margin.right,
bottom: params.margin.bottom,
left: params.margin.left
},
width,
height,
propsHeight: params.height,
propsWidth: params.width
}
});
});
}, [store, params.height, params.width,
// Margin is an object, so we need to include all the properties to prevent infinite loops.
params.margin.left, params.margin.right, params.margin.top, params.margin.bottom]);
React.useEffect(() => {
// Ensure the error detection occurs after the first rendering.
stateRef.current.displayError = true;
}, []);
// This effect is used to compute the size of the container on the initial render.
// It is not bound to the raf loop to avoid an unwanted "resize" event.
// https://github.com/mui/mui-x/issues/13477#issuecomment-2336634785
(0, _useEnhancedEffect.default)(() => {
// computeRun is used to avoid infinite loops.
if (hasInSize || !stateRef.current.initialCompute || stateRef.current.computeRun > MAX_COMPUTE_RUN) {
return;
}
const computedSize = computeSize();
if (computedSize.width !== innerWidth || computedSize.height !== innerHeight) {
stateRef.current.computeRun += 1;
if (computedSize.width !== undefined) {
setInnerWidth(computedSize.width);
}
if (computedSize.height !== undefined) {
setInnerHeight(computedSize.height);
}
} else if (stateRef.current.initialCompute) {
stateRef.current.initialCompute = false;
}
}, [innerHeight, innerWidth, computeSize, hasInSize]);
(0, _useEnhancedEffect.default)(() => {
if (hasInSize) {
return () => {};
}
computeSize();
const elementToObserve = svgRef.current;
if (typeof ResizeObserver === 'undefined') {
return () => {};
}
let animationFrame;
const observer = new ResizeObserver(() => {
// See https://github.com/mui/mui-x/issues/8733
animationFrame = requestAnimationFrame(() => {
computeSize();
});
});
if (elementToObserve) {
observer.observe(elementToObserve);
}
return () => {
if (animationFrame) {
cancelAnimationFrame(animationFrame);
}
if (elementToObserve) {
observer.unobserve(elementToObserve);
}
};
}, [computeSize, hasInSize, svgRef]);
if (process.env.NODE_ENV !== 'production') {
if (stateRef.current.displayError && params.width === undefined && innerWidth === 0) {
console.error(`MUI X Charts: ChartContainer does not have \`width\` prop, and its container has no \`width\` defined.`);
stateRef.current.displayError = false;
}
if (stateRef.current.displayError && params.height === undefined && innerHeight === 0) {
console.error(`MUI X Charts: ChartContainer does not have \`height\` prop, and its container has no \`height\` defined.`);
stateRef.current.displayError = false;
}
}
const drawingArea = (0, _useSelector.useSelector)(store, _useChartDimensions.selectorChartDrawingArea);
const isXInside = React.useCallback(x => x >= drawingArea.left - 1 && x <= drawingArea.left + drawingArea.width, [drawingArea.left, drawingArea.width]);
const isYInside = React.useCallback(y => y >= drawingArea.top - 1 && y <= drawingArea.top + drawingArea.height, [drawingArea.height, drawingArea.top]);
const isPointInside = React.useCallback((x, y, targetElement) => {
// For element allowed to overflow, wrapping them in <g data-drawing-container /> make them fully part of the drawing area.
if (targetElement && targetElement.closest('[data-drawing-container]')) {
return true;
}
return isXInside(x) && isYInside(y);
}, [isXInside, isYInside]);
return {
instance: {
isPointInside,
isXInside,
isYInside
}
};
};
exports.useChartDimensions = useChartDimensions;
useChartDimensions.params = {
width: true,
height: true,
margin: true
};
useChartDimensions.getDefaultizedParams = ({
params
}) => (0, _extends2.default)({}, params, {
margin: (0, _defaultizeMargin.defaultizeMargin)(params.margin, _constants.DEFAULT_MARGINS)
});
useChartDimensions.getInitialState = ({
width,
height,
margin
}) => {
return {
dimensions: {
margin,
width: width ?? 0,
height: height ?? 0,
propsWidth: width,
propsHeight: height
}
};
};
;