Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

centerInCategory leaves enough space for all of the x values, but does not take into consideration that the columns with the same x value are stacked #17610

Closed
vitaliy-kretsul opened this issue Aug 16, 2022 · 6 comments · Fixed by #17682

Comments

@vitaliy-kretsul
Copy link

vitaliy-kretsul commented Aug 16, 2022

Prerequisites

Column chart with grouping: true and centerInCategory: true and series containing multiple points for same x value. Columns for repeated x values are displayed overlaying each other.

Expected behaviour

Overlaying columns displayed with the same 'normal' distance to neighbouring columns as between any other regular columns.

Actual behaviour

Instead overlaying columns are rendered with empty space, enough for all repeating x values be displayed separately, without taking into account that the columns with the same x value are stacked.

Live demo with steps to reproduce

https://jsfiddle.net/Cortez/h85dgapz/

Product version

Highcharts 10.2.0

Affected browser(s)

Google Chrome 104.0.5112.79

Additional

Related forum discussion:
https://www.highcharts.com/forum/viewtopic.php?t=49260

@raf18seb
Copy link
Contributor

Hi @vitaliy-kretsul, thank you for reporting the issue and the late reply.

I agree, this is a bug. Simplified demo: https://jsfiddle.net/BlackLabel/mr32L9n6/ (with centerInCategory both false and true values, the chart should look exactly the same).

@vitaliy-kretsul
Copy link
Author

@raf18seb Thanks for your reply. Any hope for a temporary workaround?

@raf18seb
Copy link
Contributor

@vitaliy-kretsul,
I spent some time on it but wasn't able to find a quick workaround, sorry.

@vitaliy-kretsul
Copy link
Author

@raf18seb
thanks for your effort. Can I expect this fix with next release? Or you can not give any prognosis on that?
Thanks!

@raf18seb
Copy link
Contributor

@vitaliy-kretsul,

We decided to take a closer look at it. Can't promise anything, but there's a big chance a fix for this bug will be added to the core with the next release (10.2.2 or 10.3.0).
ps 10.2.1 was released 2 days ago, so we're planning the next release by a few weeks at the soonest (or even months, no ETA yet)

@pawelfus
Copy link
Contributor

pawelfus commented Aug 31, 2022

Edit (the previous solution had a bug, thanks @hubertkozik!)
Workaround:
Demo: https://jsfiddle.net/BlackLabel/0tz18457/3/
Plugin:

(function(H) {
  H.seriesTypes.column.prototype.adjustForMissingColumns = function(
    x,
    pointWidth,
    point,
    metrics
  ) {
    const stacking = this.options.stacking;
    if (!point.isNull && metrics.columnCount > 1) {
      const reversedStacks = this.yAxis.options.reversedStacks;
      let indexInCategory = 0,
        totalInCategory = reversedStacks ? 0 : -metrics.columnCount;

      // Loop over all the stacks on the Y axis. When stacking is enabled,
      // these are real point stacks. When stacking is not enabled, but
      // `centerInCategory` is true, there is one stack handling the
      // grouping of points in each category. This is done in the
      // `setGroupedPoints` function.
      H.objectEach(
        this.yAxis.stacking && this.yAxis.stacking.stacks,
        (stack) => {
          if (typeof point.x === 'number') {
            const stackItem = stack[point.x.toString()];

            if (stackItem) {
              // In case of multiple points with the same X,
              // get the first point
              const key = [
                  this.index,
                  point.x,
                  0
                ].join(','),
                pointValues = stackItem.points[key];

              // If true `stacking` is enabled, count the total
              // number of non-null stacks in the category, and
              // note which index this point is within those
              // stacks.
              if (stacking) {
                if (pointValues) {
                  indexInCategory = totalInCategory;
                }
                if (stackItem.hasValidPoints) {
                  reversedStacks ? // #16169
                    totalInCategory++ : totalInCategory--;
                }

                // If `stacking` is not enabled, look for the index
                // and total of the `group` stack.
              } else if (H.isArray(pointValues)) {
                // If there are multiple stacks with the same X
                // reduce position by previous series max value:
                let seriesIndexes = Object
                  .keys(stackItem.points)
                  .filter((pointKey) =>
                    // Filter out duplicate X's
                    !pointKey.match(',') &&
                    // Filter out null points
                    stackItem.points[pointKey] &&
                    stackItem.points[pointKey].length > 1
                  )
                  .map(parseFloat)
                  .sort((a, b) => b - a);

                console.log(
                  seriesIndexes,
                  seriesIndexes.indexOf(this.index)
                );

                indexInCategory = seriesIndexes.indexOf(this.index);
                totalInCategory = seriesIndexes.length;
              }
            }
          }
        }
      );

      // Compute the adjusted x position
      const boxWidth = (totalInCategory - 1) * metrics.paddedWidth +
        pointWidth;
      x = (point.plotX || 0) + boxWidth / 2 - pointWidth -
        indexInCategory * metrics.paddedWidth;

    }
    return x;
  }
})(Highcharts);

The same solution will be used in core.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants