( seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>, xScale: LinearScale, )
| 284 | }>; |
| 285 | |
| 286 | export function computeBarLayoutPx( |
| 287 | seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>, |
| 288 | xScale: LinearScale, |
| 289 | ): BarLayoutPx { |
| 290 | const clusterSlots = computeBarClusterSlots(seriesConfigs); |
| 291 | const clusterCount = clusterSlots.clusterCount; |
| 292 | |
| 293 | const categoryStep = computeBarCategoryStep(seriesConfigs); |
| 294 | const categoryWidthPx = computeCategoryWidthPx(seriesConfigs, xScale, categoryStep); |
| 295 | |
| 296 | const layout = computeSharedBarLayout(seriesConfigs); |
| 297 | const barGap = clamp01(layout.barGap ?? DEFAULT_BAR_GAP); |
| 298 | const barCategoryGap = clamp01(layout.barCategoryGap ?? DEFAULT_BAR_CATEGORY_GAP); |
| 299 | |
| 300 | const categoryInnerWidthPx = Math.max(0, categoryWidthPx * (1 - barCategoryGap)); |
| 301 | const denom = clusterCount + Math.max(0, clusterCount - 1) * barGap; |
| 302 | const maxBarWidthPx = denom > 0 ? categoryInnerWidthPx / denom : 0; |
| 303 | |
| 304 | let barWidthPx = 0; |
| 305 | const rawBarWidth = layout.barWidth; |
| 306 | if (typeof rawBarWidth === 'number') { |
| 307 | barWidthPx = Math.max(0, rawBarWidth); |
| 308 | barWidthPx = Math.min(barWidthPx, maxBarWidthPx); |
| 309 | } else if (typeof rawBarWidth === 'string') { |
| 310 | const p = parsePercent(rawBarWidth); |
| 311 | barWidthPx = p == null ? 0 : maxBarWidthPx * clamp01(p); |
| 312 | } |
| 313 | |
| 314 | if (!(barWidthPx > 0)) { |
| 315 | // Auto-width: max per-bar width that still avoids overlap (given clusterCount and barGap). |
| 316 | barWidthPx = maxBarWidthPx; |
| 317 | } |
| 318 | |
| 319 | const gapPx = barWidthPx * barGap; |
| 320 | const clusterWidthPx = clusterCount * barWidthPx + Math.max(0, clusterCount - 1) * gapPx; |
| 321 | |
| 322 | return { |
| 323 | categoryStep, |
| 324 | categoryWidthPx, |
| 325 | barWidthPx, |
| 326 | gapPx, |
| 327 | clusterWidthPx, |
| 328 | clusterSlots, |
| 329 | }; |
| 330 | } |
| 331 | |
| 332 | const computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => { |
| 333 | let yMin = Number.POSITIVE_INFINITY; |
no test coverage detected