nivo
nivo copied to clipboard
ResponsiveLine strange refresh when updating data
Describe/explain the bug
I have a Chart component for the ResponsiveLine which receives some parameters and data series. I'm calculating the ticks accordingly to the length of my series and the dates (for example, dynamically saying like every 7 days
, every 2 months
, and so on ).
I'm not remounting the component when the data changes. I'm just passing the updates settings to the props, because I wanted it to animate when the data changes.
However, it seems to have a strange behavious when the data length is greater than 40 data points. When it's less than that, the component refreshes and animate smoothly, but if I pass something like 2 series of 42 and 50 points the animation crashes, the app slows down, the labels start to overlap, like in this example gif:
On the other hand, if I force the component to re-mount the problem does not happen (but then I dont have the animation)
Expected behavior Chart animation occurs normally
Desktop (please complete the following information):
- OS: MacOS 10.15.4
- Browser Chrome, Firefox...
- Version:
"@nivo/line": "^0.61.1",
Additional context This is my component
<ResponsiveLine
data={data as Serie[]}
margin={{
top: 20, right: 30, bottom: 80, left: 50,
}}
xScale={{
type: 'time', format: '%Y-%m-%d', precision: 'day', useUTC: false,
}}
yScale={{
type: 'linear', min: 0, max: maxYScale, stacked: false, reverse: false,
}}
tooltip={LineTooltip}
axisBottom={{
orient: 'bottom',
renderTick: LineDateTick,
tickValues: xScaleTickValues,
}}
axisLeft={{
orient: 'left',
tickSize: 0,
tickPadding: 15,
tickRotation: 0,
tickValues,
legend: '',
legendOffset: -40,
legendPosition: 'middle',
format: (value): string => formatLeftAxis(value, divisor, unit),
}}
colors={{ datum: 'color' }}
pointSize={5}
pointColor="#FFFF"
pointBorderWidth={2}
pointBorderColor={{ from: 'serieColor' }}
pointLabelYOffset={-15}
enableSlices={false}
useMesh
onMouseMove={handleMouseMove}
crosshairType="cross"
motionStiffness={280}
legends={enableLegends ? [{
anchor: 'bottom',
direction: 'row',
justify: false,
translateX: 20,
translateY: 75,
itemsSpacing: 0,
itemDirection: 'left-to-right',
itemWidth: 190,
itemHeight: 30,
itemOpacity: 0.75,
symbolSize: 12,
symbolShape: 'circle',
symbolBorderColor: 'rgba(0, 0, 0, .5)',
}] : []}
theme={{
axis: {
domain: {
line: {
stroke: '#F3F3F3',
strokeWidth: 1,
},
},
},
grid: {
line: {
stroke: '#FFFF',
strokeWidth: 1,
},
},
}}
/>
In case it is something not possible to fix, is there any kind of "intro" animation for the chart once it gets mounted?
@nigellima, to be able to transition between each dataset, we have to preserve some kind of ID for the dots, this ID is computed using the x/y coordinates, I think what's happening there is that some points keep the same ID, so they're not being updated correctly, the scale changes, but not the ID.
@nigellima, to be able to transition between each dataset, we have to preserve some kind of ID for the dots, this ID is computed using the x/y coordinates, I think what's happening there is that some points keep the same ID, so they're not being updated correctly, the scale changes, but not the ID.
Thanks for replying @plouc
In that case, what could be the workaround?
I need to have a look at it and reproduce the issue, I'm not sure what would be the best to preserve transitions while having correct target values, probably need to experiment.
I need to have a look at it and reproduce the issue, I'm not sure what would be the best to preserve transitions while having correct target values, probably need to experiment.
Thank you very much @plouc
In the meantime, is there any kind of intro animation? Like, instead of keeping the chart component alive and just update the series props, I could remount every time the series changes and then have an animation at the beginning
@plouc Hello. How are you? Do you have any updates on this issue? Or, could you point me to where this issue is possibly present so I could help to fix this?
Some updates on this?
I am also looking for an update on this, I've disabled the animations on my graphs for now.
My workaround with React Hooks is to have a useEffect to watch for changes to data (whether it's coming from app state or a prop) and assign to a local state variable, eg:
const [localData, setLocalData] = useState([])
useEffect(() => {
setLocalData(data)
}, [data])
return (
<ResponsiveLine
data={localData}
...
@nigellima @johnnyxbell @luizfelipelaviola
If i understood your problem correctly, this must fix it:
You should check if each Object in dataset for the chart includes the "id" key:value, it should be updated each time you update the date:
e.g. [{ id: "3asd25", data;[]},{id: "aszx9cz1", data;[]}.{id: "asd567sdf", data;[]}...]
In this case, during the re-render of component, that will be caused be receiving new data, the redraw will be held without bug.
Probable variants for you: You can either update "id" field at backend on each request or generate the id on comparison in case of data change during receiving at front ( but having this logic on front is not the better practice )
Hope this could help you.
@asaeed's solution worked great. Thanks mate
@DmytroMatrosov 's solution is more performant. using localData
as @asaeed mentioned, will cause a small flicker, you will see old and new line for a moment which has a very bad UX. also causes the whole chart to re-render.
how do I randomize id but still have it display in the legend correctly? now legend is showing the random string now
Bump. Ran into a similar issue when attempting to alter the data on button click. The chart rendered data which was not being passed to the chart (The data was updated properly). Both of @asaeed and @DmytroMatrosov solutions worked. However the first caused a flicker in a chart. The second is a good workaround, but our id's are being used in the legends, so I'd prefer not to change them.
Is this going to be worked on soon?
Bump facing same issue mentioned by @joseph-mccombs any fixes? My legend and other features use ids