@opendata-ai/openchart-engine 8.6.4 → 8.8.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.
package/dist/index.d.ts CHANGED
@@ -437,7 +437,7 @@ interface NormalizedBarListSpec {
437
437
 
438
438
  interface NormalizedGeoMapSpec {
439
439
  type: 'map';
440
- geo: Required<Omit<GeoMapGeo, 'projection'>> & {
440
+ geo: Required<Omit<GeoMapGeo, 'projection' | 'zoom'>> & {
441
441
  projection?: GeoMapProjection;
442
442
  };
443
443
  data: Record<string, unknown>[];
package/dist/index.js CHANGED
@@ -7511,6 +7511,7 @@ function normalizeYouDrawIt(spec) {
7511
7511
  return {
7512
7512
  prompt: "Draw your guess",
7513
7513
  revealLabel: "Show me",
7514
+ resetLabel: "Clear",
7514
7515
  ...spec.youDrawIt
7515
7516
  };
7516
7517
  }
@@ -9107,6 +9108,35 @@ function validateTileMapSpec(spec, errors) {
9107
9108
  });
9108
9109
  }
9109
9110
  }
9111
+ function validateGeoMapZoom(zoom, errors) {
9112
+ if (zoom === void 0 || typeof zoom === "boolean") return;
9113
+ if (typeof zoom !== "object" || zoom === null || Array.isArray(zoom)) {
9114
+ errors.push({
9115
+ message: "Spec error: geo.zoom must be a boolean or an object { maxZoom?, controls? }",
9116
+ path: "geo.zoom",
9117
+ code: "INVALID_TYPE",
9118
+ suggestion: "Use zoom: true, or zoom: { maxZoom: 8, controls: true }"
9119
+ });
9120
+ return;
9121
+ }
9122
+ const cfg = zoom;
9123
+ if (cfg.maxZoom !== void 0 && (typeof cfg.maxZoom !== "number" || !Number.isFinite(cfg.maxZoom) || cfg.maxZoom < 1)) {
9124
+ errors.push({
9125
+ message: "Spec error: geo.zoom.maxZoom must be a number >= 1",
9126
+ path: "geo.zoom.maxZoom",
9127
+ code: "INVALID_VALUE",
9128
+ suggestion: "maxZoom is a multiple of the full map, e.g. maxZoom: 8. The default is 12."
9129
+ });
9130
+ }
9131
+ if (cfg.controls !== void 0 && typeof cfg.controls !== "boolean") {
9132
+ errors.push({
9133
+ message: "Spec error: geo.zoom.controls must be a boolean",
9134
+ path: "geo.zoom.controls",
9135
+ code: "INVALID_TYPE",
9136
+ suggestion: "Use controls: false to hide the zoom buttons"
9137
+ });
9138
+ }
9139
+ }
9110
9140
  function validateGeoMapSpec(spec, errors) {
9111
9141
  if (!spec.geo || typeof spec.geo !== "object") {
9112
9142
  errors.push({
@@ -9227,6 +9257,7 @@ function validateGeoMapSpec(spec, errors) {
9227
9257
  });
9228
9258
  }
9229
9259
  }
9260
+ validateGeoMapZoom(geo.zoom, errors);
9230
9261
  const encoding = spec.encoding;
9231
9262
  const hasPoints = spec.points && typeof spec.points === "object" && !Array.isArray(spec.points);
9232
9263
  const specData = spec.data;
@@ -13469,6 +13500,21 @@ function resolveYInvert(scaleY, area3) {
13469
13500
  bottomData
13470
13501
  };
13471
13502
  }
13503
+ var AT_FROM_EPSILON = 1e-6;
13504
+ function resolveAnchor(points, fromX) {
13505
+ const sorted = [...points].sort((a, b) => a.x - b.x);
13506
+ for (let i = 0; i < sorted.length; i++) {
13507
+ const p = sorted[i];
13508
+ if (Math.abs(p.x - fromX) <= AT_FROM_EPSILON) return { x: fromX, y: p.y };
13509
+ if (p.x > fromX) {
13510
+ if (i === 0) return void 0;
13511
+ const prev = sorted[i - 1];
13512
+ const t = (fromX - prev.x) / (p.x - prev.x);
13513
+ return { x: fromX, y: prev.y + t * (p.y - prev.y) };
13514
+ }
13515
+ }
13516
+ return void 0;
13517
+ }
13472
13518
  function resolveYouDrawIt(config, marks, scales, chartArea, xField) {
13473
13519
  if (!config || !scales.x) return void 0;
13474
13520
  const targetLine = marks.find((m) => m.type === "line");
@@ -13479,7 +13525,7 @@ function resolveYouDrawIt(config, marks, scales, chartArea, xField) {
13479
13525
  const samples = [];
13480
13526
  if (targetLine.dataPoints?.length) {
13481
13527
  for (const dp of targetLine.dataPoints) {
13482
- if (dp.x < fromX - 0.5) continue;
13528
+ if (dp.x <= fromX + AT_FROM_EPSILON) continue;
13483
13529
  if (seen.has(dp.x)) continue;
13484
13530
  seen.add(dp.x);
13485
13531
  const raw = xField ? dp.datum[xField] : void 0;
@@ -13489,7 +13535,7 @@ function resolveYouDrawIt(config, marks, scales, chartArea, xField) {
13489
13535
  }
13490
13536
  if (samples.length === 0) {
13491
13537
  for (const p of targetLine.points) {
13492
- if (p.x < fromX - 0.5) continue;
13538
+ if (p.x <= fromX + AT_FROM_EPSILON) continue;
13493
13539
  if (seen.has(p.x)) continue;
13494
13540
  seen.add(p.x);
13495
13541
  samples.push({ px: p.x, xValue: p.x });
@@ -13511,15 +13557,18 @@ function resolveYouDrawIt(config, marks, scales, chartArea, xField) {
13511
13557
  }
13512
13558
  }
13513
13559
  const yInvert = resolveYInvert(scales.y, chartArea);
13560
+ const anchor = resolveAnchor(targetLine.points, fromX);
13514
13561
  return {
13515
13562
  fromX,
13516
13563
  area: chartArea,
13517
13564
  samples,
13518
13565
  prompt: config.prompt ?? "Draw your guess",
13519
13566
  revealLabel: config.revealLabel ?? "Show me",
13567
+ resetLabel: config.resetLabel ?? "Clear",
13520
13568
  lineColor: targetLine.stroke,
13521
13569
  targetSeriesKey: targetLine.seriesKey,
13522
13570
  ...yInvert ? { yInvert } : {},
13571
+ ...anchor ? { anchor } : {},
13523
13572
  ...comparisonPoints ? { comparisonPoints } : {}
13524
13573
  };
13525
13574
  }