@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 CHANGED
@@ -103,7 +103,7 @@ var require_search_bounds = __commonJS({
103
103
  }
104
104
  return -1;
105
105
  }
106
- function norm(a2, y4, c4, l, h2, f2) {
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 norm(a2, y4, c4, l, h2, ge);
114
+ return norm2(a2, y4, c4, l, h2, ge);
115
115
  },
116
116
  gt: function(a2, y4, c4, l, h2) {
117
- return norm(a2, y4, c4, l, h2, gt2);
117
+ return norm2(a2, y4, c4, l, h2, gt2);
118
118
  },
119
119
  lt: function(a2, y4, c4, l, h2) {
120
- return norm(a2, y4, c4, l, h2, lt2);
120
+ return norm2(a2, y4, c4, l, h2, lt2);
121
121
  },
122
122
  le: function(a2, y4, c4, l, h2) {
123
- return norm(a2, y4, c4, l, h2, le);
123
+ return norm2(a2, y4, c4, l, h2, le);
124
124
  },
125
125
  eq: function(a2, y4, c4, l, h2) {
126
- return norm(a2, y4, c4, l, h2, eq2);
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.replace(`'`, `''`)}'`;
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.aggregate ? sql`ALL` : []);
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 (!(stats?.length || stats?.size)) return info;
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 Array.from(result).map((desc2) => ({
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 {QueryType | QueryType[]} query The query or an array of queries.
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 builder object
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 builder object
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
- return query.type === "exec" ? req : query.type === "arrow" ? decodeIPC2(await (await req).arrayBuffer()) : (await req).json();
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.value = this;
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]) => ({ table: table3, column: c4, stats: 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(field3);
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 G = array3(size, value);
44566
- const n = value.length;
44567
- for (let i = 0; i < n; ++i) {
44568
- G[index2[i]] = value[i];
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 G;
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 { bins: bins2 = 1024, bandwidth = 20, ...channels } = options;
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.grid ? this.convolve().update() : null;
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
- return binLinear1d(q2, x4, v3);
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 { columns: { index: index2, density: density3 } } = toDataColumns(data);
45458
- this.grid = grid1d(this.bins, index2, density3);
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 { bins: bins2, bandwidth, dim, grid: grid2, plot: plot3, extent: [lo, hi] } = this;
45463
- const neg = grid2.some((v4) => v4 < 0);
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 scale3 = 1 / delta;
45472
- const _b2 = new Float64Array(bins2);
45473
- const _v2 = new Float64Array(bins2);
45474
- for (let i = 0; i < bins2; ++i) {
45475
- _b2[i] = b0 + i * delta;
45476
- _v2[i] = result[i] * scale3;
45477
- }
45478
- this.data = { numRows: bins2, columns: { [b2]: _b2, [v3]: _v2 } };
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 options = dim === "x" ? { y: columns.y } : { x: columns.x };
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 } }, xsel, ysel } = this;
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) return;
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) return;
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 MosaicClient {
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((value2) => isObject3(value2) ? value2 : { value: value2 });
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
- this.selection.activate(clausePoint(this.field, 0, { source: this }));
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 MosaicClient {
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.activate(this.clause(""));
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 MosaicClient {
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.activate(this.clause(0));
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 MosaicClient {
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.pending = false;
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 { pending, loaded } = this;
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 || pending || loaded) return;
48155
+ if (back || isPending || loaded) return;
48007
48156
  if (scrollHeight - scrollTop < 2 * clientHeight) {
48008
- this.pending = true;
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 from2 = this.sourceTable();
48054
- return this.columns.map((name2) => column(name2, from2));
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.pending) {
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.pending = false;
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,