|
1 | | -import {ascending, descending, max, sort} from 'd3'; |
| 1 | +import {ascending, descending, sort} from 'd3'; |
2 | 2 | import type {ScaleBand, ScaleLinear, ScaleTime} from 'd3'; |
3 | 3 | import get from 'lodash/get'; |
4 | 4 |
|
5 | 5 | import type {BarXSeriesData, LabelData} from '../../../types'; |
6 | 6 | import {getDataCategoryValue, getLabelsSize} from '../../../utils'; |
7 | 7 | import {getFormattedValue} from '../../../utils/chart/format'; |
8 | | -import {MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH} from '../../constants'; |
9 | 8 | import type {PreparedXAxis, PreparedYAxis} from '../../useAxis/types'; |
10 | 9 | import type {ChartScale} from '../../useAxisScales'; |
11 | | -import type {PreparedBarXSeries, PreparedSeriesOptions} from '../../useSeries/types'; |
| 10 | +import type {PreparedBarXSeries, PreparedSeriesOptions, StackedSeries} from '../../useSeries/types'; |
| 11 | +import {getSeriesStackId} from '../../useSeries/utils'; |
12 | 12 | import type {PreparedSplit} from '../../useSplit/types'; |
| 13 | +import {getBarXLayout} from '../../utils/bar-x'; |
13 | 14 |
|
14 | 15 | import type {PreparedBarXData} from './types'; |
15 | 16 |
|
@@ -86,10 +87,7 @@ export const prepareBarXData = async (args: { |
86 | 87 | split, |
87 | 88 | } = args; |
88 | 89 | const stackGap: number = seriesOptions['bar-x'].stackGap; |
89 | | - const categories = get(xAxis, 'categories', [] as string[]); |
90 | | - const barMaxWidth = get(seriesOptions, 'bar-x.barMaxWidth'); |
91 | | - const barPadding = get(seriesOptions, 'bar-x.barPadding'); |
92 | | - const groupPadding = get(seriesOptions, 'bar-x.groupPadding'); |
| 90 | + const categories = xAxis?.categories ?? []; |
93 | 91 | const sortingOptions = get(seriesOptions, 'bar-x.dataSorting'); |
94 | 92 | const comparator = sortingOptions?.direction === 'desc' ? descending : ascending; |
95 | 93 | const sortKey = (() => { |
@@ -122,64 +120,42 @@ export const prepareBarXData = async (args: { |
122 | 120 | if (!isSeriesDataValid(d)) { |
123 | 121 | return; |
124 | 122 | } |
125 | | - const xValue = |
| 123 | + const key = |
126 | 124 | xAxis.type === 'category' |
127 | 125 | ? getDataCategoryValue({axisDirection: 'x', categories, data: d}) |
128 | 126 | : d.x; |
129 | 127 |
|
130 | | - if (typeof xValue !== 'undefined') { |
131 | | - if (!data[xValue]) { |
132 | | - data[xValue] = {}; |
| 128 | + if (key !== undefined) { |
| 129 | + if (!data[key]) { |
| 130 | + data[key] = {}; |
133 | 131 | } |
134 | 132 |
|
135 | | - const xGroup = data[xValue]; |
136 | | - |
137 | | - if (!xGroup[s.stackId]) { |
138 | | - xGroup[s.stackId] = []; |
| 133 | + const stackId = getSeriesStackId(s as StackedSeries); |
| 134 | + if (!data[key][stackId]) { |
| 135 | + data[key][stackId] = []; |
139 | 136 | } |
140 | 137 |
|
141 | | - xGroup[s.stackId].push({data: d, series: s}); |
| 138 | + data[key][stackId].push({data: d, series: s}); |
142 | 139 | } |
143 | 140 | }); |
144 | 141 | }); |
145 | 142 |
|
146 | | - let bandWidth = Infinity; |
147 | | - |
148 | | - if (xAxis.type === 'category') { |
149 | | - const xBandScale = xScale as ScaleBand<string>; |
150 | | - bandWidth = xBandScale.bandwidth(); |
151 | | - } else { |
152 | | - const xLinearScale = xScale as ScaleLinear<number, number> | ScaleTime<number, number>; |
153 | | - const xValues = series.reduce<number[]>((acc, s) => { |
154 | | - s.data.forEach((dataItem) => acc.push(Number(dataItem.x))); |
155 | | - return acc; |
156 | | - }, []); |
157 | | - |
158 | | - xValues.sort().forEach((xValue, index) => { |
159 | | - if (index > 0 && xValue !== xValues[index - 1]) { |
160 | | - const dist = xLinearScale(xValue) - xLinearScale(xValues[index - 1]); |
161 | | - if (dist < bandWidth) { |
162 | | - bandWidth = dist; |
163 | | - } |
164 | | - } |
165 | | - }); |
166 | | - } |
167 | | - |
168 | 143 | const result: PreparedBarXData[] = []; |
169 | 144 |
|
170 | 145 | const plotIndexes = Array.from(dataByPlots.keys()); |
171 | 146 | for (let plotDataIndex = 0; plotDataIndex < plotIndexes.length; plotDataIndex++) { |
172 | 147 | const data = dataByPlots.get(plotIndexes[plotDataIndex]) ?? {}; |
173 | | - const maxGroupSize = max(Object.values(data), (d) => Object.values(d).length) || 1; |
174 | | - const groupGap = Math.max(bandWidth * groupPadding, MIN_BAR_GROUP_GAP); |
175 | | - const groupWidth = bandWidth - groupGap; |
176 | | - const rectGap = Math.max(bandWidth * barPadding, MIN_BAR_GAP); |
177 | | - const rectWidth = Math.max( |
178 | | - MIN_BAR_WIDTH, |
179 | | - Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth), |
180 | | - ); |
181 | | - |
182 | 148 | const groupedData = Object.entries(data); |
| 149 | + const { |
| 150 | + bandSize, |
| 151 | + barGap: rectGap, |
| 152 | + barSize: rectWidth, |
| 153 | + } = getBarXLayout({ |
| 154 | + groupedData: data, |
| 155 | + seriesOptions, |
| 156 | + scale: xScale, |
| 157 | + }); |
| 158 | + |
183 | 159 | for (let groupedDataIndex = 0; groupedDataIndex < groupedData.length; groupedDataIndex++) { |
184 | 160 | const [xValue, val] = groupedData[groupedDataIndex]; |
185 | 161 | const stacks = Object.values(val); |
@@ -216,12 +192,12 @@ export const prepareBarXData = async (args: { |
216 | 192 | continue; |
217 | 193 | } |
218 | 194 |
|
219 | | - xCenter = (xBandScale(xValue as string) || 0) + xBandScale.bandwidth() / 2; |
| 195 | + xCenter = (xBandScale(xValue as string) || 0) + bandSize / 2; |
220 | 196 | } else { |
221 | | - const xLinearScale = xScale as |
| 197 | + const scale = xScale as |
222 | 198 | | ScaleLinear<number, number> |
223 | 199 | | ScaleTime<number, number>; |
224 | | - xCenter = xLinearScale(Number(xValue)); |
| 200 | + xCenter = scale(Number(xValue)); |
225 | 201 | } |
226 | 202 |
|
227 | 203 | const x = |
|
0 commit comments