Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[charts] Use <circle /> instead of <path /> for line marks by default #15220

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
38 changes: 38 additions & 0 deletions docs/data/charts/line-demo/CustomLineMarks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react';
import { LineChart } from '@mui/x-charts/LineChart';

const uData = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
const pData = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
const xLabels = [
'Page A',
'Page B',
'Page C',
'Page D',
'Page E',
'Page F',
'Page G',
];

export default function CustomLineMarks() {
return (
<LineChart
width={500}
height={300}
series={[
{
data: pData,
label: 'pv',
shape: 'cross',
showMark: ({ index }) => index % 2 === 0,
},
{
data: uData,
label: 'uv',
shape: 'diamond',
showMark: ({ index }) => index % 2 === 0,
},
]}
xAxis={[{ scaleType: 'point', data: xLabels }]}
/>
);
}
38 changes: 38 additions & 0 deletions docs/data/charts/line-demo/CustomLineMarks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react';
import { LineChart } from '@mui/x-charts/LineChart';

const uData = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
const pData = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
const xLabels = [
'Page A',
'Page B',
'Page C',
'Page D',
'Page E',
'Page F',
'Page G',
];

export default function CustomLineMarks() {
return (
<LineChart
width={500}
height={300}
series={[
{
data: pData,
label: 'pv',
shape: 'cross',
showMark: ({ index }) => index % 2 === 0,
},
{
data: uData,
label: 'uv',
shape: 'diamond',
showMark: ({ index }) => index % 2 === 0,
},
]}
xAxis={[{ scaleType: 'point', data: xLabels }]}
/>
);
}
7 changes: 7 additions & 0 deletions docs/data/charts/line-demo/line-demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,10 @@ To do so, the `slots.line` is set with a custom components that render the defau
- The second one is clipped to show predictions (from the limit to the right of the chart) with dash styling.

{{"demo": "LineWithPrediction.js"}}

## CustomLineMarks

Notice that using another shape than "circle" renders a `<path />` instead of the `<circle />` for mark elements.
This modification implies a small drop of rendering performances (around +50ms to render 1.000 marks).

{{"demo": "CustomLineMarks.js"}}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ If you used axes in a pie chart please open an issue, we would be curious to get
The `resolveSizeBeforeRender` prop has been removed from all components.
If you were using this prop, you can safely remove it.

## Remove `experimentalMarkRendering` prop ✅

The `experimentalMarkRendering` prop has been removed from the LineChart component.
The line mark are now `<circle />` element by default.
And you can chose another shape by adding a `shape` property to your line series.

The codemod only removes the `experimentalMarkRendering` prop.
If you relied on the fact that marks were `path` elements, you need to update your logic.
Comment on lines +153 to +158
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should add this to the changelog in PR description


## Rename `labelFontSize` and `tickFontSize` props ✅

The `labelFontSize` and `tickFontSize` props have been removed in favor of the style objects `labelStyle` and `tickStyle` respectively.
Expand Down
1 change: 0 additions & 1 deletion docs/pages/x/api/charts/line-chart-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"dataset": { "type": { "name": "arrayOf", "description": "Array&lt;object&gt;" } },
"disableAxisListener": { "type": { "name": "bool" }, "default": "false" },
"disableLineItemHighlight": { "type": { "name": "bool" } },
"experimentalMarkRendering": { "type": { "name": "bool" } },
"grid": {
"type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" }
},
Expand Down
1 change: 0 additions & 1 deletion docs/pages/x/api/charts/line-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"dataset": { "type": { "name": "arrayOf", "description": "Array&lt;object&gt;" } },
"disableAxisListener": { "type": { "name": "bool" }, "default": "false" },
"disableLineItemHighlight": { "type": { "name": "bool" } },
"experimentalMarkRendering": { "type": { "name": "bool" } },
"grid": {
"type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" }
},
Expand Down
6 changes: 6 additions & 0 deletions docs/pages/x/api/charts/line-series-type.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
"type": { "description": "string | ((location: 'tooltip' | 'legend') =&gt; string)" }
},
"labelMarkType": { "type": { "description": "ChartsLabelMarkProps['type']" } },
"shape": {
"type": {
"description": "'circle' | 'cross' | 'diamond' | 'square' | 'star' | 'triangle' | 'wye'"
},
"default": "'circle'"
},
"showMark": { "type": { "description": "boolean | ((params: ShowMarkParams) =&gt; boolean)" } },
"stack": { "type": { "description": "string" } },
"stackOffset": { "type": { "description": "StackOffsetType" }, "default": "'none'" },
Expand Down
1 change: 0 additions & 1 deletion docs/pages/x/api/charts/mark-plot.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"props": {
"experimentalRendering": { "type": { "name": "bool" }, "default": "false" },
"onItemClick": {
"type": { "name": "func" },
"signature": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
"disableLineItemHighlight": {
"description": "If <code>true</code>, render the line highlight item."
},
"experimentalMarkRendering": {
"description": "If <code>true</code> marks will render <code>&lt;circle /&gt;</code> instead of <code>&lt;path /&gt;</code> and drop theme override for faster rendering."
},
"grid": { "description": "Option to display a cartesian grid in the background." },
"height": {
"description": "The height of the chart in px. If not defined, it takes the height of the parent element."
Expand Down
3 changes: 0 additions & 3 deletions docs/translations/api-docs/charts/line-chart/line-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
"disableLineItemHighlight": {
"description": "If <code>true</code>, render the line highlight item."
},
"experimentalMarkRendering": {
"description": "If <code>true</code> marks will render <code>&lt;circle /&gt;</code> instead of <code>&lt;path /&gt;</code> and drop theme override for faster rendering."
},
"grid": { "description": "Option to display a cartesian grid in the background." },
"height": {
"description": "The height of the chart in px. If not defined, it takes the height of the parent element."
Expand Down
3 changes: 3 additions & 0 deletions docs/translations/api-docs/charts/line-series-type.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
"labelMarkType": {
"description": "Defines the mark type for the series.<br /><br />There is a default mark type for each series type.<br /><br />It allows custom values which will be passed to the mark component if it was customized."
},
"shape": {
"description": "The shape of the mark elements.<br />Using &#39;circle&#39; renders a <code>&amp;lt;circle /&amp;gt;</code> element, while all other options render a <code>&amp;lt;path /&amp;gt;</code> instead. The path causes a small decrease in performance."
},
"showMark": {
"description": "Define which items of the series should display a mark.<br />If can be a boolean that applies to all items.<br />Or a callback that gets some item properties and returns true if the item should be displayed."
},
Expand Down
3 changes: 0 additions & 3 deletions docs/translations/api-docs/charts/mark-plot/mark-plot.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
{
"componentDescription": "",
"propDescriptions": {
"experimentalRendering": {
"description": "If <code>true</code> the mark element will only be able to render circle. Giving fewer customization options, but saving around 40ms per 1.000 marks."
},
"onItemClick": {
"description": "Callback fired when a line mark item is clicked.",
"typeDescriptions": {
Expand Down
10 changes: 0 additions & 10 deletions packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,6 @@ MarkPlotZoom.propTypes = {
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the TypeScript types and run "pnpm proptypes" |
// ----------------------------------------------------------------------
/**
* If `true` the mark element will only be able to render circle.
* Giving fewer customization options, but saving around 40ms per 1.000 marks.
* @default false
*/
experimentalRendering: PropTypes.bool,
/**
* Callback fired when a line mark item is clicked.
* @param {React.MouseEvent<SVGPathElement, MouseEvent>} event The event source of the callback.
Expand Down Expand Up @@ -246,10 +240,6 @@ LineChartPro.propTypes = {
* If `true`, render the line highlight item.
*/
disableLineItemHighlight: PropTypes.bool,
/**
* If `true` marks will render `<circle />` instead of `<path />` and drop theme override for faster rendering.
*/
experimentalMarkRendering: PropTypes.bool,
/**
* Option to display a cartesian grid in the background.
*/
Expand Down
15 changes: 0 additions & 15 deletions packages/x-charts/src/LineChart/CircleMarkElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { useTheme } from '@mui/material/styles';
import { warnOnce } from '@mui/x-internals/warning';
import { animated, useSpring } from '@react-spring/web';
import { useInteractionItemProps } from '../hooks/useInteractionItemProps';
import { useItemHighlighted } from '../context';
Expand All @@ -13,10 +12,6 @@ import { useStore } from '../internals/store/useStore';

export type CircleMarkElementProps = Omit<MarkElementOwnerState, 'isFaded' | 'isHighlighted'> &
Omit<React.SVGProps<SVGPathElement>, 'ref' | 'id'> & {
/**
* The shape of the marker.
*/
shape: 'circle' | 'cross' | 'diamond' | 'square' | 'star' | 'triangle' | 'wye';
/**
* If `true`, animations are skipped.
* @default false
Expand Down Expand Up @@ -50,19 +45,9 @@ function CircleMarkElement(props: CircleMarkElementProps) {
dataIndex,
onClick,
skipAnimation,
shape,
...other
} = props;

if (shape !== 'circle') {
warnOnce(
[
`MUI X: The mark element of your line chart have shape "${shape}" which is not supported when using \`experimentalRendering=true\`.`,
'Only "circle" are supported with `experimentalRendering`.',
].join('\n'),
'error',
);
}
const theme = useTheme();
const getInteractionItemProps = useInteractionItemProps();
const { isFaded, isHighlighted } = useItemHighlighted({
Expand Down
8 changes: 0 additions & 8 deletions packages/x-charts/src/LineChart/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@ export interface LineChartProps
* @default false
*/
skipAnimation?: boolean;
/**
* If `true` marks will render `<circle />` instead of `<path />` and drop theme override for faster rendering.
*/
experimentalMarkRendering?: boolean;
}

/**
Expand Down Expand Up @@ -226,10 +222,6 @@ LineChart.propTypes = {
* If `true`, render the line highlight item.
*/
disableLineItemHighlight: PropTypes.bool,
/**
* If `true` marks will render `<circle />` instead of `<path />` and drop theme override for faster rendering.
*/
experimentalMarkRendering: PropTypes.bool,
/**
* Option to display a cartesian grid in the background.
*/
Expand Down
40 changes: 32 additions & 8 deletions packages/x-charts/src/LineChart/LineHighlightElement.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { symbol as d3Symbol, symbolsFill as d3SymbolsFill } from '@mui/x-charts-vendor/d3-shape';
import composeClasses from '@mui/utils/composeClasses';
import generateUtilityClass from '@mui/utils/generateUtilityClass';
import { styled } from '@mui/material/styles';
import generateUtilityClasses from '@mui/utils/generateUtilityClasses';
import { SeriesId } from '../models/seriesType/common';
import { getSymbol } from '../internals/getSymbol';

export interface LineHighlightElementClasses {
/** Styles applied to the root element. */
Expand Down Expand Up @@ -40,7 +42,7 @@ const useUtilityClasses = (ownerState: LineHighlightElementOwnerState) => {
return composeClasses(slots, getHighlightElementUtilityClass, classes);
};

const HighlightElement = styled('circle', {
const HighlightPathElement = styled('path', {
name: 'MuiHighlightElement',
slot: 'Root',
overridesResolver: (_, styles) => styles.root,
Expand All @@ -50,8 +52,22 @@ const HighlightElement = styled('circle', {
fill: ownerState.color,
}));

export type LineHighlightElementProps = LineHighlightElementOwnerState &
Omit<React.SVGProps<SVGCircleElement>, 'ref' | 'id'>;
const HighlightCircleElement = styled('circle', {
name: 'MuiHighlightElement',
slot: 'Root',
overridesResolver: (_, styles) => styles.root,
})<{ ownerState: LineHighlightElementOwnerState }>(({ ownerState }) => ({
transform: `translate(${ownerState.x}px, ${ownerState.y}px)`,
transformOrigin: `${ownerState.x}px ${ownerState.y}px`,
fill: ownerState.color,
}));

export type LineHighlightElementProps =
| (LineHighlightElementOwnerState &
({ shape: 'circle' } & Omit<React.SVGProps<SVGCircleElement>, 'ref' | 'id'>))
| (LineHighlightElementOwnerState & {
shape: 'cross' | 'diamond' | 'square' | 'star' | 'triangle' | 'wye';
} & Omit<React.SVGProps<SVGPathElement>, 'ref' | 'id'>);

/**
* Demos:
Expand All @@ -64,7 +80,7 @@ export type LineHighlightElementProps = LineHighlightElementOwnerState &
* - [LineHighlightElement API](https://mui.com/x/api/charts/line-highlight-element/)
*/
function LineHighlightElement(props: LineHighlightElementProps) {
const { x, y, id, classes: innerClasses, color, ...other } = props;
const { x, y, id, classes: innerClasses, color, shape, ...other } = props;

const ownerState = {
id,
Expand All @@ -75,14 +91,20 @@ function LineHighlightElement(props: LineHighlightElementProps) {
};
const classes = useUtilityClasses(ownerState);

const Element = shape === 'circle' ? HighlightCircleElement : HighlightPathElement;

const additionalProps =
shape === 'circle'
? { cx: 0, cy: 0, r: other.r === undefined ? 5 : other.r }
: {
d: d3Symbol(d3SymbolsFill[getSymbol(shape)])()!,
};
return (
<HighlightElement
<Element
pointerEvents="none"
ownerState={ownerState}
className={classes.root}
cx={0}
cy={0}
r={other.r === undefined ? 5 : other.r}
{...additionalProps}
{...other}
/>
);
Expand All @@ -95,6 +117,8 @@ LineHighlightElement.propTypes = {
// ----------------------------------------------------------------------
classes: PropTypes.object,
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
shape: PropTypes.oneOf(['circle', 'cross', 'diamond', 'square', 'star', 'triangle', 'wye'])
.isRequired,
} as any;

export { LineHighlightElement };
2 changes: 2 additions & 0 deletions packages/x-charts/src/LineChart/LineHighlightPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function LineHighlightPlot(props: LineHighlightPlotProps) {
stackedData,
data,
disableHighlight,
shape = 'circle',
} = series[seriesId];

if (disableHighlight || data[highlightedIndex] == null) {
Expand Down Expand Up @@ -114,6 +115,7 @@ function LineHighlightPlot(props: LineHighlightPlotProps) {
color={colorGetter(highlightedIndex)}
x={x}
y={y}
shape={shape}
{...slotProps?.lineHighlight}
/>
);
Expand Down
Loading
Loading