@opendata-ai/openchart-engine 7.9.2 → 7.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +86 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/axes.test.ts +106 -35
- package/src/__tests__/rotation.test.ts +83 -0
- package/src/layout/axes/rotation.ts +130 -14
- package/src/layout/axes/ticks.ts +2 -2
- package/src/layout/axes.ts +37 -98
- package/src/layout/plan.ts +18 -3
- package/src/layout/scales.ts +29 -5
package/src/layout/plan.ts
CHANGED
|
@@ -36,7 +36,7 @@ import { legendGap } from '../legend/wrap';
|
|
|
36
36
|
import { yTickPositionIsInline } from './axes';
|
|
37
37
|
import { resolveBandTickAngle } from './axes/rotation';
|
|
38
38
|
import { buildContinuousTicks, scaleSupportsTickCount, targetTickCount } from './axes/ticks';
|
|
39
|
-
import { computeScales, estimateBandwidth } from './scales';
|
|
39
|
+
import { computeScales, estimateBandStep, estimateBandwidth } from './scales';
|
|
40
40
|
import { bottomMargin, chromeToInput, INLINE_TICK_OVERHANG_PAD, scalePadding } from './shared';
|
|
41
41
|
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
@@ -342,8 +342,21 @@ export function resolveLayoutPlan(
|
|
|
342
342
|
// bandwidth = step * (1 - paddingInner). Uses the same override resolution
|
|
343
343
|
// as buildBandScale so paddingInner/paddingOuter are honored here too.
|
|
344
344
|
const bandwidth = estimateBandwidth(encoding.x?.scale, plotWidth, xLabels.length);
|
|
345
|
+
const step = estimateBandStep(encoding.x?.scale, plotWidth, xLabels.length);
|
|
346
|
+
// Mirror categoricalTicks' explicit tickCount cap: retained ticks sit a
|
|
347
|
+
// multiple of the band step apart, so the drawn labels and their anchor
|
|
348
|
+
// spacing — not the full category set — drive the angle here, matching
|
|
349
|
+
// what computeAxes measures from actual tick positions.
|
|
350
|
+
const xTickCount = xAxis?.tickCount as number | undefined;
|
|
351
|
+
let drawnLabels = xLabels;
|
|
352
|
+
let anchorSpacing = step;
|
|
353
|
+
if (xTickCount && xLabels.length > xTickCount) {
|
|
354
|
+
const capStride = Math.ceil(xLabels.length / xTickCount);
|
|
355
|
+
drawnLabels = xLabels.filter((_, i) => i % capStride === 0);
|
|
356
|
+
anchorSpacing = step * capStride;
|
|
357
|
+
}
|
|
345
358
|
let maxXLabelWidth = 0;
|
|
346
|
-
for (const label of
|
|
359
|
+
for (const label of drawnLabels) {
|
|
347
360
|
const w = measure(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
|
|
348
361
|
if (w > maxXLabelWidth) maxXLabelWidth = w;
|
|
349
362
|
}
|
|
@@ -351,7 +364,9 @@ export function resolveLayoutPlan(
|
|
|
351
364
|
undefined,
|
|
352
365
|
maxXLabelWidth,
|
|
353
366
|
bandwidth,
|
|
354
|
-
|
|
367
|
+
drawnLabels.length,
|
|
368
|
+
anchorSpacing,
|
|
369
|
+
theme.fonts.sizes.axisTick,
|
|
355
370
|
);
|
|
356
371
|
}
|
|
357
372
|
|
package/src/layout/scales.ts
CHANGED
|
@@ -470,19 +470,43 @@ function evenRange(start: number, end: number, count: number): number[] {
|
|
|
470
470
|
* each independently. step = width / (n - paddingInner + 2*paddingOuter);
|
|
471
471
|
* bandwidth = step * (1 - paddingInner).
|
|
472
472
|
*/
|
|
473
|
+
/** d3 scaleBand padding resolution: `padding` sets both, overrides win. */
|
|
474
|
+
function resolveBandPadding(scaleConfig: EncodingChannel['scale'] | undefined): {
|
|
475
|
+
paddingInner: number;
|
|
476
|
+
paddingOuter: number;
|
|
477
|
+
} {
|
|
478
|
+
const padding = scaleConfig?.padding ?? 0.35;
|
|
479
|
+
return {
|
|
480
|
+
paddingInner: scaleConfig?.paddingInner ?? padding,
|
|
481
|
+
paddingOuter: scaleConfig?.paddingOuter ?? padding,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
473
485
|
export function estimateBandwidth(
|
|
474
486
|
scaleConfig: EncodingChannel['scale'] | undefined,
|
|
475
487
|
plotWidth: number,
|
|
476
488
|
n: number,
|
|
489
|
+
): number {
|
|
490
|
+
const { paddingInner } = resolveBandPadding(scaleConfig);
|
|
491
|
+
return estimateBandStep(scaleConfig, plotWidth, n) * (1 - paddingInner);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Estimate d3 scaleBand step (center-to-center band distance) for a given
|
|
496
|
+
* plot width and category count, using the same padding resolution as
|
|
497
|
+
* estimateBandwidth. The step — not the bandwidth — is the anchor spacing
|
|
498
|
+
* that drives rotated-label collision checks.
|
|
499
|
+
*/
|
|
500
|
+
export function estimateBandStep(
|
|
501
|
+
scaleConfig: EncodingChannel['scale'] | undefined,
|
|
502
|
+
plotWidth: number,
|
|
503
|
+
n: number,
|
|
477
504
|
): number {
|
|
478
505
|
if (n <= 0) return 0;
|
|
479
|
-
const
|
|
480
|
-
const paddingInner = scaleConfig?.paddingInner ?? padding;
|
|
481
|
-
const paddingOuter = scaleConfig?.paddingOuter ?? padding;
|
|
506
|
+
const { paddingInner, paddingOuter } = resolveBandPadding(scaleConfig);
|
|
482
507
|
const denom = n - paddingInner + 2 * paddingOuter;
|
|
483
508
|
if (denom <= 0) return 0;
|
|
484
|
-
|
|
485
|
-
return step * (1 - paddingInner);
|
|
509
|
+
return plotWidth / denom;
|
|
486
510
|
}
|
|
487
511
|
|
|
488
512
|
function buildBandScale(
|