echarts icon indicating copy to clipboard operation
echarts copied to clipboard

[Bug] minorTicks spacing for time series has unexpected behavior for the right and left-most intervals.

Open petersonzilli opened this issue 1 year ago • 6 comments

Version

5.4.3

Link to Minimal Reproduction

https://codepen.io/petersonzilli/pen/VwGgQgb

Steps to Reproduce

  1. You can start from the "Dynamic Data + Time Axis" example
  2. then add the xAxis.minorTick = true configuration.
  3. (optionally) add the xAxis.minorSplit = true to the config too.
  4. then start to look into the right and left sides of the generated graph and see the not expected behavior for ticks/split lines of a time series.

Current Behavior

the number of intervals is made constant for the graph. there are always 5 minorTicks/minorSplits. thus the time ranges expressed by the ticks vary across the graph.

Expected Behavior

For a time series, one can expect that the minorTicks/minorSplits express allways the same time range, and the space between the minorTicks/minorSplits does not vary across the graph

Environment

- OS: MacOS
- Browser: Chrome 111.0.5563.110
- Framework: pure javascript and echarts

Any additional comments?

No response

petersonzilli avatar Mar 26 '23 18:03 petersonzilli

image In this image you can see the first 5 ticks and also the last 5 ticks are smaller than the regular ticks for the central time range.

petersonzilli avatar May 01 '23 23:05 petersonzilli

I also faced this issue in my project.

I also expect the the minor tick distance should be equal for every minor tick in the graph. For me, the prefferrable solution if you show as many minor tick on the edges as you can.

A less preferable but acceptable solution: you hide minor ticks on both edges. No minor ticks is better than incorrect minor ticks.

kaatula avatar May 25 '23 11:05 kaatula

The split interval should be the same or it would be a quite wired graph.

buptsb avatar Jun 01 '23 02:06 buptsb

If you turn on the alternating background (xAxis.splitArea.show = true) for the x-axis, I think you can see the reason why the minor ticks behave like this (I assume): the first and last segment are not as wide as all others - but also in this cases the same number of minor ticks are rendered.

I also agree that this should be changed, the distance of minor ticks should be consistent all the time.

ptandler avatar Aug 16 '23 08:08 ptandler

bump. any update on this? we are experiencing the same problems

elnipa avatar Feb 08 '24 12:02 elnipa

I've just come up against the same issue and have quickly modified the source code to rectifiy it. I don't have time to make a PR right now but the simplest solution is to modify the getMinorTicks function to the following:

    IntervalScale.prototype.getMinorTicks = function (splitNumber) {
      var ticks = this.getTicks(true);
      var minorTicks = [];

      // Shouldn't be neccessary, but if we don't have at least 2 full ticks, short circuit.
      if(!ticks[2] || !ticks[1]) {
        return minorTicks;
      }

        var extent = this.getExtent();
      var fullTickInterval = null;
      var i = ticks.length;
      // Loop backwards through ticks to find the largest - This is required in order to handle DST in time axis.
      while(i--) {
        var nextTick = ticks[i];
        var prevTick = ticks[i - 1];
        var interval = nextTick.value - prevTick.value;

        // if the largest found interval so far has been found twice, we can safely break out of the loop
        if(interval === fullTickInterval) {
          break;
        }

        if(fullTickInterval === null || interval > fullTickInterval) {
          fullTickInterval = interval;
        }
      }


      for (var i = 1; i < ticks.length; i++) {
        var nextTick = ticks[i];
        var prevTick = ticks[i - 1];
        var count = 0;
        var minorTicksGroup = [];
          var minorInterval = fullTickInterval / splitNumber;

        // If this is the first tick, loop backwards from the nextTick
        if(i === 1) {
          var count = splitNumber;
          while (count > 0) {
            var minorTick = roundNumber(nextTick.value - (count * minorInterval));
            // console.log('minortick: ' + minorTick +  ' ex0: ' + extent[0] + ' ex1: ' + extent[1]);
            if (minorTick > extent[0] && minorTick < extent[1] && minorTick < nextTick.value) {
              minorTicksGroup.unshift(minorTick);
            }
            count--;
          }
        } else {

          while (count < splitNumber - 1) {
            var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval);
            // console.log('minortick: ' + minorTick +  'ex0: ' + extent[0] + ' ex1: ' + extent[1]);
            if (minorTick > extent[0] && minorTick < extent[1] && minorTick < nextTick.value) {
              minorTicksGroup.push(minorTick);
            }
            count++;
          }
        }
        minorTicks.push(minorTicksGroup);
      }
      return minorTicks;
    };

I'm sure there will be a more efficient way of doing it, but simply pre-calculating the interval of a full tick and using that to consitently calculate the minorTick distances as well as laying out the first set of minorTicks backwards from the first fullTick, seems to do the job nicely.

Anyway, this dirty hack did what I need; hopefully it helps someone.

GordoRank avatar Apr 09 '24 19:04 GordoRank