@opendata-ai/openchart-engine 6.2.0 → 6.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opendata-ai/openchart-engine",
3
- "version": "6.2.0",
3
+ "version": "6.2.1",
4
4
  "description": "Headless compiler for openchart: spec validation, data compilation, scales, and layout",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Riley Hilliard",
@@ -45,7 +45,7 @@
45
45
  "typecheck": "tsc --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "@opendata-ai/openchart-core": "6.2.0",
48
+ "@opendata-ai/openchart-core": "6.2.1",
49
49
  "d3-array": "^3.2.0",
50
50
  "d3-format": "^3.1.2",
51
51
  "d3-interpolate": "^3.0.0",
@@ -255,7 +255,8 @@ function formatTickLabel(value: unknown, resolvedScale: ResolvedScale): string {
255
255
  if (TEMPORAL_SCALE_TYPES.has(resolvedScale.type)) {
256
256
  const temporalFmt = buildTemporalFormatter(formatStr);
257
257
  if (temporalFmt) return temporalFmt(value as Date);
258
- return formatDate(value as Date);
258
+ const useUtc = resolvedScale.type === 'utc';
259
+ return formatDate(value as Date, undefined, undefined, useUtc);
259
260
  }
260
261
 
261
262
  if (NUMERIC_SCALE_TYPES.has(resolvedScale.type)) {
@@ -190,6 +190,7 @@ export function computeDimensions(
190
190
 
191
191
  // Reserve right margin for text annotations near the chart's right edge.
192
192
  // Without this, annotation text at the last data point clips outside the SVG.
193
+ // Account for anchor direction and offset.dx to avoid over-reserving space.
193
194
  if (spec.annotations.length > 0 && encoding.x) {
194
195
  const xField = encoding.x.field;
195
196
  // Find the maximum x value in the data
@@ -203,7 +204,23 @@ export function computeDimensions(
203
204
  for (const ann of spec.annotations) {
204
205
  if (ann.type === 'text' && String(ann.x) === maxXStr) {
205
206
  const textWidth = estimateTextWidth(ann.text, ann.fontSize ?? 11, ann.fontWeight ?? 600);
206
- margins.right = Math.max(margins.right, padding + textWidth + 12);
207
+ const dx = ann.offset?.dx ?? 0;
208
+ // How much text extends right of the anchor point depends on alignment:
209
+ // - anchor "right" or "left": text is off to one side, full width extends
210
+ // - anchor "top"/"bottom"/"auto"/undefined: text is centered, half extends right
211
+ const anchor = ann.anchor ?? 'auto';
212
+ const baseRightExtent =
213
+ anchor === 'left'
214
+ ? textWidth
215
+ : // text is to the right of anchor
216
+ anchor === 'right'
217
+ ? 0
218
+ : // text is to the left of anchor
219
+ textWidth / 2; // centered (top/bottom/auto)
220
+ const rightOverflow = Math.max(0, baseRightExtent + dx);
221
+ if (rightOverflow > 0) {
222
+ margins.right = Math.max(margins.right, padding + rightOverflow + 12);
223
+ }
207
224
  }
208
225
  }
209
226
  }