@mui/x-charts
Version:
The community edition of MUI X Charts components.
92 lines (89 loc) • 3.41 kB
JavaScript
'use client';
import * as React from 'react';
import { useChartContext } from "../context/ChartProvider/index.js";
import { isBandScale } from "../internals/isBandScale.js";
import { isInfinity } from "../internals/isInfinity.js";
const offsetRatio = {
start: 0,
extremities: 0,
end: 1,
middle: 0.5
};
export function useTicks(options) {
const {
scale,
tickNumber,
valueFormatter,
tickInterval,
tickPlacement = 'extremities',
tickLabelPlacement: tickLabelPlacementProp,
direction
} = options;
const {
instance
} = useChartContext();
return React.useMemo(() => {
// band scale
if (isBandScale(scale)) {
const domain = scale.domain();
const tickLabelPlacement = tickLabelPlacementProp ?? 'middle';
if (scale.bandwidth() > 0) {
// scale type = 'band'
const filteredDomain = typeof tickInterval === 'function' && domain.filter(tickInterval) || typeof tickInterval === 'object' && tickInterval || domain;
return [...filteredDomain.map(value => ({
value,
formattedValue: valueFormatter?.(value, {
location: 'tick',
scale
}) ?? `${value}`,
offset: scale(value) - (scale.step() - scale.bandwidth()) / 2 + offsetRatio[tickPlacement] * scale.step(),
labelOffset: tickLabelPlacement === 'tick' ? 0 : scale.step() * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement])
})), ...(tickPlacement === 'extremities' ? [{
formattedValue: undefined,
offset: scale.range()[1],
labelOffset: 0
}] : [])];
}
// scale type = 'point'
const filteredDomain = typeof tickInterval === 'function' && domain.filter(tickInterval) || typeof tickInterval === 'object' && tickInterval || domain;
return filteredDomain.map(value => ({
value,
formattedValue: valueFormatter?.(value, {
location: 'tick',
scale
}) ?? `${value}`,
offset: scale(value),
labelOffset: 0
}));
}
const domain = scale.domain();
// Skip axis rendering if no data is available
// - The domains contains Infinity for continuous scales.
if (domain.some(isInfinity)) {
return [];
}
const tickLabelPlacement = tickLabelPlacementProp;
const ticks = typeof tickInterval === 'object' ? tickInterval : scale.ticks(tickNumber);
// Ticks inside the drawing area
const visibleTicks = [];
for (let i = 0; i < ticks.length; i += 1) {
const value = ticks[i];
const offset = scale(value);
const isInside = direction === 'x' ? instance.isXInside(offset) : instance.isYInside(offset);
if (isInside) {
visibleTicks.push({
value,
formattedValue: valueFormatter?.(value, {
location: 'tick',
scale
}) ?? scale.tickFormat(tickNumber)(value),
offset,
// Allowing the label to be placed in the middle of a continuous scale is weird.
// But it is useful in some cases, like funnel categories with a linear scale.
labelOffset: tickLabelPlacement === 'middle' ? scale(ticks[i - 1] ?? 0) - (offset + scale(ticks[i - 1] ?? 0)) / 2 : 0
});
}
}
return visibleTicks;
}, [scale, tickLabelPlacementProp, tickInterval, tickNumber, tickPlacement, valueFormatter, direction, instance]);
}