@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 +100 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/gradient-utils.test.ts +125 -0
- package/src/gradient-utils.ts +134 -0
- package/src/mount.ts +2 -2
- package/src/svg-renderer.ts +17 -5
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(
|
|
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:
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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:
|
|
6862
|
+
xmlns: SVG_NS3,
|
|
6776
6863
|
overflow: "visible"
|
|
6777
6864
|
});
|
|
6778
6865
|
svg.style.height = `${height}px`;
|