@uwdata/vgplot 0.12.1 → 0.13.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 +431 -276
- 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
|
@@ -103,7 +103,7 @@ var require_search_bounds = __commonJS({
|
|
|
103
103
|
}
|
|
104
104
|
return -1;
|
|
105
105
|
}
|
|
106
|
-
function
|
|
106
|
+
function norm2(a2, y4, c4, l, h2, f2) {
|
|
107
107
|
if (typeof c4 === "function") {
|
|
108
108
|
return f2(a2, y4, c4, l === void 0 ? 0 : l | 0, h2 === void 0 ? a2.length - 1 : h2 | 0);
|
|
109
109
|
}
|
|
@@ -111,19 +111,19 @@ var require_search_bounds = __commonJS({
|
|
|
111
111
|
}
|
|
112
112
|
module.exports = {
|
|
113
113
|
ge: function(a2, y4, c4, l, h2) {
|
|
114
|
-
return
|
|
114
|
+
return norm2(a2, y4, c4, l, h2, ge);
|
|
115
115
|
},
|
|
116
116
|
gt: function(a2, y4, c4, l, h2) {
|
|
117
|
-
return
|
|
117
|
+
return norm2(a2, y4, c4, l, h2, gt2);
|
|
118
118
|
},
|
|
119
119
|
lt: function(a2, y4, c4, l, h2) {
|
|
120
|
-
return
|
|
120
|
+
return norm2(a2, y4, c4, l, h2, lt2);
|
|
121
121
|
},
|
|
122
122
|
le: function(a2, y4, c4, l, h2) {
|
|
123
|
-
return
|
|
123
|
+
return norm2(a2, y4, c4, l, h2, le);
|
|
124
124
|
},
|
|
125
125
|
eq: function(a2, y4, c4, l, h2) {
|
|
126
|
-
return
|
|
126
|
+
return norm2(a2, y4, c4, l, h2, eq2);
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
}
|
|
@@ -484,168 +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 {object[]|null} The fields to retrieve info for.
|
|
567
|
-
*/
|
|
568
|
-
fields() {
|
|
569
|
-
return null;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Called by the coordinator to set the field info for this client.
|
|
573
|
-
* @param {*} info The field info result.
|
|
574
|
-
* @returns {this}
|
|
575
|
-
*/
|
|
576
|
-
fieldInfo(info) {
|
|
577
|
-
return this;
|
|
578
|
-
}
|
|
579
|
-
/**
|
|
580
|
-
* Return a query specifying the data needed by this client.
|
|
581
|
-
* @param {*} [filter] The filtering criteria to apply in the query.
|
|
582
|
-
* @returns {*} The client query
|
|
583
|
-
*/
|
|
584
|
-
query(filter3) {
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Called by the coordinator to inform the client that a query is pending.
|
|
589
|
-
* @returns {this}
|
|
590
|
-
*/
|
|
591
|
-
queryPending() {
|
|
592
|
-
return this;
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* Called by the coordinator to return a query result.
|
|
596
|
-
* @param {*} data The query result.
|
|
597
|
-
* @returns {this}
|
|
598
|
-
*/
|
|
599
|
-
queryResult(data) {
|
|
600
|
-
return this;
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Called by the coordinator to report a query execution error.
|
|
604
|
-
* @param {*} error
|
|
605
|
-
* @returns {this}
|
|
606
|
-
*/
|
|
607
|
-
queryError(error) {
|
|
608
|
-
return this;
|
|
609
|
-
}
|
|
610
|
-
/**
|
|
611
|
-
* Request the coordinator to execute a query for this client.
|
|
612
|
-
* If an explicit query is not provided, the client query method will
|
|
613
|
-
* be called, filtered by the current filterBy selection.
|
|
614
|
-
* @returns {Promise}
|
|
615
|
-
*/
|
|
616
|
-
requestQuery(query) {
|
|
617
|
-
const q2 = query || this.query(this.filterBy?.predicate(this));
|
|
618
|
-
return this._coordinator.requestQuery(this, q2);
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* Request that the coordinator perform a throttled update of this client
|
|
622
|
-
* using the default query. Unlike requestQuery, for which every call will
|
|
623
|
-
* result in an executed query, multiple calls to requestUpdate may be
|
|
624
|
-
* consolidated into a single update.
|
|
625
|
-
*/
|
|
626
|
-
requestUpdate() {
|
|
627
|
-
this._requestUpdate();
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Reset this client, initiating new field info and query requests.
|
|
631
|
-
* @returns {Promise}
|
|
632
|
-
*/
|
|
633
|
-
initialize() {
|
|
634
|
-
return this._coordinator.initializeClient(this);
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Requests a client update.
|
|
638
|
-
* For example to (re-)render an interface component.
|
|
639
|
-
*
|
|
640
|
-
* @returns {this | Promise<any>}
|
|
641
|
-
*/
|
|
642
|
-
update() {
|
|
643
|
-
return this;
|
|
644
|
-
}
|
|
645
|
-
};
|
|
646
|
-
|
|
647
487
|
// ../../node_modules/@uwdata/flechette/src/constants.js
|
|
648
488
|
var MAGIC = Uint8Array.of(65, 82, 82, 79, 87, 49);
|
|
489
|
+
var EOS = Uint8Array.of(255, 255, 255, 255, 0, 0, 0, 0);
|
|
649
490
|
var Version = (
|
|
650
491
|
/** @type {const} */
|
|
651
492
|
{
|
|
@@ -3060,7 +2901,7 @@ function literalToSQL(value) {
|
|
|
3060
2901
|
case "number":
|
|
3061
2902
|
return Number.isFinite(value) ? `${value}` : "NULL";
|
|
3062
2903
|
case "string":
|
|
3063
|
-
return `'${value.
|
|
2904
|
+
return `'${value.replaceAll(`'`, `''`)}'`;
|
|
3064
2905
|
case "boolean":
|
|
3065
2906
|
return value ? "TRUE" : "FALSE";
|
|
3066
2907
|
default:
|
|
@@ -3451,6 +3292,9 @@ var ColumnNameRefNode = class extends ColumnRefNode {
|
|
|
3451
3292
|
};
|
|
3452
3293
|
|
|
3453
3294
|
// ../sql/src/ast/column-param.js
|
|
3295
|
+
function isColumnParam(value) {
|
|
3296
|
+
return value instanceof ColumnParamNode;
|
|
3297
|
+
}
|
|
3454
3298
|
var ColumnParamNode = class extends ColumnRefNode {
|
|
3455
3299
|
/**
|
|
3456
3300
|
* Instantiate a column param node.
|
|
@@ -4591,6 +4435,9 @@ function entropy(expr) {
|
|
|
4591
4435
|
function first(expr) {
|
|
4592
4436
|
return aggFn("first", expr);
|
|
4593
4437
|
}
|
|
4438
|
+
function geomean(expr) {
|
|
4439
|
+
return aggFn("geomean", expr);
|
|
4440
|
+
}
|
|
4594
4441
|
function kurtosis(expr) {
|
|
4595
4442
|
return aggFn("kurtosis", expr);
|
|
4596
4443
|
}
|
|
@@ -5039,7 +4886,7 @@ function collectAggregates(root2) {
|
|
|
5039
4886
|
function collectColumns(root2) {
|
|
5040
4887
|
const cols = {};
|
|
5041
4888
|
walk(root2, (node) => {
|
|
5042
|
-
if (node.type === COLUMN_REF) {
|
|
4889
|
+
if (node.type === COLUMN_REF || node.type === COLUMN_PARAM) {
|
|
5043
4890
|
cols[node] = node;
|
|
5044
4891
|
}
|
|
5045
4892
|
});
|
|
@@ -5170,21 +5017,21 @@ function bin2d(q2, xp, yp, aggs, xn, groupby) {
|
|
|
5170
5017
|
}
|
|
5171
5018
|
|
|
5172
5019
|
// ../sql/src/transforms/bin-linear-1d.js
|
|
5173
|
-
function binLinear1d(query, x4, weight) {
|
|
5020
|
+
function binLinear1d(query, x4, weight = void 0, groupby = []) {
|
|
5174
5021
|
const w = weight ? (x5) => mul(x5, weight) : (x5) => x5;
|
|
5175
5022
|
const p0 = floor(x4);
|
|
5176
5023
|
const p1 = add(p0, 1);
|
|
5177
5024
|
return Query.from(Query.unionAll(
|
|
5178
5025
|
query.clone().select({ i: int322(p0), w: w(sub(p1, x4)) }),
|
|
5179
5026
|
query.clone().select({ i: int322(p1), w: w(sub(x4, p0)) })
|
|
5180
|
-
)).select({ index: "i", density: sum("w") }).groupby("index").having(neq("density", 0));
|
|
5027
|
+
)).select({ index: "i", density: sum("w") }, groupby).groupby("index", groupby).having(neq("density", 0));
|
|
5181
5028
|
}
|
|
5182
5029
|
|
|
5183
5030
|
// ../sql/src/transforms/bin-linear-2d.js
|
|
5184
5031
|
function identity(x4) {
|
|
5185
5032
|
return x4;
|
|
5186
5033
|
}
|
|
5187
|
-
function binLinear2d(q2, xp, yp, weight, xn, groupby) {
|
|
5034
|
+
function binLinear2d(q2, xp, yp, weight, xn, groupby = []) {
|
|
5188
5035
|
const w = weight ? (x4) => mul(x4, weight) : identity;
|
|
5189
5036
|
const subq = (i, w2) => q2.clone().select({ xp, yp, i, w: w2 });
|
|
5190
5037
|
const index2 = (x4, y4) => add(x4, mul(y4, xn));
|
|
@@ -5385,6 +5232,8 @@ function sufficientStatistics(node, preagg, avg2) {
|
|
|
5385
5232
|
return sumExpr(preagg, node);
|
|
5386
5233
|
case "avg":
|
|
5387
5234
|
return avgExpr(preagg, node);
|
|
5235
|
+
case "geomean":
|
|
5236
|
+
return geomeanExpr(preagg, node);
|
|
5388
5237
|
case "arg_max":
|
|
5389
5238
|
return argmaxExpr(preagg, node);
|
|
5390
5239
|
case "arg_min":
|
|
@@ -5468,6 +5317,12 @@ function avgExpr(preagg, node) {
|
|
|
5468
5317
|
const { expr, name: name2 } = countExpr(preagg, node);
|
|
5469
5318
|
return div(sum(mul(as, name2)), expr);
|
|
5470
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
|
+
}
|
|
5471
5326
|
function argmaxExpr(preagg, node) {
|
|
5472
5327
|
const expr = addStat(preagg, node);
|
|
5473
5328
|
const maxy = addStat(preagg, max(node.args[1]), node);
|
|
@@ -5914,7 +5769,7 @@ var statMap = {
|
|
|
5914
5769
|
[Min]: min,
|
|
5915
5770
|
[Nulls]: (column3) => count().where(isNull(column3))
|
|
5916
5771
|
};
|
|
5917
|
-
function summarize(table3, column3, stats) {
|
|
5772
|
+
function summarize({ table: table3, column: column3, stats }) {
|
|
5918
5773
|
return Query.from(table3).select(Array.from(stats, (s2) => ({ [s2]: statMap[s2](column3) })));
|
|
5919
5774
|
}
|
|
5920
5775
|
async function queryFieldInfo(mc, fields) {
|
|
@@ -5925,7 +5780,7 @@ async function queryFieldInfo(mc, fields) {
|
|
|
5925
5780
|
}
|
|
5926
5781
|
}
|
|
5927
5782
|
async function getFieldInfo(mc, { table: table3, column: column3, stats }) {
|
|
5928
|
-
const q2 = Query.from({ source: table3 }).select({ column: column3 }).groupby(column3
|
|
5783
|
+
const q2 = Query.from({ source: table3 }).select({ column: column3 }).groupby(isNode(column3) && isAggregateExpression(column3) ? sql`ALL` : []);
|
|
5929
5784
|
const [desc2] = Array.from(await mc.query(Query.describe(q2)));
|
|
5930
5785
|
const info = {
|
|
5931
5786
|
table: table3,
|
|
@@ -5934,16 +5789,16 @@ async function getFieldInfo(mc, { table: table3, column: column3, stats }) {
|
|
|
5934
5789
|
type: jsType(desc2.column_type),
|
|
5935
5790
|
nullable: desc2.null === "YES"
|
|
5936
5791
|
};
|
|
5937
|
-
if (!
|
|
5792
|
+
if (!stats?.length) return info;
|
|
5938
5793
|
const [result] = await mc.query(
|
|
5939
|
-
summarize(table3, column3, stats),
|
|
5794
|
+
summarize({ table: table3, column: column3, stats }),
|
|
5940
5795
|
{ persist: true }
|
|
5941
5796
|
);
|
|
5942
5797
|
return Object.assign(info, result);
|
|
5943
5798
|
}
|
|
5944
5799
|
async function getTableInfo(mc, table3) {
|
|
5945
|
-
const result = await mc.query(`DESCRIBE ${asTableRef(table3)}`);
|
|
5946
|
-
return
|
|
5800
|
+
const result = Array.from(await mc.query(`DESCRIBE ${asTableRef(table3)}`));
|
|
5801
|
+
return result.map((desc2) => ({
|
|
5947
5802
|
table: table3,
|
|
5948
5803
|
column: desc2.column_name,
|
|
5949
5804
|
sqlType: desc2.column_type,
|
|
@@ -6540,13 +6395,13 @@ var Coordinator = class {
|
|
|
6540
6395
|
}
|
|
6541
6396
|
/**
|
|
6542
6397
|
* Issue a query for which no result (return value) is needed.
|
|
6543
|
-
* @param {
|
|
6398
|
+
* @param { import('./types.js').QueryType[] |
|
|
6399
|
+
* import('./types.js').QueryType} query The query or an array of queries.
|
|
6544
6400
|
* Each query should be either a Query builder object or a SQL string.
|
|
6545
6401
|
* @param {object} [options] An options object.
|
|
6546
6402
|
* @param {number} [options.priority] The query priority, defaults to
|
|
6547
6403
|
* `Priority.Normal`.
|
|
6548
|
-
* @returns {QueryResult} A query result
|
|
6549
|
-
* promise.
|
|
6404
|
+
* @returns {QueryResult} A query result promise.
|
|
6550
6405
|
*/
|
|
6551
6406
|
exec(query, { priority = Priority.Normal } = {}) {
|
|
6552
6407
|
query = Array.isArray(query) ? query.filter((x4) => x4).join(";\n") : query;
|
|
@@ -6555,11 +6410,14 @@ var Coordinator = class {
|
|
|
6555
6410
|
/**
|
|
6556
6411
|
* Issue a query to the backing database. The submitted query may be
|
|
6557
6412
|
* consolidate with other queries and its results may be cached.
|
|
6558
|
-
* @param {QueryType} query The query as either a Query
|
|
6559
|
-
* or a SQL string.
|
|
6413
|
+
* @param {import('./types.js').QueryType} query The query as either a Query
|
|
6414
|
+
* builder object or a SQL string.
|
|
6560
6415
|
* @param {object} [options] An options object.
|
|
6561
6416
|
* @param {'arrow' | 'json'} [options.type] The query result format type.
|
|
6562
|
-
* @param {boolean} [options.cache=true] If true, cache the query result
|
|
6417
|
+
* @param {boolean} [options.cache=true] If true, cache the query result
|
|
6418
|
+
* client-side within the QueryManager.
|
|
6419
|
+
* @param {boolean} [options.persist] If true, request the database
|
|
6420
|
+
* server to persist a cached query server-side.
|
|
6563
6421
|
* @param {number} [options.priority] The query priority, defaults to
|
|
6564
6422
|
* `Priority.Normal`.
|
|
6565
6423
|
* @returns {QueryResult} A query result promise.
|
|
@@ -6575,8 +6433,8 @@ var Coordinator = class {
|
|
|
6575
6433
|
/**
|
|
6576
6434
|
* Issue a query to prefetch data for later use. The query result is cached
|
|
6577
6435
|
* for efficient future access.
|
|
6578
|
-
* @param {QueryType} query The query as either a Query
|
|
6579
|
-
* or a SQL string.
|
|
6436
|
+
* @param {import('./types.js').QueryType} query The query as either a Query
|
|
6437
|
+
* builder object or a SQL string.
|
|
6580
6438
|
* @param {object} [options] An options object.
|
|
6581
6439
|
* @param {'arrow' | 'json'} [options.type] The query result format type.
|
|
6582
6440
|
* @returns {QueryResult} A query result promise.
|
|
@@ -6611,13 +6469,13 @@ var Coordinator = class {
|
|
|
6611
6469
|
* Update client data by submitting the given query and returning the
|
|
6612
6470
|
* data (or error) to the client.
|
|
6613
6471
|
* @param {MosaicClient} client A Mosaic client.
|
|
6614
|
-
* @param {QueryType} query The data query.
|
|
6472
|
+
* @param {import('./types.js').QueryType} query The data query.
|
|
6615
6473
|
* @param {number} [priority] The query priority.
|
|
6616
6474
|
* @returns {Promise} A Promise that resolves upon completion of the update.
|
|
6617
6475
|
*/
|
|
6618
6476
|
updateClient(client, query, priority = Priority.Normal) {
|
|
6619
6477
|
client.queryPending();
|
|
6620
|
-
return this.query(query, { priority }).then(
|
|
6478
|
+
return client._pending = this.query(query, { priority }).then(
|
|
6621
6479
|
(data) => client.queryResult(data).update(),
|
|
6622
6480
|
(err) => {
|
|
6623
6481
|
this._logger.error(err);
|
|
@@ -6630,7 +6488,7 @@ var Coordinator = class {
|
|
|
6630
6488
|
* the client is simply updated. Otherwise `updateClient` is called. As a
|
|
6631
6489
|
* side effect, this method clears the current preaggregator state.
|
|
6632
6490
|
* @param {MosaicClient} client The client to update.
|
|
6633
|
-
* @param {QueryType | null} [query] The query to issue.
|
|
6491
|
+
* @param {import('./types.js').QueryType | null} [query] The query to issue.
|
|
6634
6492
|
*/
|
|
6635
6493
|
requestQuery(client, query) {
|
|
6636
6494
|
this.preaggregator.clear();
|
|
@@ -6647,7 +6505,7 @@ var Coordinator = class {
|
|
|
6647
6505
|
}
|
|
6648
6506
|
clients.add(client);
|
|
6649
6507
|
client.coordinator = this;
|
|
6650
|
-
this.initializeClient(client);
|
|
6508
|
+
client._pending = this.initializeClient(client);
|
|
6651
6509
|
connectSelection(this, client.filterBy, client);
|
|
6652
6510
|
}
|
|
6653
6511
|
async initializeClient(client) {
|
|
@@ -6655,6 +6513,7 @@ var Coordinator = class {
|
|
|
6655
6513
|
if (fields?.length) {
|
|
6656
6514
|
client.fieldInfo(await queryFieldInfo(this, fields));
|
|
6657
6515
|
}
|
|
6516
|
+
await client.prepare();
|
|
6658
6517
|
return client.requestQuery();
|
|
6659
6518
|
}
|
|
6660
6519
|
/**
|
|
@@ -7274,6 +7133,179 @@ var SelectionResolver = class {
|
|
|
7274
7133
|
}
|
|
7275
7134
|
};
|
|
7276
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
|
+
|
|
7277
7309
|
// ../core/src/connectors/rest.js
|
|
7278
7310
|
function restConnector(uri = "http://localhost:3000/") {
|
|
7279
7311
|
return {
|
|
@@ -7295,7 +7327,11 @@ function restConnector(uri = "http://localhost:3000/") {
|
|
|
7295
7327
|
headers: { "Content-Type": "application/json" },
|
|
7296
7328
|
body: JSON.stringify(query)
|
|
7297
7329
|
});
|
|
7298
|
-
|
|
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();
|
|
7299
7335
|
}
|
|
7300
7336
|
};
|
|
7301
7337
|
}
|
|
@@ -19947,6 +19983,7 @@ __export(api_exports, {
|
|
|
19947
19983
|
fyTicks: () => fyTicks,
|
|
19948
19984
|
geo: () => geo2,
|
|
19949
19985
|
geojson: () => geojson,
|
|
19986
|
+
geomean: () => geomean,
|
|
19950
19987
|
graticule: () => graticule3,
|
|
19951
19988
|
grid: () => grid,
|
|
19952
19989
|
gridFx: () => gridFx2,
|
|
@@ -44039,6 +44076,9 @@ var DEFAULT_ATTRIBUTES = {
|
|
|
44039
44076
|
marginBottom: 30
|
|
44040
44077
|
};
|
|
44041
44078
|
var Plot = class {
|
|
44079
|
+
/**
|
|
44080
|
+
* @param {HTMLElement} [element]
|
|
44081
|
+
*/
|
|
44042
44082
|
constructor(element) {
|
|
44043
44083
|
this.attributes = { ...DEFAULT_ATTRIBUTES };
|
|
44044
44084
|
this.listeners = null;
|
|
@@ -44046,12 +44086,12 @@ var Plot = class {
|
|
|
44046
44086
|
this.legends = [];
|
|
44047
44087
|
this.marks = [];
|
|
44048
44088
|
this.markset = null;
|
|
44089
|
+
this.params = /* @__PURE__ */ new Map();
|
|
44090
|
+
this.synch = synchronizer();
|
|
44049
44091
|
this.element = element || document.createElement("div");
|
|
44050
44092
|
this.element.setAttribute("class", "plot");
|
|
44051
44093
|
this.element.style.display = "flex";
|
|
44052
|
-
this.element
|
|
44053
|
-
this.params = /* @__PURE__ */ new Map();
|
|
44054
|
-
this.synch = synchronizer();
|
|
44094
|
+
Object.assign(this.element, { value: this });
|
|
44055
44095
|
}
|
|
44056
44096
|
margins() {
|
|
44057
44097
|
return {
|
|
@@ -44195,7 +44235,9 @@ function isColor2(value) {
|
|
|
44195
44235
|
|
|
44196
44236
|
// ../plot/src/marks/util/is-constant-option.js
|
|
44197
44237
|
var constantOptions = /* @__PURE__ */ new Set([
|
|
44238
|
+
"offset",
|
|
44198
44239
|
"order",
|
|
44240
|
+
"reverse",
|
|
44199
44241
|
"sort",
|
|
44200
44242
|
"label",
|
|
44201
44243
|
"anchor",
|
|
@@ -44267,7 +44309,7 @@ var isFieldObject = (channel, field3) => {
|
|
|
44267
44309
|
var fieldEntry = (channel, field3) => ({
|
|
44268
44310
|
channel,
|
|
44269
44311
|
field: field3,
|
|
44270
|
-
as: isColumnRef(field3) ? field3.column : channel
|
|
44312
|
+
as: isColumnRef(field3) && !isColumnParam(field3) ? field3.column : channel
|
|
44271
44313
|
});
|
|
44272
44314
|
var valueEntry = (channel, value) => ({ channel, value });
|
|
44273
44315
|
var isDataArray = (source) => Array.isArray(source);
|
|
@@ -44363,7 +44405,11 @@ var Mark2 = class extends MosaicClient {
|
|
|
44363
44405
|
reqs[channel]?.forEach((s2) => entry.add(s2));
|
|
44364
44406
|
}
|
|
44365
44407
|
const table3 = this.sourceTable();
|
|
44366
|
-
return Array.from(fields, ([c4, s2]) => ({
|
|
44408
|
+
return Array.from(fields, ([c4, s2]) => ({
|
|
44409
|
+
table: table3,
|
|
44410
|
+
column: c4,
|
|
44411
|
+
stats: Array.from(s2)
|
|
44412
|
+
}));
|
|
44367
44413
|
}
|
|
44368
44414
|
fieldInfo(info) {
|
|
44369
44415
|
const lookup = Object.fromEntries(info.map((x4) => [x4.column, x4]));
|
|
@@ -44420,7 +44466,7 @@ function markQuery(channels, table3, skip = []) {
|
|
|
44420
44466
|
const { channel, field: field3, as } = c4;
|
|
44421
44467
|
if (skip.includes(channel)) continue;
|
|
44422
44468
|
if (channel === "orderby") {
|
|
44423
|
-
q2.orderby(c4.value);
|
|
44469
|
+
q2.orderby(c4.value ?? field3);
|
|
44424
44470
|
} else if (field3) {
|
|
44425
44471
|
if (isAggregateExpression(field3)) {
|
|
44426
44472
|
aggr = true;
|
|
@@ -44552,7 +44598,7 @@ var ConnectedMark = class extends Mark2 {
|
|
|
44552
44598
|
const cols = q2._select.map((c4) => c4.alias).filter((c4) => c4 !== as && c4 !== value);
|
|
44553
44599
|
return m4(q2, expr, as, value, cols);
|
|
44554
44600
|
} else {
|
|
44555
|
-
return q2.orderby(
|
|
44601
|
+
return q2.orderby(as);
|
|
44556
44602
|
}
|
|
44557
44603
|
}
|
|
44558
44604
|
};
|
|
@@ -44561,13 +44607,33 @@ var ConnectedMark = class extends Mark2 {
|
|
|
44561
44607
|
function array3(size, proto = []) {
|
|
44562
44608
|
return new proto.constructor(size);
|
|
44563
44609
|
}
|
|
44564
|
-
function grid1d(size, index2, value) {
|
|
44565
|
-
const
|
|
44566
|
-
const
|
|
44567
|
-
|
|
44568
|
-
|
|
44610
|
+
function grid1d(size, index2, value, columns, groupby) {
|
|
44611
|
+
const numRows = index2.length;
|
|
44612
|
+
const result = {};
|
|
44613
|
+
const cells = [];
|
|
44614
|
+
if (groupby?.length) {
|
|
44615
|
+
const group3 = new Int32Array(numRows);
|
|
44616
|
+
const gvalues = groupby.map((name2) => columns[name2]);
|
|
44617
|
+
const cellMap = {};
|
|
44618
|
+
for (let row = 0; row < numRows; ++row) {
|
|
44619
|
+
const key = gvalues.map((group4) => group4[row]);
|
|
44620
|
+
group3[row] = cellMap[key] ??= cells.push(key) - 1;
|
|
44621
|
+
}
|
|
44622
|
+
for (let i = 0; i < groupby.length; ++i) {
|
|
44623
|
+
result[groupby[i]] = cells.map((cell3) => cell3[i]);
|
|
44624
|
+
}
|
|
44625
|
+
const G = result._grid = cells.map(() => array3(size, value));
|
|
44626
|
+
for (let row = 0; row < numRows; ++row) {
|
|
44627
|
+
G[group3[row]][index2[row]] = value[row];
|
|
44628
|
+
}
|
|
44629
|
+
} else {
|
|
44630
|
+
cells.push([]);
|
|
44631
|
+
const [G] = result._grid = [array3(size, value)];
|
|
44632
|
+
for (let row = 0; row < numRows; ++row) {
|
|
44633
|
+
G[index2[row]] = value[row];
|
|
44634
|
+
}
|
|
44569
44635
|
}
|
|
44570
|
-
return
|
|
44636
|
+
return { numRows: cells.length, columns: result };
|
|
44571
44637
|
}
|
|
44572
44638
|
function grid2d(w, h2, index2, columns, aggregates, groupby, interpolate) {
|
|
44573
44639
|
const numRows = index2.length;
|
|
@@ -45425,9 +45491,16 @@ function stripXY(mark2, filter3) {
|
|
|
45425
45491
|
}
|
|
45426
45492
|
|
|
45427
45493
|
// ../plot/src/marks/Density1DMark.js
|
|
45494
|
+
var GROUPBY = { fill: 1, stroke: 1, z: 1 };
|
|
45428
45495
|
var Density1DMark = class extends Mark2 {
|
|
45429
45496
|
constructor(type2, source, options) {
|
|
45430
|
-
const {
|
|
45497
|
+
const {
|
|
45498
|
+
bins: bins2 = 1024,
|
|
45499
|
+
bandwidth = 20,
|
|
45500
|
+
normalize: normalize4 = false,
|
|
45501
|
+
stack: stack2 = false,
|
|
45502
|
+
...channels
|
|
45503
|
+
} = options;
|
|
45431
45504
|
const dim = type2.endsWith("X") ? "y" : "x";
|
|
45432
45505
|
super(type2, source, channels, dim === "x" ? xext : yext);
|
|
45433
45506
|
this.dim = dim;
|
|
@@ -45436,7 +45509,13 @@ var Density1DMark = class extends Mark2 {
|
|
|
45436
45509
|
});
|
|
45437
45510
|
this.bandwidth = handleParam(bandwidth, (value) => {
|
|
45438
45511
|
this.bandwidth = value;
|
|
45439
|
-
return this.
|
|
45512
|
+
return this.grids ? this.convolve().update() : null;
|
|
45513
|
+
});
|
|
45514
|
+
this.normalize = handleParam(normalize4, (value) => {
|
|
45515
|
+
return this.normalize = value, this.convolve().update();
|
|
45516
|
+
});
|
|
45517
|
+
this.stack = handleParam(stack2, (value) => {
|
|
45518
|
+
return this.stack = value, this.update();
|
|
45440
45519
|
});
|
|
45441
45520
|
}
|
|
45442
45521
|
get filterStable() {
|
|
@@ -45451,42 +45530,67 @@ var Density1DMark = class extends Mark2 {
|
|
|
45451
45530
|
const [x4, bx] = binExpr(this, dim, bins2, extent4);
|
|
45452
45531
|
const q2 = markQuery(channels, this.sourceTable(), [dim]).where(filter3.concat(isBetween(bx, extent4)));
|
|
45453
45532
|
const v3 = this.channelField("weight") ? "weight" : null;
|
|
45454
|
-
|
|
45533
|
+
const g2 = this.groupby = channels.flatMap((c4) => {
|
|
45534
|
+
return GROUPBY[c4.channel] && c4.field ? c4.as : [];
|
|
45535
|
+
});
|
|
45536
|
+
return binLinear1d(q2, x4, v3, g2);
|
|
45455
45537
|
}
|
|
45456
45538
|
queryResult(data) {
|
|
45457
|
-
const
|
|
45458
|
-
this.
|
|
45539
|
+
const c4 = toDataColumns(data).columns;
|
|
45540
|
+
this.grids = grid1d(this.bins, c4.index, c4.density, c4, this.groupby);
|
|
45459
45541
|
return this.convolve();
|
|
45460
45542
|
}
|
|
45461
45543
|
convolve() {
|
|
45462
|
-
const {
|
|
45463
|
-
|
|
45544
|
+
const {
|
|
45545
|
+
bins: bins2,
|
|
45546
|
+
bandwidth,
|
|
45547
|
+
normalize: normalize4,
|
|
45548
|
+
dim,
|
|
45549
|
+
grids,
|
|
45550
|
+
groupby,
|
|
45551
|
+
plot: plot3,
|
|
45552
|
+
extent: [lo, hi]
|
|
45553
|
+
} = this;
|
|
45554
|
+
const cols = grids.columns;
|
|
45555
|
+
const numGrids = grids.numRows;
|
|
45556
|
+
const b2 = this.channelField(dim).as;
|
|
45557
|
+
const v3 = dim === "x" ? "y" : "x";
|
|
45464
45558
|
const size = dim === "x" ? plot3.innerWidth() : plot3.innerHeight();
|
|
45559
|
+
const neg = cols._grid.some((grid2) => grid2.some((v4) => v4 < 0));
|
|
45465
45560
|
const config = dericheConfig(bandwidth * (bins2 - 1) / size, neg);
|
|
45466
|
-
const result = dericheConv1d(config, grid2, bins2);
|
|
45467
|
-
const v3 = dim === "x" ? "y" : "x";
|
|
45468
|
-
const b2 = this.channelField(dim).as;
|
|
45469
45561
|
const b0 = +lo;
|
|
45470
45562
|
const delta = (hi - b0) / (bins2 - 1);
|
|
45471
|
-
const
|
|
45472
|
-
const _b2 = new Float64Array(
|
|
45473
|
-
const _v2 = new Float64Array(
|
|
45474
|
-
|
|
45475
|
-
|
|
45476
|
-
|
|
45477
|
-
|
|
45478
|
-
|
|
45563
|
+
const numRows = bins2 * numGrids;
|
|
45564
|
+
const _b2 = new Float64Array(numRows);
|
|
45565
|
+
const _v2 = new Float64Array(numRows);
|
|
45566
|
+
const _g2 = groupby.reduce((m2, name2) => (m2[name2] = Array(numRows), m2), {});
|
|
45567
|
+
for (let k3 = 0, g2 = 0; g2 < numGrids; ++g2) {
|
|
45568
|
+
groupby.forEach((name2) => _g2[name2].fill(cols[name2][g2], k3, k3 + bins2));
|
|
45569
|
+
const grid2 = cols._grid[g2];
|
|
45570
|
+
const result = dericheConv1d(config, grid2, bins2);
|
|
45571
|
+
const scale3 = 1 / norm(grid2, result, delta, normalize4);
|
|
45572
|
+
for (let i = 0; i < bins2; ++i, ++k3) {
|
|
45573
|
+
_b2[k3] = b0 + i * delta;
|
|
45574
|
+
_v2[k3] = result[i] * scale3;
|
|
45575
|
+
}
|
|
45576
|
+
}
|
|
45577
|
+
this.data = { numRows, columns: { [b2]: _b2, [v3]: _v2, ..._g2 } };
|
|
45479
45578
|
return this;
|
|
45480
45579
|
}
|
|
45481
45580
|
plotSpecs() {
|
|
45482
|
-
const { type: type2, data: { numRows: length4, columns }, channels, dim } = this;
|
|
45483
|
-
const
|
|
45581
|
+
const { type: type2, data: { numRows: length4, columns }, channels, dim, stack: stack2 } = this;
|
|
45582
|
+
const _2 = type2.startsWith("area") && !stack2 ? "2" : "";
|
|
45583
|
+
const options = dim === "x" ? { [`y${_2}`]: columns.y } : { [`x${_2}`]: columns.x };
|
|
45484
45584
|
for (const c4 of channels) {
|
|
45485
45585
|
options[c4.channel] = channelOption(c4, columns);
|
|
45486
45586
|
}
|
|
45487
45587
|
return [{ type: type2, data: { length: length4 }, options }];
|
|
45488
45588
|
}
|
|
45489
45589
|
};
|
|
45590
|
+
function norm(grid2, smoothed, delta, type2) {
|
|
45591
|
+
const value = type2 === true || type2 === "sum" ? sum2(grid2) : type2 === "max" ? max2(smoothed) : delta;
|
|
45592
|
+
return value || 1;
|
|
45593
|
+
}
|
|
45490
45594
|
|
|
45491
45595
|
// ../plot/src/marks/Density2DMark.js
|
|
45492
45596
|
var Density2DMark = class extends Grid2DMark {
|
|
@@ -46654,12 +46758,13 @@ var Nearest = class {
|
|
|
46654
46758
|
selection2.update(that.clause(void 0));
|
|
46655
46759
|
});
|
|
46656
46760
|
svg.addEventListener("pointerenter", (evt) => {
|
|
46657
|
-
if (!evt.buttons)
|
|
46658
|
-
const v3 = this.channels.map(() => 0);
|
|
46659
|
-
selection2.activate(this.clause(v3));
|
|
46660
|
-
}
|
|
46761
|
+
if (!evt.buttons) this.activate();
|
|
46661
46762
|
});
|
|
46662
46763
|
}
|
|
46764
|
+
activate() {
|
|
46765
|
+
const v3 = this.channels.map(() => 0);
|
|
46766
|
+
this.selection.activate(this.clause(v3));
|
|
46767
|
+
}
|
|
46663
46768
|
};
|
|
46664
46769
|
function calculateXY(svg, mark2) {
|
|
46665
46770
|
const { data: { columns } } = mark2;
|
|
@@ -46755,7 +46860,7 @@ var PanZoom = class {
|
|
|
46755
46860
|
this.svg = svg;
|
|
46756
46861
|
if (this.initialized) return;
|
|
46757
46862
|
else this.initialized = true;
|
|
46758
|
-
const { panx, pany, mark: { plot: { element } }
|
|
46863
|
+
const { panx, pany, mark: { plot: { element } } } = this;
|
|
46759
46864
|
this.xscale = svg.scale("x");
|
|
46760
46865
|
this.yscale = svg.scale("y");
|
|
46761
46866
|
const rx = this.xscale.range.slice().sort(asc2);
|
|
@@ -46772,19 +46877,21 @@ var PanZoom = class {
|
|
|
46772
46877
|
element.addEventListener("pointerenter", (evt) => {
|
|
46773
46878
|
if (enter) return;
|
|
46774
46879
|
else enter = true;
|
|
46775
|
-
if (evt.buttons)
|
|
46776
|
-
if (panx) {
|
|
46777
|
-
const { xscale, xfield } = this;
|
|
46778
|
-
xsel.activate(this.clause(xscale.domain, xfield, xscale));
|
|
46779
|
-
}
|
|
46780
|
-
if (pany) {
|
|
46781
|
-
const { yscale, yfield } = this;
|
|
46782
|
-
ysel.activate(this.clause(yscale.domain, yfield, yscale));
|
|
46783
|
-
}
|
|
46880
|
+
if (!evt.buttons) this.activate();
|
|
46784
46881
|
});
|
|
46785
46882
|
element.addEventListener("pointerleave", () => enter = false);
|
|
46786
46883
|
}
|
|
46787
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
|
+
}
|
|
46788
46895
|
};
|
|
46789
46896
|
function extent3(ext, defaultTrue, defaultFalse) {
|
|
46790
46897
|
return ext ? Array.isArray(ext) ? ext : defaultTrue : defaultFalse;
|
|
@@ -47169,8 +47276,8 @@ var Toggle = class {
|
|
|
47169
47276
|
channels,
|
|
47170
47277
|
peers = true
|
|
47171
47278
|
}) {
|
|
47172
|
-
this.value = null;
|
|
47173
47279
|
this.mark = mark2;
|
|
47280
|
+
this.value = null;
|
|
47174
47281
|
this.selection = selection2;
|
|
47175
47282
|
this.peers = peers;
|
|
47176
47283
|
const fields = this.fields = [];
|
|
@@ -47222,10 +47329,12 @@ var Toggle = class {
|
|
|
47222
47329
|
}
|
|
47223
47330
|
});
|
|
47224
47331
|
svg.addEventListener("pointerenter", (evt) => {
|
|
47225
|
-
if (evt.buttons)
|
|
47226
|
-
this.selection.activate(this.clause([this.fields.map(() => 0)]));
|
|
47332
|
+
if (!evt.buttons) this.activate();
|
|
47227
47333
|
});
|
|
47228
47334
|
}
|
|
47335
|
+
activate() {
|
|
47336
|
+
this.selection.activate(this.clause([this.fields.map(() => 0)]));
|
|
47337
|
+
}
|
|
47229
47338
|
};
|
|
47230
47339
|
function isTargetElement(groups2, node) {
|
|
47231
47340
|
return groups2.some((g2) => g2.contains(node));
|
|
@@ -47519,11 +47628,30 @@ var BinTransformNode = class extends ExprNode {
|
|
|
47519
47628
|
}
|
|
47520
47629
|
};
|
|
47521
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
|
+
|
|
47522
47650
|
// ../inputs/src/Menu.js
|
|
47523
47651
|
var isObject3 = (v3) => {
|
|
47524
47652
|
return v3 && typeof v3 === "object" && !Array.isArray(v3);
|
|
47525
47653
|
};
|
|
47526
|
-
var Menu = class extends
|
|
47654
|
+
var Menu = class extends Input {
|
|
47527
47655
|
/**
|
|
47528
47656
|
* Create a new menu input.
|
|
47529
47657
|
* @param {object} [options] Options object
|
|
@@ -47554,6 +47682,7 @@ var Menu = class extends MosaicClient {
|
|
|
47554
47682
|
constructor({
|
|
47555
47683
|
element,
|
|
47556
47684
|
filterBy,
|
|
47685
|
+
as,
|
|
47557
47686
|
from: from2,
|
|
47558
47687
|
column: column3,
|
|
47559
47688
|
label = column3,
|
|
@@ -47561,26 +47690,22 @@ var Menu = class extends MosaicClient {
|
|
|
47561
47690
|
// TODO
|
|
47562
47691
|
options,
|
|
47563
47692
|
value,
|
|
47564
|
-
field: field3 = column3
|
|
47565
|
-
as
|
|
47693
|
+
field: field3 = column3
|
|
47566
47694
|
} = {}) {
|
|
47567
|
-
super(filterBy);
|
|
47695
|
+
super(filterBy, element);
|
|
47568
47696
|
this.from = from2;
|
|
47569
47697
|
this.column = column3;
|
|
47570
47698
|
this.format = format3;
|
|
47571
47699
|
this.field = field3;
|
|
47572
47700
|
const selection2 = this.selection = as;
|
|
47573
|
-
this.element = element ?? document.createElement("div");
|
|
47574
|
-
this.element.setAttribute("class", "input");
|
|
47575
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47576
47701
|
const lab3 = document.createElement("label");
|
|
47577
47702
|
lab3.innerText = label || column3;
|
|
47578
47703
|
this.element.appendChild(lab3);
|
|
47579
47704
|
this.select = document.createElement("select");
|
|
47580
47705
|
this.element.appendChild(this.select);
|
|
47581
47706
|
if (options) {
|
|
47582
|
-
this.data = options.map((
|
|
47583
|
-
this.selectedValue(value
|
|
47707
|
+
this.data = options.map((opt) => isObject3(opt) ? opt : { value: opt });
|
|
47708
|
+
this.selectedValue(value === void 0 ? "" : value);
|
|
47584
47709
|
this.update();
|
|
47585
47710
|
}
|
|
47586
47711
|
if (selection2) {
|
|
@@ -47622,7 +47747,9 @@ var Menu = class extends MosaicClient {
|
|
|
47622
47747
|
this.select.selectedIndex = this.from ? 0 : -1;
|
|
47623
47748
|
}
|
|
47624
47749
|
activate() {
|
|
47625
|
-
|
|
47750
|
+
if (isSelection(this.selection)) {
|
|
47751
|
+
this.selection.activate(clausePoint(this.field, 0, { source: this }));
|
|
47752
|
+
}
|
|
47626
47753
|
}
|
|
47627
47754
|
publish(value) {
|
|
47628
47755
|
const { selection: selection2, field: field3 } = this;
|
|
@@ -47654,7 +47781,7 @@ var Menu = class extends MosaicClient {
|
|
|
47654
47781
|
}
|
|
47655
47782
|
if (selection2) {
|
|
47656
47783
|
const value = isSelection(selection2) ? selection2.valueFor(this) : selection2.value;
|
|
47657
|
-
this.selectedValue(value
|
|
47784
|
+
this.selectedValue(value === void 0 ? "" : value);
|
|
47658
47785
|
}
|
|
47659
47786
|
return this;
|
|
47660
47787
|
}
|
|
@@ -47662,7 +47789,7 @@ var Menu = class extends MosaicClient {
|
|
|
47662
47789
|
|
|
47663
47790
|
// ../inputs/src/Search.js
|
|
47664
47791
|
var _id = 0;
|
|
47665
|
-
var Search = class extends
|
|
47792
|
+
var Search = class extends Input {
|
|
47666
47793
|
/**
|
|
47667
47794
|
* Create a new text search input.
|
|
47668
47795
|
* @param {object} [options] Options object
|
|
@@ -47698,16 +47825,13 @@ var Search = class extends MosaicClient {
|
|
|
47698
47825
|
field: field3 = column3,
|
|
47699
47826
|
as
|
|
47700
47827
|
} = {}) {
|
|
47701
|
-
super(filterBy);
|
|
47828
|
+
super(filterBy, element);
|
|
47702
47829
|
this.id = "search_" + ++_id;
|
|
47703
47830
|
this.type = type2;
|
|
47704
47831
|
this.from = from2;
|
|
47705
47832
|
this.column = column3;
|
|
47706
47833
|
this.selection = as;
|
|
47707
47834
|
this.field = field3;
|
|
47708
|
-
this.element = element ?? document.createElement("div");
|
|
47709
|
-
this.element.setAttribute("class", "input");
|
|
47710
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47711
47835
|
if (label) {
|
|
47712
47836
|
const lab3 = document.createElement("label");
|
|
47713
47837
|
lab3.setAttribute("for", this.id);
|
|
@@ -47745,7 +47869,9 @@ var Search = class extends MosaicClient {
|
|
|
47745
47869
|
return clauseMatch(field3, value, { source: this, method: type2 });
|
|
47746
47870
|
}
|
|
47747
47871
|
activate() {
|
|
47748
|
-
this.selection
|
|
47872
|
+
if (isSelection(this.selection)) {
|
|
47873
|
+
this.selection.activate(this.clause(""));
|
|
47874
|
+
}
|
|
47749
47875
|
}
|
|
47750
47876
|
publish(value) {
|
|
47751
47877
|
const { selection: selection2 } = this;
|
|
@@ -47782,7 +47908,7 @@ var Search = class extends MosaicClient {
|
|
|
47782
47908
|
|
|
47783
47909
|
// ../inputs/src/Slider.js
|
|
47784
47910
|
var _id2 = 0;
|
|
47785
|
-
var Slider = class extends
|
|
47911
|
+
var Slider = class extends Input {
|
|
47786
47912
|
/**
|
|
47787
47913
|
* Create a new slider input.
|
|
47788
47914
|
* @param {object} [options] Options object
|
|
@@ -47828,7 +47954,7 @@ var Slider = class extends MosaicClient {
|
|
|
47828
47954
|
field: field3 = column3,
|
|
47829
47955
|
width: width2
|
|
47830
47956
|
} = {}) {
|
|
47831
|
-
super(filterBy);
|
|
47957
|
+
super(filterBy, element);
|
|
47832
47958
|
this.id = "slider_" + ++_id2;
|
|
47833
47959
|
this.from = from2;
|
|
47834
47960
|
this.column = column3 || "value";
|
|
@@ -47838,9 +47964,6 @@ var Slider = class extends MosaicClient {
|
|
|
47838
47964
|
this.min = min5;
|
|
47839
47965
|
this.max = max4;
|
|
47840
47966
|
this.step = step;
|
|
47841
|
-
this.element = element || document.createElement("div");
|
|
47842
|
-
this.element.setAttribute("class", "input");
|
|
47843
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47844
47967
|
if (label) {
|
|
47845
47968
|
const desc2 = document.createElement("label");
|
|
47846
47969
|
desc2.setAttribute("for", this.id);
|
|
@@ -47921,7 +48044,9 @@ var Slider = class extends MosaicClient {
|
|
|
47921
48044
|
}
|
|
47922
48045
|
}
|
|
47923
48046
|
activate() {
|
|
47924
|
-
this.selection
|
|
48047
|
+
if (isSelection(this.selection)) {
|
|
48048
|
+
this.selection.activate(this.clause(0));
|
|
48049
|
+
}
|
|
47925
48050
|
}
|
|
47926
48051
|
publish(value) {
|
|
47927
48052
|
const { selection: selection2 } = this;
|
|
@@ -47954,10 +48079,36 @@ function localize(f2) {
|
|
|
47954
48079
|
|
|
47955
48080
|
// ../inputs/src/Table.js
|
|
47956
48081
|
var _id3 = -1;
|
|
47957
|
-
var Table3 = class extends
|
|
48082
|
+
var Table3 = class extends Input {
|
|
47958
48083
|
/**
|
|
47959
48084
|
* Create a new Table instance.
|
|
47960
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.
|
|
47961
48112
|
*/
|
|
47962
48113
|
constructor({
|
|
47963
48114
|
element,
|
|
@@ -47972,8 +48123,9 @@ var Table3 = class extends MosaicClient {
|
|
|
47972
48123
|
rowBatch = 100,
|
|
47973
48124
|
as
|
|
47974
48125
|
} = {}) {
|
|
47975
|
-
super(filterBy);
|
|
48126
|
+
super(filterBy, element, null);
|
|
47976
48127
|
this.id = `table-${++_id3}`;
|
|
48128
|
+
this.element.setAttribute("id", this.id);
|
|
47977
48129
|
this.from = from2;
|
|
47978
48130
|
this.columns = columns;
|
|
47979
48131
|
this.format = format3;
|
|
@@ -47984,28 +48136,25 @@ var Table3 = class extends MosaicClient {
|
|
|
47984
48136
|
}
|
|
47985
48137
|
this.offset = 0;
|
|
47986
48138
|
this.limit = +rowBatch;
|
|
47987
|
-
this.
|
|
48139
|
+
this.isPending = false;
|
|
47988
48140
|
this.selection = as;
|
|
47989
48141
|
this.currentRow = -1;
|
|
47990
48142
|
this.sortHeader = null;
|
|
47991
48143
|
this.sortColumn = null;
|
|
47992
48144
|
this.sortDesc = false;
|
|
47993
|
-
this.element = element || document.createElement("div");
|
|
47994
|
-
this.element.setAttribute("id", this.id);
|
|
47995
|
-
Object.defineProperty(this.element, "value", { value: this });
|
|
47996
48145
|
if (typeof width2 === "number") this.element.style.width = `${width2}px`;
|
|
47997
48146
|
if (maxWidth) this.element.style.maxWidth = `${maxWidth}px`;
|
|
47998
48147
|
this.element.style.maxHeight = `${height2}px`;
|
|
47999
48148
|
this.element.style.overflow = "auto";
|
|
48000
48149
|
let prevScrollTop = -1;
|
|
48001
48150
|
this.element.addEventListener("scroll", (evt) => {
|
|
48002
|
-
const {
|
|
48151
|
+
const { isPending, loaded } = this;
|
|
48003
48152
|
const { scrollHeight, scrollTop, clientHeight } = evt.target;
|
|
48004
48153
|
const back = scrollTop < prevScrollTop;
|
|
48005
48154
|
prevScrollTop = scrollTop;
|
|
48006
|
-
if (back ||
|
|
48155
|
+
if (back || isPending || loaded) return;
|
|
48007
48156
|
if (scrollHeight - scrollTop < 2 * clientHeight) {
|
|
48008
|
-
this.
|
|
48157
|
+
this.isPending = true;
|
|
48009
48158
|
this.requestData(this.offset + this.limit);
|
|
48010
48159
|
}
|
|
48011
48160
|
});
|
|
@@ -48050,8 +48199,8 @@ var Table3 = class extends MosaicClient {
|
|
|
48050
48199
|
coordinator().prefetch(query.clone().offset(offset2 + this.limit));
|
|
48051
48200
|
}
|
|
48052
48201
|
fields() {
|
|
48053
|
-
const
|
|
48054
|
-
return this.columns.map((
|
|
48202
|
+
const table3 = this.sourceTable();
|
|
48203
|
+
return this.columns.map((column3) => ({ column: column3, table: table3 }));
|
|
48055
48204
|
}
|
|
48056
48205
|
fieldInfo(info) {
|
|
48057
48206
|
this.schema = info;
|
|
@@ -48079,7 +48228,7 @@ var Table3 = class extends MosaicClient {
|
|
|
48079
48228
|
return Query.from(this.sourceTable()).select(schema.map((s2) => s2.column)).where(filter3).orderby(sortColumn ? sortDesc ? desc(sortColumn) : sortColumn : []).limit(limit).offset(offset2);
|
|
48080
48229
|
}
|
|
48081
48230
|
queryResult(data) {
|
|
48082
|
-
if (!this.
|
|
48231
|
+
if (!this.isPending) {
|
|
48083
48232
|
this.loaded = false;
|
|
48084
48233
|
this.data = [];
|
|
48085
48234
|
this.body.replaceChildren();
|
|
@@ -48109,9 +48258,14 @@ var Table3 = class extends MosaicClient {
|
|
|
48109
48258
|
if (numRows < limit) {
|
|
48110
48259
|
this.loaded = true;
|
|
48111
48260
|
}
|
|
48112
|
-
this.
|
|
48261
|
+
this.isPending = false;
|
|
48113
48262
|
return this;
|
|
48114
48263
|
}
|
|
48264
|
+
activate() {
|
|
48265
|
+
if (isSelection(this.selection)) {
|
|
48266
|
+
this.selection.activate(this.clause([]));
|
|
48267
|
+
}
|
|
48268
|
+
}
|
|
48115
48269
|
sort(event, column3) {
|
|
48116
48270
|
if (column3 === this.sortColumn) {
|
|
48117
48271
|
this.sortDesc = !this.sortDesc;
|
|
@@ -49233,6 +49387,7 @@ export {
|
|
|
49233
49387
|
fyTicks,
|
|
49234
49388
|
geo2 as geo,
|
|
49235
49389
|
geojson,
|
|
49390
|
+
geomean,
|
|
49236
49391
|
graticule3 as graticule,
|
|
49237
49392
|
grid,
|
|
49238
49393
|
gridFx2 as gridFx,
|