2

I'm building a Gantt milestone chart that shows certain milestones from multiple projects, and each of the projects can be considered part of a "group".

When the chart initially loads, I show all the projects, and I set a custom zoom level of Jan 1 of "this year" to Jan 1 five years in the future by calling chart.xAxis[0].setExtremes().

There is a control to allow filtering by project group. Every time a new filtering selection is made, the chart reloads, and I reset the zoom to that same range.

However, with some of the data, the setExtremes is not respected, and Highcharts decides on it's own what range to show, and I can't figure out why. Especially because if I show data from one group (eg "Group 4"), the zoom is respected, but then if I add in another group (eg show "Group 4" and "Group 2"), the the zoom is not respected.

BUT - if I try the same thing with a different set of data (eg show "Group 5", then add in "Group 2"), then the zoom is maintained correctly after adding in what seems to be the "suspect" data.

Very confusing.

I set up a code sandbox with fake project and group names, but with the actual date data.

Also might be easier to see if you load the sandbox outside of the editor: https://g26rq.csb.app/

What is it about the data that's causing this behavior?


Update to address the comment:

All data required is fetched from the server on initial component mount and is stored in state in a way that I can just pull from that when the filter settings change so I don't have to keep going back to the server.

That being said, the order of operations are set up like this:

  1. Any "change" event on the group filter select control sets the overall component state in such a way that the Highcharts chart component should be unmounted/destroyed. (Basically the bit of state where I store the series data is cleared/emptied.)
  2. After all selections have been finalized, the "blur" event on the select control starts the process of data transformation/application.
  3. Data that corresponds to the filter settings is pulled from where the overall data is stored in state, transformed into the necessary Highcharts series format, and then the series data is set into state.
  4. After the component re-renders with the series data present in state, the Highcharts component is allowed to render, and I specify a callback function in the Highcharts component props which corresponds to a chart.events.load event handler. Since the previous chart was destroyed and is now essentially being created anew, the load event will occur.
  5. The callback/load event handler is what calls setExtremes.

I see that the console.log added to the render event occurs after the console.log I put in the function where I call setExtremes, but that is to be expected. According to the Higcharts documentation on the load and render events:

load: Highcharts.ChartLoadCallbackFunction

Fires when the chart is finished loading.

...

There is also a second parameter to the chart constructor where a callback function can be passed to be executed on chart.load.

(I'm guessing that the Highcharts React component is using that to pass in the callback function I am specifying in the component's callback prop.)

render: Highcharts.ChartRenderCallbackFunction

Fires after initial load of the chart (directly after the load event), and after each redraw (directly after the redraw event).

So it's no surprise that the render happens after I setExtremes, but that doesn't necessarily mean that I'm calling setExtremes before the chart is ready. Considering that I'm destroying/re-creating the chart every time the filter settings change, and that render might be fired by any manual zoom change by users (not to mention probably fires after my own forced setExtremes), it would seem to me that doing my setExtremes from the load event is exactly where it should happen.

Dylan Cristy
  • 916
  • 11
  • 29
  • I think that it might be related to the order of operations. I added a `console.log` to the render event and it seems that the extremes are set before the chart is initializing: https://codesandbox.io/s/gantt-wrong-zoom-forked-tg2ph?file=/src/App.js What is the order after choose group: 1. set extremes, 2. data fetch, 3. apply data, 4. extremes are caluclated and set base on the data – Sebastian Wędzel Aug 31 '21 at 08:53
  • @SebastianWędzel updated my answer to address your comment. – Dylan Cristy Aug 31 '21 at 15:24
  • `it would seem to me that doing my setExtremes from the load event is exactly where it should happen.` - looks like you are on the good track - have you tested it? Does it work? – Sebastian Wędzel Sep 01 '21 at 08:21
  • @SebastianWędzel that's exactly the reason for my question - it works with most of the data, but not all. When calling `setExtremes` while showing certain subsets of the data, the min `X` and max `X` I try to set using `setExtremes` are ignored by Highcharts, and it sets it's own extremes. I'm trying to figure out why, to see if there is something I can do to fix it. – Dylan Cristy Sep 01 '21 at 13:12

1 Answers1

2

I took a look closer into this issue and it seems that it is related to the xAxis minRange property, because by default it is calculated as:

The default minRange for the x axis is five times the smallest interval between any of the data points.

So your extremes don't fit for some data sets.

Demo: https://jsfiddle.net/BlackLabel/mnfb3pv1/

As a solution you can set the minRange to some fixed value:

Demo: https://jsfiddle.net/BlackLabel/pu60fkaL/

Your demo with set minRange: https://codesandbox.io/s/gantt-wrong-zoom-forked-b5dhl?file=/src/App.js

API: https://api.highcharts.com/highstock/xAxis.minRange

Sebastian Wędzel
  • 11,417
  • 1
  • 6
  • 16