@opendata-ai/openchart-vanilla 6.9.0 → 6.11.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.js CHANGED
@@ -3259,7 +3259,7 @@ function escapeHtml(str) {
3259
3259
  }
3260
3260
 
3261
3261
  // src/mount.ts
3262
- import { elementRef, isLayerSpec } from "@opendata-ai/openchart-core";
3262
+ import { elementRef, getRepresentativeColor, isLayerSpec } from "@opendata-ai/openchart-core";
3263
3263
  import { compileChart, compileLayer } from "@opendata-ai/openchart-engine";
3264
3264
 
3265
3265
  // src/animation.ts
@@ -3304,8 +3304,93 @@ function setupTableAnimationCleanup(wrapper) {
3304
3304
  // src/svg-renderer.ts
3305
3305
  import { BRAND_FONT_SIZE as BRAND_FONT_SIZE2, BRAND_MIN_WIDTH as BRAND_MIN_WIDTH2, estimateTextWidth } from "@opendata-ai/openchart-core";
3306
3306
  import { clampStaggerDelay } from "@opendata-ai/openchart-engine";
3307
+
3308
+ // src/gradient-utils.ts
3309
+ import { isGradientDef } from "@opendata-ai/openchart-core";
3307
3310
  var SVG_NS = "http://www.w3.org/2000/svg";
3311
+ function gradientKey(def) {
3312
+ return sortedStringify(def);
3313
+ }
3314
+ function sortedStringify(value) {
3315
+ if (value === null || value === void 0) return String(value);
3316
+ if (Array.isArray(value)) return `[${value.map(sortedStringify).join(",")}]`;
3317
+ if (typeof value === "object") {
3318
+ const sorted = Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${sortedStringify(value[k])}`);
3319
+ return `{${sorted.join(",")}}`;
3320
+ }
3321
+ return JSON.stringify(value);
3322
+ }
3323
+ function createGradientElement(def, id) {
3324
+ if (def.gradient === "linear") {
3325
+ return createLinearGradient(def, id);
3326
+ }
3327
+ return createRadialGradient(def, id);
3328
+ }
3329
+ function createLinearGradient(def, id) {
3330
+ const el = document.createElementNS(SVG_NS, "linearGradient");
3331
+ el.setAttribute("id", id);
3332
+ el.setAttribute("gradientUnits", "objectBoundingBox");
3333
+ el.setAttribute("x1", String(def.x1 ?? 0));
3334
+ el.setAttribute("y1", String(def.y1 ?? 0));
3335
+ el.setAttribute("x2", String(def.x2 ?? 0));
3336
+ el.setAttribute("y2", String(def.y2 ?? 1));
3337
+ for (const stop of def.stops) {
3338
+ appendStop(el, stop);
3339
+ }
3340
+ return el;
3341
+ }
3342
+ function createRadialGradient(def, id) {
3343
+ const el = document.createElementNS(SVG_NS, "radialGradient");
3344
+ el.setAttribute("id", id);
3345
+ el.setAttribute("gradientUnits", "objectBoundingBox");
3346
+ el.setAttribute("cx", String(def.x2 ?? 0.5));
3347
+ el.setAttribute("cy", String(def.y2 ?? 0.5));
3348
+ el.setAttribute("r", String(def.r2 ?? 0.5));
3349
+ el.setAttribute("fx", String(def.x1 ?? 0.5));
3350
+ el.setAttribute("fy", String(def.y1 ?? 0.5));
3351
+ el.setAttribute("fr", String(def.r1 ?? 0));
3352
+ for (const stop of def.stops) {
3353
+ appendStop(el, stop);
3354
+ }
3355
+ return el;
3356
+ }
3357
+ function appendStop(parent, stop) {
3358
+ const stopEl = document.createElementNS(SVG_NS, "stop");
3359
+ stopEl.setAttribute("offset", String(stop.offset));
3360
+ stopEl.setAttribute("stop-color", stop.color);
3361
+ if (stop.opacity !== void 0) {
3362
+ stopEl.setAttribute("stop-opacity", String(stop.opacity));
3363
+ }
3364
+ parent.appendChild(stopEl);
3365
+ }
3366
+ function buildGradientDefs(marks, defs) {
3367
+ const map = /* @__PURE__ */ new Map();
3368
+ let counter = 0;
3369
+ for (const mark of marks) {
3370
+ const fill = mark.fill;
3371
+ if (fill && isGradientDef(fill)) {
3372
+ const key = gradientKey(fill);
3373
+ if (!map.has(key)) {
3374
+ const id = `oc-grad-${counter++}`;
3375
+ const el = createGradientElement(fill, id);
3376
+ defs.appendChild(el);
3377
+ map.set(key, id);
3378
+ }
3379
+ }
3380
+ }
3381
+ return map;
3382
+ }
3383
+ function resolveMarkFill(fill, gradientMap) {
3384
+ if (typeof fill === "string") return fill;
3385
+ const key = gradientKey(fill);
3386
+ const id = gradientMap.get(key);
3387
+ return id ? `url(#${id})` : "#000000";
3388
+ }
3389
+
3390
+ // src/svg-renderer.ts
3391
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
3308
3392
  var currentAnimation;
3393
+ var currentGradientMap = /* @__PURE__ */ new Map();
3309
3394
  function stampAnimationAttrs(el, mark, fallbackIndex) {
3310
3395
  if (!currentAnimation?.enabled) return;
3311
3396
  const idx = mark.animationIndex ?? fallbackIndex;
@@ -3334,7 +3419,7 @@ function computeXAxisExtent(layout) {
3334
3419
  return xAxis.label ? 48 : 26;
3335
3420
  }
3336
3421
  function createSVGElement(tag) {
3337
- return document.createElementNS(SVG_NS, tag);
3422
+ return document.createElementNS(SVG_NS2, tag);
3338
3423
  }
3339
3424
  function setAttrs(el, attrs) {
3340
3425
  for (const [key, value] of Object.entries(attrs)) {
@@ -3649,7 +3734,7 @@ function renderAreaMark(mark, index2) {
3649
3734
  const fill = createSVGElement("path");
3650
3735
  setAttrs(fill, {
3651
3736
  d: mark.path,
3652
- fill: mark.fill,
3737
+ fill: resolveMarkFill(mark.fill, currentGradientMap),
3653
3738
  "fill-opacity": mark.fillOpacity,
3654
3739
  stroke: "none"
3655
3740
  });
@@ -3682,7 +3767,7 @@ function renderRectMark(mark, index2) {
3682
3767
  y: mark.y,
3683
3768
  width: mark.width,
3684
3769
  height: mark.height,
3685
- fill: mark.fill
3770
+ fill: resolveMarkFill(mark.fill, currentGradientMap)
3686
3771
  });
3687
3772
  if (mark.stroke) {
3688
3773
  rect.setAttribute("stroke", mark.stroke);
@@ -3713,7 +3798,7 @@ function renderArcMark(mark, index2) {
3713
3798
  const path = createSVGElement("path");
3714
3799
  setAttrs(path, {
3715
3800
  d: mark.path,
3716
- fill: mark.fill,
3801
+ fill: resolveMarkFill(mark.fill, currentGradientMap),
3717
3802
  stroke: mark.stroke,
3718
3803
  "stroke-width": mark.strokeWidth
3719
3804
  });
@@ -3740,7 +3825,7 @@ function renderPointMark(mark, index2) {
3740
3825
  cx: mark.cx,
3741
3826
  cy: mark.cy,
3742
3827
  r: mark.r,
3743
- fill: mark.fill,
3828
+ fill: resolveMarkFill(mark.fill, currentGradientMap),
3744
3829
  stroke: mark.stroke,
3745
3830
  "stroke-width": mark.strokeWidth
3746
3831
  });
@@ -4184,7 +4269,7 @@ function renderChartSVG(layout, container, opts) {
4184
4269
  const svg = createSVGElement("svg");
4185
4270
  setAttrs(svg, {
4186
4271
  viewBox: `0 0 ${width} ${height}`,
4187
- xmlns: SVG_NS,
4272
+ xmlns: SVG_NS2,
4188
4273
  // WebKit/iOS Safari getBBox() bug: text with dominant-baseline:hanging
4189
4274
  // reports bounding boxes extending above y=0. The SVG spec default
4190
4275
  // overflow is "hidden", which clips this phantom extent. Setting
@@ -4241,6 +4326,7 @@ function renderChartSVG(layout, container, opts) {
4241
4326
  });
4242
4327
  clipPath.appendChild(clipRect);
4243
4328
  defs.appendChild(clipPath);
4329
+ currentGradientMap = buildGradientDefs(layout.marks, defs);
4244
4330
  svg.appendChild(defs);
4245
4331
  renderAxes(svg, layout);
4246
4332
  const clippedGroup = createSVGElement("g");
@@ -4269,6 +4355,7 @@ function renderChartSVG(layout, container, opts) {
4269
4355
  renderChrome(svg, layout);
4270
4356
  renderBrand(svg, layout);
4271
4357
  currentAnimation = void 0;
4358
+ currentGradientMap = /* @__PURE__ */ new Map();
4272
4359
  container.appendChild(svg);
4273
4360
  return svg;
4274
4361
  }
@@ -4511,7 +4598,7 @@ function collectVoronoiPoints(layout) {
4511
4598
  const points = [];
4512
4599
  for (const mark of layout.marks) {
4513
4600
  if ((mark.type === "line" || mark.type === "area") && mark.dataPoints) {
4514
- const color = mark.type === "line" ? mark.stroke : mark.fill;
4601
+ const color = mark.type === "line" ? mark.stroke : getRepresentativeColor(mark.fill);
4515
4602
  for (const dp of mark.dataPoints) {
4516
4603
  points.push({ ...dp, color });
4517
4604
  }
@@ -4902,7 +4989,7 @@ function wireAnnotationDrag(svg, specAnnotations, onAnnotationEdit, onEdit, setD
4902
4989
  };
4903
4990
  }
4904
4991
  function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4905
- const SVG_NS3 = "http://www.w3.org/2000/svg";
4992
+ const SVG_NS4 = "http://www.w3.org/2000/svg";
4906
4993
  const cleanups = [];
4907
4994
  const annotationGroups = svg.querySelectorAll(".oc-annotation-text");
4908
4995
  for (const el of annotationGroups) {
@@ -4941,7 +5028,7 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4941
5028
  const createdHandles = [];
4942
5029
  for (const ep of endpoints) {
4943
5030
  if (!Number.isFinite(ep.cx) || !Number.isFinite(ep.cy)) continue;
4944
- const handleEl = document.createElementNS(SVG_NS3, "circle");
5031
+ const handleEl = document.createElementNS(SVG_NS4, "circle");
4945
5032
  handleEl.setAttribute("class", "oc-connector-handle");
4946
5033
  handleEl.setAttribute("data-endpoint", ep.name);
4947
5034
  handleEl.setAttribute("cx", String(ep.cx));
@@ -6405,7 +6492,7 @@ import { compileSankey } from "@opendata-ai/openchart-engine";
6405
6492
  // src/sankey-renderer.ts
6406
6493
  import { BRAND_FONT_SIZE as BRAND_FONT_SIZE3, BRAND_MIN_WIDTH as BRAND_MIN_WIDTH3, estimateTextWidth as estimateTextWidth2 } from "@opendata-ai/openchart-core";
6407
6494
  import { clampStaggerDelay as clampStaggerDelay2 } from "@opendata-ai/openchart-engine";
6408
- var SVG_NS2 = "http://www.w3.org/2000/svg";
6495
+ var SVG_NS3 = "http://www.w3.org/2000/svg";
6409
6496
  var XLINK_NS2 = "http://www.w3.org/1999/xlink";
6410
6497
  var BRAND_URL2 = "https://tryopendata.ai";
6411
6498
  var EASE_VAR_MAP2 = {
@@ -6413,7 +6500,7 @@ var EASE_VAR_MAP2 = {
6413
6500
  snappy: "var(--oc-ease-snappy)"
6414
6501
  };
6415
6502
  function createSVGElement2(tag) {
6416
- return document.createElementNS(SVG_NS2, tag);
6503
+ return document.createElementNS(SVG_NS3, tag);
6417
6504
  }
6418
6505
  function setAttrs2(el, attrs) {
6419
6506
  for (const [key, value] of Object.entries(attrs)) {
@@ -6772,7 +6859,7 @@ function renderSankeySVG(layout, animation) {
6772
6859
  const svg = createSVGElement2("svg");
6773
6860
  setAttrs2(svg, {
6774
6861
  viewBox: `0 0 ${width} ${height}`,
6775
- xmlns: SVG_NS2,
6862
+ xmlns: SVG_NS3,
6776
6863
  overflow: "visible"
6777
6864
  });
6778
6865
  svg.style.height = `${height}px`;