@opendata-ai/openchart-engine 2.3.5 → 2.5.0

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.
@@ -90,8 +90,34 @@ export function computeDimensions(
90
90
  // Estimate x-axis height below chart area: tick labels sit 14px below,
91
91
  // axis title sits 35px below. These extend past the chart area bottom
92
92
  // and source/footer chrome must be positioned below them.
93
- const hasXAxisLabel = !!(encoding.x?.axis as Record<string, unknown> | undefined)?.label;
94
- const xAxisHeight = isRadial ? 0 : hasXAxisLabel ? 48 : 26;
93
+ const xAxis = encoding.x?.axis as (Record<string, unknown> & { tickAngle?: number }) | undefined;
94
+ const hasXAxisLabel = !!xAxis?.label;
95
+ const xTickAngle = xAxis?.tickAngle;
96
+
97
+ let xAxisHeight: number;
98
+ if (isRadial) {
99
+ xAxisHeight = 0;
100
+ } else if (xTickAngle && Math.abs(xTickAngle) > 10) {
101
+ // Rotated labels: estimate height from the longest label text.
102
+ // At -90 degrees, the label height = text width. At -45, it's width * sin(45).
103
+ const angleRad = Math.abs(xTickAngle) * (Math.PI / 180);
104
+ const xField = encoding.x?.field;
105
+ let maxLabelWidth = 40; // fallback
106
+ if (xField) {
107
+ for (const row of spec.data) {
108
+ const label = String(row[xField] ?? '');
109
+ const w = estimateTextWidth(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
110
+ if (w > maxLabelWidth) maxLabelWidth = w;
111
+ }
112
+ }
113
+ // Rotated label height: width * sin(angle), plus a small gap
114
+ const rotatedHeight = maxLabelWidth * Math.sin(angleRad) + 6;
115
+ // Cap at a reasonable max to avoid absurd margins
116
+ const labelHeight = Math.min(rotatedHeight, 120);
117
+ xAxisHeight = hasXAxisLabel ? labelHeight + 20 : labelHeight;
118
+ } else {
119
+ xAxisHeight = hasXAxisLabel ? 48 : 26;
120
+ }
95
121
 
96
122
  // Build margins: padding + chrome + axis space
97
123
  const margins: Margins = {