diff --git a/packages/charts/src/chart_types/partition_chart/layout/utils/treemap.ts b/packages/charts/src/chart_types/partition_chart/layout/utils/treemap.ts index 9f1ec62684..9d26e6a6e9 100644 --- a/packages/charts/src/chart_types/partition_chart/layout/utils/treemap.ts +++ b/packages/charts/src/chart_types/partition_chart/layout/utils/treemap.ts @@ -29,11 +29,11 @@ function layVector( areaAccessor: (e: ArrayEntry) => number, ): LayoutElement { const area = nodes.reduce((p, n) => p + areaAccessor(n), 0); - const dependentSize = area / independentSize; // here we lose a bit of accuracy + const dependentSize = independentSize === 0 ? 0 : area / independentSize; // here we lose a bit of accuracy let currentOffset = 0; const sectionOffsets = [currentOffset]; const sectionSizes = nodes.map((e, i) => { - const sectionSize = areaAccessor(e) / dependentSize; // here we gain back a bit of accuracy + const sectionSize = dependentSize === 0 ? 0 : areaAccessor(e) / dependentSize; // here we gain back a bit of accuracy if (i < nodes.length - 1) sectionOffsets.push((currentOffset += sectionSize)); return sectionSize; }); diff --git a/packages/charts/src/chart_types/partition_chart/partition.test.tsx b/packages/charts/src/chart_types/partition_chart/partition.test.tsx index feef8a404b..caad8cb57f 100644 --- a/packages/charts/src/chart_types/partition_chart/partition.test.tsx +++ b/packages/charts/src/chart_types/partition_chart/partition.test.tsx @@ -9,11 +9,13 @@ import { Store } from 'redux'; import { computeLegendSelector } from './state/selectors/compute_legend'; +import { partitionMultiGeometries } from './state/selectors/geometries'; import { getLegendItemsLabels } from './state/selectors/get_legend_items_labels'; import { MockGlobalSpec, MockSeriesSpec } from '../../mocks/specs'; import { MockStore } from '../../mocks/store'; import { GlobalChartState } from '../../state/chart_state'; import { LegendItemLabel } from '../../state/selectors/get_legend_items_labels'; +import { LIGHT_THEME } from '../../utils/themes/light_theme'; // sorting is useful to ensure tests pass even if order changes (where order doesn't matter) const ascByLabel = (a: LegendItemLabel, b: LegendItemLabel) => (a.label < b.label ? -1 : a.label > b.label ? 1 : 0); @@ -160,5 +162,31 @@ describe('Retain hierarchy even with arbitrary names', () => { ); expect(getLegendItemsLabels(store.getState()).map((l) => l.label)).toEqual([]); }); + it('avoid max stack call with zero value at specific dimensions', () => { + MockStore.updateDimensions(store, { width: 557, height: 360, top: 0, left: 0 }); + MockStore.addSpecs( + [ + MockGlobalSpec.settings({ showLegend: false, theme: LIGHT_THEME }), + MockSeriesSpec.treemap({ + data: [ + { cat: 'a', val: 1 }, + { cat: 'b', val: 1 }, + { cat: 'c', val: 0 }, + { cat: 'd', val: 1 }, + ], + valueAccessor: (d: { cat: string; val: number }) => d.val, + layers: [ + { + groupByRollup: (d: { cat: string; val: number }) => d.cat, + }, + ], + }), + ], + store, + ); + expect(() => { + partitionMultiGeometries(store.getState()); + }).not.toThrow(); + }); }); });