Display tooltip with diferent values for each bar using recharts - reactjs

I have a chart and I want to display a tooltip for each bar with its data.
I used this example from their documentation https://recharts.org/en-US/examples/CustomContentOfTooltip
I created a custom tooltip element
const CustomTooltip = ({ active, payload }: TooltipProps<number, string>) =>{
console.log(payload)
if (active) {
return (
<div className="custom-tooltip">
{payload && payload[0] &&
<p className="label">{`${payload![0].name}: ${payload![0].value}`}</p>
}
</div>
);
}
return null;
};
and this is bar chart element where I use the custom tooltip as in the example above.
<BarChart>
...
<Tooltip cursor={false} content={<CustomTooltip />} />
{Object.values(dataKeyBar).map(({chart, color}, index) => {
return <Bar
radius={barSize}
key={`bar-${index}`}
barSize={barSize}
dataKey={chart}
fill={color}
/>
})}
</BarChart>
My problem is no matter what bar I'm hovering, I get the same data in my tooltip -
{`${payload![0].name}: ${payload![0].value}`}
the payload looks like this:
what I have tried to display different data in the tooltip for each bar is for the customTooltip but the tooltip is not showing at all.
{payload && payload.map((bar: any) => {
return <div className="custom-tooltip"><p className="label">{`${bar.name}: ${bar.value}`}</p></div>
})}
How can I display a tooltip with different data for each bar?

From what i'm seeing right now you are locating the Custom Tooltip component outside of map, so no matter where you hover over you'll get the same result sure, did you try to call it inside map ?

Related

React fullcalendar with tooltip

I am trying to add a tooltip on hover when hovering over the event in fullcalendar. The alert works but the tooltip doesen't appear. Any tips to get me going?
const events = [
{
title: "Event 1",
start: "2021-10-04",
end: "2021-10-06",
},
{
title: "Event 2",
start: "2021-10-04",
}
];
export default function Calendar() {
return (
<div>
<FullCalendar
events={events}
eventMouseEnter={
(arg) => {
<ReactTooltip id="registerTip" place="top" effect="solid">
{arg.event.title}
</ReactTooltip>
// alert(arg.event.title);
}
}
plugins={[dayGridPlugin]}
/>
</div>
);
}
Example (Working example):
https://codesandbox.io/s/0m03n?file=/src/App.js:136-165
TL.DR: To add a tooltip to the whole calendar:
return (
<ReactTooltip id="registerTip" place="top" effect="solid">
<FullCalendar events={events} plugins={[dayGridPlugin]} />
<ReactTooltip />
);
To add a tooltip only to the title, you must use custom views components where your wrap the view with the tooltip: https://fullcalendar.io/docs/content-injection
For any component to show on the screen, it has to be rendered. On a very high level, that generally means that one component has to do return (<ComponentToRender />).
In your example, you are simply executing the code for the <ReactTooltip /> when hovering the calendar, not actually rendering the tooltip.
Pay attention that returning the <ReactTooltip /> on the onMouseEnter wouldn't work either. In that case you would be returning it on the callback, not on the component itself.
For your understanding, the <ReactTooltip /> probably has some internal logic that does something (on a very pseudo code level) like:
const [showTooltip, setShowTooltip] = useState();
onMouseEnter = setShowTooltip(true);
onMouseLeave = setShowTooltip(false);
...
return (
<>
{showTooltip && <Tooltip>}
{children}
</>

Is there a way to add a tooltip to the rating component on Material UI?

I am trying to add a tooltip to each star of the rating component on Material UI [v4] but I am not being able to.
Is there a way to achieve this without having to use another rating library?
These are the links for the components I am trying to implement:
https://material-ui.com/es/api/rating/
https://material-ui.com/es/api/tooltip/
Thanks in advance!
Provide a custom IconContainerComponent and create your own Tooltip inside.
<Rating
IconContainerComponent = {
function IconContainer(props) {
// trigger your custom tooltip here
const { value, ...other } = props;
return <span {...other} />;
}
}
/>
I tried using the solution of #hamidreza which was similar to the one posted here but it did not work for me.
I know I'm a bit late to this but here is my solution:
Enclosing the <Rating> component with <Box> or a div (due to multiple child errors from Tooltip) then placing it as a child of the <Tooltip> component.
const [value, setVal] = React.useState(2);
const [tipValue, setTipValue] = React.useState(2);
<Tooltip title={tipValue === -1 ? value : tipValue}>
<Box display="inline-block">
<Rating
value={value}
onChange={(event, newValue) => {
setVal(newValue);
}}
onChangeActive={(event, newHover) => {
setTipValue(newHover);
}}
/>
</Box>
</Tooltip>
Working Demo:
https://codesandbox.io/s/blue-haze-jlvbb8?file=/demo.tsx
Splitting the tipValue and the value for me was necessary. This is to change the Tooltip message on hovering on the Rating component.

Recharts stacked barchart order and legend are inconsistent

I'm making a figure with ReCharts in ReactJS. In stacked bar chart, legend order is not consistent with vertical bar chart. Bar chart order should be from the top to the bottom to be consistent with legend. Does anyone know a workaround to fix it?
I have tried to change order of Legend by adding className to <Legend />, but it didn't work. className isn't general props? It has ul and li, so I am happy if I can change ul and li's style to reverse order.
official example: https://recharts.org/en-US/examples/StackedBarChart
issue: https://github.com/recharts/recharts/issues/209
jsfiddle: http://jsfiddle.net/j8csfvh1/12
In this case you can render a custom legend with a you're custom structure (html and css) and based on payload value using the prop content, here is the documentation :
https://recharts.org/en-US/api/Legend#content
Here is an adaptation of your code, it needs just some enhancement in term of css:
http://jsfiddle.net/tahalz/9427x1m8/
const renderLegend = (props) => {
const { payload } = props;
console.log(payload)
return (
<div>
{
payload.reverse().map((entry, index) => (
<span key={`item-${index}`}><div style={{display:'inline-block',width:'12px',height:'12px',backgroundColor:entry.color}}></div>{entry.value}</span>
))
}
</div>
);
}
...
<Legend content={renderLegend}/>

How to send unique props to similar Parents?

I currently made a custom component that acts similar to a carousel called Scrollbar. When I select a specific item it dynamically loads the information and displays a content div that has information on the item such as id, name, thumbnail-Image, etc..
The problem I am trying to solve is that I want to display multiple Scrollbars and only have one content div active at a time. The issue is that each Scrollbar has their own content div. I need a way to communicate which one is active.
I'm thinking possibly I need another component lets call it Home that displays multiple Scrollbars and onClick, it sets the current one Active and the rest inActive. All the Scrollbars should still be displaying however, one dynamic content div will appear below the active Scrollbar.
This sounds like I need to send one Scrollbar's prop isActive = true and the others isActive = false. I am unsure how to achieve this.
Here are short versions of my components:
Scrollbar.js
const Scrollbar = ({category, isActive }) => {
return (
<div className="scrollbar">
<h2>{category}</h2>
<div className="item-wrapper" style={{maxWidth: `${scrollbarWidth}px`}}>
.
.
.
.
//Handles Navigating the Scrollbar Left and Right
<SlideButton type="prev" onClick={handlePrev}/>
<SlideButton type="next" onClick={handleNext}/>
</div>
//Dynamic Content gets shown here when user clicks on an item & Scrollbar (tbd)
{isActive && currentCard && <Content activeCard={currentCard} clickFunc={handleCardChange} /> }
</div>
);
}
export default Scrollbar;
Home.js
const Home = () => {
return (
<div className="home">
<Scrollbar key="0" category="Scroll 1" activeBar={null} />,
<Scrollbar key="1" category="Scroll 2" activeBar={null} />
</div>
);
}
export default Home;
The Home component should hold the id of who is the activeBar with useState. It should pass setActiveBar to each Scrollbar.
const Home = () => {
const [activeBar, setActiveBar] = useState(0)
return (
<div className="home">
<Scrollbar
key="0"
id="0"
category="Scroll 1"
activeBar={activeBar}
setActiveBar={setActiveBar}
/>,
<Scrollbar
key="1"
id="1"
category="Scroll 2"
activeBar={activeBar}
setActiveBar={setActiveBar}
/>
</div>
);
}
The Scrollbar component should check if it's id is identical to activeBar, and set isActive accordingly. It should also set itself to be the activeBar when clicked.
const Scrollbar = ({category, id, activeBar, onClick }) => {
const isActive = activeBar === id;
return (
<div
onClick={() => setActiveBar(id)}
className="scrollbar"
>

React - changing text based on what element is hovered

I have a rectangle div box on my page that contains various elements including a Font Awesome download icon. I want to display a specific text when the user hovers over the entire div, and then I want to change that text when the download button is hovered. I see the text change/show when the div is hovered, but don't see the text change when the download button is hovered. I added a console log in the download hover and that does show up. So I'm guessing the component is not re-rendering to display the updated text.
const [viewDownloadText, setViewDownloadText] = useState('');
...
return (
<div
className={'product d-flex'}
key={product.id}
onClick={() => openPDF(product.name)}
onMouseOver={() => setViewDownloadText('Click to view')}
onMouseOut={() => setViewDownloadText('')}
>
{viewDownloadText && (
<div className={'click-text'}>{viewDownloadText}</div>
)}
<FontAwesomeIcon
className={'SDS-download'}
icon={faFileDownload}
size={'2x'}
onMouseOver={() => {
console.log('download set!');
setViewDownloadText('Click to download');
}}
onMouseOut={() => {
setViewDownloadText('Click to view');
}}
/>
</div>
);

Resources