Skip to content

Commit

Permalink
[charts] Clean the axis rendering (#8948)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfauquette authored May 16, 2023
1 parent d7ac79c commit 52330d2
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 163 deletions.
52 changes: 52 additions & 0 deletions packages/x-charts/src/Axis/axisClasses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
unstable_generateUtilityClass as generateUtilityClass,
unstable_generateUtilityClasses as generateUtilityClasses,
} from '@mui/utils';

export interface AxisClasses {
/** Styles applied to the root element. */
root: string;
/** Styles applied to the main line element. */
line: string;
/** Styles applied to group ingruding the tick and its label. */
tickContainer: string;
/** Styles applied to ticks. */
tick: string;
/** Styles applied to ticks label. */
tickLabel: string;
/** Styles applied to the axis label. */
label: string;
/** Styles applied to x axes. */
directionX: string;
/** Styles applied to y axes. */
directionY: string;
/** Styles applied to the top axis. */
top: string;
/** Styles applied to the bottom axis. */
bottom: string;
/** Styles applied to the left axis. */
left: string;
/** Styles applied to the right axis. */
right: string;
}

export type XAxisClassKey = keyof AxisClasses;

export function getAxisUtilityClass(slot: string) {
return generateUtilityClass('MuiAxis', slot);
}

export const axisClasses: AxisClasses = generateUtilityClasses('MuiAxis', [
'root',
'line',
'tickContainer',
'tick',
'tickLabel',
'label',
'directionX',
'directionY',
'top',
'bottom',
'left',
'right',
]);
2 changes: 1 addition & 1 deletion packages/x-charts/src/BarChart/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export function BarChart(props: BarChartProps) {
tooltip?.trigger !== 'axis' && highlight?.x === 'none' && highlight?.y === 'none'
}
>
<BarPlot />
<Axis topAxis={topAxis} leftAxis={leftAxis} rightAxis={rightAxis} bottomAxis={bottomAxis} />
<BarPlot />
<Highlight {...highlight} />
<Tooltip {...tooltip} />
{children}
Expand Down
2 changes: 1 addition & 1 deletion packages/x-charts/src/LineChart/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export function LineChart(props: LineChartProps) {
tooltip?.trigger !== 'axis' && highlight?.x === 'none' && highlight?.y === 'none'
}
>
<LinePlot />
<Axis topAxis={topAxis} leftAxis={leftAxis} rightAxis={rightAxis} bottomAxis={bottomAxis} />
<LinePlot />

<Highlight {...highlight} />
<Tooltip {...tooltip} />
Expand Down
2 changes: 1 addition & 1 deletion packages/x-charts/src/ScatterChart/ScatterChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export function ScatterChart(props: ScatterChartProps) {
yAxis={yAxis}
sx={sx}
>
<ScatterPlot />
<Axis topAxis={topAxis} leftAxis={leftAxis} rightAxis={rightAxis} bottomAxis={bottomAxis} />
<ScatterPlot />
<Highlight x="none" y="none" {...highlight} />
<Tooltip trigger="item" {...tooltip} />
{children}
Expand Down
99 changes: 63 additions & 36 deletions packages/x-charts/src/XAxis/XAxis.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,98 @@
import * as React from 'react';
import { unstable_composeClasses as composeClasses } from '@mui/utils';
import { useThemeProps, useTheme, Theme } from '@mui/material/styles';
import { CartesianContext } from '../context/CartesianContextProvider';
import { DrawingContext } from '../context/DrawingProvider';
import useTicks from '../hooks/useTicks';
import { XAxisProps } from '../models/axis';
import { getAxisUtilityClass } from '../Axis/axisClasses';
import { Line, Tick, TickLabel, Label } from '../internals/components/AxisSharedComponents';

export function XAxis(props: XAxisProps) {
const useUtilityClasses = (ownerState: XAxisProps & { theme: Theme }) => {
const { classes, position } = ownerState;
const slots = {
root: ['root', 'directionX', position],
line: ['line'],
tickContainer: ['tickContainer'],
tick: ['tick'],
tickLabel: ['tickLabel'],
label: ['label'],
};

return composeClasses(slots, getAxisUtilityClass, classes);
};
const defaultProps = {
position: 'bottom',
disableLine: false,
disableTicks: false,
tickFontSize: 10,
labelFontSize: 14,
tickSize: 6,
} as const;

export function XAxis(inProps: XAxisProps) {
const props = useThemeProps({ props: { ...defaultProps, ...inProps }, name: 'MuiXAxis' });
const {
xAxis: {
[props.axisId]: { scale: xScale, ...settings },
[props.axisId]: { scale: xScale, ticksNumber, ...settings },
},
} = React.useContext(CartesianContext);

const defaultizedProps = { ...defaultProps, ...settings, ...props };
const {
position = 'bottom',
disableLine = false,
disableTicks = false,
fill = 'currentColor',
fontSize = 10,
position,
disableLine,
disableTicks,
tickFontSize,
label,
labelFontSize = 14,
stroke = 'currentColor',
tickSize: tickSizeProp = 6,
} = { ...settings, ...props };
labelFontSize,
tickSize: tickSizeProp,
} = defaultizedProps;

const theme = useTheme();
const classes = useUtilityClasses({ ...defaultizedProps, theme });

const { left, top, width, height } = React.useContext(DrawingContext);

const tickSize = disableTicks ? 4 : tickSizeProp;

const xTicks = useTicks({ scale: xScale });

const xTicks = useTicks({ scale: xScale, ticksNumber });
const positionSigne = position === 'bottom' ? 1 : -1;

return (
<g transform={`translate(0, ${position === 'bottom' ? top + height : top})`}>
<g
transform={`translate(0, ${position === 'bottom' ? top + height : top})`}
className={classes.root}
>
{!disableLine && (
<line
x1={xScale.range()[0]}
x2={xScale.range()[1]}
stroke={stroke}
shapeRendering="crispEdges"
/>
<Line x1={xScale.range()[0]} x2={xScale.range()[1]} className={classes.line} />
)}
{xTicks.map(({ value, offset }, index) => (
<g key={index} transform={`translate(${offset}, 0)`}>
{!disableTicks && (
<line y2={positionSigne * tickSize} stroke={stroke} shapeRendering="crispEdges" />
)}
<text
fill={fill}
transform={`translate(0, ${positionSigne * (fontSize + tickSize + 2)})`}
textAnchor="middle"
fontSize={fontSize}
<g key={index} transform={`translate(${offset}, 0)`} className={classes.tickContainer}>
{!disableTicks && <Tick y2={positionSigne * tickSize} className={classes.tick} />}
<TickLabel
transform={`translate(0, ${positionSigne * (tickFontSize + tickSize + 2)})`}
sx={{
fontSize: tickFontSize,
}}
className={classes.tickLabel}
>
{value.toLocaleString()}
</text>
</TickLabel>
</g>
))}
{label && (
<text
fill={fill}
<Label
transform={`translate(${left + width / 2}, ${
positionSigne * (fontSize + tickSize + 20)
positionSigne * (tickFontSize + tickSize + 20)
})`}
fontSize={labelFontSize}
textAnchor="middle"
sx={{
fontSize: labelFontSize,
}}
className={classes.label}
>
{label}
</text>
</Label>
)}
</g>
);
Expand Down
101 changes: 65 additions & 36 deletions packages/x-charts/src/YAxis/YAxis.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,100 @@
import * as React from 'react';
import { unstable_composeClasses as composeClasses } from '@mui/utils';
import { useThemeProps, useTheme, Theme } from '@mui/material/styles';
import { CartesianContext } from '../context/CartesianContextProvider';
import { DrawingContext } from '../context/DrawingProvider';
import useTicks from '../hooks/useTicks';
import { YAxisProps } from '../models/axis';
import { Line, Tick, TickLabel, Label } from '../internals/components/AxisSharedComponents';
import { getAxisUtilityClass } from '../Axis/axisClasses';

export function YAxis(props: YAxisProps) {
const useUtilityClasses = (ownerState: YAxisProps & { theme: Theme }) => {
const { classes, position } = ownerState;
const slots = {
root: ['root', 'directionY', position],
line: ['line'],
tickContainer: ['tickContainer'],
tick: ['tick'],
tickLabel: ['tickLabel'],
label: ['label'],
};

return composeClasses(slots, getAxisUtilityClass, classes);
};

const defaultProps = {
position: 'left',
disableLine: false,
disableTicks: false,
tickFontSize: 10,
labelFontSize: 14,
tickSize: 6,
} as const;

export function YAxis(inProps: YAxisProps) {
const props = useThemeProps({ props: { ...defaultProps, ...inProps }, name: 'MuiYAxis' });
const {
yAxis: {
[props.axisId]: { scale: yScale, ...settings },
[props.axisId]: { scale: yScale, ticksNumber, ...settings },
},
} = React.useContext(CartesianContext);

const defaultizedProps = { ...defaultProps, ...settings, ...props };
const {
position = 'left',
disableLine = false,
disableTicks = false,
fill = 'currentColor',
fontSize = 10,
position,
disableLine,
disableTicks,
tickFontSize,
label,
labelFontSize = 14,
stroke = 'currentColor',
tickSize: tickSizeProp = 6,
} = { ...settings, ...props };
labelFontSize,
tickSize: tickSizeProp,
} = defaultizedProps;

const theme = useTheme();
const classes = useUtilityClasses({ ...defaultizedProps, theme });

const { left, top, width, height } = React.useContext(DrawingContext);

const tickSize = disableTicks ? 4 : tickSizeProp;

const yTicks = useTicks({ scale: yScale });
const yTicks = useTicks({ scale: yScale, ticksNumber });

const positionSigne = position === 'right' ? 1 : -1;

return (
<g transform={`translate(${position === 'right' ? left + width : left}, 0)`}>
<g
transform={`translate(${position === 'right' ? left + width : left}, 0)`}
className={classes.root}
>
{!disableLine && (
<line
y1={yScale.range()[0]}
y2={yScale.range()[1]}
stroke={stroke}
shapeRendering="crispEdges"
/>
<Line y1={yScale.range()[0]} y2={yScale.range()[1]} className={classes.line} />
)}
{yTicks.map(({ value, offset }, index) => (
<g key={index} transform={`translate(0, ${offset})`}>
{!disableTicks && (
<line x2={positionSigne * tickSize} stroke={stroke} shapeRendering="crispEdges" />
)}
<text
fill={fill}
transform={`translate(${positionSigne * (fontSize + tickSize + 2)}, 0)`}
textAnchor="middle"
fontSize={fontSize}
<g key={index} transform={`translate(0, ${offset})`} className={classes.tickContainer}>
{!disableTicks && <Tick x2={positionSigne * tickSize} className={classes.tick} />}
<TickLabel
transform={`translate(${positionSigne * (tickFontSize + tickSize + 2)}, 0)`}
sx={{
fontSize: tickFontSize,
}}
className={classes.tickLabel}
>
{value}
</text>
</TickLabel>
</g>
))}
{label && (
<text
fill={fill}
style={{}}
transform={`translate(${positionSigne * (fontSize + tickSize + 20)}, ${
<Label
transform={`translate(${positionSigne * (tickFontSize + tickSize + 20)}, ${
top + height / 2
}) rotate(${positionSigne * 90})`}
fontSize={labelFontSize}
textAnchor="middle"
sx={{
fontSize: labelFontSize,
}}
className={classes.label}
>
{label}
</text>
</Label>
)}
</g>
);
Expand Down
Loading

0 comments on commit 52330d2

Please sign in to comment.