@mui/x-charts
Version:
The community edition of MUI X Charts components.
98 lines (92 loc) • 3.53 kB
JavaScript
'use client';
import * as React from 'react';
import { isBandScale } from "../internals/isBandScale.js";
const offsetRatio = {
start: 0,
extremities: 0,
end: 1,
middle: 0.5,
tick: 0
};
export function useTicksGrouped(options) {
const {
scale,
tickInterval,
tickLabelPlacement = 'middle',
tickPlacement = 'extremities',
groups
} = options;
return React.useMemo(() => {
const domain = scale.domain();
const filteredDomain = typeof tickInterval === 'function' && domain.filter(tickInterval) || typeof tickInterval === 'object' && tickInterval || domain;
if (scale.bandwidth() > 0) {
// scale type = 'band'
const entries = mapToGrouping(filteredDomain, groups, tickPlacement, tickLabelPlacement, scale);
if (entries[0]) {
entries[0].ignoreTick = true;
}
return [{
formattedValue: undefined,
offset: scale.range()[0],
labelOffset: 0,
groupIndex: groups.length - 1
}, ...entries,
// Last tick
{
formattedValue: undefined,
offset: scale.range()[1],
labelOffset: 0,
groupIndex: groups.length - 1
}];
}
// scale type = 'point'
return mapToGrouping(filteredDomain, groups, tickPlacement, tickLabelPlacement, scale);
}, [scale, tickInterval, groups, tickPlacement, tickLabelPlacement]);
}
function mapToGrouping(tickValues, groups, tickPlacement, tickLabelPlacement, scale) {
const allTickItems = [];
// Map to keep track of offsets and their corresponding tick indexes
// Used to remove redundant ticks when they are in the same position
const dataIndexToTickIndex = new Map();
let currentValueCount = 0;
for (let groupIndex = 0; groupIndex < groups.length; groupIndex += 1) {
for (let dataIndex = 0; dataIndex < tickValues.length; dataIndex += 1) {
const tickValue = tickValues[dataIndex];
const groupValue = groups[groupIndex].getValue(tickValue, dataIndex);
const lastItem = allTickItems[allTickItems.length - 1];
// Check if this is a new unique value for this group
const isNew = lastItem?.value !== groupValue || lastItem?.groupIndex !== groupIndex;
if (isNew) {
currentValueCount = 1;
// Calculate tick offset
const tickOffset = isBandScale(scale) ? scale(tickValue) - (scale.step() - scale.bandwidth()) / 2 + offsetRatio[tickPlacement] * scale.step() : scale(tickValue);
// Calculate the label offset
const labelOffset = scale.step() * currentValueCount * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement]);
// Add a new item
allTickItems.push({
value: groupValue,
formattedValue: `${groupValue}`,
offset: tickOffset,
groupIndex,
dataIndex,
ignoreTick: false,
labelOffset
});
if (!dataIndexToTickIndex.has(dataIndex)) {
dataIndexToTickIndex.set(dataIndex, new Set());
}
const tickIndexes = dataIndexToTickIndex.get(dataIndex);
for (const previousIndex of tickIndexes.values()) {
allTickItems[previousIndex].ignoreTick = true;
}
tickIndexes.add(allTickItems.length - 1);
} else {
currentValueCount += 1;
// Calculate the label offset
const labelOffset = scale.step() * currentValueCount * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement]);
lastItem.labelOffset = labelOffset;
}
}
}
return allTickItems;
}