@bicharts/chart-host 0.6.56 → 0.6.58
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/{chunk-CMHGGW3Y.mjs → chunk-5NSU3MYW.mjs} +41 -110
- package/dist/chunk-WNGJUPEI.mjs +114 -0
- package/dist/chunk-ZEZXNAFL.mjs +467 -0
- package/dist/dax.mjs +60 -0
- package/dist/geo.mjs +3 -3
- package/dist/index.mjs +49 -47
- package/dist/page.mjs +28 -0
- package/dist/react.mjs +207 -8
- package/dist/testing.mjs +46 -1
- package/dist/types/controls.d.ts +50 -0
- package/dist/types/dax.d.ts +22 -0
- package/dist/types/filterScope.d.ts +133 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/markNotes.d.ts +30 -0
- package/dist/types/page.d.ts +3 -0
- package/dist/types/react.d.ts +73 -2
- package/dist/types/testing/index.d.ts +1 -0
- package/dist/types/testing/interact.d.ts +17 -0
- package/package.json +11 -1
|
@@ -0,0 +1,467 @@
|
|
|
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
|
+
|
|
3
|
+
// src/filterScope.ts
|
|
4
|
+
function keyString(values) {
|
|
5
|
+
return JSON.stringify(values.map((v) => v instanceof Date ? `__date:${v.getTime()}` : v === void 0 ? null : v));
|
|
6
|
+
}
|
|
7
|
+
function keyOfRow(row, columns) {
|
|
8
|
+
return columns.map((c) => row?.[c]);
|
|
9
|
+
}
|
|
10
|
+
function toKeys(input, width) {
|
|
11
|
+
if (input == null) return [];
|
|
12
|
+
if (!Array.isArray(input)) return width === 1 ? [[input]] : [];
|
|
13
|
+
if (input.length === 0) return [];
|
|
14
|
+
if (width === 1) return input.map((v) => Array.isArray(v) ? [v[0]] : [v]);
|
|
15
|
+
if (input.every((v) => Array.isArray(v))) return input.map((v) => v.slice(0, width));
|
|
16
|
+
return input.length === width ? [input.slice()] : [];
|
|
17
|
+
}
|
|
18
|
+
var nextId = 0;
|
|
19
|
+
function createFilter(columns, opts = {}) {
|
|
20
|
+
const cols = Array.isArray(columns) ? columns.slice() : [columns];
|
|
21
|
+
if (!cols.length || cols.some((c) => typeof c !== "string" || !c)) {
|
|
22
|
+
throw new Error('createFilter: name the key column(s), e.g. createFilter("RegionCode")');
|
|
23
|
+
}
|
|
24
|
+
const display = opts.display == null ? cols : Array.isArray(opts.display) ? opts.display.slice() : [opts.display];
|
|
25
|
+
let keys = [];
|
|
26
|
+
let keySet = /* @__PURE__ */ new Set();
|
|
27
|
+
let rows = [];
|
|
28
|
+
let reason = null;
|
|
29
|
+
let version = 0;
|
|
30
|
+
const subs = /* @__PURE__ */ new Set();
|
|
31
|
+
const kept = /* @__PURE__ */ new WeakMap();
|
|
32
|
+
const commit = (nextKeys, nextRows, why) => {
|
|
33
|
+
const nextSet = new Set(nextKeys.map(keyString));
|
|
34
|
+
if (nextSet.size === keySet.size && [...nextSet].every((k) => keySet.has(k))) {
|
|
35
|
+
if (nextRows.length) rows = nextRows;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
keys = nextKeys;
|
|
39
|
+
keySet = nextSet;
|
|
40
|
+
rows = nextRows;
|
|
41
|
+
reason = why;
|
|
42
|
+
version++;
|
|
43
|
+
for (const cb of Array.from(subs)) cb(filter, why);
|
|
44
|
+
};
|
|
45
|
+
const dedupe = (ks) => {
|
|
46
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
47
|
+
return ks.filter((k) => {
|
|
48
|
+
const s = keyString(k);
|
|
49
|
+
if (seen2.has(s)) return false;
|
|
50
|
+
seen2.add(s);
|
|
51
|
+
return true;
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
const seen = /* @__PURE__ */ new Map();
|
|
55
|
+
const remember = (list) => {
|
|
56
|
+
for (const r of list) seen.set(keyString(keyOfRow(r, cols)), r);
|
|
57
|
+
};
|
|
58
|
+
const displayOf = (k, more) => {
|
|
59
|
+
const s = keyString(k);
|
|
60
|
+
const row = (more ?? []).find((r) => keyString(keyOfRow(r, cols)) === s) ?? seen.get(s);
|
|
61
|
+
const parts = row ? display.map((d) => row[d]) : k;
|
|
62
|
+
const text = parts.filter((p) => p != null && p !== "").map(String).join(" \u2192 ");
|
|
63
|
+
return text || k.filter((p) => p != null && p !== "").map(String).join(" \u2192 ");
|
|
64
|
+
};
|
|
65
|
+
let warnedKeep = false;
|
|
66
|
+
const filter = {
|
|
67
|
+
id: opts.id ?? `f${++nextId}`,
|
|
68
|
+
columns: cols,
|
|
69
|
+
label: opts.label ?? cols.join(" / "),
|
|
70
|
+
get active() {
|
|
71
|
+
return keys.length > 0;
|
|
72
|
+
},
|
|
73
|
+
get keys() {
|
|
74
|
+
return keys;
|
|
75
|
+
},
|
|
76
|
+
get rows() {
|
|
77
|
+
return rows;
|
|
78
|
+
},
|
|
79
|
+
get row() {
|
|
80
|
+
return rows[0] ?? null;
|
|
81
|
+
},
|
|
82
|
+
get value() {
|
|
83
|
+
return keys.length ? keys[0][0] : null;
|
|
84
|
+
},
|
|
85
|
+
get values() {
|
|
86
|
+
return keys.map((k) => k[0]);
|
|
87
|
+
},
|
|
88
|
+
get text() {
|
|
89
|
+
return keys.map((k) => displayOf(k)).join(", ");
|
|
90
|
+
},
|
|
91
|
+
textOf(key, more) {
|
|
92
|
+
const k = Array.isArray(key) ? key : [key];
|
|
93
|
+
return displayOf(k.slice(0, cols.length), more);
|
|
94
|
+
},
|
|
95
|
+
get reason() {
|
|
96
|
+
return reason;
|
|
97
|
+
},
|
|
98
|
+
get version() {
|
|
99
|
+
return version;
|
|
100
|
+
},
|
|
101
|
+
selectRows(selected, why = "page") {
|
|
102
|
+
const list = (selected ?? []).filter((r) => r && typeof r === "object");
|
|
103
|
+
remember(list);
|
|
104
|
+
commit(dedupe(list.map((r) => keyOfRow(r, cols))), list, why);
|
|
105
|
+
},
|
|
106
|
+
set(input, why = "page") {
|
|
107
|
+
const ks = dedupe(toKeys(input, cols.length));
|
|
108
|
+
const want = new Set(ks.map(keyString));
|
|
109
|
+
commit(ks, rows.filter((r) => want.has(keyString(keyOfRow(r, cols)))), why);
|
|
110
|
+
},
|
|
111
|
+
clear(why = "page") {
|
|
112
|
+
commit([], [], why);
|
|
113
|
+
},
|
|
114
|
+
has(row, on) {
|
|
115
|
+
if (!keys.length || !row) return false;
|
|
116
|
+
const where = on && on.length ? on : cols;
|
|
117
|
+
if (cols.length === 1 && where.length > 1) {
|
|
118
|
+
return where.some((c) => keySet.has(keyString([row[c]])));
|
|
119
|
+
}
|
|
120
|
+
return keySet.has(keyString(keyOfRow(row, where)));
|
|
121
|
+
},
|
|
122
|
+
keep(input, on) {
|
|
123
|
+
const list = input ?? [];
|
|
124
|
+
const colKey = (on ?? cols).join("");
|
|
125
|
+
const hit = kept.get(list);
|
|
126
|
+
if (hit && hit.version === version && hit.cols === colKey) return hit.out;
|
|
127
|
+
const where = on && on.length ? on : cols;
|
|
128
|
+
if (keys.length && list.length && !warnedKeep && !list.some((r) => r && where.some((c) => c in r))) {
|
|
129
|
+
warnedKeep = true;
|
|
130
|
+
try {
|
|
131
|
+
console.warn(`[chart-host] filter "${filter.label}": these rows have no ${where.join(" / ")} column, so keep() drops them all - filter their query (filterQuery + treatAs) or add the key column.`);
|
|
132
|
+
} catch {
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const out = keys.length ? list.filter((r) => filter.has(r, on)) : list.slice();
|
|
136
|
+
kept.set(list, { version, cols: colKey, out });
|
|
137
|
+
return out;
|
|
138
|
+
},
|
|
139
|
+
onChange(cb) {
|
|
140
|
+
subs.add(cb);
|
|
141
|
+
return () => {
|
|
142
|
+
subs.delete(cb);
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
return filter;
|
|
147
|
+
}
|
|
148
|
+
function createFilterScope() {
|
|
149
|
+
const list = [];
|
|
150
|
+
const offs = /* @__PURE__ */ new Map();
|
|
151
|
+
const subs = /* @__PURE__ */ new Set();
|
|
152
|
+
const notify = () => {
|
|
153
|
+
for (const cb of Array.from(subs)) cb(scope);
|
|
154
|
+
};
|
|
155
|
+
const scope = {
|
|
156
|
+
get filters() {
|
|
157
|
+
return list.slice();
|
|
158
|
+
},
|
|
159
|
+
get active() {
|
|
160
|
+
return list.filter((f) => f.active);
|
|
161
|
+
},
|
|
162
|
+
filter(columns, opts) {
|
|
163
|
+
const f = createFilter(columns, opts);
|
|
164
|
+
scope.add(f);
|
|
165
|
+
return f;
|
|
166
|
+
},
|
|
167
|
+
add(f) {
|
|
168
|
+
if (!offs.has(f)) {
|
|
169
|
+
list.push(f);
|
|
170
|
+
offs.set(f, f.onChange(() => notify()));
|
|
171
|
+
notify();
|
|
172
|
+
}
|
|
173
|
+
return () => {
|
|
174
|
+
const off = offs.get(f);
|
|
175
|
+
if (!off) return;
|
|
176
|
+
off();
|
|
177
|
+
offs.delete(f);
|
|
178
|
+
const i = list.indexOf(f);
|
|
179
|
+
if (i >= 0) list.splice(i, 1);
|
|
180
|
+
notify();
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
clearAll(why = "page") {
|
|
184
|
+
for (const f of list.slice()) f.clear(why);
|
|
185
|
+
},
|
|
186
|
+
onChange(cb) {
|
|
187
|
+
subs.add(cb);
|
|
188
|
+
return () => {
|
|
189
|
+
subs.delete(cb);
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
return scope;
|
|
194
|
+
}
|
|
195
|
+
function payloadRowReader(getPayload) {
|
|
196
|
+
return {
|
|
197
|
+
rowAt(i) {
|
|
198
|
+
const p = getPayload();
|
|
199
|
+
const r = p?.rows?.[i];
|
|
200
|
+
if (!p || !r) return null;
|
|
201
|
+
const o = {};
|
|
202
|
+
p.columns.forEach((c, k) => {
|
|
203
|
+
o[c.name] = r[k];
|
|
204
|
+
});
|
|
205
|
+
return o;
|
|
206
|
+
},
|
|
207
|
+
rowCount() {
|
|
208
|
+
return getPayload()?.rows?.length ?? 0;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
var sortedEq = (a, b) => {
|
|
213
|
+
if (a.length !== b.length) return false;
|
|
214
|
+
const x = a.slice().sort((p, q) => p - q), y = b.slice().sort((p, q) => p - q);
|
|
215
|
+
return x.every((v, i) => v === y[i]);
|
|
216
|
+
};
|
|
217
|
+
function bindFilter(host, filter, opts) {
|
|
218
|
+
const token = {};
|
|
219
|
+
const ownerKeys = () => keysString(filter.keys);
|
|
220
|
+
const isMine = () => {
|
|
221
|
+
const o = owners.get(filter);
|
|
222
|
+
return !!o && o.token === token && o.keys === ownerKeys();
|
|
223
|
+
};
|
|
224
|
+
{
|
|
225
|
+
const o = owners.get(filter);
|
|
226
|
+
if (o && o.orphan && o.keys === ownerKeys()) owners.set(filter, { token, keys: o.keys, orphan: false });
|
|
227
|
+
}
|
|
228
|
+
const wanted = () => {
|
|
229
|
+
if (!filter.active) return [];
|
|
230
|
+
const out = [];
|
|
231
|
+
const n = opts.rowCount();
|
|
232
|
+
for (let i = 0; i < n; i++) {
|
|
233
|
+
const r = opts.rowAt(i);
|
|
234
|
+
if (r && filter.has(r)) out.push(i);
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
};
|
|
238
|
+
const paint = () => {
|
|
239
|
+
const want = wanted();
|
|
240
|
+
const cur = host.selection.current ?? [];
|
|
241
|
+
if (sortedEq(want, cur)) return;
|
|
242
|
+
if (want.length) host.selection.highlight(want);
|
|
243
|
+
else if (cur.length) host.selection.clear();
|
|
244
|
+
};
|
|
245
|
+
const offHost = host.selection.onChange((idxs, source) => {
|
|
246
|
+
if (source === "host") return;
|
|
247
|
+
if (!idxs.length) {
|
|
248
|
+
if (filter.active) filter.clear("clear");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const rows = idxs.map((i) => opts.rowAt(i)).filter((r) => !!r);
|
|
252
|
+
if (!rows.length) return;
|
|
253
|
+
filter.selectRows(rows, "click");
|
|
254
|
+
owners.set(filter, { token, keys: ownerKeys(), orphan: false });
|
|
255
|
+
});
|
|
256
|
+
const offFilter = filter.onChange(() => {
|
|
257
|
+
const o = owners.get(filter);
|
|
258
|
+
if (o && o.keys !== ownerKeys()) owners.delete(filter);
|
|
259
|
+
paint();
|
|
260
|
+
});
|
|
261
|
+
return {
|
|
262
|
+
reconcile() {
|
|
263
|
+
if (filter.active && opts.rowCount() > 0 && isMine()) {
|
|
264
|
+
const drawn = /* @__PURE__ */ new Set();
|
|
265
|
+
const n = opts.rowCount();
|
|
266
|
+
for (let i = 0; i < n; i++) {
|
|
267
|
+
const r = opts.rowAt(i);
|
|
268
|
+
if (r) drawn.add(keyString(keyOfRow(r, filter.columns)));
|
|
269
|
+
}
|
|
270
|
+
const keep = filter.keys.filter((k) => drawn.has(keyString(k)));
|
|
271
|
+
if (keep.length !== filter.keys.length) {
|
|
272
|
+
filter.set(keep, "data");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
paint();
|
|
277
|
+
},
|
|
278
|
+
paint,
|
|
279
|
+
detach() {
|
|
280
|
+
offHost();
|
|
281
|
+
offFilter();
|
|
282
|
+
const o = owners.get(filter);
|
|
283
|
+
if (o && o.token === token) owners.set(filter, { ...o, orphan: true });
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
var owners = /* @__PURE__ */ new WeakMap();
|
|
288
|
+
var keysString = (keys) => keys.map((k) => keyString(k)).sort().join("|");
|
|
289
|
+
function fromVegaInteraction(filter, events) {
|
|
290
|
+
const before = filter.version;
|
|
291
|
+
for (const ev of events ?? []) {
|
|
292
|
+
if (ev?.action === "clear") {
|
|
293
|
+
filter.clear("clear");
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (ev?.action !== "select") continue;
|
|
297
|
+
const keys = [];
|
|
298
|
+
for (const sel of ev.selections ?? []) {
|
|
299
|
+
const preds = sel?.predicates ?? [];
|
|
300
|
+
const key = filter.columns.map((c) => {
|
|
301
|
+
const p = preds.find((q) => q?.name === c && (q.type === void 0 || q.type === "set"));
|
|
302
|
+
return p && p.values && p.values.length ? p.values[0] : void 0;
|
|
303
|
+
});
|
|
304
|
+
if (key.every((v) => v !== void 0)) keys.push(key);
|
|
305
|
+
}
|
|
306
|
+
if (keys.length) filter.set(keys, "click");
|
|
307
|
+
}
|
|
308
|
+
return filter.version !== before;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/controls.ts
|
|
312
|
+
var same = (a, b) => a.length === b.length && a.every((x, i) => x.key === b[i].key && x.label === b[i].label && x.text === b[i].text && JSON.stringify(x.value) === JSON.stringify(b[i].value));
|
|
313
|
+
function createControls(initial) {
|
|
314
|
+
const ui = initial ? { knobs: { ...initial } } : {};
|
|
315
|
+
let info = [];
|
|
316
|
+
let version = 0;
|
|
317
|
+
const subs = /* @__PURE__ */ new Set();
|
|
318
|
+
const appliers = /* @__PURE__ */ new Set();
|
|
319
|
+
const notify = () => {
|
|
320
|
+
version++;
|
|
321
|
+
for (const cb of Array.from(subs)) cb(c);
|
|
322
|
+
};
|
|
323
|
+
const c = {
|
|
324
|
+
get values() {
|
|
325
|
+
const out = {};
|
|
326
|
+
for (const i of info) out[i.key] = i.value;
|
|
327
|
+
if (!info.length && ui.knobs && typeof ui.knobs === "object") Object.assign(out, ui.knobs);
|
|
328
|
+
return out;
|
|
329
|
+
},
|
|
330
|
+
get info() {
|
|
331
|
+
return info;
|
|
332
|
+
},
|
|
333
|
+
get summary() {
|
|
334
|
+
return info.map((i) => [i.label, i.text].filter(Boolean).join(" ")).filter(Boolean).join(" \xB7 ");
|
|
335
|
+
},
|
|
336
|
+
get ready() {
|
|
337
|
+
return info.length > 0;
|
|
338
|
+
},
|
|
339
|
+
get version() {
|
|
340
|
+
return version;
|
|
341
|
+
},
|
|
342
|
+
set(values) {
|
|
343
|
+
const knobs = { ...ui.knobs ?? {}, ...values };
|
|
344
|
+
ui.knobs = knobs;
|
|
345
|
+
for (const a of Array.from(appliers)) a();
|
|
346
|
+
},
|
|
347
|
+
reset() {
|
|
348
|
+
delete ui.knobs;
|
|
349
|
+
for (const a of Array.from(appliers)) a();
|
|
350
|
+
},
|
|
351
|
+
onChange(cb) {
|
|
352
|
+
subs.add(cb);
|
|
353
|
+
return () => {
|
|
354
|
+
subs.delete(cb);
|
|
355
|
+
};
|
|
356
|
+
},
|
|
357
|
+
_ui: ui,
|
|
358
|
+
_attach(onApply) {
|
|
359
|
+
appliers.add(onApply);
|
|
360
|
+
return () => {
|
|
361
|
+
appliers.delete(onApply);
|
|
362
|
+
};
|
|
363
|
+
},
|
|
364
|
+
_report(next) {
|
|
365
|
+
if (same(info, next)) return;
|
|
366
|
+
info = next;
|
|
367
|
+
notify();
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
return c;
|
|
371
|
+
}
|
|
372
|
+
function readControls(container) {
|
|
373
|
+
const bag = container.__lchKnobs;
|
|
374
|
+
if (!bag || typeof bag !== "object") return [];
|
|
375
|
+
const keys = Object.keys(bag);
|
|
376
|
+
if (!keys.length) return [];
|
|
377
|
+
const groups = Array.from(container.querySelectorAll("g.llm-slider"));
|
|
378
|
+
return keys.map((key, i) => {
|
|
379
|
+
const g = groups.find((x) => x.getAttribute("data-knob") === key) ?? groups[i] ?? null;
|
|
380
|
+
const txt = (sel) => (g?.querySelector(sel)?.textContent ?? "").trim();
|
|
381
|
+
return { key, value: bag[key], label: txt(".llm-slider-label"), text: txt(".llm-slider-readout") };
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function attachControls(getHost, container, controls) {
|
|
385
|
+
const c = controls;
|
|
386
|
+
const read = () => c._report(readControls(container));
|
|
387
|
+
const setUiState = (s) => {
|
|
388
|
+
if (!s || typeof s !== "object") return;
|
|
389
|
+
for (const k of Object.keys(c._ui)) delete c._ui[k];
|
|
390
|
+
Object.assign(c._ui, s);
|
|
391
|
+
Promise.resolve().then(read);
|
|
392
|
+
};
|
|
393
|
+
const off = c._attach(() => {
|
|
394
|
+
const host = getHost();
|
|
395
|
+
if (!host) return;
|
|
396
|
+
host.setOptions({ uiState: c._ui });
|
|
397
|
+
host.rendered.then(read, () => {
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
return {
|
|
401
|
+
options: { uiState: c._ui, setUiState },
|
|
402
|
+
read,
|
|
403
|
+
detach: off
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// src/markNotes.ts
|
|
408
|
+
var keyText = (k) => JSON.stringify(k.map((v) => v == null ? "" : String(v).trim()));
|
|
409
|
+
function defaultKey(n, width) {
|
|
410
|
+
return width > 1 ? [n.markKey, n.markKeyTo] : [n.markKey];
|
|
411
|
+
}
|
|
412
|
+
function noteBadges(notes, opts) {
|
|
413
|
+
const cols = typeof opts.columns === "string" ? [opts.columns] : opts.columns.slice();
|
|
414
|
+
const keyOf = opts.keyOf ?? ((n) => defaultKey(n, cols.length));
|
|
415
|
+
const textOf = opts.textOf ?? ((n) => String(n.body ?? ""));
|
|
416
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
417
|
+
for (const n of notes ?? []) {
|
|
418
|
+
if (opts.chart !== void 0 && n.chart !== opts.chart) continue;
|
|
419
|
+
const key = keyOf(n).slice(0, cols.length);
|
|
420
|
+
if (key.length < cols.length || key.some((v) => v == null || v === "")) continue;
|
|
421
|
+
const id = keyText(key);
|
|
422
|
+
const hit = byKey.get(id);
|
|
423
|
+
if (hit) hit.list.push(n);
|
|
424
|
+
else byKey.set(id, { key, list: [n] });
|
|
425
|
+
}
|
|
426
|
+
return [...byKey.entries()].map(([id, { key, list }]) => {
|
|
427
|
+
const title = list.length > 1 ? `${textOf(list[0])} (+${list.length - 1} more)` : textOf(list[0]);
|
|
428
|
+
const base = { id, label: String(list.length), title };
|
|
429
|
+
if (cols.length === 1) return { ...base, column: cols[0], value: key[0] };
|
|
430
|
+
const where = {};
|
|
431
|
+
cols.forEach((c, i) => {
|
|
432
|
+
where[c] = key[i];
|
|
433
|
+
});
|
|
434
|
+
return { ...base, where };
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
function badgeKey(a) {
|
|
438
|
+
try {
|
|
439
|
+
const v = JSON.parse(String(a.id ?? ""));
|
|
440
|
+
if (Array.isArray(v)) return v;
|
|
441
|
+
} catch {
|
|
442
|
+
}
|
|
443
|
+
if (a.where) return Object.values(a.where);
|
|
444
|
+
return a.value !== void 0 ? [a.value] : [];
|
|
445
|
+
}
|
|
446
|
+
function notesFor(notes, key, opts) {
|
|
447
|
+
const cols = typeof opts.columns === "string" ? [opts.columns] : opts.columns.slice();
|
|
448
|
+
const want = !key ? null : Array.isArray(key) ? key : key.keys[0] ?? null;
|
|
449
|
+
if (!want) return [];
|
|
450
|
+
const keyOf = opts.keyOf ?? ((n) => defaultKey(n, cols.length));
|
|
451
|
+
const target = keyText(want.slice(0, cols.length));
|
|
452
|
+
return (notes ?? []).filter((n) => (opts.chart === void 0 || n.chart === opts.chart) && keyText(keyOf(n).slice(0, cols.length)) === target);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export {
|
|
456
|
+
createFilter,
|
|
457
|
+
createFilterScope,
|
|
458
|
+
payloadRowReader,
|
|
459
|
+
bindFilter,
|
|
460
|
+
fromVegaInteraction,
|
|
461
|
+
createControls,
|
|
462
|
+
readControls,
|
|
463
|
+
attachControls,
|
|
464
|
+
noteBadges,
|
|
465
|
+
badgeKey,
|
|
466
|
+
notesFor
|
|
467
|
+
};
|
package/dist/dax.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
import "./chunk-GHODWOAL.mjs";
|
|
3
|
+
|
|
4
|
+
// src/dax.ts
|
|
5
|
+
var COLUMN_REF = /^(?:'(?:[^']|'')+'|[A-Za-z_][A-Za-z0-9_]*)\[[^\]]+\]$/;
|
|
6
|
+
function daxLiteral(v) {
|
|
7
|
+
if (v == null) return "BLANK()";
|
|
8
|
+
if (typeof v === "boolean") return v ? "TRUE()" : "FALSE()";
|
|
9
|
+
if (typeof v === "number") {
|
|
10
|
+
if (!Number.isFinite(v)) throw new Error(`daxLiteral: ${v} has no DAX literal`);
|
|
11
|
+
return String(v);
|
|
12
|
+
}
|
|
13
|
+
if (typeof v === "bigint") return v.toString();
|
|
14
|
+
if (v instanceof Date) {
|
|
15
|
+
if (Number.isNaN(v.getTime())) throw new Error("daxLiteral: an invalid Date");
|
|
16
|
+
return `DATE(${v.getFullYear()}, ${v.getMonth() + 1}, ${v.getDate()})` + (v.getHours() || v.getMinutes() || v.getSeconds() ? ` + TIME(${v.getHours()}, ${v.getMinutes()}, ${v.getSeconds()})` : "");
|
|
17
|
+
}
|
|
18
|
+
return `"${String(v).replace(/"/g, '""')}"`;
|
|
19
|
+
}
|
|
20
|
+
function treatAs(selection, ...columnRefs) {
|
|
21
|
+
if (!columnRefs.length) throw new Error(`treatAs: name the model column, e.g. treatAs(region, "'Geography'[RegionCode]")`);
|
|
22
|
+
for (const c of columnRefs) {
|
|
23
|
+
if (!COLUMN_REF.test(c.trim())) throw new Error(`treatAs: "${c}" isn't a column reference like 'Table'[Column]`);
|
|
24
|
+
}
|
|
25
|
+
const keys = !selection ? [] : isFilter(selection) ? selection.keys.slice() : selection.map((k) => Array.isArray(k) ? k : [k]);
|
|
26
|
+
if (!keys.length) return null;
|
|
27
|
+
const width = columnRefs.length;
|
|
28
|
+
for (const k of keys) {
|
|
29
|
+
if (k.length < width) throw new Error(`treatAs: a key has ${k.length} value(s) for ${width} column(s)`);
|
|
30
|
+
}
|
|
31
|
+
const rows = keys.map((k) => width === 1 ? daxLiteral(k[0]) : `(${k.slice(0, width).map(daxLiteral).join(", ")})`);
|
|
32
|
+
return `TREATAS({${rows.join(", ")}}, ${columnRefs.map((c) => c.trim()).join(", ")})`;
|
|
33
|
+
}
|
|
34
|
+
function calculateTable(table, ...filters) {
|
|
35
|
+
const live = filters.filter((f) => typeof f === "string" && f.trim().length > 0);
|
|
36
|
+
return live.length ? `CALCULATETABLE(
|
|
37
|
+
${table},
|
|
38
|
+
${live.join(",\n")}
|
|
39
|
+
)` : table;
|
|
40
|
+
}
|
|
41
|
+
function filterQuery(query, ...filters) {
|
|
42
|
+
const live = filters.filter((f) => typeof f === "string" && f.trim().length > 0);
|
|
43
|
+
if (!live.length) return query;
|
|
44
|
+
const evals = query.match(/\bEVALUATE\b/gi) ?? [];
|
|
45
|
+
if (evals.length !== 1) throw new Error(`filterQuery: expected one EVALUATE, found ${evals.length}`);
|
|
46
|
+
const m = /^([\s\S]*?\bEVALUATE\b)([\s\S]*?)(\bORDER\s+BY\b[\s\S]*)?$/i.exec(query);
|
|
47
|
+
const head = m[1], table = m[2].trim(), tail = m[3] ?? "";
|
|
48
|
+
return `${head}
|
|
49
|
+
${calculateTable(table, ...live)}
|
|
50
|
+
${tail}`.replace(/\n$/, "");
|
|
51
|
+
}
|
|
52
|
+
function isFilter(x) {
|
|
53
|
+
return !!x && typeof x === "object" && Array.isArray(x.keys) && typeof x.has === "function";
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
calculateTable,
|
|
57
|
+
daxLiteral,
|
|
58
|
+
filterQuery,
|
|
59
|
+
treatAs
|
|
60
|
+
};
|
package/dist/geo.mjs
CHANGED
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
WORLD_110M
|
|
9
9
|
} from "./chunk-ABGDJ3NJ.mjs";
|
|
10
|
-
import {
|
|
11
|
-
US_ZIP3
|
|
12
|
-
} from "./chunk-D3N3JUMK.mjs";
|
|
13
10
|
import {
|
|
14
11
|
US_STATES
|
|
15
12
|
} from "./chunk-75ZJSYIF.mjs";
|
|
13
|
+
import {
|
|
14
|
+
US_ZIP3
|
|
15
|
+
} from "./chunk-D3N3JUMK.mjs";
|
|
16
16
|
import "./chunk-GHODWOAL.mjs";
|
|
17
17
|
|
|
18
18
|
// src/geo.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,63 +1,28 @@
|
|
|
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
|
import {
|
|
3
|
-
ACTIVE_TICK_CLASS,
|
|
4
|
-
ANIMATION_OPTION_KEYS,
|
|
5
|
-
ANIM_LOOP_DELAY_DEFAULT,
|
|
6
|
-
ANIM_LOOP_DELAY_MIN,
|
|
7
|
-
ANIM_MAX_IDEAL_FRAMES_DEFAULT,
|
|
8
|
-
ANIM_MAX_IDEAL_FRAMES_MAX,
|
|
9
|
-
ANIM_MAX_IDEAL_FRAMES_MIN,
|
|
10
|
-
ANIM_PLAY_SPEED_DEFAULT,
|
|
11
|
-
ANIM_PLAY_SPEED_MAX,
|
|
12
|
-
ANIM_PLAY_SPEED_MIN,
|
|
13
3
|
ANNOTATION_CLASS,
|
|
14
4
|
ANNOTATION_LAYER_CLASS,
|
|
15
|
-
APPROXIMATE_POSITIONS_DEFAULT,
|
|
16
5
|
AUTO_RAMP_CLASSES,
|
|
17
6
|
AUTO_RAMP_DRAWN_OPACITY,
|
|
18
7
|
AUTO_RAMP_MIN_STEP_DELTA_E,
|
|
19
|
-
AXIS_FILTER_CLASS,
|
|
20
8
|
AXIS_PIN_BAND_PAD_PX,
|
|
21
9
|
AXIS_PIN_MAX_BAND_FRACTION,
|
|
22
10
|
AXIS_PIN_MIN_LABELS,
|
|
23
11
|
AXIS_PIN_TRACK_REACH_PX,
|
|
24
12
|
BACKING_MAJORITY,
|
|
25
|
-
COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT,
|
|
26
|
-
COLOR_SCALE_SELF_CLAMP_PCT_MAX,
|
|
27
|
-
COLOR_SCALE_SELF_CLAMP_PCT_MIN,
|
|
28
|
-
CONTAINER_SLOT_ANIM_STOP,
|
|
29
|
-
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
30
|
-
CONTAINER_SLOT_UI_STATE,
|
|
31
|
-
CONTAINER_SLOT_XF_CLEAR,
|
|
32
|
-
CONTROL_CLASS,
|
|
33
13
|
D3_PLUGIN_PACKAGES,
|
|
34
14
|
DARK_TEXT,
|
|
35
|
-
DIM_OPACITY_DEFAULT,
|
|
36
|
-
DIM_OPACITY_VAR,
|
|
37
15
|
FIT_CONTENT_SELECTOR,
|
|
38
|
-
FLIP_DIRECTION_DEFAULT,
|
|
39
|
-
FLIP_INTERVAL_MAX_MS,
|
|
40
|
-
FLIP_INTERVAL_MIN_MS,
|
|
41
|
-
FLIP_MODE_DEFAULT,
|
|
42
|
-
GEO_POINT_PRECISIONS,
|
|
43
16
|
GLYPH_SAMPLE_N,
|
|
44
|
-
HOST_CONTAINER_CLASS,
|
|
45
|
-
HOST_CONTRACT_VERSION,
|
|
46
17
|
L,
|
|
47
18
|
LABEL_CONTRAST_CAP,
|
|
48
19
|
LABEL_CONTRAST_DONE_ATTR,
|
|
49
20
|
LABEL_PILL_CLASS,
|
|
50
|
-
LEGEND_MARK_CLASS,
|
|
51
|
-
LIFT_SELECTED_CLASS,
|
|
52
21
|
LIGHT_TEXT,
|
|
53
|
-
MARK_CLASS,
|
|
54
|
-
MARK_SELECTED_CLASS,
|
|
55
22
|
MAX_FRAME_GROW_FACTOR,
|
|
56
|
-
MAX_MAP_POINTS_DEFAULT,
|
|
57
23
|
MIN_CONTRAST,
|
|
58
24
|
MIN_HIT_BAND_PX,
|
|
59
25
|
MIN_RAMP_FILLS,
|
|
60
|
-
NO_ROW_MARKS_ATTR,
|
|
61
26
|
PAGE_MATCH_TOLERANCE,
|
|
62
27
|
PHANTOM_FRACTION,
|
|
63
28
|
PILL_MIN_ALPHA,
|
|
@@ -65,23 +30,16 @@ import {
|
|
|
65
30
|
PILL_OPAQUE_ALPHA,
|
|
66
31
|
Qe,
|
|
67
32
|
Qn,
|
|
68
|
-
ROW_IDX_ATTR,
|
|
69
33
|
SAME_SHADE_DELTA_E,
|
|
70
34
|
SCROLL_SLACK_PX,
|
|
71
|
-
SEASONAL_MARKERS_DEFAULT,
|
|
72
|
-
SELECTION_ACTIVE_CLASS,
|
|
73
35
|
SELECTION_GLYPH_CLASS,
|
|
74
|
-
SNAPSHOT_SVG_ATTR,
|
|
75
36
|
STRADDLE_COLS,
|
|
76
37
|
STRADDLE_MIN_SHARE,
|
|
77
38
|
STRADDLE_PILL_ALPHA,
|
|
78
39
|
STRADDLE_ROWS,
|
|
79
40
|
STRADDLE_TARGET_CONTRAST,
|
|
80
|
-
VALUE_AXIS_BASELINE_DEFAULT,
|
|
81
41
|
VALUE_AXIS_MIN_FIT,
|
|
82
|
-
VIEW_ONLY_UI_STATE_KEYS,
|
|
83
42
|
WHITE_TEXT_BG_LUM,
|
|
84
|
-
XFILTER_REFRESH_EVENT,
|
|
85
43
|
Zn,
|
|
86
44
|
_3,
|
|
87
45
|
applyLabelContrast,
|
|
@@ -97,7 +55,6 @@ import {
|
|
|
97
55
|
censusHitBands,
|
|
98
56
|
censusMarks,
|
|
99
57
|
censusValuePlacement,
|
|
100
|
-
chartOwnsTimeline,
|
|
101
58
|
clearGeoCache,
|
|
102
59
|
clearSelectionGlyphs,
|
|
103
60
|
collectD3GlyphCenters,
|
|
@@ -138,7 +95,6 @@ import {
|
|
|
138
95
|
noopViewStateProvider,
|
|
139
96
|
o,
|
|
140
97
|
paintSelectionGlyphs,
|
|
141
|
-
periodTickSuppressesFeedback,
|
|
142
98
|
pickColorOver,
|
|
143
99
|
pillBacksGlyph,
|
|
144
100
|
pinScrolledAxis,
|
|
@@ -163,10 +119,56 @@ import {
|
|
|
163
119
|
toRGBA,
|
|
164
120
|
toSourceRows,
|
|
165
121
|
unpinScrolledAxis,
|
|
166
|
-
valuePlacementFlag
|
|
167
|
-
|
|
168
|
-
} from "./chunk-CMHGGW3Y.mjs";
|
|
122
|
+
valuePlacementFlag
|
|
123
|
+
} from "./chunk-5NSU3MYW.mjs";
|
|
169
124
|
import "./chunk-A2GMXZP7.mjs";
|
|
125
|
+
import {
|
|
126
|
+
ACTIVE_TICK_CLASS,
|
|
127
|
+
ANIMATION_OPTION_KEYS,
|
|
128
|
+
ANIM_LOOP_DELAY_DEFAULT,
|
|
129
|
+
ANIM_LOOP_DELAY_MIN,
|
|
130
|
+
ANIM_MAX_IDEAL_FRAMES_DEFAULT,
|
|
131
|
+
ANIM_MAX_IDEAL_FRAMES_MAX,
|
|
132
|
+
ANIM_MAX_IDEAL_FRAMES_MIN,
|
|
133
|
+
ANIM_PLAY_SPEED_DEFAULT,
|
|
134
|
+
ANIM_PLAY_SPEED_MAX,
|
|
135
|
+
ANIM_PLAY_SPEED_MIN,
|
|
136
|
+
APPROXIMATE_POSITIONS_DEFAULT,
|
|
137
|
+
AXIS_FILTER_CLASS,
|
|
138
|
+
COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT,
|
|
139
|
+
COLOR_SCALE_SELF_CLAMP_PCT_MAX,
|
|
140
|
+
COLOR_SCALE_SELF_CLAMP_PCT_MIN,
|
|
141
|
+
CONTAINER_SLOT_ANIM_STOP,
|
|
142
|
+
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
143
|
+
CONTAINER_SLOT_UI_STATE,
|
|
144
|
+
CONTAINER_SLOT_XF_CLEAR,
|
|
145
|
+
CONTROL_CLASS,
|
|
146
|
+
DIM_OPACITY_DEFAULT,
|
|
147
|
+
DIM_OPACITY_VAR,
|
|
148
|
+
FLIP_DIRECTION_DEFAULT,
|
|
149
|
+
FLIP_INTERVAL_MAX_MS,
|
|
150
|
+
FLIP_INTERVAL_MIN_MS,
|
|
151
|
+
FLIP_MODE_DEFAULT,
|
|
152
|
+
GEO_POINT_PRECISIONS,
|
|
153
|
+
HOST_CONTAINER_CLASS,
|
|
154
|
+
HOST_CONTRACT_VERSION,
|
|
155
|
+
LEGEND_MARK_CLASS,
|
|
156
|
+
LIFT_SELECTED_CLASS,
|
|
157
|
+
MARK_CLASS,
|
|
158
|
+
MARK_SELECTED_CLASS,
|
|
159
|
+
MAX_MAP_POINTS_DEFAULT,
|
|
160
|
+
NO_ROW_MARKS_ATTR,
|
|
161
|
+
ROW_IDX_ATTR,
|
|
162
|
+
SEASONAL_MARKERS_DEFAULT,
|
|
163
|
+
SELECTION_ACTIVE_CLASS,
|
|
164
|
+
SNAPSHOT_SVG_ATTR,
|
|
165
|
+
VALUE_AXIS_BASELINE_DEFAULT,
|
|
166
|
+
VIEW_ONLY_UI_STATE_KEYS,
|
|
167
|
+
XFILTER_REFRESH_EVENT,
|
|
168
|
+
chartOwnsTimeline,
|
|
169
|
+
periodTickSuppressesFeedback,
|
|
170
|
+
withoutViewOnlyKeys
|
|
171
|
+
} from "./chunk-WNGJUPEI.mjs";
|
|
170
172
|
import "./chunk-GHODWOAL.mjs";
|
|
171
173
|
|
|
172
174
|
// src/optionsVocabulary.ts
|