@opendata-ai/openchart-engine 8.0.0-rc.17 → 8.0.0-rc.19
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 +96 -30
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9087,7 +9087,7 @@ function resolvePosition2(value2, channelType, scale) {
|
|
|
9087
9087
|
}
|
|
9088
9088
|
}
|
|
9089
9089
|
}
|
|
9090
|
-
function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
9090
|
+
function computeScatterMarks(spec, scales, _chartArea, _strategy, theme) {
|
|
9091
9091
|
const encoding = spec.encoding;
|
|
9092
9092
|
const xChannel = encoding.x;
|
|
9093
9093
|
const yChannel = encoding.y;
|
|
@@ -9105,6 +9105,10 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
9105
9105
|
const sizeField = sizeEnc?.field;
|
|
9106
9106
|
const resolvedSize = buildSizeScale(sizeEnc, spec.data, SIZE_SCALE_DEFAULTS.point);
|
|
9107
9107
|
const sizeScale = resolvedSize?.scale;
|
|
9108
|
+
const constFill = spec.markDef.fill;
|
|
9109
|
+
const constSize = spec.markDef.size;
|
|
9110
|
+
const bg = theme?.colors?.background;
|
|
9111
|
+
const defaultStroke = bg && bg !== "transparent" ? bg : "#ffffff";
|
|
9108
9112
|
const keyEnc = encoding.key && "field" in encoding.key ? encoding.key : void 0;
|
|
9109
9113
|
const keyField = keyEnc?.field;
|
|
9110
9114
|
const marks = [];
|
|
@@ -9119,10 +9123,12 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
9119
9123
|
if (isSequentialColor && colorField) {
|
|
9120
9124
|
const val = Number(row[colorField]);
|
|
9121
9125
|
color2 = Number.isFinite(val) ? getSequentialColor(scales, val) : getColor(scales, "__default__");
|
|
9122
|
-
} else {
|
|
9126
|
+
} else if (colorField) {
|
|
9123
9127
|
color2 = getColor(scales, category ?? "__default__");
|
|
9128
|
+
} else {
|
|
9129
|
+
color2 = constFill ?? getColor(scales, "__default__");
|
|
9124
9130
|
}
|
|
9125
|
-
let radius = DEFAULT_POINT_RADIUS2;
|
|
9131
|
+
let radius = constSize != null ? constSize : DEFAULT_POINT_RADIUS2;
|
|
9126
9132
|
if (sizeScale && sizeField) {
|
|
9127
9133
|
const sizeVal = Number(row[sizeField]);
|
|
9128
9134
|
if (Number.isFinite(sizeVal)) {
|
|
@@ -9143,9 +9149,9 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
9143
9149
|
cy,
|
|
9144
9150
|
r: radius,
|
|
9145
9151
|
fill: color2,
|
|
9146
|
-
stroke:
|
|
9147
|
-
strokeWidth: 1,
|
|
9148
|
-
fillOpacity: 0.7,
|
|
9152
|
+
stroke: spec.markDef.stroke ?? defaultStroke,
|
|
9153
|
+
strokeWidth: spec.markDef.strokeWidth ?? 1,
|
|
9154
|
+
fillOpacity: spec.markDef.opacity ?? 0.7,
|
|
9149
9155
|
data: row,
|
|
9150
9156
|
aria
|
|
9151
9157
|
});
|
|
@@ -9186,7 +9192,7 @@ function linearRegression(points) {
|
|
|
9186
9192
|
const intercept = (sumY - slope * sumX) / n;
|
|
9187
9193
|
return { slope, intercept };
|
|
9188
9194
|
}
|
|
9189
|
-
function computeTrendLine(marks) {
|
|
9195
|
+
function computeTrendLine(marks, stroke = TRENDLINE_COLOR, strokeWidth = TRENDLINE_STROKE_WIDTH) {
|
|
9190
9196
|
if (marks.length < 2) return null;
|
|
9191
9197
|
const points = marks.map((m) => ({ x: m.cx, y: m.cy }));
|
|
9192
9198
|
const result = linearRegression(points);
|
|
@@ -9209,8 +9215,8 @@ function computeTrendLine(marks) {
|
|
|
9209
9215
|
{ x: minX, y: y12 },
|
|
9210
9216
|
{ x: maxX, y: y2 }
|
|
9211
9217
|
],
|
|
9212
|
-
stroke
|
|
9213
|
-
strokeWidth
|
|
9218
|
+
stroke,
|
|
9219
|
+
strokeWidth,
|
|
9214
9220
|
strokeDasharray: TRENDLINE_DASH,
|
|
9215
9221
|
data: [],
|
|
9216
9222
|
aria
|
|
@@ -9218,13 +9224,20 @@ function computeTrendLine(marks) {
|
|
|
9218
9224
|
}
|
|
9219
9225
|
|
|
9220
9226
|
// src/charts/scatter/index.ts
|
|
9221
|
-
var scatterRenderer = (spec, scales, chartArea, strategy,
|
|
9222
|
-
const pointMarks = computeScatterMarks(spec, scales, chartArea, strategy);
|
|
9227
|
+
var scatterRenderer = (spec, scales, chartArea, strategy, theme) => {
|
|
9228
|
+
const pointMarks = computeScatterMarks(spec, scales, chartArea, strategy, theme);
|
|
9223
9229
|
const marks = [...pointMarks];
|
|
9224
|
-
|
|
9225
|
-
|
|
9230
|
+
const trendline = spec.markDef?.trendline;
|
|
9231
|
+
if (trendline !== false) {
|
|
9232
|
+
const config = typeof trendline === "object" ? trendline : void 0;
|
|
9233
|
+
const stroke = config?.stroke ?? theme?.colors?.text;
|
|
9234
|
+
const trendLine = computeTrendLine(pointMarks, stroke, config?.strokeWidth);
|
|
9226
9235
|
if (trendLine) {
|
|
9227
|
-
|
|
9236
|
+
if (config?.layer === "above") {
|
|
9237
|
+
marks.push(trendLine);
|
|
9238
|
+
} else {
|
|
9239
|
+
marks.unshift(trendLine);
|
|
9240
|
+
}
|
|
9228
9241
|
}
|
|
9229
9242
|
}
|
|
9230
9243
|
return marks;
|
|
@@ -15430,11 +15443,9 @@ function compileLayerIndependent(leaves, layerSpec, options, compileChart2) {
|
|
|
15430
15443
|
};
|
|
15431
15444
|
const xField0 = leaf0.encoding?.x?.field;
|
|
15432
15445
|
const xField1 = leaf1.encoding?.x?.field;
|
|
15433
|
-
const
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
let leaf0WithUnionX = ensureXDomainCoverage(leaf0, xField0, unionXValues);
|
|
15437
|
-
let leaf1WithUnionX = ensureXDomainCoverage(leaf1, xField1, unionXValues);
|
|
15446
|
+
const union = withUnionXDomain(leaf0, leaf1);
|
|
15447
|
+
let leaf0WithUnionX = union.leaf0;
|
|
15448
|
+
let leaf1WithUnionX = union.leaf1;
|
|
15438
15449
|
const aligned = alignYDomains(leaf0WithUnionX, leaf1WithUnionX);
|
|
15439
15450
|
if (aligned) {
|
|
15440
15451
|
leaf0WithUnionX = withYDomain(leaf0WithUnionX, aligned.domain0);
|
|
@@ -15581,20 +15592,75 @@ function compileLayerIndependent(leaves, layerSpec, options, compileChart2) {
|
|
|
15581
15592
|
tooltipDescriptors: mergedTooltips
|
|
15582
15593
|
};
|
|
15583
15594
|
}
|
|
15584
|
-
function
|
|
15585
|
-
if (!
|
|
15586
|
-
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
|
|
15591
|
-
|
|
15595
|
+
function withXDomain(leaf, domain) {
|
|
15596
|
+
if (!leaf.encoding?.x) return leaf;
|
|
15597
|
+
return {
|
|
15598
|
+
...leaf,
|
|
15599
|
+
encoding: {
|
|
15600
|
+
...leaf.encoding,
|
|
15601
|
+
x: {
|
|
15602
|
+
...leaf.encoding.x,
|
|
15603
|
+
scale: {
|
|
15604
|
+
...leaf.encoding.x.scale,
|
|
15605
|
+
domain
|
|
15606
|
+
}
|
|
15607
|
+
}
|
|
15592
15608
|
}
|
|
15609
|
+
};
|
|
15610
|
+
}
|
|
15611
|
+
function withUnionXDomain(leaf0, leaf1) {
|
|
15612
|
+
const xEnc0 = leaf0.encoding?.x;
|
|
15613
|
+
const xEnc1 = leaf1.encoding?.x;
|
|
15614
|
+
const xField0 = xEnc0?.field;
|
|
15615
|
+
const xField1 = xEnc1?.field;
|
|
15616
|
+
if (!xField0 || !xField1) return { leaf0, leaf1 };
|
|
15617
|
+
const xType = xEnc0?.type ?? xEnc1?.type;
|
|
15618
|
+
const pinned0 = xEnc0?.scale?.domain !== void 0;
|
|
15619
|
+
const pinned1 = xEnc1?.scale?.domain !== void 0;
|
|
15620
|
+
if (pinned0 && pinned1) return { leaf0, leaf1 };
|
|
15621
|
+
const values0 = leaf0.data.map((row) => row[xField0]);
|
|
15622
|
+
const values1 = leaf1.data.map((row) => row[xField1]);
|
|
15623
|
+
const allValues = [...values0, ...values1].filter((v) => v != null);
|
|
15624
|
+
if (allValues.length === 0) return { leaf0, leaf1 };
|
|
15625
|
+
let domain;
|
|
15626
|
+
if (xType === "temporal") {
|
|
15627
|
+
let minMs = Number.POSITIVE_INFINITY;
|
|
15628
|
+
let maxMs = Number.NEGATIVE_INFINITY;
|
|
15629
|
+
for (const v of allValues) {
|
|
15630
|
+
const ms = (v instanceof Date ? v : new Date(String(v))).getTime();
|
|
15631
|
+
if (Number.isNaN(ms)) continue;
|
|
15632
|
+
if (ms < minMs) minMs = ms;
|
|
15633
|
+
if (ms > maxMs) maxMs = ms;
|
|
15634
|
+
}
|
|
15635
|
+
if (minMs <= maxMs) {
|
|
15636
|
+
domain = [new Date(minMs).toISOString(), new Date(maxMs).toISOString()];
|
|
15637
|
+
}
|
|
15638
|
+
} else if (xType === "quantitative") {
|
|
15639
|
+
let min4 = Number.POSITIVE_INFINITY;
|
|
15640
|
+
let max4 = Number.NEGATIVE_INFINITY;
|
|
15641
|
+
for (const v of allValues) {
|
|
15642
|
+
const n = typeof v === "number" ? v : Number(v);
|
|
15643
|
+
if (!Number.isFinite(n)) continue;
|
|
15644
|
+
if (n < min4) min4 = n;
|
|
15645
|
+
if (n > max4) max4 = n;
|
|
15646
|
+
}
|
|
15647
|
+
if (min4 <= max4) domain = [min4, max4];
|
|
15648
|
+
} else {
|
|
15649
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15650
|
+
const categories = [];
|
|
15651
|
+
for (const v of allValues) {
|
|
15652
|
+
const s = String(v);
|
|
15653
|
+
if (!seen.has(s)) {
|
|
15654
|
+
seen.add(s);
|
|
15655
|
+
categories.push(s);
|
|
15656
|
+
}
|
|
15657
|
+
}
|
|
15658
|
+
if (categories.length > 0) domain = categories;
|
|
15593
15659
|
}
|
|
15594
|
-
if (
|
|
15660
|
+
if (domain === void 0) return { leaf0, leaf1 };
|
|
15595
15661
|
return {
|
|
15596
|
-
|
|
15597
|
-
|
|
15662
|
+
leaf0: pinned0 ? leaf0 : withXDomain(leaf0, domain),
|
|
15663
|
+
leaf1: pinned1 ? leaf1 : withXDomain(leaf1, domain)
|
|
15598
15664
|
};
|
|
15599
15665
|
}
|
|
15600
15666
|
function alignYDomains(leaf0, leaf1) {
|