@bicharts/chart-host 0.6.74 → 0.6.75
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/README.md +11 -0
- package/dist/{chunk-WNGJUPEI.mjs → chunk-7JWL6LYE.mjs} +9 -1
- package/dist/{chunk-4FTLE3ZK.mjs → chunk-OEN7WGNS.mjs} +218 -75
- package/dist/index.mjs +41 -2
- package/dist/react.mjs +2 -2
- package/dist/testing.mjs +1 -1
- package/dist/types/clippedText.d.ts +24 -0
- package/dist/types/contract.d.ts +5 -1
- package/dist/types/host.d.ts +23 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/qualifyTable.d.ts +27 -0
- package/dist/types/selection.d.ts +57 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -267,6 +267,17 @@ would show its selected lines at 38%, which the eye reads as dimmed. Such a char
|
|
|
267
267
|
painted at full opacity. Undeclared charts are unchanged, so alpha used as an encoding (a depth
|
|
268
268
|
cue, a hierarchy level) is never flattened by a fix meant for another chart.
|
|
269
269
|
|
|
270
|
+
**Which marks count as selected.** By default a mark is selected when *any* of the rows in its
|
|
271
|
+
`data-row-idx` list is selected, which is what lights a legend swatch together with its series. A
|
|
272
|
+
chart whose marks share rows declares the other rule by stamping
|
|
273
|
+
`data-lch-sel-rule="clicked-marks"` on an element it draws (its own `<svg>`): then exactly the
|
|
274
|
+
marks the reader clicked are selected and every other mark is dimmed, Ctrl/Cmd/Shift-click adds or
|
|
275
|
+
removes a mark, and a selection set from outside lights the marks whose rows equal it. A mark is
|
|
276
|
+
named by `data-mark-key` when it carries one, else by its row list. A word cloud is the case it was
|
|
277
|
+
made for: every word shares a comment with many others, so the default lit most of the cloud on one
|
|
278
|
+
click. The cross-filter sent out is the same under both rules. `onSelectionPaint` reports how each
|
|
279
|
+
paint of a declaring chart decided, including when no mark matched and the default was used.
|
|
280
|
+
|
|
270
281
|
## Architecture — three layers, and why it matters if you contribute
|
|
271
282
|
|
|
272
283
|
Read this before adding code. The package has **three** concerns, and they are independent.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
2
2
|
|
|
3
3
|
// src/contract.ts
|
|
4
|
-
var HOST_CONTRACT_VERSION = "1.
|
|
4
|
+
var HOST_CONTRACT_VERSION = "1.14.0";
|
|
5
5
|
var GEO_POINT_PRECISIONS = ["latlon", "city", "zip3", "state", "country"];
|
|
6
6
|
var MARK_CLASS = "d3-mark";
|
|
7
7
|
var LEGEND_MARK_CLASS = "d3-legend-mark";
|
|
@@ -9,6 +9,9 @@ var AXIS_FILTER_CLASS = "d3-axis-filter";
|
|
|
9
9
|
var LIFT_SELECTED_CLASS = "d3-lift-selected";
|
|
10
10
|
var CONTROL_CLASS = "lch-control";
|
|
11
11
|
var ROW_IDX_ATTR = "data-row-idx";
|
|
12
|
+
var SELECTION_RULE_ATTR = "data-lch-sel-rule";
|
|
13
|
+
var SELECTION_RULE_CLICKED_MARKS = "clicked-marks";
|
|
14
|
+
var MARK_KEY_ATTR = "data-mark-key";
|
|
12
15
|
var NO_ROW_MARKS_ATTR = "data-lch-no-row-marks";
|
|
13
16
|
var SNAPSHOT_SVG_ATTR = "data-lch-snapshot";
|
|
14
17
|
var XFILTER_REFRESH_EVENT = "llm-xfilter-refresh";
|
|
@@ -16,6 +19,7 @@ var CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
|
|
|
16
19
|
var CONTAINER_SLOT_XF_CLEAR = "__llmXfClear";
|
|
17
20
|
var CONTAINER_SLOT_INITIAL_XF_MARK = "__llmInitialXfMark";
|
|
18
21
|
var CONTAINER_SLOT_UI_STATE = "__lchUiState";
|
|
22
|
+
var CONTAINER_SLOT_CLICKED_MARKS = "__lchClickedMarks";
|
|
19
23
|
var VIEW_ONLY_UI_STATE_KEYS = Object.freeze(["camera", "llmZoom"]);
|
|
20
24
|
function withoutViewOnlyKeys(bag) {
|
|
21
25
|
if (!bag || typeof bag !== "object") return bag;
|
|
@@ -74,6 +78,9 @@ export {
|
|
|
74
78
|
LIFT_SELECTED_CLASS,
|
|
75
79
|
CONTROL_CLASS,
|
|
76
80
|
ROW_IDX_ATTR,
|
|
81
|
+
SELECTION_RULE_ATTR,
|
|
82
|
+
SELECTION_RULE_CLICKED_MARKS,
|
|
83
|
+
MARK_KEY_ATTR,
|
|
77
84
|
NO_ROW_MARKS_ATTR,
|
|
78
85
|
SNAPSHOT_SVG_ATTR,
|
|
79
86
|
XFILTER_REFRESH_EVENT,
|
|
@@ -81,6 +88,7 @@ export {
|
|
|
81
88
|
CONTAINER_SLOT_XF_CLEAR,
|
|
82
89
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
83
90
|
CONTAINER_SLOT_UI_STATE,
|
|
91
|
+
CONTAINER_SLOT_CLICKED_MARKS,
|
|
84
92
|
VIEW_ONLY_UI_STATE_KEYS,
|
|
85
93
|
withoutViewOnlyKeys,
|
|
86
94
|
HOST_CONTAINER_CLASS,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
COLOR_SCALE_SELF_CLAMP_PCT_MAX,
|
|
21
21
|
COLOR_SCALE_SELF_CLAMP_PCT_MIN,
|
|
22
22
|
CONTAINER_SLOT_ANIM_STOP,
|
|
23
|
+
CONTAINER_SLOT_CLICKED_MARKS,
|
|
23
24
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
24
25
|
CONTAINER_SLOT_UI_STATE,
|
|
25
26
|
CONTAINER_SLOT_XF_CLEAR,
|
|
@@ -33,18 +34,21 @@ import {
|
|
|
33
34
|
LEGEND_MARK_CLASS,
|
|
34
35
|
LIFT_SELECTED_CLASS,
|
|
35
36
|
MARK_CLASS,
|
|
37
|
+
MARK_KEY_ATTR,
|
|
36
38
|
MARK_SELECTED_CLASS,
|
|
37
39
|
MAX_MAP_POINTS_DEFAULT,
|
|
38
40
|
NO_ROW_MARKS_ATTR,
|
|
39
41
|
ROW_IDX_ATTR,
|
|
40
42
|
SEASONAL_MARKERS_DEFAULT,
|
|
41
43
|
SELECTION_ACTIVE_CLASS,
|
|
44
|
+
SELECTION_RULE_ATTR,
|
|
45
|
+
SELECTION_RULE_CLICKED_MARKS,
|
|
42
46
|
SNAPSHOT_SVG_ATTR,
|
|
43
47
|
VALUE_AXIS_BASELINE_DEFAULT,
|
|
44
48
|
XFILTER_REFRESH_EVENT,
|
|
45
49
|
chartOwnsTimeline,
|
|
46
50
|
periodTickSuppressesFeedback
|
|
47
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-7JWL6LYE.mjs";
|
|
48
52
|
import {
|
|
49
53
|
__commonJS,
|
|
50
54
|
__toESM
|
|
@@ -252,69 +256,69 @@ var require_papaparse_min = __commonJS({
|
|
|
252
256
|
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
253
257
|
}
|
|
254
258
|
function E4(C2) {
|
|
255
|
-
var S2 = (C2 = C2 || {}).delimiter, O4 = C2.newline, x3 = C2.comments, I2 = C2.step,
|
|
259
|
+
var S2 = (C2 = C2 || {}).delimiter, O4 = C2.newline, x3 = C2.comments, I2 = C2.step, A2 = C2.preview, T = C2.fastMode, D2 = null, L4 = false, F4 = null == C2.quoteChar ? '"' : C2.quoteChar, j4 = F4;
|
|
256
260
|
if (void 0 !== C2.escapeChar && (j4 = C2.escapeChar), ("string" != typeof S2 || -1 < v.BAD_DELIMITERS.indexOf(S2)) && (S2 = ","), x3 === S2) throw new Error("Comment character same as delimiter");
|
|
257
261
|
true === x3 ? x3 = "#" : ("string" != typeof x3 || -1 < v.BAD_DELIMITERS.indexOf(x3)) && (x3 = false), "\n" !== O4 && "\r" !== O4 && "\r\n" !== O4 && (O4 = "\n");
|
|
258
|
-
var
|
|
262
|
+
var z2 = 0, M2 = false;
|
|
259
263
|
this.parse = function(i2, t, r4) {
|
|
260
264
|
if ("string" != typeof i2) throw new Error("Input must be a string");
|
|
261
|
-
var n2 = i2.length, e = S2.length, s4 = O4.length, a4 = x3.length, o5 = q2(I2), h5 = [], u5 = [], d4 = [], f5 =
|
|
265
|
+
var n2 = i2.length, e = S2.length, s4 = O4.length, a4 = x3.length, o5 = q2(I2), h5 = [], u5 = [], d4 = [], f5 = z2 = 0;
|
|
262
266
|
if (!i2) return w3();
|
|
263
267
|
if (T || false !== T && -1 === i2.indexOf(F4)) {
|
|
264
268
|
for (var l4 = i2.split(O4), c4 = 0; c4 < l4.length; c4++) {
|
|
265
|
-
if (d4 = l4[c4],
|
|
269
|
+
if (d4 = l4[c4], z2 += d4.length, c4 !== l4.length - 1) z2 += O4.length;
|
|
266
270
|
else if (r4) return w3();
|
|
267
271
|
if (!x3 || d4.substring(0, a4) !== x3) {
|
|
268
272
|
if (o5) {
|
|
269
273
|
if (h5 = [], k3(d4.split(S2)), R4(), M2) return w3();
|
|
270
274
|
} else k3(d4.split(S2));
|
|
271
|
-
if (
|
|
275
|
+
if (A2 && A2 <= c4) return h5 = h5.slice(0, A2), w3(true);
|
|
272
276
|
}
|
|
273
277
|
}
|
|
274
278
|
return w3();
|
|
275
279
|
}
|
|
276
|
-
for (var p5 = i2.indexOf(S2,
|
|
277
|
-
if (-1 === (m5 = i2.indexOf(F4, m5 + 1))) return r4 || u5.push({ type: "Quotes", code: "MissingQuotes", message: "Quoted field unterminated", row: h5.length, index:
|
|
278
|
-
if (m5 === n2 - 1) return E5(i2.substring(
|
|
280
|
+
for (var p5 = i2.indexOf(S2, z2), g6 = i2.indexOf(O4, z2), _5 = new RegExp(U2(j4) + U2(F4), "g"), m5 = i2.indexOf(F4, z2); ; ) if (i2[z2] === F4) for (m5 = z2, z2++; ; ) {
|
|
281
|
+
if (-1 === (m5 = i2.indexOf(F4, m5 + 1))) return r4 || u5.push({ type: "Quotes", code: "MissingQuotes", message: "Quoted field unterminated", row: h5.length, index: z2 }), E5();
|
|
282
|
+
if (m5 === n2 - 1) return E5(i2.substring(z2, m5).replace(_5, F4));
|
|
279
283
|
if (F4 === j4 && i2[m5 + 1] === j4) m5++;
|
|
280
284
|
else if (F4 === j4 || 0 === m5 || i2[m5 - 1] !== j4) {
|
|
281
285
|
-1 !== p5 && p5 < m5 + 1 && (p5 = i2.indexOf(S2, m5 + 1));
|
|
282
286
|
var y4 = v2(-1 === (g6 = -1 !== g6 && g6 < m5 + 1 ? i2.indexOf(O4, m5 + 1) : g6) ? p5 : Math.min(p5, g6));
|
|
283
287
|
if (i2.substr(m5 + 1 + y4, e) === S2) {
|
|
284
|
-
d4.push(i2.substring(
|
|
288
|
+
d4.push(i2.substring(z2, m5).replace(_5, F4)), i2[z2 = m5 + 1 + y4 + e] !== F4 && (m5 = i2.indexOf(F4, z2)), p5 = i2.indexOf(S2, z2), g6 = i2.indexOf(O4, z2);
|
|
285
289
|
break;
|
|
286
290
|
}
|
|
287
291
|
y4 = v2(g6);
|
|
288
292
|
if (i2.substring(m5 + 1 + y4, m5 + 1 + y4 + s4) === O4) {
|
|
289
|
-
if (d4.push(i2.substring(
|
|
290
|
-
if (
|
|
293
|
+
if (d4.push(i2.substring(z2, m5).replace(_5, F4)), b5(m5 + 1 + y4 + s4), p5 = i2.indexOf(S2, z2), m5 = i2.indexOf(F4, z2), o5 && (R4(), M2)) return w3();
|
|
294
|
+
if (A2 && h5.length >= A2) return w3(true);
|
|
291
295
|
break;
|
|
292
296
|
}
|
|
293
|
-
u5.push({ type: "Quotes", code: "InvalidQuotes", message: "Trailing quote on quoted field is malformed", row: h5.length, index:
|
|
297
|
+
u5.push({ type: "Quotes", code: "InvalidQuotes", message: "Trailing quote on quoted field is malformed", row: h5.length, index: z2 }), m5++;
|
|
294
298
|
}
|
|
295
299
|
}
|
|
296
|
-
else if (x3 && 0 === d4.length && i2.substring(
|
|
300
|
+
else if (x3 && 0 === d4.length && i2.substring(z2, z2 + a4) === x3) {
|
|
297
301
|
if (-1 === g6) return w3();
|
|
298
|
-
|
|
299
|
-
} else if (-1 !== p5 && (p5 < g6 || -1 === g6)) d4.push(i2.substring(
|
|
302
|
+
z2 = g6 + s4, g6 = i2.indexOf(O4, z2), p5 = i2.indexOf(S2, z2);
|
|
303
|
+
} else if (-1 !== p5 && (p5 < g6 || -1 === g6)) d4.push(i2.substring(z2, p5)), z2 = p5 + e, p5 = i2.indexOf(S2, z2);
|
|
300
304
|
else {
|
|
301
305
|
if (-1 === g6) break;
|
|
302
|
-
if (d4.push(i2.substring(
|
|
303
|
-
if (
|
|
306
|
+
if (d4.push(i2.substring(z2, g6)), b5(g6 + s4), o5 && (R4(), M2)) return w3();
|
|
307
|
+
if (A2 && h5.length >= A2) return w3(true);
|
|
304
308
|
}
|
|
305
309
|
return E5();
|
|
306
310
|
function k3(e2) {
|
|
307
|
-
h5.push(e2), f5 =
|
|
311
|
+
h5.push(e2), f5 = z2;
|
|
308
312
|
}
|
|
309
313
|
function v2(e2) {
|
|
310
314
|
var t2 = 0;
|
|
311
315
|
return t2 = -1 !== e2 && (e2 = i2.substring(m5 + 1, e2)) && "" === e2.trim() ? e2.length : t2;
|
|
312
316
|
}
|
|
313
317
|
function E5(e2) {
|
|
314
|
-
return r4 || (void 0 === e2 && (e2 = i2.substring(
|
|
318
|
+
return r4 || (void 0 === e2 && (e2 = i2.substring(z2)), d4.push(e2), z2 = n2, k3(d4), o5 && R4()), w3();
|
|
315
319
|
}
|
|
316
320
|
function b5(e2) {
|
|
317
|
-
|
|
321
|
+
z2 = e2, k3(d4), d4 = [], g6 = i2.indexOf(O4, z2);
|
|
318
322
|
}
|
|
319
323
|
function w3(e2) {
|
|
320
324
|
if (C2.header && !t && h5.length && !L4) {
|
|
@@ -339,7 +343,7 @@ var require_papaparse_min = __commonJS({
|
|
|
339
343
|
}, this.abort = function() {
|
|
340
344
|
M2 = true;
|
|
341
345
|
}, this.getCharIndex = function() {
|
|
342
|
-
return
|
|
346
|
+
return z2;
|
|
343
347
|
};
|
|
344
348
|
}
|
|
345
349
|
function g5(e) {
|
|
@@ -918,15 +922,15 @@ function resolveAutoColorScale(p4) {
|
|
|
918
922
|
};
|
|
919
923
|
const candidates = p4.isHighContrast ? [normHex(p4.themeAccent), normHex(p4.themeFg)] : [...palette.map(normHex), normHex(p4.themeAccent), normHex(p4.themeFg)];
|
|
920
924
|
const accent = candidates.find(usable) ?? FALLBACK_ACCENT;
|
|
921
|
-
const
|
|
925
|
+
const A2 = hexToLab(accent);
|
|
922
926
|
let t = 0.1;
|
|
923
|
-
let low = mixLab(bg,
|
|
927
|
+
let low = mixLab(bg, A2, t);
|
|
924
928
|
while (t < 0.6 && deltaE2000(paintedOver(labToHex(low), canvas, AUTO_RAMP_DRAWN_OPACITY), bg) < SAME_SHADE_DELTA_E) {
|
|
925
929
|
t += 0.02;
|
|
926
|
-
low = mixLab(bg,
|
|
930
|
+
low = mixLab(bg, A2, t);
|
|
927
931
|
}
|
|
928
932
|
const lowHex = labToHex(low);
|
|
929
|
-
let high = { ...
|
|
933
|
+
let high = { ...A2 };
|
|
930
934
|
let highHex = labToHex(high);
|
|
931
935
|
for (let step = 0; step < 80 && autoRampMinStep(lowHex, highHex, canvas) < AUTO_RAMP_MIN_STEP_DELTA_E; step++) {
|
|
932
936
|
const L4 = Math.max(4, Math.min(98, high.L + (darkCanvas ? 1 : -1)));
|
|
@@ -1520,23 +1524,23 @@ function E3(n) {
|
|
|
1520
1524
|
if (a3 && i && P3(a3) !== i && (a3 = null), n.city !== void 0 && n.city !== null) {
|
|
1521
1525
|
let r2 = u2(String(n.city)), s2 = D(r2, R(String(n.city))), c2 = s2 ? _(s2, n.mapKind) : null;
|
|
1522
1526
|
if (c2 && c2.length) {
|
|
1523
|
-
let d2 = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), T = d2 ? u2(d2) : "", y2 = d2 ? t3(d2) : null, f4 = [],
|
|
1527
|
+
let d2 = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), T = d2 ? u2(d2) : "", y2 = d2 ? t3(d2) : null, f4 = [], N2 = -1;
|
|
1524
1528
|
for (let M2 of c2) {
|
|
1525
1529
|
let l2 = M2.row, p4 = 0;
|
|
1526
1530
|
if (d2 && l2.a1 !== "") if (y2 && l2.a1 === y2 || u2(l2.a1) === T) p4++;
|
|
1527
1531
|
else continue;
|
|
1528
1532
|
if (i) if (G(l2.cc) === i) p4++;
|
|
1529
1533
|
else continue;
|
|
1530
|
-
p4 >
|
|
1534
|
+
p4 > N2 ? (N2 = p4, f4 = [M2]) : p4 === N2 && f4.push(M2);
|
|
1531
1535
|
}
|
|
1532
1536
|
f4.some((M2) => M2.primary) && (f4 = f4.filter((M2) => M2.primary));
|
|
1533
|
-
let
|
|
1534
|
-
for (let M2 of f4)
|
|
1535
|
-
if (
|
|
1537
|
+
let A2 = /* @__PURE__ */ new Map();
|
|
1538
|
+
for (let M2 of f4) A2.set(M2.row.lon.toFixed(2) + "," + M2.row.lat.toFixed(2), M2.row);
|
|
1539
|
+
if (A2.size === 1) {
|
|
1536
1540
|
let M2 = f4[0].row;
|
|
1537
1541
|
return { lat: M2.lat, lon: M2.lon, precision: "city" };
|
|
1538
1542
|
}
|
|
1539
|
-
if (
|
|
1543
|
+
if (A2.size > 1) return { ambiguous: true, matches: A2.size };
|
|
1540
1544
|
}
|
|
1541
1545
|
}
|
|
1542
1546
|
if (!i || L3.has(i)) for (let r2 of r3(n.zip)) {
|
|
@@ -1556,15 +1560,15 @@ function E3(n) {
|
|
|
1556
1560
|
var b = { latlon: 0, city: 1, zip3: 2, state: 3, country: 4 };
|
|
1557
1561
|
var e3 = 8;
|
|
1558
1562
|
function J3(n, e) {
|
|
1559
|
-
let t = new Array(n.length), o4 = new Array(n.length), i = new Array(n.length), a3 = /* @__PURE__ */ new Set(), r2 = [], s2 = /* @__PURE__ */ new Set(), c2 = [], d2 = /* @__PURE__ */ new Set(), T = [], y2 = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 }, f4 = 0,
|
|
1563
|
+
let t = new Array(n.length), o4 = new Array(n.length), i = new Array(n.length), a3 = /* @__PURE__ */ new Set(), r2 = [], s2 = /* @__PURE__ */ new Set(), c2 = [], d2 = /* @__PURE__ */ new Set(), T = [], y2 = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 }, f4 = 0, N2 = 0, A2 = null;
|
|
1560
1564
|
for (let l2 = 0; l2 < n.length; ++l2) {
|
|
1561
1565
|
let p4 = n[l2], C2 = E3({ ...p4, mapKind: e });
|
|
1562
1566
|
if (B3(C2)) {
|
|
1563
|
-
t[l2] = null, o4[l2] = null, i[l2] = null,
|
|
1567
|
+
t[l2] = null, o4[l2] = null, i[l2] = null, N2++;
|
|
1564
1568
|
let S2 = W(p4);
|
|
1565
1569
|
S2 && !d2.has(S2.toLowerCase()) && (d2.add(S2.toLowerCase()), T.length < e3 && T.push(S2));
|
|
1566
1570
|
} else if (C2) {
|
|
1567
|
-
if (t[l2] = C2.lat, o4[l2] = C2.lon, i[l2] = C2.precision, f4++, y2[C2.precision]++, (
|
|
1571
|
+
if (t[l2] = C2.lat, o4[l2] = C2.lon, i[l2] = C2.precision, f4++, y2[C2.precision]++, (A2 === null || b[C2.precision] > b[A2]) && (A2 = C2.precision), b[C2.precision] > b.city) {
|
|
1568
1572
|
let S2 = W(p4);
|
|
1569
1573
|
S2 && !s2.has(S2.toLowerCase()) && (s2.add(S2.toLowerCase()), c2.length < e3 && c2.push(S2));
|
|
1570
1574
|
}
|
|
@@ -1575,7 +1579,7 @@ function J3(n, e) {
|
|
|
1575
1579
|
}
|
|
1576
1580
|
}
|
|
1577
1581
|
let M2 = !C3() && n.some((l2) => l2.city !== null && l2.city !== void 0 && String(l2.city).trim() !== "");
|
|
1578
|
-
return { lat: t, lon: o4, precisions: i, precision:
|
|
1582
|
+
return { lat: t, lon: o4, precisions: i, precision: A2, precisionCounts: y2, coarseExamples: c2, unmatched: r2, ambiguousRows: N2, ambiguousExamples: T, matchedRows: f4, totalRows: n.length, ...M2 ? { cityTableMissing: true } : {} };
|
|
1579
1583
|
}
|
|
1580
1584
|
function W(n) {
|
|
1581
1585
|
let e = [n.city, n.state, n.zip, n.country].filter((t) => t != null && String(t).trim() !== "").map((t) => String(t).trim()).join(", ");
|
|
@@ -1754,10 +1758,10 @@ function Rn(n, s2) {
|
|
|
1754
1758
|
return s2 === "us-zip5" ? w2.has(n.slice(0, 3)) : true;
|
|
1755
1759
|
}
|
|
1756
1760
|
function Fn(n, s2) {
|
|
1757
|
-
let o4 = new Array(n.length), r2 = /* @__PURE__ */ new Set(), I2 = [],
|
|
1761
|
+
let o4 = new Array(n.length), r2 = /* @__PURE__ */ new Set(), I2 = [], N2 = 0;
|
|
1758
1762
|
for (let h4 = 0; h4 < n.length; ++h4) {
|
|
1759
1763
|
let M2 = En(n[h4], s2), O4 = M2 !== null && Rn(M2, s2) ? M2 : null;
|
|
1760
|
-
if (o4[h4] = O4, O4 !== null)
|
|
1764
|
+
if (o4[h4] = O4, O4 !== null) N2++;
|
|
1761
1765
|
else {
|
|
1762
1766
|
let d2 = n[h4];
|
|
1763
1767
|
if (d2 != null) {
|
|
@@ -1769,7 +1773,7 @@ function Fn(n, s2) {
|
|
|
1769
1773
|
}
|
|
1770
1774
|
}
|
|
1771
1775
|
}
|
|
1772
|
-
return { iso: o4, unmatched: I2, matchedRows:
|
|
1776
|
+
return { iso: o4, unmatched: I2, matchedRows: N2, totalRows: n.length };
|
|
1773
1777
|
}
|
|
1774
1778
|
|
|
1775
1779
|
// ../shape-core/dist/chunk-OPDY2YEA.mjs
|
|
@@ -1890,10 +1894,10 @@ function F3(e) {
|
|
|
1890
1894
|
}
|
|
1891
1895
|
return Array.from(t);
|
|
1892
1896
|
}
|
|
1893
|
-
function
|
|
1897
|
+
function N(e) {
|
|
1894
1898
|
let t = F3(e);
|
|
1895
1899
|
if (t.length === 0 || ne2(e) < 95) return false;
|
|
1896
|
-
let n = t.filter((
|
|
1900
|
+
let n = t.filter((l2) => te(l2) && !t3(l2)).length, o4 = t.filter((l2) => !te(l2) && !!t3(l2)).length;
|
|
1897
1901
|
return n >= 1 && n >= o4;
|
|
1898
1902
|
}
|
|
1899
1903
|
function ce3(e, t) {
|
|
@@ -1908,7 +1912,7 @@ function ne2(e) {
|
|
|
1908
1912
|
for (let o4 of t) te(o4) && n++;
|
|
1909
1913
|
return Math.round(n / t.length * 1e3) / 10;
|
|
1910
1914
|
}
|
|
1911
|
-
function
|
|
1915
|
+
function $4(e) {
|
|
1912
1916
|
let t = F3(e);
|
|
1913
1917
|
if (t.length === 0) return 0;
|
|
1914
1918
|
let n = 0;
|
|
@@ -1934,11 +1938,11 @@ function re2(e) {
|
|
|
1934
1938
|
function de(e, t) {
|
|
1935
1939
|
return y(t, fn) ? true : oe2(e).some((n) => /^\d{5}(-\d{4})?$/.test(n.replace(/\.0+$/, "")));
|
|
1936
1940
|
}
|
|
1937
|
-
function
|
|
1941
|
+
function jn(e, t) {
|
|
1938
1942
|
let n = F3(e);
|
|
1939
1943
|
if (n.length === 0) return 0;
|
|
1940
1944
|
let o4 = 0;
|
|
1941
|
-
for (let
|
|
1945
|
+
for (let l2 of n) j3(l2, t) && o4++;
|
|
1942
1946
|
return Math.round(o4 / n.length * 1e3) / 10;
|
|
1943
1947
|
}
|
|
1944
1948
|
function ee3(e, t) {
|
|
@@ -1946,18 +1950,18 @@ function ee3(e, t) {
|
|
|
1946
1950
|
for (let o4 of F3(e)) t(o4) && n++;
|
|
1947
1951
|
return n;
|
|
1948
1952
|
}
|
|
1949
|
-
function
|
|
1953
|
+
function Yn3(e, t) {
|
|
1950
1954
|
let n = 0;
|
|
1951
1955
|
for (let o4 of oe2(e)) t(o4) && n++;
|
|
1952
1956
|
return n;
|
|
1953
1957
|
}
|
|
1954
|
-
function
|
|
1955
|
-
let u4 = [],
|
|
1958
|
+
function Qn2(e, t, n, o4, l2) {
|
|
1959
|
+
let u4 = [], a3 = [], i = {}, h4 = {}, C2 = new Set(e), y2 = (s2) => t.map((d2) => d2[s2]);
|
|
1956
1960
|
for (let s2 of ["city", "country"]) {
|
|
1957
1961
|
let d2 = n?.[s2];
|
|
1958
1962
|
d2 && C2.has(d2) && (i[s2] = d2);
|
|
1959
1963
|
}
|
|
1960
|
-
let g5 = new Set(
|
|
1964
|
+
let g5 = new Set(l2 ?? e);
|
|
1961
1965
|
for (let s2 of ["lat", "lon"]) {
|
|
1962
1966
|
let d2 = n?.[s2];
|
|
1963
1967
|
d2 && g5.has(d2) && (i[s2] = d2);
|
|
@@ -1965,67 +1969,67 @@ function Yn3(e, t, n, o4, a3) {
|
|
|
1965
1969
|
let f4 = n?.zip;
|
|
1966
1970
|
if (f4 && C2.has(f4)) {
|
|
1967
1971
|
let s2 = y2(f4), d2 = re2(s2);
|
|
1968
|
-
d2 < 95 ?
|
|
1972
|
+
d2 < 95 ? a3.push(`zip=${f4} (only ${d2}% of values read as ZIPs)`) : de(s2, f4) ? i.zip = f4 : a3.push(`zip=${f4} (all values are 3-4 digits with nothing to say they are postal)`);
|
|
1969
1973
|
}
|
|
1970
1974
|
let c2 = n?.state;
|
|
1971
1975
|
if (c2 && C2.has(c2)) {
|
|
1972
1976
|
let s2 = y2(c2), d2 = F3(s2);
|
|
1973
|
-
d2.length > 0 && d2.every((S2) => ce3(S2, o4)) ?
|
|
1977
|
+
d2.length > 0 && d2.every((S2) => ce3(S2, o4)) ? a3.push(`state=${c2} (every value is "CA", which is both Canada and California)`) : N(s2) ? (a3.push(`state=${c2} (every value is a country, not a state)`), i.country || (i.country = c2)) : $4(s2) < 95 ? a3.push(`state=${c2} (only ${$4(s2)}% of values are states/provinces)`) : i.state = c2;
|
|
1974
1978
|
}
|
|
1975
1979
|
let p4 = new Set(Object.values(i).filter(Boolean)), b4 = e.filter((s2) => !p4.has(s2) && !s2.startsWith("__"));
|
|
1976
1980
|
if (!i.state) {
|
|
1977
1981
|
let s2 = null;
|
|
1978
1982
|
for (let d2 of b4) {
|
|
1979
1983
|
let S2 = y2(d2);
|
|
1980
|
-
if (
|
|
1981
|
-
let
|
|
1982
|
-
if (
|
|
1984
|
+
if (N(S2)) continue;
|
|
1985
|
+
let O4 = $4(S2);
|
|
1986
|
+
if (O4 < 95) continue;
|
|
1983
1987
|
let K3 = ee3(S2, (G4) => !!t3(G4)), Ne = ee3(S2, (G4) => !!t3(G4) && !ce3(G4, o4));
|
|
1984
|
-
K3 < Z3 && Ne < 1 || (!s2 ||
|
|
1988
|
+
K3 < Z3 && Ne < 1 || (!s2 || O4 > s2.pct) && (s2 = { name: d2, pct: O4 });
|
|
1985
1989
|
}
|
|
1986
1990
|
s2 && (i.state = s2.name, p4.add(s2.name), u4.push(`state=${s2.name} (${s2.pct}% states/provinces)`));
|
|
1987
1991
|
}
|
|
1988
1992
|
if (!i.zip) for (let s2 of b4) {
|
|
1989
1993
|
if (p4.has(s2)) continue;
|
|
1990
1994
|
let d2 = y2(s2), S2 = re2(d2);
|
|
1991
|
-
if (!(S2 < 95) && de(d2, s2) && !(
|
|
1995
|
+
if (!(S2 < 95) && de(d2, s2) && !(Yn3(d2, (O4) => r3(O4).length > 0) < Z3)) {
|
|
1992
1996
|
i.zip = s2, p4.add(s2), u4.push(`zip=${s2} (${S2}% ZIP codes)`);
|
|
1993
1997
|
break;
|
|
1994
1998
|
}
|
|
1995
1999
|
}
|
|
1996
2000
|
let T = i.country;
|
|
1997
|
-
if (!T || !
|
|
2001
|
+
if (!T || !N(y2(T))) {
|
|
1998
2002
|
let s2 = null;
|
|
1999
2003
|
for (let d2 of b4) {
|
|
2000
|
-
if (p4.has(d2) || !
|
|
2004
|
+
if (p4.has(d2) || !N(y2(d2))) continue;
|
|
2001
2005
|
let S2 = ne2(y2(d2));
|
|
2002
2006
|
(!s2 || S2 > s2.pct) && (s2 = { name: d2, pct: S2 });
|
|
2003
2007
|
}
|
|
2004
|
-
s2 && (T && (
|
|
2008
|
+
s2 && (T && (a3.push(`country=${T} (only ${ne2(y2(T))}% of values are country identifiers; using ${s2.name} instead)`), h4.country = T), i.country = s2.name, p4.add(s2.name), u4.push(`country=${s2.name}`));
|
|
2005
2009
|
}
|
|
2006
2010
|
if (!i.city) {
|
|
2007
2011
|
let s2 = null;
|
|
2008
2012
|
for (let d2 of b4) {
|
|
2009
2013
|
if (p4.has(d2)) continue;
|
|
2010
|
-
let S2 = y2(d2),
|
|
2011
|
-
|
|
2014
|
+
let S2 = y2(d2), O4 = jn(S2, o4);
|
|
2015
|
+
O4 < D3 || ee3(S2, (K3) => j3(K3, o4)) < Z3 || (!s2 || O4 > s2.pct) && (s2 = { name: d2, pct: O4 });
|
|
2012
2016
|
}
|
|
2013
2017
|
s2 && (i.city = s2.name, u4.push(`city=${s2.name} (${s2.pct}% known cities)`));
|
|
2014
2018
|
}
|
|
2015
|
-
let
|
|
2019
|
+
let L4 = i.country ? y2(i.country) : [], R4 = !!i.country && N(L4), A2 = R4 ? new Set(L4.map((s2) => k(s2 == null ? null : String(s2))).filter(Boolean)).size : 0, x3 = R4 && A2 >= 2, w3 = !!(i.lat && i.lon) && t.some((s2) => {
|
|
2016
2020
|
let d2 = +String(s2[i.lat] ?? "").trim(), S2 = +String(s2[i.lon] ?? "").trim();
|
|
2017
2021
|
return isFinite(d2) && isFinite(S2) && d2 >= -90 && d2 <= 90 && S2 >= -180 && S2 <= 180 && String(s2[i.lat] ?? "").trim() !== "" && String(s2[i.lon] ?? "").trim() !== "";
|
|
2018
2022
|
});
|
|
2019
|
-
return i.lat && i.lon && !w3 &&
|
|
2023
|
+
return i.lat && i.lon && !w3 && a3.push(`lat/lon=${i.lat}/${i.lon} (no row holds a usable coordinate pair)`), i.country && !x3 && !(i.city || i.state || i.zip || w3) && a3.push(R4 ? `country=${i.country} (every row resolves to the same country - nothing to place apart)` : `country=${i.country} (values are not country identifiers)`), { bind: !!(i.city || i.state || i.zip || x3 || w3) ? i : null, backfilled: u4, refused: a3, ...Object.keys(h4).length ? { labelFallback: h4 } : {} };
|
|
2020
2024
|
}
|
|
2021
2025
|
var r = (e, ...t) => ({ part: e, langs: Object.freeze(t) });
|
|
2022
2026
|
var ie2 = Object.freeze({ jaar: r("year", "nl"), kwartaal: r("quarter", "nl"), maand: r("month", "nl"), dag: r("day", "nl", "sv", "da", "nb"), jahr: r("year", "de"), quartal: r("quarter", "de"), monat: r("month", "de"), tag: r("day", "de"), ann\u00E9e: r("year", "fr"), mois: r("month", "fr"), jour: r("day", "fr"), trimestre: r("quarter", "fr", "es", "pt", "it"), a\u00F1o: r("year", "es"), mes: r("month", "es"), d\u00EDa: r("day", "es"), ano: r("year", "pt"), m\u00EAs: r("month", "pt"), dia: r("day", "pt"), anno: r("year", "it"), mese: r("month", "it"), giorno: r("day", "it"), \u0433\u043E\u0434: r("year", "ru"), \u043C\u0435\u0441\u044F\u0446: r("month", "ru"), \u0440\u0456\u043A: r("year", "uk"), \u043C\u0456\u0441\u044F\u0446\u044C: r("month", "uk"), \u043A\u0432\u0430\u0440\u0442\u0430\u043B: r("quarter", "ru", "uk"), \u0434\u0435\u043D\u044C: r("day", "ru", "uk"), rok: r("year", "pl", "cs", "sk"), kwarta\u0142: r("quarter", "pl"), miesi\u0105c: r("month", "pl"), dzie\u0144: r("day", "pl"), \u010Dtvrtlet\u00ED: r("quarter", "cs"), m\u011Bs\u00EDc: r("month", "cs"), den: r("day", "cs"), \u0161tvr\u0165rok: r("quarter", "sk"), mesiac: r("month", "sk"), de\u0148: r("day", "sk"), \u00E5r: r("year", "sv", "da", "nb"), kvartal: r("quarter", "sv", "da", "nb"), m\u00E5nad: r("month", "sv"), m\u00E5ned: r("month", "da", "nb"), vuosi: r("year", "fi"), vuosinelj\u00E4nnes: r("quarter", "fi"), kuukausi: r("month", "fi"), p\u00E4iv\u00E4: r("day", "fi"), \u00E9v: r("year", "hu"), negyed\u00E9v: r("quarter", "hu"), h\u00F3nap: r("month", "hu"), nap: r("day", "hu"), y\u0131l: r("year", "tr"), \u00E7eyrek: r("quarter", "tr"), ay: r("month", "tr"), g\u00FCn: r("day", "tr"), \u03AD\u03C4\u03BF\u03C2: r("year", "el"), \u03C4\u03C1\u03AF\u03BC\u03B7\u03BD\u03BF: r("quarter", "el"), \u03BC\u03AE\u03BD\u03B1\u03C2: r("month", "el"), \u03B7\u03BC\u03AD\u03C1\u03B1: r("day", "el"), an: r("year", "ro"), trimestru: r("quarter", "ro"), lun\u0103: r("month", "ro"), zi: r("day", "ro"), godina: r("year", "hr"), tromjese\u010Dje: r("quarter", "hr"), mjesec: r("month", "hr"), dan: r("day", "hr"), \u5E74: r("year", "ja", "zh"), \u56DB\u534A\u671F: r("quarter", "ja"), \u5B63\u5EA6: r("quarter", "zh"), \u6708: r("month", "ja", "zh"), \u65E5: r("day", "ja", "zh"), \uC5F0\uB3C4: r("year", "ko"), \uBD84\uAE30: r("quarter", "ko"), \uC6D4: r("month", "ko"), \uC77C: r("day", "ko"), tahun: r("year", "id"), kuartal: r("quarter", "id"), triwulan: r("quarter", "id"), bulan: r("month", "id"), hari: r("day", "id"), n\u0103m: r("year", "vi"), qu\u00FD: r("quarter", "vi"), th\u00E1ng: r("month", "vi"), ng\u00E0y: r("day", "vi"), \u0E1B\u0E35: r("year", "th"), \u0E44\u0E15\u0E23\u0E21\u0E32\u0E2A: r("quarter", "th"), \u0E40\u0E14\u0E37\u0E2D\u0E19: r("month", "th"), \u0E27\u0E31\u0E19: r("day", "th"), \u0627\u0644\u0633\u0646\u0629: r("year", "ar"), \u0633\u0646\u0629: r("year", "ar"), \u0627\u0644\u0639\u0627\u0645: r("year", "ar"), \u0639\u0627\u0645: r("year", "ar"), \u0627\u0644\u0631\u0628\u0639: r("quarter", "ar"), \u0631\u0628\u0639: r("quarter", "ar"), "\u0631\u0628\u0639 \u0627\u0644\u0633\u0646\u0629": r("quarter", "ar"), \u0627\u0644\u0634\u0647\u0631: r("month", "ar"), \u0634\u0647\u0631: r("month", "ar"), \u0627\u0644\u064A\u0648\u0645: r("day", "ar"), \u064A\u0648\u0645: r("day", "ar"), \u05E9\u05E0\u05D4: r("year", "he"), \u05E8\u05D1\u05E2\u05D5\u05DF: r("quarter", "he"), \u05D7\u05D5\u05D3\u05E9: r("month", "he"), \u05D9\u05D5\u05DD: r("day", "he"), \u0935\u0930\u094D\u0937: r("year", "hi"), \u0938\u093E\u0932: r("year", "hi"), \u0924\u093F\u092E\u093E\u0939\u0940: r("quarter", "hi"), \u092E\u0939\u0940\u0928\u093E: r("month", "hi"), \u092E\u093E\u0939: r("month", "hi"), \u0926\u093F\u0928: r("day", "hi"), \u0633\u0627\u0644: r("year", "fa"), \u0645\u0627\u0647: r("month", "fa"), \u0631\u0648\u0632: r("day", "fa") });
|
|
2023
|
-
var
|
|
2027
|
+
var Xn2 = Object.freeze(Array.from(new Set(Object.values(ie2).flatMap((e) => e.langs))));
|
|
2024
2028
|
var fe = Object.freeze(["fa", "ar", "he", "th"]);
|
|
2025
|
-
var
|
|
2026
|
-
var
|
|
2027
|
-
var
|
|
2028
|
-
var
|
|
2029
|
+
var vr = Object.freeze({ integer: "number", decimal: "number", double: "number", datetime: "date", date: "date", boolean: "boolean", string: "text" });
|
|
2030
|
+
var Dr = Object.freeze({ RENDER_START: "render-start", RENDER_OK: "render-ok", RENDER_ERROR: "render-error", VIEW: "view", VIEW_VERDICT: "view-verdict", REDRAW: "redraw", INTERACT: "interact" });
|
|
2031
|
+
var kr = Object.freeze(["open", "generate", "version", "rebind", "data", "sample", "fix", "resize", "other"]);
|
|
2032
|
+
var Ae = 2 ** 31 - 1;
|
|
2029
2033
|
|
|
2030
2034
|
// src/payload.ts
|
|
2031
2035
|
var ROW_IDX_COLUMN = "__rowIdx__";
|
|
@@ -2040,7 +2044,7 @@ function resolvePointChannel(cols, rowObjs, point) {
|
|
|
2040
2044
|
let labelCol;
|
|
2041
2045
|
if (bind) {
|
|
2042
2046
|
const dims = cols.filter((c2) => !c2.isMeasure).map((c2) => c2.name);
|
|
2043
|
-
const res =
|
|
2047
|
+
const res = Qn2(dims, rowObjs, bind, point?.mapKind, cols.map((c2) => c2.name));
|
|
2044
2048
|
bind = res.bind;
|
|
2045
2049
|
rolesBackfilled = res.backfilled;
|
|
2046
2050
|
rolesRefused = res.refused;
|
|
@@ -2346,6 +2350,48 @@ function nextSelection(current, rowIdxs, mods = {}) {
|
|
|
2346
2350
|
const same = cur.length === rowIdxs.length && rowIdxs.every((r2) => cur.includes(r2));
|
|
2347
2351
|
return same ? [] : rowIdxs.slice();
|
|
2348
2352
|
}
|
|
2353
|
+
function selectionRuleOf(container) {
|
|
2354
|
+
try {
|
|
2355
|
+
const el = container?.querySelector?.(`[${SELECTION_RULE_ATTR}]`);
|
|
2356
|
+
return el?.getAttribute(SELECTION_RULE_ATTR) === SELECTION_RULE_CLICKED_MARKS ? "clicked-marks" : "any-row";
|
|
2357
|
+
} catch {
|
|
2358
|
+
return "any-row";
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
function markKeyOf(el) {
|
|
2362
|
+
if (!el) return "";
|
|
2363
|
+
const k3 = el.getAttribute(MARK_KEY_ATTR);
|
|
2364
|
+
if (k3 != null && k3 !== "") return k3;
|
|
2365
|
+
return "rows:" + (el.getAttribute(ROW_IDX_ATTR) || "").replace(/\s+/g, "");
|
|
2366
|
+
}
|
|
2367
|
+
var toSet = (s2) => new Set(Array.from(s2 ?? []));
|
|
2368
|
+
function sameRowSet(a3, b4) {
|
|
2369
|
+
const A2 = toSet(a3), B4 = toSet(b4);
|
|
2370
|
+
if (A2.size !== B4.size) return false;
|
|
2371
|
+
for (const r2 of A2) if (!B4.has(r2)) return false;
|
|
2372
|
+
return true;
|
|
2373
|
+
}
|
|
2374
|
+
function planSelectionPaint(marks, selection, rule, clicked) {
|
|
2375
|
+
const sel = toSet(selection);
|
|
2376
|
+
if (sel.size === 0) return { on: marks.map(() => false), mode: "none", keys: [] };
|
|
2377
|
+
const anyRow = () => marks.map((m4) => m4.rows.some((r2) => sel.has(r2)));
|
|
2378
|
+
if (rule !== "clicked-marks") return { on: anyRow(), mode: "any-row", keys: [] };
|
|
2379
|
+
if (clicked && clicked.keys.length && sameRowSet(clicked.selection, sel)) {
|
|
2380
|
+
const want = new Set(clicked.keys);
|
|
2381
|
+
const on = marks.map((m4) => m4.rows.length > 0 && want.has(m4.key));
|
|
2382
|
+
if (on.some(Boolean)) return { on, mode: "clicked", keys: marks.filter((_4, i) => on[i]).map((m4) => m4.key) };
|
|
2383
|
+
}
|
|
2384
|
+
const exact = marks.map((m4) => m4.rows.length > 0 && sameRowSet(m4.rows, sel));
|
|
2385
|
+
if (exact.some(Boolean)) return { on: exact, mode: "exact", keys: marks.filter((_4, i) => exact[i]).map((m4) => m4.key) };
|
|
2386
|
+
return { on: anyRow(), mode: "fallback-any-row", keys: [] };
|
|
2387
|
+
}
|
|
2388
|
+
function nextClickedMarks(prev, current, key, next, mods = {}) {
|
|
2389
|
+
if (!next.length) return null;
|
|
2390
|
+
if (!(mods.ctrl || mods.shift)) return { keys: [key], selection: next.slice() };
|
|
2391
|
+
const held = prev && sameRowSet(prev.selection, current) ? prev.keys : [];
|
|
2392
|
+
const keys = held.includes(key) ? held.filter((k3) => k3 !== key) : [...held, key];
|
|
2393
|
+
return { keys, selection: next.slice() };
|
|
2394
|
+
}
|
|
2349
2395
|
function isInsideControl(target, container) {
|
|
2350
2396
|
let el = target;
|
|
2351
2397
|
if (el && el.nodeType !== 1) el = el.parentElement ?? el.parentNode ?? null;
|
|
@@ -2384,9 +2430,9 @@ function createMarkResolver(env) {
|
|
|
2384
2430
|
const m4 = el.getScreenCTM();
|
|
2385
2431
|
if (!m4) return Number.MAX_VALUE;
|
|
2386
2432
|
let best = Number.MAX_VALUE;
|
|
2387
|
-
const
|
|
2388
|
-
for (let i = 0; i <=
|
|
2389
|
-
const pt2 = el.getPointAtLength(L4 * i /
|
|
2433
|
+
const N2 = 64;
|
|
2434
|
+
for (let i = 0; i <= N2; i++) {
|
|
2435
|
+
const pt2 = el.getPointAtLength(L4 * i / N2);
|
|
2390
2436
|
const dx = m4.a * pt2.x + m4.c * pt2.y + m4.e - x3;
|
|
2391
2437
|
const dy = m4.b * pt2.x + m4.d * pt2.y + m4.f - y2;
|
|
2392
2438
|
const d2 = dx * dx + dy * dy;
|
|
@@ -2542,14 +2588,14 @@ function collectD3GlyphCenters(container, baseRect, out) {
|
|
|
2542
2588
|
const isArcSector = /[Aa]/.test(dAttr) && !/[CcSsQqTt]/.test(dAttr);
|
|
2543
2589
|
let local;
|
|
2544
2590
|
if (isArcSector) {
|
|
2545
|
-
const
|
|
2591
|
+
const N2 = 24;
|
|
2546
2592
|
let ax = 0, ay = 0;
|
|
2547
|
-
for (let k3 = 0; k3 <
|
|
2548
|
-
const sp = el.getPointAtLength(len * k3 /
|
|
2593
|
+
for (let k3 = 0; k3 < N2; k3++) {
|
|
2594
|
+
const sp = el.getPointAtLength(len * k3 / N2);
|
|
2549
2595
|
ax += sp.x;
|
|
2550
2596
|
ay += sp.y;
|
|
2551
2597
|
}
|
|
2552
|
-
const cand = new Point(ax /
|
|
2598
|
+
const cand = new Point(ax / N2, ay / N2);
|
|
2553
2599
|
let inside = true;
|
|
2554
2600
|
try {
|
|
2555
2601
|
if (typeof el.isPointInFill === "function") {
|
|
@@ -2828,6 +2874,49 @@ function hitBandFlag(c2) {
|
|
|
2828
2874
|
return c2.uncovered > 0 ? "hitband:d3:thin" : "hitband:d3:ok";
|
|
2829
2875
|
}
|
|
2830
2876
|
|
|
2877
|
+
// src/clippedText.ts
|
|
2878
|
+
var CLIP_TOLERANCE_PX = 1;
|
|
2879
|
+
var MAX_REPORTED = 8;
|
|
2880
|
+
function censusClippedText(container) {
|
|
2881
|
+
const none = { measured: 0, clipped: [], clippedCount: 0, laidOut: false };
|
|
2882
|
+
try {
|
|
2883
|
+
const svg = container?.querySelector?.("svg");
|
|
2884
|
+
if (!svg) return none;
|
|
2885
|
+
const f4 = svg.getBoundingClientRect();
|
|
2886
|
+
if (!f4 || !(f4.width > 0) || !(f4.height > 0)) return none;
|
|
2887
|
+
const view = svg.ownerDocument?.defaultView;
|
|
2888
|
+
const clipped = [];
|
|
2889
|
+
let measured = 0;
|
|
2890
|
+
for (const t of Array.from(svg.querySelectorAll("text"))) {
|
|
2891
|
+
const r2 = t.getBoundingClientRect();
|
|
2892
|
+
if (!r2 || !(r2.width > 0) || !(r2.height > 0)) continue;
|
|
2893
|
+
const s2 = view?.getComputedStyle?.(t);
|
|
2894
|
+
if (s2 && (s2.display === "none" || s2.visibility === "hidden" || s2.opacity === "0")) continue;
|
|
2895
|
+
measured++;
|
|
2896
|
+
const top = f4.top - r2.top, left = f4.left - r2.left, bottom = r2.bottom - f4.bottom, right = r2.right - f4.right;
|
|
2897
|
+
if (top > CLIP_TOLERANCE_PX || left > CLIP_TOLERANCE_PX || bottom > CLIP_TOLERANCE_PX || right > CLIP_TOLERANCE_PX) {
|
|
2898
|
+
clipped.push({
|
|
2899
|
+
text: String(t.textContent ?? "").slice(0, 40),
|
|
2900
|
+
top: Math.max(0, Math.round(top)),
|
|
2901
|
+
left: Math.max(0, Math.round(left)),
|
|
2902
|
+
bottom: Math.max(0, Math.round(bottom)),
|
|
2903
|
+
right: Math.max(0, Math.round(right))
|
|
2904
|
+
});
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
clipped.sort((a3, b4) => Math.max(b4.top, b4.left, b4.bottom, b4.right) - Math.max(a3.top, a3.left, a3.bottom, a3.right));
|
|
2908
|
+
return { measured, clipped: clipped.slice(0, MAX_REPORTED), clippedCount: clipped.length, laidOut: true };
|
|
2909
|
+
} catch {
|
|
2910
|
+
return none;
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
function clippedTextFlag(c2) {
|
|
2914
|
+
if (!c2.laidOut || c2.clippedCount === 0) return "";
|
|
2915
|
+
const worst = c2.clipped[0];
|
|
2916
|
+
const side = ["top", "left", "bottom", "right"].reduce((a3, k3) => worst[k3] > worst[a3] ? k3 : a3, "top");
|
|
2917
|
+
return `${c2.clippedCount} of ${c2.measured} text label(s) are cut off by the frame; the worst, "${worst.text}", by ${worst[side]}px at the ${side}.`;
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2831
2920
|
// src/valuePlacement.ts
|
|
2832
2921
|
var MIN_MARKS2 = 24;
|
|
2833
2922
|
var ELEMENT_CAP4 = 5e3;
|
|
@@ -4269,6 +4358,13 @@ function createChartHost(container, config) {
|
|
|
4269
4358
|
let activeTickEl = null;
|
|
4270
4359
|
let selectionIsPeriod = false;
|
|
4271
4360
|
let selectionFromChart = false;
|
|
4361
|
+
const clickedMarks = () => container[CONTAINER_SLOT_CLICKED_MARKS] ?? null;
|
|
4362
|
+
const setClickedMarks = (c2) => {
|
|
4363
|
+
try {
|
|
4364
|
+
container[CONTAINER_SLOT_CLICKED_MARKS] = c2;
|
|
4365
|
+
} catch {
|
|
4366
|
+
}
|
|
4367
|
+
};
|
|
4272
4368
|
const subs = /* @__PURE__ */ new Set();
|
|
4273
4369
|
const ensureAffordanceStyles = () => {
|
|
4274
4370
|
try {
|
|
@@ -4340,6 +4436,31 @@ function createChartHost(container, config) {
|
|
|
4340
4436
|
if (active && tickStillDrawn) activeTickEl.classList?.add(ACTIVE_TICK_CLASS);
|
|
4341
4437
|
const wanted = new Set(sel ?? []);
|
|
4342
4438
|
const marks = container.querySelectorAll(`.${MARK_CLASS}[${ROW_IDX_ATTR}], .${LEGEND_MARK_CLASS}[${ROW_IDX_ATTR}]`);
|
|
4439
|
+
const rule = selectionRuleOf(container);
|
|
4440
|
+
if (rule !== "any-row") {
|
|
4441
|
+
const list = Array.from(marks);
|
|
4442
|
+
const plan = planSelectionPaint(
|
|
4443
|
+
list.map((m4) => ({ key: markKeyOf(m4), rows: parseRowIdxs(m4.getAttribute(ROW_IDX_ATTR)) })),
|
|
4444
|
+
active ? wanted : [],
|
|
4445
|
+
rule,
|
|
4446
|
+
clickedMarks()
|
|
4447
|
+
);
|
|
4448
|
+
list.forEach((m4, i) => m4.classList?.[plan.on[i] ? "add" : "remove"](MARK_SELECTED_CLASS));
|
|
4449
|
+
setClickedMarks(plan.keys.length ? { keys: plan.keys, selection: Array.from(wanted) } : null);
|
|
4450
|
+
if (active) {
|
|
4451
|
+
try {
|
|
4452
|
+
config.onSelectionPaint?.({
|
|
4453
|
+
rule,
|
|
4454
|
+
mode: plan.mode,
|
|
4455
|
+
lit: plan.on.filter(Boolean).length,
|
|
4456
|
+
marks: list.length,
|
|
4457
|
+
selection: wanted.size
|
|
4458
|
+
});
|
|
4459
|
+
} catch {
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4343
4464
|
for (const m4 of Array.from(marks)) {
|
|
4344
4465
|
const rows = parseRowIdxs(m4.getAttribute(ROW_IDX_ATTR));
|
|
4345
4466
|
const on = active && rows.some((r2) => wanted.has(r2));
|
|
@@ -4401,6 +4522,13 @@ function createChartHost(container, config) {
|
|
|
4401
4522
|
const multi = !!(e?.ctrlKey || e?.metaKey || e?.shiftKey);
|
|
4402
4523
|
const next = nextSelection(current, rows, { ctrl: !!(e?.ctrlKey || e?.metaKey), shift: !!e?.shiftKey });
|
|
4403
4524
|
const toggledOff = !multi && next.length === 0;
|
|
4525
|
+
setClickedMarks(nextClickedMarks(
|
|
4526
|
+
clickedMarks(),
|
|
4527
|
+
current,
|
|
4528
|
+
markKeyOf(el),
|
|
4529
|
+
next,
|
|
4530
|
+
{ ctrl: !!(e?.ctrlKey || e?.metaKey), shift: !!e?.shiftKey }
|
|
4531
|
+
));
|
|
4404
4532
|
notify(next, "user", toggledOff ? null : tick);
|
|
4405
4533
|
};
|
|
4406
4534
|
container.addEventListener(XFILTER_REFRESH_EVENT, onXf);
|
|
@@ -4481,6 +4609,12 @@ function createChartHost(container, config) {
|
|
|
4481
4609
|
} catch {
|
|
4482
4610
|
}
|
|
4483
4611
|
}
|
|
4612
|
+
if (config.onClippedTextCensus) {
|
|
4613
|
+
try {
|
|
4614
|
+
config.onClippedTextCensus(censusClippedText(container));
|
|
4615
|
+
} catch {
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4484
4618
|
if (config.onValuePlacementCensus) {
|
|
4485
4619
|
try {
|
|
4486
4620
|
config.onValuePlacementCensus(censusValuePlacement(container, data));
|
|
@@ -4624,6 +4758,7 @@ function createChartHost(container, config) {
|
|
|
4624
4758
|
} catch {
|
|
4625
4759
|
}
|
|
4626
4760
|
}
|
|
4761
|
+
setClickedMarks(null);
|
|
4627
4762
|
notify([], "host");
|
|
4628
4763
|
},
|
|
4629
4764
|
highlight(rowIdxs) {
|
|
@@ -4855,6 +4990,11 @@ export {
|
|
|
4855
4990
|
stripJsComments,
|
|
4856
4991
|
rowIdxsFromMark,
|
|
4857
4992
|
nextSelection,
|
|
4993
|
+
selectionRuleOf,
|
|
4994
|
+
markKeyOf,
|
|
4995
|
+
sameRowSet,
|
|
4996
|
+
planSelectionPaint,
|
|
4997
|
+
nextClickedMarks,
|
|
4858
4998
|
isInsideControl,
|
|
4859
4999
|
createMarkResolver,
|
|
4860
5000
|
collectD3GlyphCenters,
|
|
@@ -4868,6 +5008,9 @@ export {
|
|
|
4868
5008
|
MIN_HIT_BAND_PX,
|
|
4869
5009
|
censusHitBands,
|
|
4870
5010
|
hitBandFlag,
|
|
5011
|
+
CLIP_TOLERANCE_PX,
|
|
5012
|
+
censusClippedText,
|
|
5013
|
+
clippedTextFlag,
|
|
4871
5014
|
VALUE_AXIS_MIN_FIT,
|
|
4872
5015
|
censusValuePlacement,
|
|
4873
5016
|
valuePlacementFlag,
|
package/dist/index.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
AXIS_PIN_MIN_LABELS,
|
|
11
11
|
AXIS_PIN_TRACK_REACH_PX,
|
|
12
12
|
BACKING_MAJORITY,
|
|
13
|
+
CLIP_TOLERANCE_PX,
|
|
13
14
|
D3_PLUGIN_PACKAGES,
|
|
14
15
|
DARK_TEXT,
|
|
15
16
|
FIT_CONTENT_SELECTOR,
|
|
@@ -51,12 +52,14 @@ import {
|
|
|
51
52
|
blankRenderFlag,
|
|
52
53
|
buildRenderPayload,
|
|
53
54
|
cellSuppressesNormalize,
|
|
55
|
+
censusClippedText,
|
|
54
56
|
censusColourSpread,
|
|
55
57
|
censusHitBands,
|
|
56
58
|
censusMarks,
|
|
57
59
|
censusValuePlacement,
|
|
58
60
|
clearGeoCache,
|
|
59
61
|
clearSelectionGlyphs,
|
|
62
|
+
clippedTextFlag,
|
|
60
63
|
collectD3GlyphCenters,
|
|
61
64
|
colourSpreadFlag,
|
|
62
65
|
compileRenderFn,
|
|
@@ -88,10 +91,12 @@ import {
|
|
|
88
91
|
labelBand,
|
|
89
92
|
le,
|
|
90
93
|
loadGeo,
|
|
94
|
+
markKeyOf,
|
|
91
95
|
measureContainerBoxes,
|
|
92
96
|
minContrastOver,
|
|
93
97
|
needsScroll,
|
|
94
98
|
newIdScope,
|
|
99
|
+
nextClickedMarks,
|
|
95
100
|
nextSelection,
|
|
96
101
|
noopViewStateProvider,
|
|
97
102
|
o,
|
|
@@ -101,6 +106,7 @@ import {
|
|
|
101
106
|
pinScrolledAxis,
|
|
102
107
|
planAxisPin,
|
|
103
108
|
planFrameGrow,
|
|
109
|
+
planSelectionPaint,
|
|
104
110
|
qe,
|
|
105
111
|
registerGeo,
|
|
106
112
|
registerGeoAsset,
|
|
@@ -109,8 +115,10 @@ import {
|
|
|
109
115
|
resolveAutoColorScale,
|
|
110
116
|
resolveOptions,
|
|
111
117
|
rowIdxsFromMark,
|
|
118
|
+
sameRowSet,
|
|
112
119
|
scopeChartIds,
|
|
113
120
|
scrollFitFor,
|
|
121
|
+
selectionRuleOf,
|
|
114
122
|
sessionViewStateProvider,
|
|
115
123
|
straddleSampleGrid,
|
|
116
124
|
straddles,
|
|
@@ -122,7 +130,7 @@ import {
|
|
|
122
130
|
toSourceRows,
|
|
123
131
|
unpinScrolledAxis,
|
|
124
132
|
valuePlacementFlag
|
|
125
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-OEN7WGNS.mjs";
|
|
126
134
|
import "./chunk-A2GMXZP7.mjs";
|
|
127
135
|
import {
|
|
128
136
|
ACTIVE_TICK_CLASS,
|
|
@@ -141,6 +149,7 @@ import {
|
|
|
141
149
|
COLOR_SCALE_SELF_CLAMP_PCT_MAX,
|
|
142
150
|
COLOR_SCALE_SELF_CLAMP_PCT_MIN,
|
|
143
151
|
CONTAINER_SLOT_ANIM_STOP,
|
|
152
|
+
CONTAINER_SLOT_CLICKED_MARKS,
|
|
144
153
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
145
154
|
CONTAINER_SLOT_UI_STATE,
|
|
146
155
|
CONTAINER_SLOT_XF_CLEAR,
|
|
@@ -157,12 +166,15 @@ import {
|
|
|
157
166
|
LEGEND_MARK_CLASS,
|
|
158
167
|
LIFT_SELECTED_CLASS,
|
|
159
168
|
MARK_CLASS,
|
|
169
|
+
MARK_KEY_ATTR,
|
|
160
170
|
MARK_SELECTED_CLASS,
|
|
161
171
|
MAX_MAP_POINTS_DEFAULT,
|
|
162
172
|
NO_ROW_MARKS_ATTR,
|
|
163
173
|
ROW_IDX_ATTR,
|
|
164
174
|
SEASONAL_MARKERS_DEFAULT,
|
|
165
175
|
SELECTION_ACTIVE_CLASS,
|
|
176
|
+
SELECTION_RULE_ATTR,
|
|
177
|
+
SELECTION_RULE_CLICKED_MARKS,
|
|
166
178
|
SNAPSHOT_SVG_ATTR,
|
|
167
179
|
VALUE_AXIS_BASELINE_DEFAULT,
|
|
168
180
|
VIEW_ONLY_UI_STATE_KEYS,
|
|
@@ -170,7 +182,7 @@ import {
|
|
|
170
182
|
chartOwnsTimeline,
|
|
171
183
|
periodTickSuppressesFeedback,
|
|
172
184
|
withoutViewOnlyKeys
|
|
173
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-7JWL6LYE.mjs";
|
|
174
186
|
import "./chunk-GHODWOAL.mjs";
|
|
175
187
|
|
|
176
188
|
// src/optionsVocabulary.ts
|
|
@@ -1328,6 +1340,20 @@ function inlineFilterGate(rowCount) {
|
|
|
1328
1340
|
}
|
|
1329
1341
|
var INLINE_FILTER_MIN_ROWS = 8;
|
|
1330
1342
|
|
|
1343
|
+
// src/qualifyTable.ts
|
|
1344
|
+
function qualifyTableRows(rows) {
|
|
1345
|
+
return rows.map((r2) => ({
|
|
1346
|
+
rank: typeof r2.rank === "number" && Number.isFinite(r2.rank) ? r2.rank : null,
|
|
1347
|
+
name: r2.name,
|
|
1348
|
+
preview: r2.isPreview === true,
|
|
1349
|
+
fit: r2.recommended === false ? "can-also-render" : "fits",
|
|
1350
|
+
description: r2.description ?? "",
|
|
1351
|
+
language: r2.language ? r2.language : null,
|
|
1352
|
+
renderer: r2.renderer ? r2.renderer : null,
|
|
1353
|
+
alsoWorthALook: r2.alsoWorthALook === true
|
|
1354
|
+
}));
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1331
1357
|
// src/sourceDateFormat.ts
|
|
1332
1358
|
function formatSourceDate(raw, opts = {}) {
|
|
1333
1359
|
const d2 = toDate(raw);
|
|
@@ -2873,10 +2899,12 @@ export {
|
|
|
2873
2899
|
BACKING_MAJORITY,
|
|
2874
2900
|
CHOOSER_MIN_HEIGHT_PX,
|
|
2875
2901
|
CHOOSER_MIN_WIDTH_PX,
|
|
2902
|
+
CLIP_TOLERANCE_PX,
|
|
2876
2903
|
COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT,
|
|
2877
2904
|
COLOR_SCALE_SELF_CLAMP_PCT_MAX,
|
|
2878
2905
|
COLOR_SCALE_SELF_CLAMP_PCT_MIN,
|
|
2879
2906
|
CONTAINER_SLOT_ANIM_STOP,
|
|
2907
|
+
CONTAINER_SLOT_CLICKED_MARKS,
|
|
2880
2908
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
2881
2909
|
CONTAINER_SLOT_UI_STATE,
|
|
2882
2910
|
CONTAINER_SLOT_XF_CLEAR,
|
|
@@ -2915,6 +2943,7 @@ export {
|
|
|
2915
2943
|
LIMIT_COUNT_MAX,
|
|
2916
2944
|
LIVE_OPTION_KEYS,
|
|
2917
2945
|
MARK_CLASS,
|
|
2946
|
+
MARK_KEY_ATTR,
|
|
2918
2947
|
MARK_SELECTED_CLASS,
|
|
2919
2948
|
MAX_FRAME_GROW_FACTOR,
|
|
2920
2949
|
MAX_MAP_POINTS_DEFAULT,
|
|
@@ -2949,6 +2978,8 @@ export {
|
|
|
2949
2978
|
SEASONAL_MARKERS_DEFAULT,
|
|
2950
2979
|
SELECTION_ACTIVE_CLASS,
|
|
2951
2980
|
SELECTION_GLYPH_CLASS,
|
|
2981
|
+
SELECTION_RULE_ATTR,
|
|
2982
|
+
SELECTION_RULE_CLICKED_MARKS,
|
|
2952
2983
|
SNAPSHOT_SVG_ATTR,
|
|
2953
2984
|
STRADDLE_COLS,
|
|
2954
2985
|
STRADDLE_MIN_SHARE,
|
|
@@ -2981,6 +3012,7 @@ export {
|
|
|
2981
3012
|
canShowLastChart,
|
|
2982
3013
|
captureSvgSnapshot,
|
|
2983
3014
|
cellSuppressesNormalize,
|
|
3015
|
+
censusClippedText,
|
|
2984
3016
|
censusColourSpread,
|
|
2985
3017
|
censusHitBands,
|
|
2986
3018
|
censusMarks,
|
|
@@ -2990,6 +3022,7 @@ export {
|
|
|
2990
3022
|
chooserFitsViewport,
|
|
2991
3023
|
clearGeoCache,
|
|
2992
3024
|
clearSelectionGlyphs,
|
|
3025
|
+
clippedTextFlag,
|
|
2993
3026
|
codeReadsDatesInLocalTime,
|
|
2994
3027
|
collectD3GlyphCenters,
|
|
2995
3028
|
colourSpreadFlag,
|
|
@@ -3051,6 +3084,7 @@ export {
|
|
|
3051
3084
|
listNeedsFilter,
|
|
3052
3085
|
loadGeo,
|
|
3053
3086
|
markDefaultModel,
|
|
3087
|
+
markKeyOf,
|
|
3054
3088
|
markerArmedBlind,
|
|
3055
3089
|
measureContainerBoxes,
|
|
3056
3090
|
minContrastOver,
|
|
@@ -3059,6 +3093,7 @@ export {
|
|
|
3059
3093
|
newIdScope,
|
|
3060
3094
|
newQualifyGroupState,
|
|
3061
3095
|
newQualifyRefusalGroupState,
|
|
3096
|
+
nextClickedMarks,
|
|
3062
3097
|
nextSelection,
|
|
3063
3098
|
noopViewStateProvider,
|
|
3064
3099
|
normaliseAggregation,
|
|
@@ -3077,6 +3112,7 @@ export {
|
|
|
3077
3112
|
pinScrolledAxis,
|
|
3078
3113
|
planAxisPin,
|
|
3079
3114
|
planFrameGrow,
|
|
3115
|
+
planSelectionPaint,
|
|
3080
3116
|
planTrivialChart,
|
|
3081
3117
|
pollGiveUpKeepsMarker,
|
|
3082
3118
|
productFeedbackSendable,
|
|
@@ -3089,6 +3125,7 @@ export {
|
|
|
3089
3125
|
qualifyPick,
|
|
3090
3126
|
qualifyRefusalHeadingFor,
|
|
3091
3127
|
qualifyRefusalReason,
|
|
3128
|
+
qualifyTableRows,
|
|
3092
3129
|
rasterizeSvgToPngDataUrl,
|
|
3093
3130
|
readQualifyChartRow,
|
|
3094
3131
|
readQualifyRefusalRow,
|
|
@@ -3112,8 +3149,10 @@ export {
|
|
|
3112
3149
|
resolveOptions,
|
|
3113
3150
|
rowIdxsFromMark,
|
|
3114
3151
|
sameMarker,
|
|
3152
|
+
sameRowSet,
|
|
3115
3153
|
scopeChartIds,
|
|
3116
3154
|
scrollFitFor,
|
|
3155
|
+
selectionRuleOf,
|
|
3117
3156
|
servedCorrelationProves,
|
|
3118
3157
|
sessionViewStateProvider,
|
|
3119
3158
|
shouldCaptureThumbnail,
|
package/dist/react.mjs
CHANGED
|
@@ -22,9 +22,9 @@ import {
|
|
|
22
22
|
loadGeo,
|
|
23
23
|
syncMemberSelection,
|
|
24
24
|
toSourceRows
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-OEN7WGNS.mjs";
|
|
26
26
|
import "./chunk-A2GMXZP7.mjs";
|
|
27
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-7JWL6LYE.mjs";
|
|
28
28
|
import "./chunk-GHODWOAL.mjs";
|
|
29
29
|
|
|
30
30
|
// src/react.tsx
|
package/dist/testing.mjs
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ClippedText {
|
|
2
|
+
text: string;
|
|
3
|
+
/** Pixels past the frame on each side (0 = inside). */
|
|
4
|
+
top: number;
|
|
5
|
+
left: number;
|
|
6
|
+
bottom: number;
|
|
7
|
+
right: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ClippedTextCensus {
|
|
10
|
+
/** Visible text elements measured. */
|
|
11
|
+
measured: number;
|
|
12
|
+
/** Those with any side more than the tolerance outside the frame, worst first, at most MAX_REPORTED. */
|
|
13
|
+
clipped: ClippedText[];
|
|
14
|
+
/** How many were clipped in all (can exceed clipped.length). */
|
|
15
|
+
clippedCount: number;
|
|
16
|
+
/** False when there was no SVG or no layout (0x0 frame): nothing was measured, and that is not a pass. */
|
|
17
|
+
laidOut: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const CLIP_TOLERANCE_PX = 1;
|
|
20
|
+
export declare const MAX_REPORTED = 8;
|
|
21
|
+
/** Counts only visible text whose box leaves the SVG's box. A host without layout (jsdom) reports laidOut false. */
|
|
22
|
+
export declare function censusClippedText(container: any): ClippedTextCensus;
|
|
23
|
+
/** A one-line verdict for a log or a report; "" when nothing is clipped or nothing could be measured. */
|
|
24
|
+
export declare function clippedTextFlag(c: ClippedTextCensus): string;
|
package/dist/types/contract.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const HOST_CONTRACT_VERSION = "1.
|
|
1
|
+
export declare const HOST_CONTRACT_VERSION = "1.14.0";
|
|
2
2
|
export type GeoPointPrecision = "latlon" | "city" | "zip3" | "state" | "country";
|
|
3
3
|
/** Every valid tier, ordered most precise → coarsest. Runtime form of GeoPointPrecision. */
|
|
4
4
|
export declare const GEO_POINT_PRECISIONS: readonly GeoPointPrecision[];
|
|
@@ -13,6 +13,9 @@ export declare const AXIS_FILTER_CLASS = "d3-axis-filter";
|
|
|
13
13
|
export declare const LIFT_SELECTED_CLASS = "d3-lift-selected";
|
|
14
14
|
export declare const CONTROL_CLASS = "lch-control";
|
|
15
15
|
export declare const ROW_IDX_ATTR = "data-row-idx";
|
|
16
|
+
export declare const SELECTION_RULE_ATTR = "data-lch-sel-rule";
|
|
17
|
+
export declare const SELECTION_RULE_CLICKED_MARKS = "clicked-marks";
|
|
18
|
+
export declare const MARK_KEY_ATTR = "data-mark-key";
|
|
16
19
|
export declare const NO_ROW_MARKS_ATTR = "data-lch-no-row-marks";
|
|
17
20
|
export declare const SNAPSHOT_SVG_ATTR = "data-lch-snapshot";
|
|
18
21
|
export declare const XFILTER_REFRESH_EVENT = "llm-xfilter-refresh";
|
|
@@ -20,6 +23,7 @@ export declare const CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
|
|
|
20
23
|
export declare const CONTAINER_SLOT_XF_CLEAR = "__llmXfClear";
|
|
21
24
|
export declare const CONTAINER_SLOT_INITIAL_XF_MARK = "__llmInitialXfMark";
|
|
22
25
|
export declare const CONTAINER_SLOT_UI_STATE = "__lchUiState";
|
|
26
|
+
export declare const CONTAINER_SLOT_CLICKED_MARKS = "__lchClickedMarks";
|
|
23
27
|
export declare const VIEW_ONLY_UI_STATE_KEYS: readonly string[];
|
|
24
28
|
/** The bag with every view-only key removed: what a host persists when the reader has not asked
|
|
25
29
|
* for their view to be remembered. Returns the SAME object when there was nothing to remove. */
|
package/dist/types/host.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { type RenderOptions, type ViewStateProvider } from "./contract";
|
|
2
2
|
import { type ResolveOptionsInput } from "./defaults";
|
|
3
|
+
import { type SelectionRule, type SelectionPaintMode } from "./selection";
|
|
4
|
+
/** What onSelectionPaint reports: the declared rule, how this paint decided, and how many marks it lit. */
|
|
5
|
+
export interface SelectionPaintReport {
|
|
6
|
+
rule: SelectionRule;
|
|
7
|
+
mode: SelectionPaintMode;
|
|
8
|
+
lit: number;
|
|
9
|
+
marks: number;
|
|
10
|
+
selection: number;
|
|
11
|
+
}
|
|
3
12
|
import { type MarkCensus } from "./blankRender";
|
|
4
13
|
import { type HitBandCensus } from "./hitBands";
|
|
5
14
|
import { type ColourSpreadCensus } from "./colourSpread";
|
|
15
|
+
import { type ClippedTextCensus } from "./clippedText";
|
|
6
16
|
import { type ValuePlacementCensus } from "./valuePlacement";
|
|
7
17
|
import { type FitRenderedChartOptions, type FitRenderedChartResult } from "./fitDom";
|
|
8
18
|
import { type LabelContrastOptions, type LabelContrastReport } from "./labelContrastDom";
|
|
@@ -113,6 +123,12 @@ export interface ChartHostConfig {
|
|
|
113
123
|
* own skew is measured on the raw column while the ramp encodes an aggregate.
|
|
114
124
|
*/
|
|
115
125
|
onColourSpreadCensus?: (census: ColourSpreadCensus) => void;
|
|
126
|
+
/**
|
|
127
|
+
* IS ANY TEXT CUT OFF BY THE FRAME? Runs after every render, counts only, and never moves anything: a title
|
|
128
|
+
* drawn above its own origin is clipped without anything throwing, so only a measurement against the SVG box
|
|
129
|
+
* sees it. A host without layout reports `laidOut: false`, which is not a pass.
|
|
130
|
+
*/
|
|
131
|
+
onClippedTextCensus?: (census: ClippedTextCensus) => void;
|
|
116
132
|
/**
|
|
117
133
|
* IS EACH DOT DRAWN AT ITS VALUE? Runs after every render, counts only.
|
|
118
134
|
*
|
|
@@ -124,6 +140,13 @@ export interface ChartHostConfig {
|
|
|
124
140
|
* a radius off it. It declines on anything that is not that shape.
|
|
125
141
|
*/
|
|
126
142
|
onValuePlacementCensus?: (census: ValuePlacementCensus) => void;
|
|
143
|
+
/**
|
|
144
|
+
* HOW A DECLARED SELECTION RULE LIT THE MARKS. Called on every selection paint of a chart that
|
|
145
|
+
* declares a rule other than the default (SELECTION_RULE_ATTR), never for one that declares none.
|
|
146
|
+
* `mode` "fallback-any-row" means no clicked or exactly-matching mark was found for the selection,
|
|
147
|
+
* so the default rule lit the chart for that paint: worth a log line.
|
|
148
|
+
*/
|
|
149
|
+
onSelectionPaint?: (report: SelectionPaintReport) => void;
|
|
127
150
|
/** This chart declares time keyframes: frame one is allowed to be empty, so no blank verdict
|
|
128
151
|
* is issued for it. */
|
|
129
152
|
animated?: boolean;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, NO_ROW_MARKS_ATTR, SNAPSHOT_SVG_ATTR, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, FLIP_INTERVAL_MIN_MS, FLIP_INTERVAL_MAX_MS, FLIP_DIRECTION_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type FlipDirection, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, } from "./contract";
|
|
1
|
+
export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, NO_ROW_MARKS_ATTR, SELECTION_RULE_ATTR, SELECTION_RULE_CLICKED_MARKS, MARK_KEY_ATTR, CONTAINER_SLOT_CLICKED_MARKS, SNAPSHOT_SVG_ATTR, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, FLIP_INTERVAL_MIN_MS, FLIP_INTERVAL_MAX_MS, FLIP_DIRECTION_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type FlipDirection, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, } from "./contract";
|
|
2
2
|
export { resolveOptions, type ResolveOptionsInput } from "./defaults";
|
|
3
3
|
export { OPTIONS_VOCABULARY, LIVE_OPTION_KEYS, MAX_MAP_POINTS_MIN, MAX_MAP_POINTS_MAX, LIMIT_COUNT_MAX, wireLimitCount, type OptionVocabularyEntry, type OptionTiming, type OptionWire, type OptionKey, } from "./optionsVocabulary";
|
|
4
4
|
export { loadGeo, geoFromCache, registerGeo, registerGeoAsset, geoAssetFor, clearGeoCache, type GeoAssetName, } from "./geoLazy";
|
|
@@ -7,13 +7,13 @@ export { loadGeo, geoFromCache, registerGeo, registerGeoAsset, geoAssetFor, clea
|
|
|
7
7
|
export declare function registerCityTable(packed: string): void;
|
|
8
8
|
export { buildRenderPayload, type RenderPayload, type GeoPointBinding } from "./payload";
|
|
9
9
|
export { codeReadsDatesInLocalTime, vegaSpecReadsDatesInLocalTime } from "./dateCells";
|
|
10
|
-
export { createChartHost, compileRenderFn, stripEsmExports, requiredD3Plugins, explainRenderFailure, sessionViewStateProvider, noopViewStateProvider, assembleD3, D3_PLUGIN_PACKAGES, type ChartHost, type ChartHostConfig, type RenderFn } from "./host";
|
|
10
|
+
export { createChartHost, compileRenderFn, stripEsmExports, requiredD3Plugins, explainRenderFailure, sessionViewStateProvider, noopViewStateProvider, assembleD3, D3_PLUGIN_PACKAGES, type ChartHost, type ChartHostConfig, type RenderFn, type SelectionPaintReport } from "./host";
|
|
11
11
|
export { ANNOTATION_CLASS, ANNOTATION_LAYER_CLASS, type MarkAnnotation, type AnnotationReport } from "./annotations";
|
|
12
12
|
export type { MarkNoteLike, NoteBadgeOptions } from "./markNotes";
|
|
13
13
|
export type { Controls, ControlInfo, ControlsAttachment } from "./controls";
|
|
14
14
|
export { createChartGroup, toSourceRows, syncMemberSelection, type ChartGroup, type ChartGroupMember, type ChartGroupSelection, type ChartGroupChange, type ChartGroupMemberOptions, type ChartGroupSourceOptions, type ChartGroupPayload } from "./group";
|
|
15
15
|
export type { Filter, FilterScope, FilterOptions, FilterKey, FilterChangeReason, FilterBinding, BindFilterOptions, VegaInteractionEvent, PageView } from "./filterScope";
|
|
16
|
-
export { createMarkResolver, isInsideControl, rowIdxsFromMark, nextSelection, collectD3GlyphCenters, clearSelectionGlyphs, paintSelectionGlyphs, SELECTION_GLYPH_CLASS, type MarkResolver, type MarkResolverEnv, type GlyphCenter, type SelectionGlyphStyle, type SelectionModifiers, } from "./selection";
|
|
16
|
+
export { createMarkResolver, isInsideControl, rowIdxsFromMark, nextSelection, selectionRuleOf, markKeyOf, planSelectionPaint, nextClickedMarks, sameRowSet, type SelectionRule, type ClickedMarks, type SelectionPaintMark, type SelectionPaintMode, type SelectionPaintPlan, collectD3GlyphCenters, clearSelectionGlyphs, paintSelectionGlyphs, SELECTION_GLYPH_CLASS, type MarkResolver, type MarkResolverEnv, type GlyphCenter, type SelectionGlyphStyle, type SelectionModifiers, } from "./selection";
|
|
17
17
|
export { planTrivialChart, compileTrivialSource, type TrivialPlan, type TrivialShapeKind } from "./trivial";
|
|
18
18
|
export { captureSvgSnapshot, svgToDataUrl, svgNaturalSize, rasterizeSvgToPngDataUrl, tableHostOf, chartSvgOf, htmlToSvgDataUrl, htmlNaturalSize, type SnapshotOptions } from "./snapshot";
|
|
19
19
|
export { shouldReview, buildReviewWire, bareBase64, actionFor, type ReviewGate, type ReviewWire, type ReviewVerdict, type ReviewAction } from "./review";
|
|
@@ -22,6 +22,7 @@ export { mountProductFeedbackBox, normaliseProductFeedbackText, productFeedbackS
|
|
|
22
22
|
export { qualifyGroupHeadingFor, newQualifyGroupState, type QualifyGroupRow, type QualifyGroupState, type QualifyGroupHeading, orderRefusalsForDisplay, refusalIsSelectable, hasRefusalsToShow, qualifyRefusalHeadingFor, newQualifyRefusalGroupState, qualifyRefusalReason, QUALIFY_REFUSAL_UNSPECIFIED, type QualifyRefusalRow, type QualifyRefusalGroupState, type QualifyRefusalHeading, } from "./qualifyGroups";
|
|
23
23
|
export { qualifyPick, qualifyAuto, qualifyCancel, launchGenerates, launchFavorStyle, chooserFitsViewport, shouldOpenChooserOnGenerate, shouldOpenInlineChooserOnGenerate, canConfirmLaunch, confirmLaunch, qualifyFailureFallsOpen, CHOOSER_MIN_WIDTH_PX, CHOOSER_MIN_HEIGHT_PX, type QualifyLaunchOutcome, type ChooserGateInput, } from "./qualifyLaunch";
|
|
24
24
|
export { normalizeFilterTerm, filterQualifyRows, readQualifyChartRow, readQualifyRefusalRow, DEFAULT_FILTER_MATCH_STYLE, filterMatchStyleOf, type FilterMatchStyle, filterFitsChooser, listNeedsFilter, qualifyFilterGate, inlineFilterGate, FILTER_MIN_TERM_CHARS, FILTER_ROW_PX, FILTER_MIN_WIDTH_PX, FILTER_MIN_HEIGHT_PX, INLINE_FILTER_MIN_ROWS, computeQualifyFilterView, qualifyFilterCountText, type QualifyFilterTier, type QualifyFilterResult, type QualifyFilterRead, type QualifyFilterGateReason, type QualifyFilterGateInput, type QualifyFilterRow, type QualifyFilterGroup, type QualifyFilterView, type QualifyFilterNoteKind, } from "./qualifyFilter";
|
|
25
|
+
export { qualifyTableRows, type QualifyTableRow, type QualifyTableSource } from "./qualifyTable";
|
|
25
26
|
export { computeSelectionCard, normaliseAggregation, type SelectionCardModel, type SelectionCardLine, type SelectionCardOptions, } from "./selectionCard";
|
|
26
27
|
export { formatSourceDate, formatSourceDateFor, isExcelDateFormat, type SourceFormats, type SourceFormatDialect, type SourceDateOptions, } from "./sourceDateFormat";
|
|
27
28
|
export { composeSummaryText } from "./summaryText";
|
|
@@ -32,6 +33,7 @@ export { decideLabelColor, toRGBA, compositeOver, relativeLuminance, contrastRat
|
|
|
32
33
|
export { censusMarks, isBlankRender, blankRenderFlag, type MarkCensus, type BlankVerdictInput } from "./blankRender";
|
|
33
34
|
export { isInvalidSentinelError, invalidSentinelReason } from "./invalidSentinel";
|
|
34
35
|
export { censusHitBands, hitBandFlag, MIN_HIT_BAND_PX, type HitBandCensus } from "./hitBands";
|
|
36
|
+
export { censusClippedText, clippedTextFlag, CLIP_TOLERANCE_PX, type ClippedTextCensus, type ClippedText } from "./clippedText";
|
|
35
37
|
export { censusColourSpread, colourSpreadFlag, SAME_SHADE_DELTA_E, MIN_RAMP_FILLS, type ColourSpreadCensus } from "./colourSpread";
|
|
36
38
|
export { censusValuePlacement, valuePlacementFlag, VALUE_AXIS_MIN_FIT, type ValuePlacementCensus } from "./valuePlacement";
|
|
37
39
|
export { SCROLL_SLACK_PX, MAX_FRAME_GROW_FACTOR, PHANTOM_FRACTION, FIT_CONTENT_SELECTOR, needsScroll, contentExtentOf, scrollFitFor, planFrameGrow, isPhantomBox, type MeasuredBox, type ContentExtent, type ScrollFit, type FrameGrowPlan, } from "./fit";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** What a what-fits row must carry to become a table row (the shape-core parse result satisfies it). */
|
|
2
|
+
export interface QualifyTableSource {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string | null;
|
|
5
|
+
rank?: number | null;
|
|
6
|
+
language?: string | null;
|
|
7
|
+
renderer?: string | null;
|
|
8
|
+
recommended?: boolean | null;
|
|
9
|
+
isPreview?: boolean | null;
|
|
10
|
+
alsoWorthALook?: boolean | null;
|
|
11
|
+
}
|
|
12
|
+
export interface QualifyTableRow {
|
|
13
|
+
/** The position in the order asked for, or null for a row the server did not rank. */
|
|
14
|
+
rank: number | null;
|
|
15
|
+
name: string;
|
|
16
|
+
/** True for a newer, less proven type (still selectable by name). */
|
|
17
|
+
preview: boolean;
|
|
18
|
+
/** "fits" = the ontology judges it a fit for this data; "can-also-render" = it can draw this, but it is a weaker fit. */
|
|
19
|
+
fit: "fits" | "can-also-render";
|
|
20
|
+
description: string;
|
|
21
|
+
language: string | null;
|
|
22
|
+
renderer: string | null;
|
|
23
|
+
/** One of the "something different" picks drawn from below the top fits. */
|
|
24
|
+
alsoWorthALook: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** The rows as table rows, in the order given (the server's order IS the ranking). */
|
|
27
|
+
export declare function qualifyTableRows(rows: readonly QualifyTableSource[]): QualifyTableRow[];
|
|
@@ -25,6 +25,63 @@ export interface SelectionModifiers {
|
|
|
25
25
|
* clear from elsewhere, a re-derived selection), and the next click on the mark then did nothing.
|
|
26
26
|
*/
|
|
27
27
|
export declare function nextSelection(current: Iterable<number> | null | undefined, rowIdxs: readonly number[], mods?: SelectionModifiers): number[];
|
|
28
|
+
/**
|
|
29
|
+
* HOW A SELECTION LIGHTS A CHART'S OWN MARKS (see SELECTION_RULE_ATTR in contract.ts).
|
|
30
|
+
* "any-row": a mark is lit when any of its rows is selected - the default, and what every chart
|
|
31
|
+
* that declares nothing gets. "clicked-marks": the marks the reader clicked are lit and every other
|
|
32
|
+
* mark is dimmed - for a chart whose marks share rows, where any-row lights most of the chart.
|
|
33
|
+
*/
|
|
34
|
+
export type SelectionRule = "any-row" | "clicked-marks";
|
|
35
|
+
/** The rule the chart in `container` declared, read off any element it drew; "any-row" when none. */
|
|
36
|
+
export declare function selectionRuleOf(container: Element | null | undefined): SelectionRule;
|
|
37
|
+
/**
|
|
38
|
+
* A mark's identity under "clicked-marks": its MARK_KEY_ATTR when it carries one, else its
|
|
39
|
+
* data-row-idx list (prefixed, so a key can never be mistaken for a row list).
|
|
40
|
+
*/
|
|
41
|
+
export declare function markKeyOf(el: Element | null | undefined): string;
|
|
42
|
+
/** The marks the reader clicked under "clicked-marks", and the selection those clicks left. */
|
|
43
|
+
export interface ClickedMarks {
|
|
44
|
+
keys: string[];
|
|
45
|
+
selection: number[];
|
|
46
|
+
}
|
|
47
|
+
/** One mark as the paint plan sees it. */
|
|
48
|
+
export interface SelectionPaintMark {
|
|
49
|
+
key: string;
|
|
50
|
+
rows: readonly number[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Which marks a paint lit, and how it decided.
|
|
54
|
+
* none - nothing is selected;
|
|
55
|
+
* any-row - the default rule;
|
|
56
|
+
* clicked - the clicked marks (their keys were recorded for this very selection);
|
|
57
|
+
* exact - no click recorded for this selection: the marks whose rows equal it;
|
|
58
|
+
* fallback-any-row - neither found a mark, so any-row decided this paint. A host logs it.
|
|
59
|
+
*/
|
|
60
|
+
export type SelectionPaintMode = "none" | "any-row" | "clicked" | "exact" | "fallback-any-row";
|
|
61
|
+
export interface SelectionPaintPlan {
|
|
62
|
+
/** One flag per mark, in the order given: true when the mark is drawn selected. */
|
|
63
|
+
on: boolean[];
|
|
64
|
+
mode: SelectionPaintMode;
|
|
65
|
+
/** The keys of the marks lit by "clicked" or "exact": the clicked set to keep. Empty otherwise. */
|
|
66
|
+
keys: string[];
|
|
67
|
+
}
|
|
68
|
+
/** True when the two hold the same rows, ignoring order and repeats. */
|
|
69
|
+
export declare function sameRowSet(a: Iterable<number> | null | undefined, b: Iterable<number> | null | undefined): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* THE ONE PAINT RULE every host applies to its marks: which of `marks` are drawn selected under
|
|
72
|
+
* `selection`. Under "any-row" a mark is lit when any of its rows is selected. Under
|
|
73
|
+
* "clicked-marks" it is lit when its key is in `clicked` - but only when `clicked` was recorded for
|
|
74
|
+
* this same selection, because a selection changed from elsewhere makes those keys stale; failing
|
|
75
|
+
* that, the marks whose rows equal the selection; failing that, any-row, reported as a fallback.
|
|
76
|
+
*/
|
|
77
|
+
export declare function planSelectionPaint(marks: readonly SelectionPaintMark[], selection: Iterable<number> | null | undefined, rule: SelectionRule, clicked: ClickedMarks | null | undefined): SelectionPaintPlan;
|
|
78
|
+
/**
|
|
79
|
+
* The clicked set a click leaves under "clicked-marks". `prev` is the set held before the click and
|
|
80
|
+
* `current` the selection then; `next` is the selection the click leaves (nextSelection's answer).
|
|
81
|
+
* A plain click makes the clicked mark the whole set; Ctrl/Cmd/Shift adds it or takes it off. A held
|
|
82
|
+
* set recorded for a different selection is stale and starts over. An empty selection holds no set.
|
|
83
|
+
*/
|
|
84
|
+
export declare function nextClickedMarks(prev: ClickedMarks | null | undefined, current: Iterable<number> | null | undefined, key: string, next: readonly number[], mods?: SelectionModifiers): ClickedMarks | null;
|
|
28
85
|
/**
|
|
29
86
|
* True when a click's target sits inside a reader-operated control the chart drew (CONTROL_CLASS
|
|
30
87
|
* on the target or an ancestor), looking no further out than `container` - a page that wraps the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.75",
|
|
4
4
|
"description": "Run a BIC-generated D3 chart in any web host: compiles the generated render() function, applies the shared option defaults, resolves mark clicks (through tooltip overlays), owns the selection affordance, and translates row indices between cross-filtered charts. The same contract the BIC Power BI visual implements, minus Power BI. React bindings at @bicharts/chart-host/react.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|