apache/echarts

[Bug] Toolbox DataZoom behaves wrong with multiple axes with different min/max

Opened this issue · 3 comments

Version

5.5.1

Link to Minimal Reproduction

https://codesandbox.io/p/sandbox/vw8p5g

Steps to Reproduce

I did encounter this bug in my professional work, so I cannot share this context but it is easily explainable via the minimal reproduction.
I have multiple yAxis and want to use the dataZoom in the toolbox. The yAxis have different min/max values set. The dataZoom is not configured specifically, so it controls all y and xAxis per default.

Current Behavior

Using the dataZoom from the toolbox sets all yAxes to the same start and end value.
This is before the zoom, look at the axes.
image
This is after the zoom, again please look at the axes.
image

Expected Behavior

Using the dataZoom from the toolbox should set all yAxes to the correct values. Inspecting the event triggered by the dataZoom reveals, that the event batch carries the correct start and end values for all axes

Environment

I reproduced the example with a CodeSandbox, I do not know which env it utilizes.
- OS:
- Browser:
- Framework:

Any additional comments?

No response

two additional observations:

  • the problem disappears when option.dataZoom is removed
  • the official example works ok

two additional observations:

* the problem disappears when _option.dataZoom_ is removed

* the [official example](https://echarts.apache.org/examples/en/editor.html?c=area-rainfall) works ok

You are right. The bug lies in the addition of different min/max values for the two yAxes in the yAxis option, that is why the official example works fine.

As this issue was a blocker for us I did try to come up with a workaround to solve this problem. It relies on a custom handler triggered by the datazoom event which then sets the correct start and end for the correct dataZoom slider. The following snippet may help people having the same issue or even fixing the bug in the codebase. I will also try to find some time, maybe I can contribute with a PR.

// Event Handlers
  const handleDataZoom = (e: SyntheticEvent) => {
    const chart = getInstanceByDom(chartRef.current)

    // @ts-ignore getOption is poorly typed, it should return an array of the yAxis
    const firstIndexWithSetRange = chart.getOption().yAxis.findIndex((yAxis) => {
      // Utilizing == here, as this is an appropriate way to check if it is null OR undefined (nullish and not falsy)
      return !(yAxis.min == null) && !(yAxis.max == null)
    })
    // The toolbox datazoom has a batch at its event, which carries the start and end
    // of all axes that are controlled by it.
    if (firstIndexWithSetRange !== -1 && e.hasOwnProperty('batch')) {
      // I totally dislike this approach as we are looking for magic strings
      // and generally this seems kind of hacky. But I think this is the best
      // fix for the overall problem. Hopefully Echarts does simply fix the zoom via the toolbox.
      // @ts-ignore We check for the existence of this prop in the if-clause
      const yAxisEventForSetRangeAxis = e.batch.find((dataZoomEvent) => {
        return dataZoomEvent.dataZoomId.includes(`yAxis${firstIndexWithSetRange}`)
      })
      const accordingYAxisToEventMaxValue = chart.getOption().yAxis[firstIndexWithSetRange].max
      chart.dispatchAction({
        type: 'dataZoom',
        dataZoomIndex: chart
          .getOption()
          // @ts-ignore As already mentioned, dataZoom is poorly typed
          .dataZoom.findIndex((dataZoomObj) => dataZoomObj?.id === DATA_ZOOM_Y_AXIS_ID),
        start: (yAxisEventForSetRangeAxis.startValue / accordingYAxisToEventMaxValue) * 100,
        end: (yAxisEventForSetRangeAxis.endValue / accordingYAxisToEventMaxValue) * 100,
      })
    }
  }

Be aware that this is just the handler itself as it fits in our company context. The important part is getting e.batch, calculating the start and end percentages and setting it via dispatchAction()