Skip to content

Commit

Permalink
new-tooltip-behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfauquette committed Nov 13, 2024
1 parent ae21ae1 commit 4d28a07
Show file tree
Hide file tree
Showing 66 changed files with 1,460 additions and 1,181 deletions.
224 changes: 61 additions & 163 deletions docs/data/charts/tooltip/CustomAxisTooltip.js
Original file line number Diff line number Diff line change
@@ -1,184 +1,82 @@
import * as React from 'react';
import NoSsr from '@mui/material/NoSsr';
import Popper from '@mui/material/Popper';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import { useAxisTooltip } from '@mui/x-charts/ChartsTooltip';
import { useSvgRef } from '@mui/x-charts/hooks';

function usePointer() {
const svgRef = useSvgRef();
const popperRef = React.useRef(null);
const positionRef = React.useRef({ x: 0, y: 0 });

// Use a ref to avoid rerendering on every mousemove event.
const [pointer, setPointer] = React.useState({
isActive: false,
isMousePointer: false,
pointerHeight: 0,
});

React.useEffect(() => {
const element = svgRef.current;
if (element === null) {
return () => {};
}

const handleOut = (event) => {
if (event.pointerType !== 'mouse') {
setPointer((prev) => ({
...prev,
isActive: false,
}));
}
};

const handleEnter = (event) => {
setPointer({
isActive: true,
isMousePointer: event.pointerType === 'mouse',
pointerHeight: event.height,
});
};

const handleMove = (event) => {
positionRef.current = {
x: event.clientX,
y: event.clientY,
};
popperRef.current?.update();
};

element.addEventListener('pointerenter', handleEnter);
element.addEventListener('pointerup', handleOut);
element.addEventListener('pointermove', handleMove);

return () => {
element.removeEventListener('pointerenter', handleEnter);
element.removeEventListener('pointerup', handleOut);
element.removeEventListener('pointermove', handleMove);
};
}, [svgRef]);

return {
...pointer,
popperRef,
anchorEl: {
getBoundingClientRect: () => ({
x: positionRef.current.x,
y: positionRef.current.y,
top: positionRef.current.y,
left: positionRef.current.x,
right: positionRef.current.x,
bottom: positionRef.current.y,
width: 0,
height: 0,
toJSON: () => '',
}),
},
};
}
import { ChartsTooltipContainer, useAxisTooltip } from '@mui/x-charts/ChartsTooltip';

export function CustomAxisTooltip() {
const tooltipData = useAxisTooltip();
const { isActive, isMousePointer, pointerHeight, popperRef, anchorEl } =
usePointer();

if (!tooltipData || !isActive) {
if (!tooltipData) {
// No data to display
return null;
}

// The pointer type can be used to have different behavior based on pointer type.
// Adapt the tooltip offset to the size of the pointer.
const yOffset = isMousePointer ? 0 : 40 - pointerHeight;

return (
<NoSsr>
<Popper
<ChartsTooltipContainer trigger="axis">
<Paper
elevation={0}
sx={{
pointerEvents: 'none',
zIndex: (theme) => theme.zIndex.modal,
}}
open
placement={isMousePointer ? 'top-end' : 'top'}
anchorEl={anchorEl}
popperRef={popperRef}
modifiers={[
{
name: 'offset',
options: {
offset: [0, yOffset],
m: 1,
border: 'solid',
borderWidth: 2,
borderColor: 'divider',
table: { borderSpacing: 0 },
thead: {
td: {
px: 1.5,
py: 0.75,
borderBottom: 'solid',
borderWidth: 2,
borderColor: 'divider',
},
},
]}
>
<Paper
elevation={0}
sx={{
m: 1,
border: 'solid',
borderWidth: 2,
borderColor: 'divider',
table: { borderSpacing: 0 },
thead: {
tbody: {
'tr:first-child': { td: { paddingTop: 1.5 } },
'tr:last-child': { td: { paddingBottom: 1.5 } },
tr: {
'td:first-child': { paddingLeft: 1.5 },
'td:last-child': { paddingRight: 1.5 },
td: {
px: 1.5,
py: 0.75,
borderBottom: 'solid',
borderWidth: 2,
borderColor: 'divider',
},
},
tbody: {
'tr:first-child': { td: { paddingTop: 1.5 } },
'tr:last-child': { td: { paddingBottom: 1.5 } },
tr: {
'td:first-child': { paddingLeft: 1.5 },
'td:last-child': { paddingRight: 1.5 },
td: {
paddingRight: '7px',
paddingBottom: '10px',
},
paddingRight: '7px',
paddingBottom: '10px',
},
},
}}
>
<table>
<thead>
<tr>
<td colSpan={3}>
<Typography>{tooltipData.axisFormattedValue}</Typography>
},
}}
>
<table>
<thead>
<tr>
<td colSpan={3}>
<Typography>{tooltipData.axisFormattedValue}</Typography>
</td>
</tr>
</thead>
<tbody>
{tooltipData.seriesItems.map((seriesItem) => (
<tr key={seriesItem.seriesId}>
<td aria-label={`${seriesItem.formattedLabel}-series-color`}>
<div
style={{
width: 10,
height: 10,
borderRadius: 2,
backgroundColor: seriesItem.color,
}}
/>
</td>
<td>
<Typography fontWeight="light">
{seriesItem.formattedLabel}
</Typography>
</td>
<td>
<Typography>{seriesItem.formattedValue}</Typography>
</td>
</tr>
</thead>
<tbody>
{tooltipData.seriesItems.map((seriesItem) => (
<tr key={seriesItem.seriesId}>
<td aria-label={`${seriesItem.formattedLabel}-series-color`}>
<div
style={{
width: 10,
height: 10,
borderRadius: 2,
backgroundColor: seriesItem.color,
}}
/>
</td>
<td>
<Typography fontWeight="light">
{seriesItem.formattedLabel}
</Typography>
</td>
<td>
<Typography>{seriesItem.formattedValue}</Typography>
</td>
</tr>
))}
</tbody>
</table>
</Paper>
</Popper>
</NoSsr>
))}
</tbody>
</table>
</Paper>
</ChartsTooltipContainer>
);
}
Loading

0 comments on commit 4d28a07

Please sign in to comment.