@bicharts/chart-host 0.6.77 → 0.6.78
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/adapters.mjs +75 -0
- package/dist/card.mjs +2 -2
- package/dist/{chunk-IMNZYSIC.mjs → chunk-BFN4NY22.mjs} +28 -548
- package/dist/{chunk-H2P63UMG.mjs → chunk-L554L6HF.mjs} +2 -2
- package/dist/{chunk-QOKQUXVV.mjs → chunk-M7VM6F73.mjs} +1 -1
- package/dist/chunk-MGAO2DR7.mjs +543 -0
- package/dist/index.mjs +22 -20
- package/dist/react.mjs +3 -2
- package/dist/types/adapters/d3.d.ts +3 -0
- package/dist/types/adapters/index.d.ts +3 -0
- package/dist/types/adapters/types.d.ts +108 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +6 -1
|
@@ -5,7 +5,18 @@ import {
|
|
|
5
5
|
Xn,
|
|
6
6
|
Yn,
|
|
7
7
|
ge
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-L554L6HF.mjs";
|
|
9
|
+
import {
|
|
10
|
+
censusHitBands,
|
|
11
|
+
createMarkResolver,
|
|
12
|
+
ensureCrossfilterHitTargets,
|
|
13
|
+
isInsideControl,
|
|
14
|
+
markKeyOf,
|
|
15
|
+
nextClickedMarks,
|
|
16
|
+
nextSelection,
|
|
17
|
+
planSelectionPaint,
|
|
18
|
+
selectionRuleOf
|
|
19
|
+
} from "./chunk-MGAO2DR7.mjs";
|
|
9
20
|
import {
|
|
10
21
|
NA_ISO3,
|
|
11
22
|
NA_LAT_MAX,
|
|
@@ -41,15 +52,12 @@ import {
|
|
|
41
52
|
LEGEND_MARK_CLASS,
|
|
42
53
|
LIFT_SELECTED_CLASS,
|
|
43
54
|
MARK_CLASS,
|
|
44
|
-
MARK_KEY_ATTR,
|
|
45
55
|
MARK_SELECTED_CLASS,
|
|
46
56
|
MAX_MAP_POINTS_DEFAULT,
|
|
47
57
|
NO_ROW_MARKS_ATTR,
|
|
48
58
|
ROW_IDX_ATTR,
|
|
49
59
|
SEASONAL_MARKERS_DEFAULT,
|
|
50
60
|
SELECTION_ACTIVE_CLASS,
|
|
51
|
-
SELECTION_RULE_ATTR,
|
|
52
|
-
SELECTION_RULE_CLICKED_MARKS,
|
|
53
61
|
SNAPSHOT_SVG_ATTR,
|
|
54
62
|
VALUE_AXIS_BASELINE_DEFAULT,
|
|
55
63
|
XFILTER_REFRESH_EVENT,
|
|
@@ -1077,436 +1085,6 @@ function stripJsComments(code) {
|
|
|
1077
1085
|
return out;
|
|
1078
1086
|
}
|
|
1079
1087
|
|
|
1080
|
-
// src/selection.ts
|
|
1081
|
-
function rowIdxsFromMark(el) {
|
|
1082
|
-
if (!el) return [];
|
|
1083
|
-
const raw = el.getAttribute("data-row-idx");
|
|
1084
|
-
if (!raw) return [];
|
|
1085
|
-
const out = [];
|
|
1086
|
-
for (const tok of raw.split(",")) {
|
|
1087
|
-
const n = parseInt(tok.trim(), 10);
|
|
1088
|
-
if (!isNaN(n) && n >= 0) out.push(n);
|
|
1089
|
-
}
|
|
1090
|
-
return out;
|
|
1091
|
-
}
|
|
1092
|
-
function nextSelection(current, rowIdxs, mods = {}) {
|
|
1093
|
-
const cur = Array.from(current ?? []);
|
|
1094
|
-
if (mods.ctrl || mods.shift) {
|
|
1095
|
-
const next = new Set(cur);
|
|
1096
|
-
for (const r of rowIdxs) {
|
|
1097
|
-
if (next.has(r)) next.delete(r);
|
|
1098
|
-
else next.add(r);
|
|
1099
|
-
}
|
|
1100
|
-
return Array.from(next);
|
|
1101
|
-
}
|
|
1102
|
-
const same = cur.length === rowIdxs.length && rowIdxs.every((r) => cur.includes(r));
|
|
1103
|
-
return same ? [] : rowIdxs.slice();
|
|
1104
|
-
}
|
|
1105
|
-
function selectionRuleOf(container) {
|
|
1106
|
-
try {
|
|
1107
|
-
const el = container?.querySelector?.(`[${SELECTION_RULE_ATTR}]`);
|
|
1108
|
-
return el?.getAttribute(SELECTION_RULE_ATTR) === SELECTION_RULE_CLICKED_MARKS ? "clicked-marks" : "any-row";
|
|
1109
|
-
} catch {
|
|
1110
|
-
return "any-row";
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
function markKeyOf(el) {
|
|
1114
|
-
if (!el) return "";
|
|
1115
|
-
const k = el.getAttribute(MARK_KEY_ATTR);
|
|
1116
|
-
if (k != null && k !== "") return k;
|
|
1117
|
-
return "rows:" + (el.getAttribute(ROW_IDX_ATTR) || "").replace(/\s+/g, "");
|
|
1118
|
-
}
|
|
1119
|
-
var toSet = (s) => new Set(Array.from(s ?? []));
|
|
1120
|
-
function sameRowSet(a, b) {
|
|
1121
|
-
const A = toSet(a), B = toSet(b);
|
|
1122
|
-
if (A.size !== B.size) return false;
|
|
1123
|
-
for (const r of A) if (!B.has(r)) return false;
|
|
1124
|
-
return true;
|
|
1125
|
-
}
|
|
1126
|
-
function planSelectionPaint(marks, selection, rule, clicked) {
|
|
1127
|
-
const sel = toSet(selection);
|
|
1128
|
-
if (sel.size === 0) return { on: marks.map(() => false), mode: "none", keys: [] };
|
|
1129
|
-
const anyRow = () => marks.map((m) => m.rows.some((r) => sel.has(r)));
|
|
1130
|
-
if (rule !== "clicked-marks") return { on: anyRow(), mode: "any-row", keys: [] };
|
|
1131
|
-
if (clicked && clicked.keys.length && sameRowSet(clicked.selection, sel)) {
|
|
1132
|
-
const want = new Set(clicked.keys);
|
|
1133
|
-
const on = marks.map((m) => m.rows.length > 0 && want.has(m.key));
|
|
1134
|
-
if (on.some(Boolean)) return { on, mode: "clicked", keys: marks.filter((_, i) => on[i]).map((m) => m.key) };
|
|
1135
|
-
}
|
|
1136
|
-
const exact = marks.map((m) => m.rows.length > 0 && sameRowSet(m.rows, sel));
|
|
1137
|
-
if (exact.some(Boolean)) return { on: exact, mode: "exact", keys: marks.filter((_, i) => exact[i]).map((m) => m.key) };
|
|
1138
|
-
return { on: anyRow(), mode: "fallback-any-row", keys: [] };
|
|
1139
|
-
}
|
|
1140
|
-
function nextClickedMarks(prev, current, key, next, mods = {}) {
|
|
1141
|
-
if (!next.length) return null;
|
|
1142
|
-
if (!(mods.ctrl || mods.shift)) return { keys: [key], selection: next.slice() };
|
|
1143
|
-
const held = prev && sameRowSet(prev.selection, current) ? prev.keys : [];
|
|
1144
|
-
const keys = held.includes(key) ? held.filter((k) => k !== key) : [...held, key];
|
|
1145
|
-
return { keys, selection: next.slice() };
|
|
1146
|
-
}
|
|
1147
|
-
function isInsideControl(target, container) {
|
|
1148
|
-
let el = target;
|
|
1149
|
-
if (el && el.nodeType !== 1) el = el.parentElement ?? el.parentNode ?? null;
|
|
1150
|
-
while (el && el !== container) {
|
|
1151
|
-
if (el.nodeType === 1 && el.classList?.contains?.(CONTROL_CLASS)) return true;
|
|
1152
|
-
el = el.parentElement ?? el.parentNode ?? null;
|
|
1153
|
-
}
|
|
1154
|
-
return false;
|
|
1155
|
-
}
|
|
1156
|
-
function createMarkResolver(env) {
|
|
1157
|
-
const { root, doc, log } = env;
|
|
1158
|
-
const isElement = (t) => {
|
|
1159
|
-
const E = doc?.defaultView?.Element ?? globalThis.Element;
|
|
1160
|
-
if (E && t instanceof E) return true;
|
|
1161
|
-
return !!t && typeof t.closest === "function" && typeof t.getAttribute === "function";
|
|
1162
|
-
};
|
|
1163
|
-
const viewStyle = (n) => {
|
|
1164
|
-
try {
|
|
1165
|
-
const gcs = doc?.defaultView?.getComputedStyle ?? (typeof getComputedStyle === "function" ? getComputedStyle : null);
|
|
1166
|
-
return gcs ? gcs(n).pointerEvents : "";
|
|
1167
|
-
} catch {
|
|
1168
|
-
return "";
|
|
1169
|
-
}
|
|
1170
|
-
};
|
|
1171
|
-
const isInvisibleStrokePath = (el) => {
|
|
1172
|
-
if (el.tagName.toLowerCase() !== "path") return false;
|
|
1173
|
-
const f2 = el.getAttribute("fill");
|
|
1174
|
-
if (f2 !== null && f2 !== "" && f2 !== "none" && f2 !== "transparent") return false;
|
|
1175
|
-
const s = (el.getAttribute("stroke") || "").trim().toLowerCase();
|
|
1176
|
-
const so = parseFloat(el.getAttribute("stroke-opacity") || "1");
|
|
1177
|
-
return s === "transparent" || s === "none" || so <= 0.01;
|
|
1178
|
-
};
|
|
1179
|
-
const distToPathCenterline = (el, x, y) => {
|
|
1180
|
-
const L = el.getTotalLength();
|
|
1181
|
-
if (!(L > 0)) return Number.MAX_VALUE;
|
|
1182
|
-
const m = el.getScreenCTM();
|
|
1183
|
-
if (!m) return Number.MAX_VALUE;
|
|
1184
|
-
let best = Number.MAX_VALUE;
|
|
1185
|
-
const N = 64;
|
|
1186
|
-
for (let i = 0; i <= N; i++) {
|
|
1187
|
-
const pt = el.getPointAtLength(L * i / N);
|
|
1188
|
-
const dx = m.a * pt.x + m.c * pt.y + m.e - x;
|
|
1189
|
-
const dy = m.b * pt.x + m.d * pt.y + m.f - y;
|
|
1190
|
-
const d = dx * dx + dy * dy;
|
|
1191
|
-
if (d < best) best = d;
|
|
1192
|
-
}
|
|
1193
|
-
return Math.sqrt(best);
|
|
1194
|
-
};
|
|
1195
|
-
const refineHitCorridor = (mark, x, y, sel) => {
|
|
1196
|
-
try {
|
|
1197
|
-
if (!mark || !isInvisibleStrokePath(mark) || !mark.getAttribute("data-row-idx")) return mark;
|
|
1198
|
-
const stack = doc.elementsFromPoint(x, y);
|
|
1199
|
-
const candidates = [];
|
|
1200
|
-
for (const el of stack) {
|
|
1201
|
-
if (!root.contains(el)) continue;
|
|
1202
|
-
if (!el.matches || !el.matches(sel)) continue;
|
|
1203
|
-
if (!el.getAttribute("data-row-idx")) continue;
|
|
1204
|
-
if (!isInvisibleStrokePath(el)) continue;
|
|
1205
|
-
candidates.push(el);
|
|
1206
|
-
}
|
|
1207
|
-
if (candidates.indexOf(mark) < 0) candidates.push(mark);
|
|
1208
|
-
if (candidates.length < 2) return mark;
|
|
1209
|
-
let best = mark;
|
|
1210
|
-
let bestD = Number.MAX_VALUE;
|
|
1211
|
-
for (const el of candidates) {
|
|
1212
|
-
const d = distToPathCenterline(el, x, y);
|
|
1213
|
-
if (d < bestD) {
|
|
1214
|
-
bestD = d;
|
|
1215
|
-
best = el;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
if (best !== mark) {
|
|
1219
|
-
log("d3-hit-corridor-refined", {
|
|
1220
|
-
candidates: candidates.length,
|
|
1221
|
-
distPx: Math.round(bestD),
|
|
1222
|
-
fromRows: (mark.getAttribute("data-row-idx") || "").slice(0, 24),
|
|
1223
|
-
toRows: (best.getAttribute("data-row-idx") || "").slice(0, 24)
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
return best;
|
|
1227
|
-
} catch {
|
|
1228
|
-
return mark;
|
|
1229
|
-
}
|
|
1230
|
-
};
|
|
1231
|
-
const findMark = (target, sel = ".d3-mark", ev) => {
|
|
1232
|
-
if (!isElement(target)) return null;
|
|
1233
|
-
const el = target;
|
|
1234
|
-
const m = el.closest(sel);
|
|
1235
|
-
if (m && ev) return refineHitCorridor(m, ev.clientX, ev.clientY, sel);
|
|
1236
|
-
return m;
|
|
1237
|
-
};
|
|
1238
|
-
const penetrateOverlayAt = (x, y, sel) => {
|
|
1239
|
-
try {
|
|
1240
|
-
const stack = doc.elementsFromPoint(x, y);
|
|
1241
|
-
for (const el of stack) {
|
|
1242
|
-
if (!root.contains(el) || !isElement(el)) continue;
|
|
1243
|
-
const cand = el.matches(sel) ? el : el.closest(sel);
|
|
1244
|
-
if (!cand || !root.contains(cand) || !cand.getAttribute("data-row-idx")) continue;
|
|
1245
|
-
log("d3_click-overlay-penetrated", { tag: el.tagName, cls: el.getAttribute("class"), via: el === cand ? "self" : "closest" });
|
|
1246
|
-
return cand;
|
|
1247
|
-
}
|
|
1248
|
-
} catch {
|
|
1249
|
-
}
|
|
1250
|
-
return null;
|
|
1251
|
-
};
|
|
1252
|
-
const resolveByGeometry = (x, y, sel) => {
|
|
1253
|
-
try {
|
|
1254
|
-
const cands = root.querySelectorAll(sel);
|
|
1255
|
-
let best = null, bestArea = Number.MAX_VALUE;
|
|
1256
|
-
if (cands.length <= 600) {
|
|
1257
|
-
for (const el of Array.from(cands)) {
|
|
1258
|
-
if (!el.getAttribute("data-row-idx")) continue;
|
|
1259
|
-
const r = el.getBoundingClientRect ? el.getBoundingClientRect() : null;
|
|
1260
|
-
if (!r || r.width <= 0 || r.height <= 0) continue;
|
|
1261
|
-
if (x < r.left || x > r.right || y < r.top || y > r.bottom) continue;
|
|
1262
|
-
const area2 = r.width * r.height;
|
|
1263
|
-
if (area2 < bestArea) {
|
|
1264
|
-
bestArea = area2;
|
|
1265
|
-
best = el;
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
const hasHittableShape = (node) => {
|
|
1270
|
-
const SHAPE = /^(rect|circle|ellipse|path|line|polygon|polyline|text|image|use)$/;
|
|
1271
|
-
const all = [node, ...Array.from(node.querySelectorAll("*"))];
|
|
1272
|
-
for (const n of all) {
|
|
1273
|
-
const tag = (n.tagName || "").toLowerCase();
|
|
1274
|
-
if (!SHAPE.test(tag)) continue;
|
|
1275
|
-
const pe = viewStyle(n);
|
|
1276
|
-
if (pe && pe !== "none") return true;
|
|
1277
|
-
}
|
|
1278
|
-
return false;
|
|
1279
|
-
};
|
|
1280
|
-
if (best && !hasHittableShape(best)) {
|
|
1281
|
-
log("d3_click-geom-resolved", { rows: (best.getAttribute("data-row-idx") || "").slice(0, 24) });
|
|
1282
|
-
return best;
|
|
1283
|
-
} else if (best) {
|
|
1284
|
-
log("d3_click-geom-skip-hittable", {});
|
|
1285
|
-
}
|
|
1286
|
-
} catch {
|
|
1287
|
-
}
|
|
1288
|
-
return null;
|
|
1289
|
-
};
|
|
1290
|
-
return { isInvisibleStrokePath, distToPathCenterline, refineHitCorridor, findMark, rowIdxsFromMark, penetrateOverlayAt, resolveByGeometry };
|
|
1291
|
-
}
|
|
1292
|
-
function collectD3GlyphCenters(container, baseRect, out) {
|
|
1293
|
-
const Point = container.ownerDocument?.defaultView?.DOMPoint ?? globalThis.DOMPoint;
|
|
1294
|
-
const marks = container.querySelectorAll(`.${MARK_CLASS}.${MARK_SELECTED_CLASS}`);
|
|
1295
|
-
const rects = [];
|
|
1296
|
-
for (let i = 0; i < marks.length; i++) {
|
|
1297
|
-
const r = marks[i].getBoundingClientRect();
|
|
1298
|
-
rects.push(r);
|
|
1299
|
-
}
|
|
1300
|
-
const CONTAINMENT_CAP = 300;
|
|
1301
|
-
const EPS2 = 1;
|
|
1302
|
-
const filterContainers = marks.length <= CONTAINMENT_CAP;
|
|
1303
|
-
const enclosesAnother = (ci) => {
|
|
1304
|
-
const c = rects[ci];
|
|
1305
|
-
const cArea = c.width * c.height;
|
|
1306
|
-
if (cArea <= 0) return false;
|
|
1307
|
-
for (let mj = 0; mj < rects.length; mj++) {
|
|
1308
|
-
if (mj === ci) continue;
|
|
1309
|
-
const m = rects[mj];
|
|
1310
|
-
const mArea = m.width * m.height;
|
|
1311
|
-
if (mArea <= 0 || mArea >= cArea) continue;
|
|
1312
|
-
if (m.left >= c.left - EPS2 && m.right <= c.right + EPS2 && m.top >= c.top - EPS2 && m.bottom <= c.bottom + EPS2) return true;
|
|
1313
|
-
}
|
|
1314
|
-
return false;
|
|
1315
|
-
};
|
|
1316
|
-
for (let i = 0; i < marks.length; i++) {
|
|
1317
|
-
const el = marks[i];
|
|
1318
|
-
const r = rects[i];
|
|
1319
|
-
if (r.width === 0 && r.height === 0) continue;
|
|
1320
|
-
if (filterContainers && enclosesAnother(i)) continue;
|
|
1321
|
-
const tag = el.tagName.toLowerCase();
|
|
1322
|
-
let sx;
|
|
1323
|
-
let sy;
|
|
1324
|
-
const cxA = el.getAttribute("data-cx"), cyA = el.getAttribute("data-cy");
|
|
1325
|
-
if (cxA != null && cyA != null && typeof el.getScreenCTM === "function") {
|
|
1326
|
-
const ctm = el.getScreenCTM();
|
|
1327
|
-
const cxN = parseFloat(cxA), cyN = parseFloat(cyA);
|
|
1328
|
-
if (ctm && isFinite(cxN) && isFinite(cyN)) {
|
|
1329
|
-
const p = new Point(cxN, cyN).matrixTransform(ctm);
|
|
1330
|
-
sx = p.x;
|
|
1331
|
-
sy = p.y;
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
if (sx === void 0 && tag === "path" && typeof el.getPointAtLength === "function") {
|
|
1335
|
-
try {
|
|
1336
|
-
const len = el.getTotalLength();
|
|
1337
|
-
const ctm = el.getScreenCTM();
|
|
1338
|
-
if (len > 0 && ctm) {
|
|
1339
|
-
const dAttr = el.getAttribute("d") || "";
|
|
1340
|
-
const isArcSector = /[Aa]/.test(dAttr) && !/[CcSsQqTt]/.test(dAttr);
|
|
1341
|
-
let local;
|
|
1342
|
-
if (isArcSector) {
|
|
1343
|
-
const N = 24;
|
|
1344
|
-
let ax = 0, ay = 0;
|
|
1345
|
-
for (let k = 0; k < N; k++) {
|
|
1346
|
-
const sp = el.getPointAtLength(len * k / N);
|
|
1347
|
-
ax += sp.x;
|
|
1348
|
-
ay += sp.y;
|
|
1349
|
-
}
|
|
1350
|
-
const cand = new Point(ax / N, ay / N);
|
|
1351
|
-
let inside = true;
|
|
1352
|
-
try {
|
|
1353
|
-
if (typeof el.isPointInFill === "function") {
|
|
1354
|
-
inside = el.isPointInFill(cand);
|
|
1355
|
-
}
|
|
1356
|
-
} catch {
|
|
1357
|
-
inside = true;
|
|
1358
|
-
}
|
|
1359
|
-
if (inside) local = cand;
|
|
1360
|
-
}
|
|
1361
|
-
if (!local) local = el.getPointAtLength(len / 2);
|
|
1362
|
-
const p = local.matrixTransform(ctm);
|
|
1363
|
-
sx = p.x;
|
|
1364
|
-
sy = p.y;
|
|
1365
|
-
}
|
|
1366
|
-
} catch {
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
if (sx === void 0 || sy === void 0) {
|
|
1370
|
-
const isRect = tag === "rect";
|
|
1371
|
-
sx = isRect ? r.left + r.width * 0.8 : r.left + r.width / 2;
|
|
1372
|
-
sy = isRect ? r.top + r.height * 0.2 : r.top + r.height / 2;
|
|
1373
|
-
}
|
|
1374
|
-
out.push({ x: sx - baseRect.left, y: sy - baseRect.top });
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
var SELECTION_GLYPH_CLASS = "lch-sel-glyph";
|
|
1378
|
-
function clearSelectionGlyphs(overlay) {
|
|
1379
|
-
if (overlay) {
|
|
1380
|
-
while (overlay.firstChild) overlay.removeChild(overlay.firstChild);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
function paintSelectionGlyphs(overlay, centers, style) {
|
|
1384
|
-
const doc = overlay.ownerDocument;
|
|
1385
|
-
const frag = doc.createDocumentFragment();
|
|
1386
|
-
const count = Math.min(centers.length, style.max ?? 600);
|
|
1387
|
-
for (let i = 0; i < count; i++) {
|
|
1388
|
-
const c = centers[i];
|
|
1389
|
-
const g = doc.createElement("span");
|
|
1390
|
-
g.className = SELECTION_GLYPH_CLASS;
|
|
1391
|
-
g.textContent = style.symbol;
|
|
1392
|
-
g.style.position = "absolute";
|
|
1393
|
-
g.style.left = c.x + "px";
|
|
1394
|
-
g.style.top = c.y + "px";
|
|
1395
|
-
g.style.transform = "translate(-50%, -50%)";
|
|
1396
|
-
g.style.font = "700 11px/1 system-ui, -apple-system, Segoe UI, sans-serif";
|
|
1397
|
-
g.style.color = style.color;
|
|
1398
|
-
const halo = style.halo;
|
|
1399
|
-
g.style.textShadow = `-1px -1px 1px ${halo}, 1px -1px 1px ${halo}, -1px 1px 1px ${halo}, 1px 1px 1px ${halo}, 0 0 2px ${halo}`;
|
|
1400
|
-
g.style.pointerEvents = "none";
|
|
1401
|
-
frag.appendChild(g);
|
|
1402
|
-
}
|
|
1403
|
-
overlay.appendChild(frag);
|
|
1404
|
-
return count;
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
// src/hitTargets.ts
|
|
1408
|
-
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1409
|
-
var HIT_ATTR = "data-lch-hit";
|
|
1410
|
-
var ELEMENT_CAP2 = 5e3;
|
|
1411
|
-
var mapsPresentationAttributes = /* @__PURE__ */ new WeakMap();
|
|
1412
|
-
function engineMapsPresentationAttributes(ownerDoc, view) {
|
|
1413
|
-
if (!ownerDoc || typeof ownerDoc !== "object") return false;
|
|
1414
|
-
const known = mapsPresentationAttributes.get(ownerDoc);
|
|
1415
|
-
if (known !== void 0) return known;
|
|
1416
|
-
let maps = false;
|
|
1417
|
-
try {
|
|
1418
|
-
const host = ownerDoc.documentElement;
|
|
1419
|
-
const probe = ownerDoc.createElementNS(SVG_NS, "svg");
|
|
1420
|
-
const shape = ownerDoc.createElementNS(SVG_NS, "rect");
|
|
1421
|
-
shape.setAttribute("fill", "none");
|
|
1422
|
-
probe.appendChild(shape);
|
|
1423
|
-
host.appendChild(probe);
|
|
1424
|
-
try {
|
|
1425
|
-
maps = String(view.getComputedStyle(shape).fill ?? "").trim().toLowerCase() === "none";
|
|
1426
|
-
} finally {
|
|
1427
|
-
host.removeChild(probe);
|
|
1428
|
-
}
|
|
1429
|
-
} catch {
|
|
1430
|
-
maps = false;
|
|
1431
|
-
}
|
|
1432
|
-
mapsPresentationAttributes.set(ownerDoc, maps);
|
|
1433
|
-
return maps;
|
|
1434
|
-
}
|
|
1435
|
-
function ensureCrossfilterHitTargets(container, doc) {
|
|
1436
|
-
const report = { tagged: 0, hitRects: 0, peFlips: 0, peStrokeOnly: 0 };
|
|
1437
|
-
try {
|
|
1438
|
-
if (!container || typeof container.querySelectorAll !== "function") return report;
|
|
1439
|
-
const els = container.querySelectorAll(
|
|
1440
|
-
`.${MARK_CLASS}, .${LEGEND_MARK_CLASS}, .${AXIS_FILTER_CLASS}`
|
|
1441
|
-
);
|
|
1442
|
-
report.tagged = els.length;
|
|
1443
|
-
if (els.length === 0 || els.length > ELEMENT_CAP2) return report;
|
|
1444
|
-
const ownerDoc = doc ?? container.ownerDocument;
|
|
1445
|
-
const view = ownerDoc?.defaultView;
|
|
1446
|
-
const computed = (el) => {
|
|
1447
|
-
try {
|
|
1448
|
-
return view?.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
1449
|
-
} catch {
|
|
1450
|
-
return null;
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
for (const el of Array.from(els)) {
|
|
1454
|
-
const tag = String(el.tagName || "").toLowerCase();
|
|
1455
|
-
if (tag === "g") {
|
|
1456
|
-
if (!el.hasAttribute?.(ROW_IDX_ATTR)) continue;
|
|
1457
|
-
if (el.querySelector?.(`rect[${HIT_ATTR}="1"]`)) continue;
|
|
1458
|
-
const cls = el.getAttribute?.("class") || "";
|
|
1459
|
-
const isFurniture = cls.indexOf(LEGEND_MARK_CLASS) >= 0 || cls.indexOf(AXIS_FILTER_CLASS) >= 0;
|
|
1460
|
-
if (!isFurniture) {
|
|
1461
|
-
let hasHittableChild = false;
|
|
1462
|
-
const kids = el.querySelectorAll?.("*") ?? [];
|
|
1463
|
-
for (const kid of Array.from(kids)) {
|
|
1464
|
-
const ktag = String(kid.tagName || "").toLowerCase();
|
|
1465
|
-
if (ktag === "g" || ktag === "tspan" || ktag === "title" || ktag === "defs") continue;
|
|
1466
|
-
const cs = computed(kid);
|
|
1467
|
-
if (!cs || cs.pointerEvents !== "none") {
|
|
1468
|
-
hasHittableChild = true;
|
|
1469
|
-
break;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
if (hasHittableChild) continue;
|
|
1473
|
-
}
|
|
1474
|
-
let bb = null;
|
|
1475
|
-
try {
|
|
1476
|
-
bb = el.getBBox?.();
|
|
1477
|
-
} catch {
|
|
1478
|
-
bb = null;
|
|
1479
|
-
}
|
|
1480
|
-
if (!bb || !(bb.width > 0) || !(bb.height > 0)) continue;
|
|
1481
|
-
const rect = ownerDoc.createElementNS(SVG_NS, "rect");
|
|
1482
|
-
rect.setAttribute("x", String(bb.x));
|
|
1483
|
-
rect.setAttribute("y", String(bb.y));
|
|
1484
|
-
rect.setAttribute("width", String(bb.width));
|
|
1485
|
-
rect.setAttribute("height", String(bb.height));
|
|
1486
|
-
rect.setAttribute("fill", "transparent");
|
|
1487
|
-
rect.setAttribute(HIT_ATTR, "1");
|
|
1488
|
-
if (rect.style) {
|
|
1489
|
-
rect.style.pointerEvents = "all";
|
|
1490
|
-
rect.style.cursor = "pointer";
|
|
1491
|
-
}
|
|
1492
|
-
el.insertBefore(rect, el.firstChild);
|
|
1493
|
-
report.hitRects++;
|
|
1494
|
-
} else {
|
|
1495
|
-
const cs = computed(el);
|
|
1496
|
-
if (cs && cs.pointerEvents === "none") {
|
|
1497
|
-
const fill = String((engineMapsPresentationAttributes(ownerDoc, view) ? cs.fill : el.getAttribute?.("fill") ?? cs.fill) ?? "").trim().toLowerCase();
|
|
1498
|
-
const unfilled = fill === "none" || fill === "transparent" || fill === "rgba(0, 0, 0, 0)";
|
|
1499
|
-
if (el.style) el.style.pointerEvents = unfilled ? "stroke" : "all";
|
|
1500
|
-
report.peFlips++;
|
|
1501
|
-
if (unfilled) report.peStrokeOnly++;
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
} catch {
|
|
1506
|
-
}
|
|
1507
|
-
return report;
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
1088
|
// src/blankRender.ts
|
|
1511
1089
|
var EMPTY2 = { markCount: 0, legendMarkCount: 0, containerKind: "empty", declaresNoRowMarks: false };
|
|
1512
1090
|
function censusMarks(container) {
|
|
@@ -1545,87 +1123,6 @@ function blankRenderFlag(lang, cause) {
|
|
|
1545
1123
|
return `blankrender:${clean(lang)}:${clean(cause)}`;
|
|
1546
1124
|
}
|
|
1547
1125
|
|
|
1548
|
-
// src/hitBands.ts
|
|
1549
|
-
var MIN_HIT_BAND_PX = 8;
|
|
1550
|
-
var ELEMENT_CAP3 = 5e3;
|
|
1551
|
-
var EMPTY3 = {
|
|
1552
|
-
openStrokes: 0,
|
|
1553
|
-
interactive: 0,
|
|
1554
|
-
hairline: 0,
|
|
1555
|
-
uncovered: 0,
|
|
1556
|
-
widestPx: 0
|
|
1557
|
-
};
|
|
1558
|
-
var OPEN_TAGS = /* @__PURE__ */ new Set(["path", "line", "polyline"]);
|
|
1559
|
-
function styleOf2(el, doc) {
|
|
1560
|
-
try {
|
|
1561
|
-
const view = doc?.defaultView;
|
|
1562
|
-
return view?.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
1563
|
-
} catch {
|
|
1564
|
-
return null;
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
function attrOrComputed(el, name, cs) {
|
|
1568
|
-
const a = el.getAttribute?.(name);
|
|
1569
|
-
if (a !== null && a !== void 0 && String(a).trim() !== "") return String(a).trim();
|
|
1570
|
-
const c = cs?.[name === "stroke-width" ? "strokeWidth" : name];
|
|
1571
|
-
return c === null || c === void 0 ? "" : String(c).trim();
|
|
1572
|
-
}
|
|
1573
|
-
function isUnfilled(fill) {
|
|
1574
|
-
const f2 = fill.toLowerCase();
|
|
1575
|
-
return f2 === "none" || f2 === "transparent" || f2 === "rgba(0, 0, 0, 0)" || f2 === "rgba(0,0,0,0)";
|
|
1576
|
-
}
|
|
1577
|
-
function widthPx(raw) {
|
|
1578
|
-
const m = /^(-?\d+(?:\.\d+)?)\s*(px)?$/i.exec(raw);
|
|
1579
|
-
if (!m) return NaN;
|
|
1580
|
-
const n = parseFloat(m[1]);
|
|
1581
|
-
return isFinite(n) ? n : NaN;
|
|
1582
|
-
}
|
|
1583
|
-
function censusHitBands(container, doc) {
|
|
1584
|
-
if (!container || typeof container.querySelectorAll !== "function") return EMPTY3;
|
|
1585
|
-
try {
|
|
1586
|
-
const els = Array.from(
|
|
1587
|
-
container.querySelectorAll(`.${MARK_CLASS}, [${ROW_IDX_ATTR}]`)
|
|
1588
|
-
);
|
|
1589
|
-
if (els.length === 0 || els.length > ELEMENT_CAP3) return EMPTY3;
|
|
1590
|
-
const ownerDoc = doc ?? container.ownerDocument;
|
|
1591
|
-
const widestByGeom = /* @__PURE__ */ new Map();
|
|
1592
|
-
const rows = [];
|
|
1593
|
-
for (const el of els) {
|
|
1594
|
-
const tag = String(el.tagName || "").toLowerCase();
|
|
1595
|
-
if (!OPEN_TAGS.has(tag)) continue;
|
|
1596
|
-
const cs = styleOf2(el, ownerDoc);
|
|
1597
|
-
const open = isUnfilled(attrOrComputed(el, "fill", cs));
|
|
1598
|
-
const w = widthPx(attrOrComputed(el, "stroke-width", cs) || "1");
|
|
1599
|
-
const geom = String(el.getAttribute?.("d") ?? "") || `${tag}#${String(el.getAttribute?.(ROW_IDX_ATTR) ?? "")}`;
|
|
1600
|
-
const inert = String(cs?.pointerEvents ?? el.style?.pointerEvents ?? "") === "none";
|
|
1601
|
-
rows.push({ el, geom, w, open, inert });
|
|
1602
|
-
if (isFinite(w)) {
|
|
1603
|
-
const prev = widestByGeom.get(geom);
|
|
1604
|
-
if (prev === void 0 || w > prev) widestByGeom.set(geom, w);
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
const out = { ...EMPTY3 };
|
|
1608
|
-
for (const r of rows) {
|
|
1609
|
-
if (!r.open) continue;
|
|
1610
|
-
out.openStrokes++;
|
|
1611
|
-
if (r.inert) continue;
|
|
1612
|
-
out.interactive++;
|
|
1613
|
-
if (isFinite(r.w) && r.w > out.widestPx) out.widestPx = Math.round(r.w);
|
|
1614
|
-
if (!(r.w < MIN_HIT_BAND_PX)) continue;
|
|
1615
|
-
out.hairline++;
|
|
1616
|
-
const best = widestByGeom.get(r.geom);
|
|
1617
|
-
if (best === void 0 || best < MIN_HIT_BAND_PX) out.uncovered++;
|
|
1618
|
-
}
|
|
1619
|
-
return out;
|
|
1620
|
-
} catch {
|
|
1621
|
-
return EMPTY3;
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
function hitBandFlag(c) {
|
|
1625
|
-
if (c.interactive === 0) return "";
|
|
1626
|
-
return c.uncovered > 0 ? "hitband:d3:thin" : "hitband:d3:ok";
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
1126
|
// src/clippedText.ts
|
|
1630
1127
|
var CLIP_TOLERANCE_PX = 1;
|
|
1631
1128
|
var MAX_REPORTED = 8;
|
|
@@ -1671,11 +1168,11 @@ function clippedTextFlag(c) {
|
|
|
1671
1168
|
|
|
1672
1169
|
// src/valuePlacement.ts
|
|
1673
1170
|
var MIN_MARKS2 = 24;
|
|
1674
|
-
var
|
|
1171
|
+
var ELEMENT_CAP2 = 5e3;
|
|
1675
1172
|
var FIT_SAMPLE = 90;
|
|
1676
1173
|
var VALUE_AXIS_MIN_FIT = 0.8;
|
|
1677
1174
|
var MIN_AXIS_SPAN_PX = 40;
|
|
1678
|
-
var
|
|
1175
|
+
var EMPTY3 = { marks: 0, axis: "", column: "", fit: 0, offShare: 0, medianOffRadii: 0 };
|
|
1679
1176
|
function num(el, name) {
|
|
1680
1177
|
const v = el.getAttribute?.(name);
|
|
1681
1178
|
if (v === null || v === void 0 || String(v).trim() === "") return NaN;
|
|
@@ -1708,12 +1205,12 @@ function robustLine(v, pos) {
|
|
|
1708
1205
|
}
|
|
1709
1206
|
function censusValuePlacement(container, data) {
|
|
1710
1207
|
try {
|
|
1711
|
-
if (!container || typeof container.querySelectorAll !== "function") return
|
|
1208
|
+
if (!container || typeof container.querySelectorAll !== "function") return EMPTY3;
|
|
1712
1209
|
const rows = data?.rows;
|
|
1713
1210
|
const columns = data?.columns ?? [];
|
|
1714
|
-
if (!Array.isArray(rows) || !rows.length || !columns.length) return
|
|
1211
|
+
if (!Array.isArray(rows) || !rows.length || !columns.length) return EMPTY3;
|
|
1715
1212
|
const els = Array.from(container.querySelectorAll(`circle[${ROW_IDX_ATTR}]`));
|
|
1716
|
-
if (els.length < MIN_MARKS2 || els.length >
|
|
1213
|
+
if (els.length < MIN_MARKS2 || els.length > ELEMENT_CAP2) return EMPTY3;
|
|
1717
1214
|
const dots = [];
|
|
1718
1215
|
const seen = /* @__PURE__ */ new Set();
|
|
1719
1216
|
for (const el of els) {
|
|
@@ -1726,7 +1223,7 @@ function censusValuePlacement(container, data) {
|
|
|
1726
1223
|
seen.add(i);
|
|
1727
1224
|
dots.push({ row, x, y, r });
|
|
1728
1225
|
}
|
|
1729
|
-
if (dots.length < MIN_MARKS2 || seen.size < dots.length * 0.9) return
|
|
1226
|
+
if (dots.length < MIN_MARKS2 || seen.size < dots.length * 0.9) return EMPTY3;
|
|
1730
1227
|
let best = null;
|
|
1731
1228
|
for (let c = 0; c < columns.length; c++) {
|
|
1732
1229
|
if (/^__.*__$/.test(String(columns[c]?.name ?? ""))) continue;
|
|
@@ -1771,7 +1268,7 @@ function censusValuePlacement(container, data) {
|
|
|
1771
1268
|
}
|
|
1772
1269
|
}
|
|
1773
1270
|
}
|
|
1774
|
-
if (!best) return
|
|
1271
|
+
if (!best) return EMPTY3;
|
|
1775
1272
|
let off = 0, measured = 0;
|
|
1776
1273
|
const radii = [];
|
|
1777
1274
|
dots.forEach((d, k) => {
|
|
@@ -1782,7 +1279,7 @@ function censusValuePlacement(container, data) {
|
|
|
1782
1279
|
radii.push(inRadii);
|
|
1783
1280
|
if (inRadii > 1) off++;
|
|
1784
1281
|
});
|
|
1785
|
-
if (measured < MIN_MARKS2) return
|
|
1282
|
+
if (measured < MIN_MARKS2) return EMPTY3;
|
|
1786
1283
|
return {
|
|
1787
1284
|
marks: measured,
|
|
1788
1285
|
axis: best.axis,
|
|
@@ -1792,7 +1289,7 @@ function censusValuePlacement(container, data) {
|
|
|
1792
1289
|
medianOffRadii: Math.round(median(radii) * 100) / 100
|
|
1793
1290
|
};
|
|
1794
1291
|
} catch {
|
|
1795
|
-
return
|
|
1292
|
+
return EMPTY3;
|
|
1796
1293
|
}
|
|
1797
1294
|
}
|
|
1798
1295
|
function valuePlacementFlag(c) {
|
|
@@ -2036,7 +1533,7 @@ function fitReadingFor(lane, c, slackPx = SCROLL_SLACK_PX, inkOf) {
|
|
|
2036
1533
|
}
|
|
2037
1534
|
var noPin = (reason) => ({ pinned: false, reason, bandPx: 0, axisAt: "", labels: 0, carried: 0, edge: null });
|
|
2038
1535
|
var CONTAINER_SLOT_AXIS_PIN = "__bicAxisPin";
|
|
2039
|
-
var
|
|
1536
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
2040
1537
|
var AXIS_PIN_MAX_CARRIED = 12;
|
|
2041
1538
|
function unpinScrolledAxis(container) {
|
|
2042
1539
|
if (!container) return;
|
|
@@ -2174,7 +1671,7 @@ function pinScrolledAxis(container, svg) {
|
|
|
2174
1671
|
if (!(r.right > r.left) || !(r.bottom > r.top)) continue;
|
|
2175
1672
|
if (r.top >= band.top && r.bottom <= band.bottom) carried.push(t);
|
|
2176
1673
|
}
|
|
2177
|
-
const pinSvg = doc.createElementNS(
|
|
1674
|
+
const pinSvg = doc.createElementNS(SVG_NS, "svg");
|
|
2178
1675
|
for (const a of ["font-family", "font-size", "font-weight", "font", "fill", "color", "text-rendering"]) {
|
|
2179
1676
|
const v = svg.getAttribute(a);
|
|
2180
1677
|
if (v) pinSvg.setAttribute(a, v);
|
|
@@ -2190,7 +1687,7 @@ function pinScrolledAxis(container, svg) {
|
|
|
2190
1687
|
pinSvg.setAttribute("aria-hidden", "true");
|
|
2191
1688
|
pinSvg.style.display = "block";
|
|
2192
1689
|
pinSvg.style.pointerEvents = "none";
|
|
2193
|
-
const back = doc.createElementNS(
|
|
1690
|
+
const back = doc.createElementNS(SVG_NS, "rect");
|
|
2194
1691
|
back.setAttribute("x", String(vbX));
|
|
2195
1692
|
back.setAttribute("y", String(vbY));
|
|
2196
1693
|
back.setAttribute("width", String(vbW));
|
|
@@ -2355,7 +1852,7 @@ function fitRenderedChart(container, opts = {}) {
|
|
|
2355
1852
|
// src/labelContrastDom.ts
|
|
2356
1853
|
var LABEL_CONTRAST_DONE_ATTR = "data-lch-contrast";
|
|
2357
1854
|
var LABEL_CONTRAST_CAP = 2e3;
|
|
2358
|
-
var
|
|
1855
|
+
var EMPTY4 = {
|
|
2359
1856
|
rects: 0,
|
|
2360
1857
|
scanned: 0,
|
|
2361
1858
|
fixed: 0,
|
|
@@ -2506,7 +2003,7 @@ function addPill(tx, fill) {
|
|
|
2506
2003
|
}
|
|
2507
2004
|
}
|
|
2508
2005
|
function applyLabelContrast(container, opts = {}) {
|
|
2509
|
-
const report = { ...
|
|
2006
|
+
const report = { ...EMPTY4 };
|
|
2510
2007
|
if (!container) {
|
|
2511
2008
|
report.skipped = "no-container";
|
|
2512
2009
|
return report;
|
|
@@ -3540,7 +3037,7 @@ function createChartHost(container, config) {
|
|
|
3540
3037
|
}
|
|
3541
3038
|
|
|
3542
3039
|
// src/group.ts
|
|
3543
|
-
var
|
|
3040
|
+
var EMPTY5 = Object.freeze({ sourceId: null, rows: Object.freeze([]) });
|
|
3544
3041
|
function toSourceRows(rowMap, payloadRowIdxs) {
|
|
3545
3042
|
if (!rowMap) return payloadRowIdxs.slice();
|
|
3546
3043
|
return payloadRowIdxs.map((i) => rowMap[i]).filter((i) => i !== void 0);
|
|
@@ -3578,7 +3075,7 @@ function createChartGroup(columns, rows, opts = {}) {
|
|
|
3578
3075
|
let geo = opts.geo ?? null;
|
|
3579
3076
|
let point = opts.point ?? null;
|
|
3580
3077
|
let destination = opts.destination ?? null;
|
|
3581
|
-
let selection =
|
|
3078
|
+
let selection = EMPTY5;
|
|
3582
3079
|
const subs = /* @__PURE__ */ new Set();
|
|
3583
3080
|
const members = /* @__PURE__ */ new Set();
|
|
3584
3081
|
const notify = (change) => {
|
|
@@ -3731,26 +3228,9 @@ export {
|
|
|
3731
3228
|
clearGeoCache,
|
|
3732
3229
|
buildRenderPayload,
|
|
3733
3230
|
stripJsComments,
|
|
3734
|
-
rowIdxsFromMark,
|
|
3735
|
-
nextSelection,
|
|
3736
|
-
selectionRuleOf,
|
|
3737
|
-
markKeyOf,
|
|
3738
|
-
sameRowSet,
|
|
3739
|
-
planSelectionPaint,
|
|
3740
|
-
nextClickedMarks,
|
|
3741
|
-
isInsideControl,
|
|
3742
|
-
createMarkResolver,
|
|
3743
|
-
collectD3GlyphCenters,
|
|
3744
|
-
SELECTION_GLYPH_CLASS,
|
|
3745
|
-
clearSelectionGlyphs,
|
|
3746
|
-
paintSelectionGlyphs,
|
|
3747
|
-
ensureCrossfilterHitTargets,
|
|
3748
3231
|
censusMarks,
|
|
3749
3232
|
isBlankRender,
|
|
3750
3233
|
blankRenderFlag,
|
|
3751
|
-
MIN_HIT_BAND_PX,
|
|
3752
|
-
censusHitBands,
|
|
3753
|
-
hitBandFlag,
|
|
3754
3234
|
CLIP_TOLERANCE_PX,
|
|
3755
3235
|
censusClippedText,
|
|
3756
3236
|
clippedTextFlag,
|