-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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] Add label
to be displayed inside bars in BarChart
#12988
[charts] Add label
to be displayed inside bars in BarChart
#12988
Conversation
Deploy preview: https://deploy-preview-12988--material-ui-x.netlify.app/ Updated pages: |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
eb70e5a
to
e07c630
Compare
@LukasTy can you take a look at this draft and let me know if there are any concerns? I'm also interested on input on the barLabel?: (item: BarItem, context: BarLabelContext) => string | null | undefined;
export type BarItem = {
seriesId: SeriesId;
dataIndex: number;
value: number | null;
};
export type BarLabelContext = {
bar: {
height: number;
width: number;
};
}; this is in contrast with arcLabel, which accepts direct "value mappings" like In my solution I went for simplicity, a single property where you can define a function to handle both While the alternative, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Superb addition! 💙 💯
Great work.
LukasTy can you take a look at this draft and let me know if there are any concerns?
I'm also interested on input on the barLabel property.
I like the function signature, it seems both simple and powerful enough. 👍
this is in contrast with arcLabel, which accepts direct "value mappings" like 'value' | 'label', which would be an option here.
IMHO, having that option would improve the feature as I imagine that at least 1/3 of users would end up just using value
or label
here. 🙈 🤷 😆
@LukasTy btw I noticed I did it probably wrong? I added the What do you think about that? |
Great clarification. Indeed, I missed that part. 🙈 |
It shouldn't prevent any of the current behaviours I believe, but I don't know, hence why I'm probing for information. In theory, if we threat data as pure, it means it can be used anywhere, which would allow us to use the same "series/datasets" between multiple charts or compositions as we wish. Eg: right now series are "locked" for each type of chart, which is odd to me, if I want to have a Will move it to the series for now |
I think @alexfauquette should pitch into this discussion with an argument for that particular direction/choice. 😉 |
Yep, waiting for when he comes back 😄 |
@alexfauquette do you agree with the last few comments? That it looks good that the I'm going through the process of moving it, but the code will be a bit more complex, so wanted to check before I commit to it 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall looks good. I will need to read it again for details. 🎉
About where to put the barLabel
topic. For pie chart, I went with series because I had the usecase of multiple nested pie series in mind, where it could make sens to have series with different way of plotting the label. For bar chart it make less sense.
It seems feasible to do every thing with your current approach, even if it ends up looking like:
balLabel={(item) => {
switch(item.seriesId) ....
}}
9c64bc1
to
5faedc8
Compare
Oops, I just pushed the initial changes, will revert it then 😅 |
4845f3b
to
3947356
Compare
|
||
export interface BarPlotProps extends Pick<BarElementProps, 'slots' | 'slotProps'> { | ||
export interface BarPlotProps { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to also add the new BarLabelSlots
. And typescript complains if we do
export interface BarPlotProps
extends Pick<BarElementProps, 'slots' | 'slotProps'>,
Pick<BarLabelProps, 'slots' | 'slotProps'> {}
Interface 'BarPlotProps' cannot simultaneously extend types
'Pick<BarElementProps, "slots" | "slotProps">'
and 'Pick<BarLabelProps, "slots" | "slotProps">'.
Also it seemed simpler to add them directly based on the above extended props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sens
On this same part of the code, you could use Pick<BarLabelProps, 'barLabel'>
to avoididuplicating the type of the barLabel
which is just passed From BarPlot
to BarLabelPlot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 extending BarLabelProps
actually fixes the weird ordering issue #12988 (comment)
So I suppose the import order matters for the script
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've a last concern about the exported elements
The <BarLabelPlot />
requires bars
which is an array wit all the processing already done. Except if the user is creating a custom BarPlots
component, they will never need of this component. And so never need the BarLabel
component.
The only component they can reuse for customization purpose is the BarLabelComponent
I would be in favor of not exporting the BarLabelPlot
and BarLabel
and their props typing. Such that user trying to customize it only have access to the slots which I assume is the good way to do it.
This comment come from reading the BarLabel API page which felt weird because I had no idea about how to use this component, and where do I get the width
/height
To prevent exporting internals, you can rely on the diff of scripts/x-charts.exports.json
to know what is exported. A common practice could be to export every thing in your files, but only cherry pick what you want to export in src/BarChart/BarLabel/index.ts
Normally the export should only take care of depth 1 (src/BarChart/index.ts
)
scripts/x-charts.exports.json
Outdated
@@ -266,6 +281,7 @@ | |||
{ "name": "useDrawingArea", "kind": "Function" }, | |||
{ "name": "useGaugeState", "kind": "Function" }, | |||
{ "name": "useSvgRef", "kind": "Function" }, | |||
{ "name": "useUtilityClasses", "kind": "Variable" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be exported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did some cleanup, let me know what you think. Also, open to suggestions on BarLabelComponent
. We could make it BarLabel
only, and rename the current one to something else, open to ideas. 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming is always an issue with those nested level of components 😅
BarLabel
could be renamed
BarLabelComponent
(swiching)BarLabelItem
BarLabelWithContent
(we don't care it's internal)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙃 Types get all funky when changing names.
Also, should owner state be accessible in slotProps
? eg:
<BarChart
slotProps={{
barLabel: {
ownerState: {
seriesId: '1',
dataIndex: 0,
color: 'red',
isFaded: false,
isHighlighted: false,
},
},
}}
/>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should owner state be accessible in
slotProps
I assume yes, user can pass whatever they want, but at their own risk. Why this question?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was checking which props they could currently pass. It feels odd that they can pass ownerProps
.
Also, these "overridable" components from slots
shouldn't receive it. 🤔
Like, if we get slots:{bar: (props) => console.log(props) }
, we get this object:
{
"style": {
"y": 200,
"x": 427.1162790697674,
"height": 50,
"width": 14.883720930232558
},
"cursor": "unset",
"ownerState": {
"id": "auto-generated-id-3",
"dataIndex": 4,
"color": "#60009B",
"isFaded": false,
"isHighlighted": false
},
"className": "MuiBarElement-root MuiBarElement-series-auto-generated-id-3"
}
For style it probably makes sense, since they are computed. Now, I would argue the ownerState
properties should be spread in the props instead of inside ownerState
, at least for overridden components, but also slotProps
.
The user shouldn't need to know about ownerState
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose if we migrate to pigment css it would solve this issue though? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I re-wrote the files and types, moved BarLabel
to BarLabelItem
and created a specific file for BarLabel
, which applies the theme to the component. I've moved the theme there because eslint was complaining that the component name didn't match (if i left it on BarLabel
), but I don't know if the order is correct, like. Which of themeAugmentation
vs slotProps
should have precedence? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you've introduced a component between the styled component and the slots you could pass an empty ownerState to the useSlotProps
and pass every info as props. Then create the owner state in the BarLabel
component
Thanks for the reply. Yeah I knew something was wrong, but forgot to flag it. One of my intentions with the Code Guidelines docs were to make these boundaries clearer. https://www.notion.so/mui-org/engineering-Code-Guidelines-X-39105ea968754d989af47346fc3bbc3f?pvs=4#2f5425c8d2064cfa8b986ae7b16a28b3 |
I you wonder why the netlify build fail, it's because the API JSON has been removed but you still have the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice result. 👏
139f471
to
f89cd77
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but I don't know if the order is correct, like. Which of themeAugmentation vs slotProps should have precedence? 😅
Anything provided on a specific component usage (i.e. via slotProps) should take precedence over theme augmentation (defaultProps and styleOverrides). 😉
@@ -74,6 +74,12 @@ | |||
"default": "BarElementPath", | |||
"class": null | |||
}, | |||
{ | |||
"name": "barLabel", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we are missing the change in SparklineChart
to make the barLabel
prop work.
Or should it be removed from that component props if we don't want it there? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in favor of removing it from the props typing. Not very usefull for scatter bar plot, and not sure we want to keep this feature when reworking the sparkline to make it more performant.
NB: José, has you can see having the scripts result in the PR help for the review process 😉
classes?: Partial<BarLabelClasses>; | ||
} | ||
|
||
export type BarItem = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a comment: We could start having those XxxItem
types which will be a good complement with the XxxItemIdentifier
in the models/seriesType/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get what you mean 🤔
I didn't see that type as well, but I'm not sure the type:'bar'
is necessary here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see that type as well
That's the point I wanted to point this type such that you know they exist for all charts.
but I'm not sure the type:'bar' is necessary here
I agree it was just to share information
@@ -74,6 +74,12 @@ | |||
"default": "BarElementPath", | |||
"class": null | |||
}, | |||
{ | |||
"name": "barLabel", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in favor of removing it from the props typing. Not very usefull for scatter bar plot, and not sure we want to keep this feature when reworking the sparkline to make it more performant.
NB: José, has you can see having the scripts result in the PR help for the review process 😉
scripts/x-charts.exports.json
Outdated
@@ -266,6 +281,7 @@ | |||
{ "name": "useDrawingArea", "kind": "Function" }, | |||
{ "name": "useGaugeState", "kind": "Function" }, | |||
{ "name": "useSvgRef", "kind": "Function" }, | |||
{ "name": "useUtilityClasses", "kind": "Variable" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you've introduced a component between the styled component and the slots you could pass an empty ownerState to the useSlotProps
and pass every info as props. Then create the owner state in the BarLabel
component
@alexfauquette regarding Everything seems to work fine, and end users should be able to use the props they need. On another note, const MyComp = (props: BarLabelOwnProps) => {}
type BarLabelOwnProps = {
children: ...
color: ...
isFaded: ...
isHighlighted: ...
}
type BarLabelProps = React.SVGProps<SVGTextElement> & BarLabelOwnProps |
What do you mean by "start thinking"? From what I see you're already doing it |
Sorry, I meant we should think of making this an official pattern with expected naming. |
Signed-off-by: Jose C Quintas Jr <[email protected]> Co-authored-by: Lukas <[email protected]> Co-authored-by: Alexandre Fauquette <[email protected]>
Signed-off-by: Jose C Quintas Jr <[email protected]> Co-authored-by: Lukas <[email protected]> Co-authored-by: Alexandre Fauquette <[email protected]>
Signed-off-by: Jose C Quintas Jr <[email protected]> Co-authored-by: Lukas <[email protected]> Co-authored-by: Alexandre Fauquette <[email protected]>
When stacking series/bars on top of each other, it becomes difficult to see the total sum of the stacked values. Is it already possible or would you guys consider displaying a total on top of the stacked bars? Otherwise thanks a lot for mui charts! It's great! Have been wanting charts from MUI for years - and now finally it's here ❤️ |
@jvskriubakken It's not yet feasible. You can follow this issue to be aware about progress on the topic #12975 If the issue does not completely describe your need, feel free to add comments, or open a new one to highlight missing part |
Add possibility of showing a
label
inside bars.https://deploy-preview-12988--material-ui-x.netlify.app/x/react-charts/bars/#labels
Resolves #12331