@uwdata/vgplot 0.12.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vgplot.js +309 -225
- package/dist/vgplot.min.js +11 -11
- package/package.json +10 -13
- package/src/api.js +1 -0
- package/vitest.config.ts +3 -0
package/dist/vgplot.js
CHANGED
|
@@ -484,169 +484,9 @@ var require_interval_tree = __commonJS({
|
|
|
484
484
|
}
|
|
485
485
|
});
|
|
486
486
|
|
|
487
|
-
// ../core/src/util/throttle.js
|
|
488
|
-
var NIL = {};
|
|
489
|
-
function throttle(callback, debounce = false) {
|
|
490
|
-
let curr;
|
|
491
|
-
let next;
|
|
492
|
-
let pending = NIL;
|
|
493
|
-
function invoke(event) {
|
|
494
|
-
curr = callback(event).catch(() => {
|
|
495
|
-
}).finally(() => {
|
|
496
|
-
if (next) {
|
|
497
|
-
const { value } = next;
|
|
498
|
-
next = null;
|
|
499
|
-
invoke(value);
|
|
500
|
-
} else {
|
|
501
|
-
curr = null;
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
function enqueue(event) {
|
|
506
|
-
next = { event };
|
|
507
|
-
}
|
|
508
|
-
function process(event) {
|
|
509
|
-
curr ? enqueue(event) : invoke(event);
|
|
510
|
-
}
|
|
511
|
-
function delay(event) {
|
|
512
|
-
if (pending !== event) {
|
|
513
|
-
requestAnimationFrame(() => {
|
|
514
|
-
const e = pending;
|
|
515
|
-
pending = NIL;
|
|
516
|
-
process(e);
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
pending = event;
|
|
520
|
-
}
|
|
521
|
-
return debounce ? delay : process;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// ../core/src/MosaicClient.js
|
|
525
|
-
var MosaicClient = class {
|
|
526
|
-
/**
|
|
527
|
-
* Constructor.
|
|
528
|
-
* @param {*} filterSelection An optional selection to interactively filter
|
|
529
|
-
* this client's data. If provided, a coordinator will re-query and update
|
|
530
|
-
* the client when the selection updates.
|
|
531
|
-
*/
|
|
532
|
-
constructor(filterSelection) {
|
|
533
|
-
this._filterBy = filterSelection;
|
|
534
|
-
this._requestUpdate = throttle(() => this.requestQuery(), true);
|
|
535
|
-
this._coordinator = null;
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Return this client's connected coordinator.
|
|
539
|
-
*/
|
|
540
|
-
get coordinator() {
|
|
541
|
-
return this._coordinator;
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Set this client's connected coordinator.
|
|
545
|
-
*/
|
|
546
|
-
set coordinator(coordinator2) {
|
|
547
|
-
this._coordinator = coordinator2;
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Return this client's filter selection.
|
|
551
|
-
*/
|
|
552
|
-
get filterBy() {
|
|
553
|
-
return this._filterBy;
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Return a boolean indicating if the client query can be sped up with
|
|
557
|
-
* materialized views of pre-aggregated data. Should return true if changes to
|
|
558
|
-
* the filterBy selection does not change the groupby domain of the client
|
|
559
|
-
* query.
|
|
560
|
-
*/
|
|
561
|
-
get filterStable() {
|
|
562
|
-
return true;
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* Return an array of fields queried by this client.
|
|
566
|
-
* @returns {import('./types.js').FieldInfoRequest[] | null}
|
|
567
|
-
* The fields to retrieve info for.
|
|
568
|
-
*/
|
|
569
|
-
fields() {
|
|
570
|
-
return null;
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* Called by the coordinator to set the field info for this client.
|
|
574
|
-
* @param {import('./types.js').FieldInfo[]} info The field info result.
|
|
575
|
-
* @returns {this}
|
|
576
|
-
*/
|
|
577
|
-
fieldInfo(info) {
|
|
578
|
-
return this;
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Return a query specifying the data needed by this client.
|
|
582
|
-
* @param {*} [filter] The filtering criteria to apply in the query.
|
|
583
|
-
* @returns {*} The client query
|
|
584
|
-
*/
|
|
585
|
-
query(filter3) {
|
|
586
|
-
return null;
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* Called by the coordinator to inform the client that a query is pending.
|
|
590
|
-
* @returns {this}
|
|
591
|
-
*/
|
|
592
|
-
queryPending() {
|
|
593
|
-
return this;
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Called by the coordinator to return a query result.
|
|
597
|
-
* @param {*} data The query result.
|
|
598
|
-
* @returns {this}
|
|
599
|
-
*/
|
|
600
|
-
queryResult(data) {
|
|
601
|
-
return this;
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Called by the coordinator to report a query execution error.
|
|
605
|
-
* @param {*} error
|
|
606
|
-
* @returns {this}
|
|
607
|
-
*/
|
|
608
|
-
queryError(error) {
|
|
609
|
-
return this;
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* Request the coordinator to execute a query for this client.
|
|
613
|
-
* If an explicit query is not provided, the client query method will
|
|
614
|
-
* be called, filtered by the current filterBy selection.
|
|
615
|
-
* @returns {Promise}
|
|
616
|
-
*/
|
|
617
|
-
requestQuery(query) {
|
|
618
|
-
const q2 = query || this.query(this.filterBy?.predicate(this));
|
|
619
|
-
return this._coordinator.requestQuery(this, q2);
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Request that the coordinator perform a throttled update of this client
|
|
623
|
-
* using the default query. Unlike requestQuery, for which every call will
|
|
624
|
-
* result in an executed query, multiple calls to requestUpdate may be
|
|
625
|
-
* consolidated into a single update.
|
|
626
|
-
*/
|
|
627
|
-
requestUpdate() {
|
|
628
|
-
this._requestUpdate();
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Reset this client, initiating new field info and query requests.
|
|
632
|
-
* @returns {Promise}
|
|
633
|
-
*/
|
|
634
|
-
initialize() {
|
|
635
|
-
return this._coordinator.initializeClient(this);
|
|
636
|
-
}
|
|
637
|
-
/**
|
|
638
|
-
* Requests a client update.
|
|
639
|
-
* For example to (re-)render an interface component.
|
|
640
|
-
*
|
|
641
|
-
* @returns {this | Promise<any>}
|
|
642
|
-
*/
|
|
643
|
-
update() {
|
|
644
|
-
return this;
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
|
|
648
487
|
// ../../node_modules/@uwdata/flechette/src/constants.js
|
|
649
488
|
var MAGIC = Uint8Array.of(65, 82, 82, 79, 87, 49);
|
|
489
|
+
var EOS = Uint8Array.of(255, 255, 255, 255, 0, 0, 0, 0);
|
|
650
490
|
var Version = (
|
|
651
491
|
/** @type {const} */
|
|
652
492
|
{
|
|
@@ -3061,7 +2901,7 @@ function literalToSQL(value) {
|
|
|
3061
2901
|
case "number":
|
|
3062
2902
|
return Number.isFinite(value) ? `${value}` : "NULL";
|
|
3063
2903
|
case "string":
|
|
3064
|
-
return `'${value.
|
|
2904
|
+
return `'${value.replaceAll(`'`, `''`)}'`;
|
|
3065
2905
|
case "boolean":
|
|
3066
2906
|
return value ? "TRUE" : "FALSE";
|
|
3067
2907
|
default:
|
|
@@ -4595,6 +4435,9 @@ function entropy(expr) {
|
|
|
4595
4435
|
function first(expr) {
|
|
4596
4436
|
return aggFn("first", expr);
|
|
4597
4437
|
}
|
|
4438
|
+
function geomean(expr) {
|
|
4439
|
+
return aggFn("geomean", expr);
|
|
4440
|
+
}
|
|
4598
4441
|
function kurtosis(expr) {
|
|
4599
4442
|
return aggFn("kurtosis", expr);
|
|
4600
4443
|
}
|
|
@@ -5389,6 +5232,8 @@ function sufficientStatistics(node, preagg, avg2) {
|
|
|
5389
5232
|
return sumExpr(preagg, node);
|
|
5390
5233
|
case "avg":
|
|
5391
5234
|
return avgExpr(preagg, node);
|
|
5235
|
+
case "geomean":
|
|
5236
|
+
return geomeanExpr(preagg, node);
|
|
5392
5237
|
case "arg_max":
|
|
5393
5238
|
return argmaxExpr(preagg, node);
|
|
5394
5239
|
case "arg_min":
|
|
@@ -5472,6 +5317,12 @@ function avgExpr(preagg, node) {
|
|
|
5472
5317
|
const { expr, name: name2 } = countExpr(preagg, node);
|
|
5473
5318
|
return div(sum(mul(as, name2)), expr);
|
|
5474
5319
|
}
|
|
5320
|
+
function geomeanExpr(preagg, node) {
|
|
5321
|
+
const x4 = node.args[0];
|
|
5322
|
+
const expr = addStat(preagg, sum(ln(x4)), node);
|
|
5323
|
+
const { expr: n } = countExpr(preagg, node);
|
|
5324
|
+
return exp(div(sum(expr), n));
|
|
5325
|
+
}
|
|
5475
5326
|
function argmaxExpr(preagg, node) {
|
|
5476
5327
|
const expr = addStat(preagg, node);
|
|
5477
5328
|
const maxy = addStat(preagg, max(node.args[1]), node);
|
|
@@ -6544,13 +6395,13 @@ var Coordinator = class {
|
|
|
6544
6395
|
}
|
|
6545
6396
|
/**
|
|
6546
6397
|
* Issue a query for which no result (return value) is needed.
|
|
6547
|
-
* @param {
|
|
6398
|
+
* @param { import('./types.js').QueryType[] |
|
|
6399
|
+
* import('./types.js').QueryType} query The query or an array of queries.
|
|
6548
6400
|
* Each query should be either a Query builder object or a SQL string.
|
|
6549
6401
|
* @param {object} [options] An options object.
|
|
6550
6402
|
* @param {number} [options.priority] The query priority, defaults to
|
|
6551
6403
|
* `Priority.Normal`.
|
|
6552
|
-
* @returns {QueryResult} A query result
|
|
6553
|
-
* promise.
|
|
6404
|
+
* @returns {QueryResult} A query result promise.
|
|
6554
6405
|
*/
|
|
6555
6406
|
exec(query, { priority = Priority.Normal } = {}) {
|
|
6556
6407
|
query = Array.isArray(query) ? query.filter((x4) => x4).join(";\n") : query;
|
|
@@ -6559,8 +6410,8 @@ var Coordinator = class {
|
|
|
6559
6410
|
/**
|
|
6560
6411
|
* Issue a query to the backing database. The submitted query may be
|
|
6561
6412
|
* consolidate with other queries and its results may be cached.
|
|
6562
|
-
* @param {QueryType} query The query as either a Query
|
|
6563
|
-
* or a SQL string.
|
|
6413
|
+
* @param {import('./types.js').QueryType} query The query as either a Query
|
|
6414
|
+
* builder object or a SQL string.
|
|
6564
6415
|
* @param {object} [options] An options object.
|
|
6565
6416
|
* @param {'arrow' | 'json'} [options.type] The query result format type.
|
|
6566
6417
|
* @param {boolean} [options.cache=true] If true, cache the query result
|
|
@@ -6582,8 +6433,8 @@ var Coordinator = class {
|
|
|
6582
6433
|
/**
|
|
6583
6434
|
* Issue a query to prefetch data for later use. The query result is cached
|
|
6584
6435
|
* for efficient future access.
|
|
6585
|
-
* @param {QueryType} query The query as either a Query
|
|
6586
|
-
* or a SQL string.
|
|
6436
|
+
* @param {import('./types.js').QueryType} query The query as either a Query
|
|
6437
|
+
* builder object or a SQL string.
|
|
6587
6438
|
* @param {object} [options] An options object.
|
|
6588
6439
|
* @param {'arrow' | 'json'} [options.type] The query result format type.
|
|
6589
6440
|
* @returns {QueryResult} A query result promise.
|
|
@@ -6618,13 +6469,13 @@ var Coordinator = class {
|
|
|
6618
6469
|
* Update client data by submitting the given query and returning the
|
|
6619
6470
|
* data (or error) to the client.
|
|
6620
6471
|
* @param {MosaicClient} client A Mosaic client.
|
|
6621
|
-
* @param {QueryType} query The data query.
|
|
6472
|
+
* @param {import('./types.js').QueryType} query The data query.
|
|
6622
6473
|
* @param {number} [priority] The query priority.
|
|
6623
6474
|
* @returns {Promise} A Promise that resolves upon completion of the update.
|
|
6624
6475
|
*/
|
|
6625
6476
|
updateClient(client, query, priority = Priority.Normal) {
|
|
6626
6477
|
client.queryPending();
|
|
6627
|
-
return this.query(query, { priority }).then(
|
|
6478
|
+
return client._pending = this.query(query, { priority }).then(
|
|
6628
6479
|
(data) => client.queryResult(data).update(),
|
|
6629
6480
|
(err) => {
|
|
6630
6481
|
this._logger.error(err);
|
|
@@ -6637,7 +6488,7 @@ var Coordinator = class {
|
|
|
6637
6488
|
* the client is simply updated. Otherwise `updateClient` is called. As a
|
|
6638
6489
|
* side effect, this method clears the current preaggregator state.
|
|
6639
6490
|
* @param {MosaicClient} client The client to update.
|
|
6640
|
-
* @param {QueryType | null} [query] The query to issue.
|
|
6491
|
+
* @param {import('./types.js').QueryType | null} [query] The query to issue.
|
|
6641
6492
|
*/
|
|
6642
6493
|
requestQuery(client, query) {
|
|
6643
6494
|
this.preaggregator.clear();
|
|
@@ -6654,7 +6505,7 @@ var Coordinator = class {
|
|
|
6654
6505
|
}
|
|
6655
6506
|
clients.add(client);
|
|
6656
6507
|
client.coordinator = this;
|
|
6657
|
-
this.initializeClient(client);
|
|
6508
|
+
client._pending = this.initializeClient(client);
|
|
6658
6509
|
connectSelection(this, client.filterBy, client);
|
|
6659
6510
|
}
|
|
6660
6511
|
async initializeClient(client) {
|
|
@@ -6662,6 +6513,7 @@ var Coordinator = class {
|
|
|
6662
6513
|
if (fields?.length) {
|
|
6663
6514
|
client.fieldInfo(await queryFieldInfo(this, fields));
|
|
6664
6515
|
}
|
|
6516
|
+
await client.prepare();
|
|
6665
6517
|
return client.requestQuery();
|
|
6666
6518
|
}
|
|
6667
6519
|
/**
|
|
@@ -7281,6 +7133,179 @@ var SelectionResolver = class {
|
|
|
7281
7133
|
}
|
|
7282
7134
|
};
|
|
7283
7135
|
|
|
7136
|
+
// ../core/src/util/throttle.js
|
|
7137
|
+
var NIL = {};
|
|
7138
|
+
function throttle(callback, debounce = false) {
|
|
7139
|
+
let curr;
|
|
7140
|
+
let next;
|
|
7141
|
+
let pending = NIL;
|
|
7142
|
+
function invoke(event) {
|
|
7143
|
+
curr = callback(event).catch(() => {
|
|
7144
|
+
}).finally(() => {
|
|
7145
|
+
if (next) {
|
|
7146
|
+
const { value } = next;
|
|
7147
|
+
next = null;
|
|
7148
|
+
invoke(value);
|
|
7149
|
+
} else {
|
|
7150
|
+
curr = null;
|
|
7151
|
+
}
|
|
7152
|
+
});
|
|
7153
|
+
}
|
|
7154
|
+
function enqueue(event) {
|
|
7155
|
+
next = { event };
|
|
7156
|
+
}
|
|
7157
|
+
function process(event) {
|
|
7158
|
+
curr ? enqueue(event) : invoke(event);
|
|
7159
|
+
}
|
|
7160
|
+
function delay(event) {
|
|
7161
|
+
if (pending !== event) {
|
|
7162
|
+
requestAnimationFrame(() => {
|
|
7163
|
+
const e = pending;
|
|
7164
|
+
pending = NIL;
|
|
7165
|
+
process(e);
|
|
7166
|
+
});
|
|
7167
|
+
}
|
|
7168
|
+
pending = event;
|
|
7169
|
+
}
|
|
7170
|
+
return debounce ? delay : process;
|
|
7171
|
+
}
|
|
7172
|
+
|
|
7173
|
+
// ../core/src/MosaicClient.js
|
|
7174
|
+
var MosaicClient = class {
|
|
7175
|
+
/**
|
|
7176
|
+
* Constructor.
|
|
7177
|
+
* @param {*} filterSelection An optional selection to interactively filter
|
|
7178
|
+
* this client's data. If provided, a coordinator will re-query and update
|
|
7179
|
+
* the client when the selection updates.
|
|
7180
|
+
*/
|
|
7181
|
+
constructor(filterSelection) {
|
|
7182
|
+
this._filterBy = filterSelection;
|
|
7183
|
+
this._requestUpdate = throttle(() => this.requestQuery(), true);
|
|
7184
|
+
this._coordinator = null;
|
|
7185
|
+
this._pending = Promise.resolve();
|
|
7186
|
+
}
|
|
7187
|
+
/**
|
|
7188
|
+
* Return this client's connected coordinator.
|
|
7189
|
+
*/
|
|
7190
|
+
get coordinator() {
|
|
7191
|
+
return this._coordinator;
|
|
7192
|
+
}
|
|
7193
|
+
/**
|
|
7194
|
+
* Set this client's connected coordinator.
|
|
7195
|
+
*/
|
|
7196
|
+
set coordinator(coordinator2) {
|
|
7197
|
+
this._coordinator = coordinator2;
|
|
7198
|
+
}
|
|
7199
|
+
/**
|
|
7200
|
+
* Return a Promise that resolves once the client has updated.
|
|
7201
|
+
*/
|
|
7202
|
+
get pending() {
|
|
7203
|
+
return this._pending;
|
|
7204
|
+
}
|
|
7205
|
+
/**
|
|
7206
|
+
* Return this client's filter selection.
|
|
7207
|
+
*/
|
|
7208
|
+
get filterBy() {
|
|
7209
|
+
return this._filterBy;
|
|
7210
|
+
}
|
|
7211
|
+
/**
|
|
7212
|
+
* Return a boolean indicating if the client query can be sped up with
|
|
7213
|
+
* materialized views of pre-aggregated data. Should return true if changes to
|
|
7214
|
+
* the filterBy selection does not change the groupby domain of the client
|
|
7215
|
+
* query.
|
|
7216
|
+
*/
|
|
7217
|
+
get filterStable() {
|
|
7218
|
+
return true;
|
|
7219
|
+
}
|
|
7220
|
+
/**
|
|
7221
|
+
* Return an array of fields queried by this client.
|
|
7222
|
+
* @returns {import('./types.js').FieldInfoRequest[] | null}
|
|
7223
|
+
* The fields to retrieve info for.
|
|
7224
|
+
*/
|
|
7225
|
+
fields() {
|
|
7226
|
+
return null;
|
|
7227
|
+
}
|
|
7228
|
+
/**
|
|
7229
|
+
* Called by the coordinator to set the field info for this client.
|
|
7230
|
+
* @param {import('./types.js').FieldInfo[]} info The field info result.
|
|
7231
|
+
* @returns {this}
|
|
7232
|
+
*/
|
|
7233
|
+
fieldInfo(info) {
|
|
7234
|
+
return this;
|
|
7235
|
+
}
|
|
7236
|
+
/**
|
|
7237
|
+
* Prepare the client before the query() method is called.
|
|
7238
|
+
*/
|
|
7239
|
+
async prepare() {
|
|
7240
|
+
}
|
|
7241
|
+
/**
|
|
7242
|
+
* Return a query specifying the data needed by this client.
|
|
7243
|
+
* @param {*} [filter] The filtering criteria to apply in the query.
|
|
7244
|
+
* @returns {*} The client query
|
|
7245
|
+
*/
|
|
7246
|
+
query(filter3) {
|
|
7247
|
+
return null;
|
|
7248
|
+
}
|
|
7249
|
+
/**
|
|
7250
|
+
* Called by the coordinator to inform the client that a query is pending.
|
|
7251
|
+
* @returns {this}
|
|
7252
|
+
*/
|
|
7253
|
+
queryPending() {
|
|
7254
|
+
return this;
|
|
7255
|
+
}
|
|
7256
|
+
/**
|
|
7257
|
+
* Called by the coordinator to return a query result.
|
|
7258
|
+
* @param {*} data The query result.
|
|
7259
|
+
* @returns {this}
|
|
7260
|
+
*/
|
|
7261
|
+
queryResult(data) {
|
|
7262
|
+
return this;
|
|
7263
|
+
}
|
|
7264
|
+
/**
|
|
7265
|
+
* Called by the coordinator to report a query execution error.
|
|
7266
|
+
* @param {*} error
|
|
7267
|
+
* @returns {this}
|
|
7268
|
+
*/
|
|
7269
|
+
queryError(error) {
|
|
7270
|
+
return this;
|
|
7271
|
+
}
|
|
7272
|
+
/**
|
|
7273
|
+
* Request the coordinator to execute a query for this client.
|
|
7274
|
+
* If an explicit query is not provided, the client query method will
|
|
7275
|
+
* be called, filtered by the current filterBy selection.
|
|
7276
|
+
* @returns {Promise}
|
|
7277
|
+
*/
|
|
7278
|
+
requestQuery(query) {
|
|
7279
|
+
const q2 = query || this.query(this.filterBy?.predicate(this));
|
|
7280
|
+
return this._coordinator.requestQuery(this, q2);
|
|
7281
|
+
}
|
|
7282
|
+
/**
|
|
7283
|
+
* Request that the coordinator perform a throttled update of this client
|
|
7284
|
+
* using the default query. Unlike requestQuery, for which every call will
|
|
7285
|
+
* result in an executed query, multiple calls to requestUpdate may be
|
|
7286
|
+
* consolidated into a single update.
|
|
7287
|
+
*/
|
|
7288
|
+
requestUpdate() {
|
|
7289
|
+
this._requestUpdate();
|
|
7290
|
+
}
|
|
7291
|
+
/**
|
|
7292
|
+
* Reset this client, initiating new field info, call the prepare method, and query requests.
|
|
7293
|
+
* @returns {Promise}
|
|
7294
|
+
*/
|
|
7295
|
+
initialize() {
|
|
7296
|
+
return this._coordinator.initializeClient(this);
|
|
7297
|
+
}
|
|
7298
|
+
/**
|
|
7299
|
+
* Requests a client update.
|
|
7300
|
+
* For example to (re-)render an interface component.
|
|
7301
|
+
*
|
|
7302
|
+
* @returns {this | Promise<any>}
|
|
7303
|
+
*/
|
|
7304
|
+
update() {
|
|
7305
|
+
return this;
|
|
7306
|
+
}
|
|
7307
|
+
};
|
|
7308
|
+
|
|
7284
7309
|
// ../core/src/connectors/rest.js
|
|
7285
7310
|
function restConnector(uri = "http://localhost:3000/") {
|
|
7286
7311
|
return {
|
|
@@ -7302,7 +7327,11 @@ function restConnector(uri = "http://localhost:3000/") {
|
|
|
7302
7327
|
headers: { "Content-Type": "application/json" },
|
|
7303
7328
|
body: JSON.stringify(query)
|
|
7304
7329
|
});
|
|
7305
|
-
|
|
7330
|
+
const res = await req;
|
|
7331
|
+
if (!res.ok) {
|
|
7332
|
+
throw new Error(`Query failed with HTTP status ${res.status}: ${await res.text()}`);
|
|
7333
|
+
}
|
|
7334
|
+
return query.type === "exec" ? req : query.type === "arrow" ? decodeIPC2(await res.arrayBuffer()) : res.json();
|
|
7306
7335
|
}
|
|
7307
7336
|
};
|
|
7308
7337
|
}
|
|
@@ -19954,6 +19983,7 @@ __export(api_exports, {
|
|
|
19954
19983
|
fyTicks: () => fyTicks,
|
|
19955
19984
|
geo: () => geo2,
|
|
19956
19985
|
geojson: () => geojson,
|
|
19986
|
+
geomean: () => geomean,
|
|
19957
19987
|
graticule: () => graticule3,
|
|
19958
19988
|
grid: () => grid,
|
|
19959
19989
|
gridFx: () => gridFx2,
|
|
@@ -44046,6 +44076,9 @@ var DEFAULT_ATTRIBUTES = {
|
|
|
44046
44076
|
marginBottom: 30
|
|
44047
44077
|
};
|
|
44048
44078
|
var Plot = class {
|
|
44079
|
+
/**
|
|
44080
|
+
* @param {HTMLElement} [element]
|
|
44081
|
+
*/
|
|
44049
44082
|
constructor(element) {
|
|
44050
44083
|
this.attributes = { ...DEFAULT_ATTRIBUTES };
|
|
44051
44084
|
this.listeners = null;
|
|
@@ -44053,12 +44086,12 @@ var Plot = class {
|
|
|
44053
44086
|
this.legends = [];
|
|
44054
44087
|
this.marks = [];
|
|
44055
44088
|
this.markset = null;
|
|
44089
|
+
this.params = /* @__PURE__ */ new Map();
|
|
44090
|
+
this.synch = synchronizer();
|
|
44056
44091
|
this.element = element || document.createElement("div");
|
|
44057
44092
|
this.element.setAttribute("class", "plot");
|
|
44058
44093
|
this.element.style.display = "flex";
|
|
44059
|
-
this.element
|
|
44060
|
-
this.params = /* @__PURE__ */ new Map();
|
|
44061
|
-
this.synch = synchronizer();
|
|
44094
|
+
Object.assign(this.element, { value: this });
|
|
44062
44095
|
}
|
|
44063
44096
|
margins() {
|
|
44064
44097
|
return {
|
|
@@ -44433,7 +44466,7 @@ function markQuery(channels, table3, skip = []) {
|
|
|
44433
44466
|
const { channel, field: field3, as } = c4;
|
|
44434
44467
|
if (skip.includes(channel)) continue;
|
|
44435
44468
|
if (channel === "orderby") {
|
|
44436
|
-
q2.orderby(c4.value);
|
|
44469
|
+
q2.orderby(c4.value ?? field3);
|
|
44437
44470
|
} else if (field3) {
|
|
44438
44471
|
if (isAggregateExpression(field3)) {
|
|
44439
44472
|
aggr = true;
|
|
@@ -44565,7 +44598,7 @@ var ConnectedMark = class extends Mark2 {
|
|
|
44565
44598
|
const cols = q2._select.map((c4) => c4.alias).filter((c4) => c4 !== as && c4 !== value);
|
|
44566
44599
|
return m4(q2, expr, as, value, cols);
|
|
44567
44600
|
} else {
|
|
44568
|
-
return q2.orderby(
|
|
44601
|
+
return q2.orderby(as);
|
|
44569
44602
|
}
|
|
44570
44603
|
}
|
|
44571
44604
|
};
|
|
@@ -46725,12 +46758,13 @@ var Nearest = class {
|
|
|
46725
46758
|
selection2.update(that.clause(void 0));
|
|
46726
46759
|
});
|
|
46727
46760
|
svg.addEventListener("pointerenter", (evt) => {
|
|
46728
|
-
if (!evt.buttons)
|
|
46729
|
-
const v3 = this.channels.map(() => 0);
|
|
46730
|
-
selection2.activate(this.clause(v3));
|
|
46731
|
-
}
|
|
46761
|
+
if (!evt.buttons) this.activate();
|
|
46732
46762
|
});
|
|
46733
46763
|
}
|
|
46764
|
+
activate() {
|
|
46765
|
+
const v3 = this.channels.map(() => 0);
|
|
46766
|
+
this.selection.activate(this.clause(v3));
|
|
46767
|
+
}
|
|
46734
46768
|
};
|
|
46735
46769
|
function calculateXY(svg, mark2) {
|
|
46736
46770
|
const { data: { columns } } = mark2;
|
|
@@ -46826,7 +46860,7 @@ var PanZoom = class {
|
|
|
46826
46860
|
this.svg = svg;
|
|
46827
46861
|
if (this.initialized) return;
|
|
46828
46862
|
else this.initialized = true;
|
|
46829
|
-
const { panx, pany, mark: { plot: { element } }
|
|
46863
|
+
const { panx, pany, mark: { plot: { element } } } = this;
|
|
46830
46864
|
this.xscale = svg.scale("x");
|
|
46831
46865
|
this.yscale = svg.scale("y");
|
|
46832
46866
|
const rx = this.xscale.range.slice().sort(asc2);
|
|
@@ -46843,19 +46877,21 @@ var PanZoom = class {
|
|
|
46843
46877
|
element.addEventListener("pointerenter", (evt) => {
|
|
46844
46878
|
if (enter) return;
|
|
46845
46879
|
else enter = true;
|
|
46846
|
-
if (evt.buttons)
|
|
46847
|
-
if (panx) {
|
|
46848
|
-
const { xscale, xfield } = this;
|
|
46849
|
-
xsel.activate(this.clause(xscale.domain, xfield, xscale));
|
|
46850
|
-
}
|
|
46851
|
-
if (pany) {
|
|
46852
|
-
const { yscale, yfield } = this;
|
|
46853
|
-
ysel.activate(this.clause(yscale.domain, yfield, yscale));
|
|
46854
|
-
}
|
|
46880
|
+
if (!evt.buttons) this.activate();
|
|
46855
46881
|
});
|
|
46856
46882
|
element.addEventListener("pointerleave", () => enter = false);
|
|
46857
46883
|
}
|
|
46858
46884
|
}
|
|
46885
|
+
activate() {
|
|
46886
|
+
if (this.panx) {
|
|
46887
|
+
const { xscale, xfield } = this;
|
|
46888
|
+
this.xsel.activate(this.clause(xscale.domain, xfield, xscale));
|
|
46889
|
+
}
|
|
46890
|
+
if (this.pany) {
|
|
46891
|
+
const { yscale, yfield } = this;
|
|
46892
|
+
this.ysel.activate(this.clause(yscale.domain, yfield, yscale));
|
|
46893
|
+
}
|
|
46894
|
+
}
|
|
46859
46895
|
};
|
|
46860
46896
|
function extent3(ext, defaultTrue, defaultFalse) {
|
|
46861
46897
|
return ext ? Array.isArray(ext) ? ext : defaultTrue : defaultFalse;
|
|
@@ -47240,8 +47276,8 @@ var Toggle = class {
|
|
|
47240
47276
|
channels,
|
|
47241
47277
|
peers = true
|
|
47242
47278
|
}) {
|
|
47243
|
-
this.value = null;
|
|
47244
47279
|
this.mark = mark2;
|
|
47280
|
+
this.value = null;
|
|
47245
47281
|
this.selection = selection2;
|
|
47246
47282
|
this.peers = peers;
|
|
47247
47283
|
const fields = this.fields = [];
|
|
@@ -47293,10 +47329,12 @@ var Toggle = class {
|
|
|
47293
47329
|
}
|
|
47294
47330
|
});
|
|
47295
47331
|
svg.addEventListener("pointerenter", (evt) => {
|
|
47296
|
-
if (evt.buttons)
|
|
47297
|
-
this.selection.activate(this.clause([this.fields.map(() => 0)]));
|
|
47332
|
+
if (!evt.buttons) this.activate();
|
|
47298
47333
|
});
|
|
47299
47334
|
}
|
|
47335
|
+
activate() {
|
|
47336
|
+
this.selection.activate(this.clause([this.fields.map(() => 0)]));
|
|
47337
|
+
}
|
|
47300
47338
|
};
|
|
47301
47339
|
function isTargetElement(groups2, node) {
|
|
47302
47340
|
return groups2.some((g2) => g2.contains(node));
|
|
@@ -47590,11 +47628,30 @@ var BinTransformNode = class extends ExprNode {
|
|
|
47590
47628
|
}
|
|
47591
47629
|
};
|
|
47592
47630
|
|
|
47631
|
+
// ../inputs/src/input.js
|
|
47632
|
+
var Input = class extends MosaicClient {
|
|
47633
|
+
/**
|
|
47634
|
+
* Create a new input instance.
|
|
47635
|
+
* @param {import('@uwdata/mosaic-core').Selection} [filterBy] A selection
|
|
47636
|
+
* with which to filter backing data that parameterizes this input.
|
|
47637
|
+
* @param {HTMLElement} [element] Optional container HTML element to use.
|
|
47638
|
+
* @param {string} [className] A class name to set on the container element.
|
|
47639
|
+
*/
|
|
47640
|
+
constructor(filterBy, element, className = "input") {
|
|
47641
|
+
super(filterBy);
|
|
47642
|
+
this.element = element || document.createElement("div");
|
|
47643
|
+
if (className) this.element.setAttribute("class", className);
|
|
47644
|
+
Object.defineProperty(this.element, "value", { value: this });
|
|
47645
|
+
}
|
|
47646
|
+
activate() {
|
|
47647
|
+
}
|
|
47648
|
+
};
|
|
47649
|
+
|
|
47593
47650
|
// ../inputs/src/Menu.js
|
|
47594
47651
|
var isObject3 = (v3) => {
|
|
47595
47652
|
return v3 && typeof v3 === "object" && !Array.isArray(v3);
|
|
47596
47653
|
};
|
|
47597
|
-
var Menu = class extends
|
|
47654
|
+
var Menu = class extends Input {
|
|
47598
47655
|
/**
|
|
47599
47656
|
* Create a new menu input.
|
|
47600
47657
|
* @param {object} [options] Options object
|
|
@@ -47635,15 +47692,12 @@ var Menu = class extends MosaicClient {
|
|
|
47635
47692
|
value,
|
|
47636
47693
|
field: field3 = column3
|
|
47637
47694
|
} = {}) {
|
|
47638
|
-
super(filterBy);
|
|
47695
|
+
super(filterBy, element);
|
|
47639
47696
|
this.from = from2;
|
|
47640
47697
|
this.column = column3;
|
|
47641
47698
|
this.format = format3;
|
|
47642
47699
|
this.field = field3;
|
|
47643
47700
|
const selection2 = this.selection = as;
|
|
47644
|
-
this.element = element ?? document.createElement("div");
|
|
47645
|
-
this.element.setAttribute("class", "input");
|
|
47646
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47647
47701
|
const lab3 = document.createElement("label");
|
|
47648
47702
|
lab3.innerText = label || column3;
|
|
47649
47703
|
this.element.appendChild(lab3);
|
|
@@ -47693,7 +47747,9 @@ var Menu = class extends MosaicClient {
|
|
|
47693
47747
|
this.select.selectedIndex = this.from ? 0 : -1;
|
|
47694
47748
|
}
|
|
47695
47749
|
activate() {
|
|
47696
|
-
|
|
47750
|
+
if (isSelection(this.selection)) {
|
|
47751
|
+
this.selection.activate(clausePoint(this.field, 0, { source: this }));
|
|
47752
|
+
}
|
|
47697
47753
|
}
|
|
47698
47754
|
publish(value) {
|
|
47699
47755
|
const { selection: selection2, field: field3 } = this;
|
|
@@ -47733,7 +47789,7 @@ var Menu = class extends MosaicClient {
|
|
|
47733
47789
|
|
|
47734
47790
|
// ../inputs/src/Search.js
|
|
47735
47791
|
var _id = 0;
|
|
47736
|
-
var Search = class extends
|
|
47792
|
+
var Search = class extends Input {
|
|
47737
47793
|
/**
|
|
47738
47794
|
* Create a new text search input.
|
|
47739
47795
|
* @param {object} [options] Options object
|
|
@@ -47769,16 +47825,13 @@ var Search = class extends MosaicClient {
|
|
|
47769
47825
|
field: field3 = column3,
|
|
47770
47826
|
as
|
|
47771
47827
|
} = {}) {
|
|
47772
|
-
super(filterBy);
|
|
47828
|
+
super(filterBy, element);
|
|
47773
47829
|
this.id = "search_" + ++_id;
|
|
47774
47830
|
this.type = type2;
|
|
47775
47831
|
this.from = from2;
|
|
47776
47832
|
this.column = column3;
|
|
47777
47833
|
this.selection = as;
|
|
47778
47834
|
this.field = field3;
|
|
47779
|
-
this.element = element ?? document.createElement("div");
|
|
47780
|
-
this.element.setAttribute("class", "input");
|
|
47781
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47782
47835
|
if (label) {
|
|
47783
47836
|
const lab3 = document.createElement("label");
|
|
47784
47837
|
lab3.setAttribute("for", this.id);
|
|
@@ -47816,7 +47869,9 @@ var Search = class extends MosaicClient {
|
|
|
47816
47869
|
return clauseMatch(field3, value, { source: this, method: type2 });
|
|
47817
47870
|
}
|
|
47818
47871
|
activate() {
|
|
47819
|
-
this.selection
|
|
47872
|
+
if (isSelection(this.selection)) {
|
|
47873
|
+
this.selection.activate(this.clause(""));
|
|
47874
|
+
}
|
|
47820
47875
|
}
|
|
47821
47876
|
publish(value) {
|
|
47822
47877
|
const { selection: selection2 } = this;
|
|
@@ -47853,7 +47908,7 @@ var Search = class extends MosaicClient {
|
|
|
47853
47908
|
|
|
47854
47909
|
// ../inputs/src/Slider.js
|
|
47855
47910
|
var _id2 = 0;
|
|
47856
|
-
var Slider = class extends
|
|
47911
|
+
var Slider = class extends Input {
|
|
47857
47912
|
/**
|
|
47858
47913
|
* Create a new slider input.
|
|
47859
47914
|
* @param {object} [options] Options object
|
|
@@ -47899,7 +47954,7 @@ var Slider = class extends MosaicClient {
|
|
|
47899
47954
|
field: field3 = column3,
|
|
47900
47955
|
width: width2
|
|
47901
47956
|
} = {}) {
|
|
47902
|
-
super(filterBy);
|
|
47957
|
+
super(filterBy, element);
|
|
47903
47958
|
this.id = "slider_" + ++_id2;
|
|
47904
47959
|
this.from = from2;
|
|
47905
47960
|
this.column = column3 || "value";
|
|
@@ -47909,9 +47964,6 @@ var Slider = class extends MosaicClient {
|
|
|
47909
47964
|
this.min = min5;
|
|
47910
47965
|
this.max = max4;
|
|
47911
47966
|
this.step = step;
|
|
47912
|
-
this.element = element || document.createElement("div");
|
|
47913
|
-
this.element.setAttribute("class", "input");
|
|
47914
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47915
47967
|
if (label) {
|
|
47916
47968
|
const desc2 = document.createElement("label");
|
|
47917
47969
|
desc2.setAttribute("for", this.id);
|
|
@@ -47992,7 +48044,9 @@ var Slider = class extends MosaicClient {
|
|
|
47992
48044
|
}
|
|
47993
48045
|
}
|
|
47994
48046
|
activate() {
|
|
47995
|
-
this.selection
|
|
48047
|
+
if (isSelection(this.selection)) {
|
|
48048
|
+
this.selection.activate(this.clause(0));
|
|
48049
|
+
}
|
|
47996
48050
|
}
|
|
47997
48051
|
publish(value) {
|
|
47998
48052
|
const { selection: selection2 } = this;
|
|
@@ -48025,10 +48079,36 @@ function localize(f2) {
|
|
|
48025
48079
|
|
|
48026
48080
|
// ../inputs/src/Table.js
|
|
48027
48081
|
var _id3 = -1;
|
|
48028
|
-
var Table3 = class extends
|
|
48082
|
+
var Table3 = class extends Input {
|
|
48029
48083
|
/**
|
|
48030
48084
|
* Create a new Table instance.
|
|
48031
48085
|
* @param {object} options Options object
|
|
48086
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
48087
|
+
* place the table element. If undefined, a new `div` element is created.
|
|
48088
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
48089
|
+
* table indicated by the *from* option.
|
|
48090
|
+
* @param {Selection} [options.as] The output selection. A selection
|
|
48091
|
+
* clause is added for the currently selected table row.
|
|
48092
|
+
* @param {{ [name: string]: 'left' | 'right' | 'center' }} [options.align]
|
|
48093
|
+
* An object that maps column names to horiztonal text alignment values. If
|
|
48094
|
+
* unspecified, alignment is determined based on the column data type.
|
|
48095
|
+
* @param {{ [name: string]: (value: any) => string }} [options.format] An
|
|
48096
|
+
* object that maps column names to format functions to use for that
|
|
48097
|
+
* column's data. Each format function takes a value as input and generates
|
|
48098
|
+
* formatted text to show in the table.
|
|
48099
|
+
* @param {string} [options.from] The name of a database table to use as a data
|
|
48100
|
+
* source for this widget. Used in conjunction with the *columns* option.
|
|
48101
|
+
* @param {string[]} [options.columns] The name of database columns to include
|
|
48102
|
+
* in the table component. If unspecified, all columns are included.
|
|
48103
|
+
* Used in conjunction with the *from* option.
|
|
48104
|
+
* @param {number | { [name: string]: number }} [options.width] If a number,
|
|
48105
|
+
* sets the desired width of the table, in pixels. If an object, is used to
|
|
48106
|
+
* set explicit pixel widts for each named column included in the object.
|
|
48107
|
+
* @param {number} [options.maxWidth] The maximum width of the table, in pixels.
|
|
48108
|
+
* @param {number} [options.height] The desired height of the table, in pixels.
|
|
48109
|
+
* @param {number} [options.rowBatch] The number of rows to request per query
|
|
48110
|
+
* batch. The batch size will be used to prefetch data beyond the currently
|
|
48111
|
+
* visible range.
|
|
48032
48112
|
*/
|
|
48033
48113
|
constructor({
|
|
48034
48114
|
element,
|
|
@@ -48043,8 +48123,9 @@ var Table3 = class extends MosaicClient {
|
|
|
48043
48123
|
rowBatch = 100,
|
|
48044
48124
|
as
|
|
48045
48125
|
} = {}) {
|
|
48046
|
-
super(filterBy);
|
|
48126
|
+
super(filterBy, element, null);
|
|
48047
48127
|
this.id = `table-${++_id3}`;
|
|
48128
|
+
this.element.setAttribute("id", this.id);
|
|
48048
48129
|
this.from = from2;
|
|
48049
48130
|
this.columns = columns;
|
|
48050
48131
|
this.format = format3;
|
|
@@ -48055,28 +48136,25 @@ var Table3 = class extends MosaicClient {
|
|
|
48055
48136
|
}
|
|
48056
48137
|
this.offset = 0;
|
|
48057
48138
|
this.limit = +rowBatch;
|
|
48058
|
-
this.
|
|
48139
|
+
this.isPending = false;
|
|
48059
48140
|
this.selection = as;
|
|
48060
48141
|
this.currentRow = -1;
|
|
48061
48142
|
this.sortHeader = null;
|
|
48062
48143
|
this.sortColumn = null;
|
|
48063
48144
|
this.sortDesc = false;
|
|
48064
|
-
this.element = element || document.createElement("div");
|
|
48065
|
-
this.element.setAttribute("id", this.id);
|
|
48066
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
48067
48145
|
if (typeof width2 === "number") this.element.style.width = `${width2}px`;
|
|
48068
48146
|
if (maxWidth) this.element.style.maxWidth = `${maxWidth}px`;
|
|
48069
48147
|
this.element.style.maxHeight = `${height2}px`;
|
|
48070
48148
|
this.element.style.overflow = "auto";
|
|
48071
48149
|
let prevScrollTop = -1;
|
|
48072
48150
|
this.element.addEventListener("scroll", (evt) => {
|
|
48073
|
-
const {
|
|
48151
|
+
const { isPending, loaded } = this;
|
|
48074
48152
|
const { scrollHeight, scrollTop, clientHeight } = evt.target;
|
|
48075
48153
|
const back = scrollTop < prevScrollTop;
|
|
48076
48154
|
prevScrollTop = scrollTop;
|
|
48077
|
-
if (back ||
|
|
48155
|
+
if (back || isPending || loaded) return;
|
|
48078
48156
|
if (scrollHeight - scrollTop < 2 * clientHeight) {
|
|
48079
|
-
this.
|
|
48157
|
+
this.isPending = true;
|
|
48080
48158
|
this.requestData(this.offset + this.limit);
|
|
48081
48159
|
}
|
|
48082
48160
|
});
|
|
@@ -48150,7 +48228,7 @@ var Table3 = class extends MosaicClient {
|
|
|
48150
48228
|
return Query.from(this.sourceTable()).select(schema.map((s2) => s2.column)).where(filter3).orderby(sortColumn ? sortDesc ? desc(sortColumn) : sortColumn : []).limit(limit).offset(offset2);
|
|
48151
48229
|
}
|
|
48152
48230
|
queryResult(data) {
|
|
48153
|
-
if (!this.
|
|
48231
|
+
if (!this.isPending) {
|
|
48154
48232
|
this.loaded = false;
|
|
48155
48233
|
this.data = [];
|
|
48156
48234
|
this.body.replaceChildren();
|
|
@@ -48180,9 +48258,14 @@ var Table3 = class extends MosaicClient {
|
|
|
48180
48258
|
if (numRows < limit) {
|
|
48181
48259
|
this.loaded = true;
|
|
48182
48260
|
}
|
|
48183
|
-
this.
|
|
48261
|
+
this.isPending = false;
|
|
48184
48262
|
return this;
|
|
48185
48263
|
}
|
|
48264
|
+
activate() {
|
|
48265
|
+
if (isSelection(this.selection)) {
|
|
48266
|
+
this.selection.activate(this.clause([]));
|
|
48267
|
+
}
|
|
48268
|
+
}
|
|
48186
48269
|
sort(event, column3) {
|
|
48187
48270
|
if (column3 === this.sortColumn) {
|
|
48188
48271
|
this.sortDesc = !this.sortDesc;
|
|
@@ -49304,6 +49387,7 @@ export {
|
|
|
49304
49387
|
fyTicks,
|
|
49305
49388
|
geo2 as geo,
|
|
49306
49389
|
geojson,
|
|
49390
|
+
geomean,
|
|
49307
49391
|
graticule3 as graticule,
|
|
49308
49392
|
grid,
|
|
49309
49393
|
gridFx2 as gridFx,
|