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