@genome-spy/core 0.44.0 → 0.46.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.
Files changed (129) hide show
  1. package/dist/bundle/{index-lmJu1tfP.js → index-BtRKzKhM.js} +6 -6
  2. package/dist/bundle/{index--cKb-dKG.js → index-BwFvhduA.js} +5 -5
  3. package/dist/bundle/{index-1QVesMzU.js → index-C8lYPtq_.js} +1 -1
  4. package/dist/bundle/{index-Pv3tKJ1W.js → index-CkI3Kd2P.js} +3 -3
  5. package/dist/bundle/{index-Y-LdHNIz.js → index-CmBp-spD.js} +1 -1
  6. package/dist/bundle/{index-z4Cs62EO.js → index-Dixm7K89.js} +4 -4
  7. package/dist/bundle/{index-noY1e-G6.js → index-Sk-Wtwdn.js} +5 -5
  8. package/dist/bundle/{index-UyrC0vvF.js → index-Z7JiNsFI.js} +4 -4
  9. package/dist/bundle/{index-LD6yPc3X.js → index-mihmTLo-.js} +1 -1
  10. package/dist/bundle/index.es.js +6339 -5615
  11. package/dist/bundle/index.js +222 -150
  12. package/dist/bundle/{long-Veu0zKh9.js → long-CYrAUkxh.js} +2 -2
  13. package/dist/bundle/{remoteFile-Ur-gRKsH.js → remoteFile-1_eCK3VV.js} +1 -1
  14. package/dist/schema.json +481 -90
  15. package/dist/src/data/collector.d.ts +1 -0
  16. package/dist/src/data/collector.d.ts.map +1 -1
  17. package/dist/src/data/collector.js +23 -5
  18. package/dist/src/data/flow.test.js +4 -0
  19. package/dist/src/data/flowNode.d.ts +10 -8
  20. package/dist/src/data/flowNode.d.ts.map +1 -1
  21. package/dist/src/data/flowNode.js +25 -15
  22. package/dist/src/data/flowOptimizer.test.js +12 -3
  23. package/dist/src/data/sources/dataSource.d.ts +17 -0
  24. package/dist/src/data/sources/dataSource.d.ts.map +1 -1
  25. package/dist/src/data/sources/dataSource.js +34 -0
  26. package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
  27. package/dist/src/data/sources/dataUtils.js +3 -1
  28. package/dist/src/data/sources/inlineSource.js +1 -1
  29. package/dist/src/data/sources/lazy/bigBedSource.d.ts +1 -1
  30. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  31. package/dist/src/data/sources/lazy/bigBedSource.js +58 -20
  32. package/dist/src/data/sources/lazy/bigWigSource.d.ts +0 -1
  33. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  34. package/dist/src/data/sources/lazy/bigWigSource.js +58 -19
  35. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +0 -8
  36. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  37. package/dist/src/data/sources/lazy/singleAxisLazySource.js +1 -15
  38. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +6 -2
  39. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  40. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +41 -23
  41. package/dist/src/data/sources/namedSource.js +1 -1
  42. package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
  43. package/dist/src/data/sources/sequenceSource.js +16 -6
  44. package/dist/src/data/sources/sequenceSource.test.js +23 -5
  45. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  46. package/dist/src/data/sources/urlSource.js +24 -7
  47. package/dist/src/data/transforms/aggregate.d.ts.map +1 -1
  48. package/dist/src/data/transforms/aggregate.js +5 -2
  49. package/dist/src/data/transforms/filter.d.ts +2 -2
  50. package/dist/src/data/transforms/filter.d.ts.map +1 -1
  51. package/dist/src/data/transforms/filter.js +3 -6
  52. package/dist/src/data/transforms/filter.test.js +6 -0
  53. package/dist/src/data/transforms/formula.d.ts +2 -2
  54. package/dist/src/data/transforms/formula.d.ts.map +1 -1
  55. package/dist/src/data/transforms/formula.js +3 -3
  56. package/dist/src/data/transforms/formula.test.js +7 -1
  57. package/dist/src/encoder/encoder.d.ts +2 -4
  58. package/dist/src/encoder/encoder.d.ts.map +1 -1
  59. package/dist/src/encoder/encoder.js +8 -8
  60. package/dist/src/encoder/encoder.test.js +3 -0
  61. package/dist/src/genomeSpy.d.ts +12 -7
  62. package/dist/src/genomeSpy.d.ts.map +1 -1
  63. package/dist/src/genomeSpy.js +132 -139
  64. package/dist/src/gl/glslScaleGenerator.js +1 -1
  65. package/dist/src/index.d.ts +1 -1
  66. package/dist/src/index.d.ts.map +1 -1
  67. package/dist/src/index.js +1 -1
  68. package/dist/src/marks/mark.d.ts +8 -5
  69. package/dist/src/marks/mark.d.ts.map +1 -1
  70. package/dist/src/marks/mark.js +67 -12
  71. package/dist/src/marks/point.common.glsl.js +1 -1
  72. package/dist/src/marks/point.d.ts +1 -4
  73. package/dist/src/marks/point.d.ts.map +1 -1
  74. package/dist/src/marks/point.js +31 -23
  75. package/dist/src/marks/point.vertex.glsl.js +1 -1
  76. package/dist/src/marks/text.d.ts.map +1 -1
  77. package/dist/src/marks/text.js +15 -7
  78. package/dist/src/spec/data.d.ts +11 -10
  79. package/dist/src/spec/mark.d.ts +11 -21
  80. package/dist/src/spec/parameter.d.ts +11 -7
  81. package/dist/src/spec/root.d.ts +0 -8
  82. package/dist/src/spec/title.d.ts +5 -4
  83. package/dist/src/spec/view.d.ts +64 -6
  84. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  85. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  86. package/dist/src/styles/genome-spy.css.js +56 -5
  87. package/dist/src/styles/genome-spy.scss +68 -10
  88. package/dist/src/styles/update.sh +6 -0
  89. package/dist/src/tooltip/dataTooltipHandler.js +1 -1
  90. package/dist/src/tooltip/refseqGeneTooltipHandler.js +1 -1
  91. package/dist/src/tooltip/tooltipHandler.d.ts +1 -1
  92. package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
  93. package/dist/src/tooltip/tooltipHandler.ts +1 -1
  94. package/dist/src/types/embedApi.d.ts +6 -0
  95. package/dist/src/types/viewContext.d.ts +11 -5
  96. package/dist/src/utils/debounce.d.ts +2 -2
  97. package/dist/src/utils/debounce.d.ts.map +1 -1
  98. package/dist/src/utils/debounce.js +5 -2
  99. package/dist/src/utils/expression.d.ts +2 -2
  100. package/dist/src/utils/expression.d.ts.map +1 -1
  101. package/dist/src/utils/expression.js +2 -2
  102. package/dist/src/utils/formatObject.d.ts +2 -2
  103. package/dist/src/utils/formatObject.d.ts.map +1 -1
  104. package/dist/src/utils/formatObject.js +2 -2
  105. package/dist/src/utils/inputBinding.d.ts +5 -0
  106. package/dist/src/utils/inputBinding.d.ts.map +1 -0
  107. package/dist/src/utils/inputBinding.js +115 -0
  108. package/dist/src/utils/ui/tooltip.js +1 -1
  109. package/dist/src/view/paramMediator.d.ts +109 -0
  110. package/dist/src/view/paramMediator.d.ts.map +1 -0
  111. package/dist/src/view/paramMediator.js +338 -0
  112. package/dist/src/view/paramMediator.test.js +224 -0
  113. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  114. package/dist/src/view/scaleResolution.js +11 -6
  115. package/dist/src/view/view.d.ts +4 -1
  116. package/dist/src/view/view.d.ts.map +1 -1
  117. package/dist/src/view/view.js +19 -5
  118. package/dist/src/view/viewFactory.d.ts +4 -1
  119. package/dist/src/view/viewFactory.d.ts.map +1 -1
  120. package/dist/src/view/viewFactory.js +86 -13
  121. package/dist/src/view/viewUtils.d.ts +7 -8
  122. package/dist/src/view/viewUtils.d.ts.map +1 -1
  123. package/dist/src/view/viewUtils.js +30 -34
  124. package/package.json +16 -17
  125. package/dist/src/paramBroker.d.ts +0 -46
  126. package/dist/src/paramBroker.d.ts.map +0 -1
  127. package/dist/src/paramBroker.js +0 -118
  128. /package/dist/bundle/{__vite-browser-external-ENoMJThg.js → __vite-browser-external-C--ziKoh.js} +0 -0
  129. /package/dist/bundle/{_commonjsHelpers-QtkX90xp.js → _commonjsHelpers-BIiJCwQW.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA+CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA0FpD;IAvFG,uBAA0B;IAE1B,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAM/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB,0BAAqC;IAGrC;;;;OAIG;IACH,8DAA8B;IA4GlC;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAyCC;IAED,0BA0EC;IAtEG,uBAOC;IAyCD,sCAA0D;IAS1D,yCAA6D;IAI7D,iBAA0C;IAW9C;;OAEG;IACH,gBAmBC;IAED,sCAwMC;IAED;;;OAGG;IACH,UAFa,QAAQ,OAAO,CAAC,CA6B5B;IAED,4BA6IC;IAjIe,iCAAoC;IAmIpD;;;OAGG;IACH,kBAHW,MAAM,KACN,MAAM,QAiEhB;IAED;;;;;;;OAOG;IACH,oDAHuB,QAAQ,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;IAED,sBAyCC;IAED,kBAIC;IAED,iCAOC;IAED,iCASC;IAED,qFAWC;;CACJ;;;;iCAh8BY,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,gBAAgB;4BAlC7C,uBAAuB;4BA0BP,uBAAuB;qBAZ9C,qBAAqB;wBAIlB,yBAAyB;yCARR,yDAAyD;oBAYvD,oBAAoB;wBAMvC,kBAAkB;wBApBlB,qBAAqB;oBAVzB,uBAAuB;qBAQtB,oBAAoB"}
1
+ {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA8CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA2FpD;IAxFG,uBAA0B;IAC1B,oDAAsB;IAItB,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAE/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB;;;;OAIG;IACH;gBAF8B,OAAO,wBAAwB,EAAE,iBAAiB;iBAAW,MAAM;OAEnE;IAE9B;;OAEG;IACH,wBAFU,WAAW,CAEkB;IA2C3C;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAqDC;IA0DG,uBAOC;IAGD,mCAGE;IAOF,sCAEE;IAGF,iBAAyC;IAW7C;;OAEG;IACH,gBAuBC;IAED,sCA8MC;IAED;;;OAGG;IACH,UAFa,QAAQ,OAAO,CAAC,CA6B5B;IAED,4BA6IC;IAjIe,iCAAoC;IAmIpD;;;OAGG;IACH,kBAHW,MAAM,KACN,MAAM,QAiEhB;IAED;;;;;;;OAOG;IACH,oDAHuB,QAAQ,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;IAED,sBA6CC;IAED,kBAIC;IAED,iCAOC;IAED,iCASC;IAED,qFAWC;;CACJ;;;;iCA16BY,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,gBAAgB;4BAjC7C,uBAAuB;4BA2BP,uBAAuB;qBAZ9C,qBAAqB;wBAIlB,yBAAyB;yCARR,yDAAyD;oBAYvD,oBAAoB;wBAdvC,qBAAqB;oBAXzB,uBAAuB;qBAStB,oBAAoB"}
@@ -1,5 +1,5 @@
1
1
  import { formats as vegaFormats } from "vega-loader";
2
- import { html, render } from "lit-html";
2
+ import { html, nothing, render } from "lit";
3
3
  import { styleMap } from "lit/directives/style-map.js";
4
4
  import SPINNER from "./img/90-ring-with-bg.svg";
5
5
 
@@ -11,6 +11,7 @@ import {
11
11
  checkForDuplicateScaleNames,
12
12
  setImplicitScaleNames,
13
13
  calculateCanvasSize,
14
+ calculateViewRootSize,
14
15
  } from "./view/viewUtils.js";
15
16
  import UnitView from "./view/unitView.js";
16
17
 
@@ -34,9 +35,7 @@ import dataTooltipHandler from "./tooltip/dataTooltipHandler.js";
34
35
  import { invalidatePrefix } from "./utils/propertyCacher.js";
35
36
  import { VIEW_ROOT_NAME, ViewFactory } from "./view/viewFactory.js";
36
37
  import { reconfigureScales } from "./view/scaleResolution.js";
37
- import ParamBroker from "./paramBroker.js";
38
- import { debounce } from "./utils/debounce.js";
39
- import { tickStep } from "d3-array";
38
+ import createBindingInputs from "./utils/inputBinding.js";
40
39
 
41
40
  /**
42
41
  * Events that are broadcasted to all views.
@@ -61,14 +60,13 @@ export default class GenomeSpy {
61
60
  */
62
61
  constructor(container, spec, options = {}) {
63
62
  this.container = container;
63
+ this.options = options;
64
+
65
+ options.inputBindingContainer ??= "default";
64
66
 
65
67
  /** @type {(() => void)[]} */
66
68
  this._destructionCallbacks = [];
67
69
 
68
- const styleElement = document.createElement("style");
69
- styleElement.innerHTML = css;
70
- container.appendChild(styleElement);
71
-
72
70
  /** Root level configuration object */
73
71
  this.spec = spec;
74
72
 
@@ -138,118 +136,55 @@ export default class GenomeSpy {
138
136
  /** @type {View} */
139
137
  this.viewRoot = undefined;
140
138
 
141
- this._paramBroker = new ParamBroker();
142
- this.#initializeParameters();
143
-
144
139
  /**
145
140
  * Views that are currently loading data using lazy sources.
146
141
  *
147
- * @type {Map<View, boolean>}
142
+ * @type {Map<View, { status: import("./types/viewContext.js").DataLoadingStatus, detail?: string }>}
148
143
  */
149
144
  this._loadingViews = new Map();
145
+
146
+ /**
147
+ * @type {HTMLElement}
148
+ */
149
+ this._inputBindingContainer = undefined;
150
150
  }
151
151
 
152
- #initializeParameters() {
153
- /** @type {import("lit-html").TemplateResult[]} */
154
- const inputs = [];
152
+ get #canvasWrapper() {
153
+ return /** @type {HTMLElement} */ (
154
+ this.container.querySelector(".canvas-wrapper")
155
+ );
156
+ }
155
157
 
156
- for (const param of this.spec.params ?? []) {
157
- const { name, value, bind } = param;
158
- const setter = this._paramBroker.allocateSetter(name);
158
+ #initializeParameterBindings() {
159
+ /** @type {import("lit").TemplateResult[]} */
160
+ const inputs = [];
159
161
 
160
- if (value != null) {
161
- setter(value);
162
- }
162
+ this.viewRoot.visit((view) => {
163
+ const mediator = view.paramMediator;
164
+ inputs.push(...createBindingInputs(mediator));
165
+ });
166
+ const ibc = this.options.inputBindingContainer;
163
167
 
164
- // TODO: Implement two-way data binding, e.g. when an external agent changes
165
- // the parameter value, the UI components should be updated.
166
-
167
- if (bind && "input" in bind) {
168
- const debouncedSetter = bind.debounce
169
- ? debounce(setter, bind.debounce, false)
170
- : setter;
171
-
172
- if (bind.input == "range") {
173
- // TODO: Show the value next to the slider
174
- inputs.push(
175
- html`<label
176
- >${bind.name ?? name}
177
- <input
178
- type="range"
179
- min=${bind.min ?? 0}
180
- max=${bind.max ?? 100}
181
- step=${bind.step ??
182
- tickStep(bind.min, bind.max, 100)}
183
- .value=${value}
184
- @input=${(/** @type {any} */ e) =>
185
- debouncedSetter(e.target.valueAsNumber)}
186
- /></label>`
187
- );
188
- } else if (bind.input == "checkbox") {
189
- inputs.push(
190
- html`<label
191
- >${bind.name ?? name}
192
- <input
193
- type="checkbox"
194
- ?checked=${value}
195
- @input=${(/** @type {any} */ e) =>
196
- debouncedSetter(e.target.checked)}
197
- /></label>`
198
- );
199
- } else if (bind.input == "radio") {
200
- inputs.push(
201
- html`<span class="label">${bind.name ?? name}</span>
202
- ${bind.options.map(
203
- (option, i) => html`<label>
204
- <input
205
- type="radio"
206
- name=${name}
207
- value=${option}
208
- .checked=${value == option}
209
- @input=${(/** @type {any} */ e) =>
210
- debouncedSetter(e.target.value)}
211
- />${bind.labels?.[i] ?? option}</label
212
- >`
213
- )}`
214
- );
215
- } else if (bind.input == "select") {
216
- inputs.push(
217
- html`<label
218
- >${bind.name ?? name}
219
- <select
220
- @input=${(/** @type {any} */ e) =>
221
- debouncedSetter(e.target.value)}
222
- >
223
- ${bind.options.map(
224
- (option, i) => html`<option
225
- value=${option}
226
- ?selected=${value == option}
227
- >
228
- ${bind.labels?.[i] ?? option}
229
- </option>`
230
- )}
231
- </select></label
232
- >`
233
- );
234
- } else {
235
- // TODO: Support other types: "text", "number", "color".
236
- throw new Error("Unsupported input type: " + bind.input);
237
- }
238
- }
168
+ if (!ibc || ibc == "none" || !inputs.length) {
169
+ return;
239
170
  }
240
171
 
241
- if (inputs.length) {
242
- const inputsDiv = document.createElement("div");
243
- this.container.appendChild(inputsDiv);
172
+ this._inputBindingContainer = element("div", {
173
+ className: "gs-input-bindings",
174
+ });
244
175
 
245
- // TODO: Move to css
246
- // @ts-ignore
247
- inputsDiv.style =
248
- "position: absolute; bottom: 10px; right: 10px; background: rgba(255, 255, 255, 0.8); padding: 10px; z-index: 1; border: 1px solid lightgray";
176
+ if (ibc == "default") {
177
+ this.container.appendChild(this._inputBindingContainer);
178
+ } else if (ibc instanceof HTMLElement) {
179
+ ibc.appendChild(this._inputBindingContainer);
180
+ } else {
181
+ throw new Error("Invalid inputBindingContainer");
182
+ }
249
183
 
184
+ if (inputs.length) {
250
185
  render(
251
- html`${inputs.map((input) => html`<div>${input}</div>`)}`,
252
- inputsDiv
186
+ html`<div class="gs-input-binding">${inputs}</div>`,
187
+ this._inputBindingContainer
253
188
  );
254
189
  }
255
190
  }
@@ -311,11 +246,13 @@ export default class GenomeSpy {
311
246
  * animations with html elements than with WebGL.
312
247
  */
313
248
  _updateLoadingIndicators() {
314
- /** @type {import("lit-html").TemplateResult[]} */
249
+ /** @type {import("lit").TemplateResult[]} */
315
250
  const indicators = [];
316
251
 
317
252
  const isSomethingVisible = () =>
318
- [...this._loadingViews.values()].some((v) => v);
253
+ [...this._loadingViews.values()].some(
254
+ (v) => v.status == "loading" || v.status == "error"
255
+ );
319
256
 
320
257
  for (const [view, status] of this._loadingViews) {
321
258
  const c = view.coords;
@@ -328,9 +265,18 @@ export default class GenomeSpy {
328
265
  };
329
266
  indicators.push(
330
267
  html`<div style=${styleMap(style)}>
331
- <div class=${status ? "loading" : ""}>
332
- <img src="${SPINNER}" alt="" />
333
- <span>Loading...</span>
268
+ <div class=${status.status}>
269
+ ${status.status == "error"
270
+ ? html`<span
271
+ >Loading
272
+ failed${status.detail
273
+ ? html`: ${status.detail}`
274
+ : nothing}</span
275
+ >`
276
+ : html`
277
+ <img src="${SPINNER}" alt="" />
278
+ <span>Loading...</span>
279
+ `}
334
280
  </div>
335
281
  </div>`
336
282
  );
@@ -339,6 +285,7 @@ export default class GenomeSpy {
339
285
 
340
286
  // Do some hacks to stop css animations of the loading indicators.
341
287
  // Otherwise they fire animation frames even when their opacity is zero.
288
+ // TODO: Instead of this, replace the animated spinners with static images.
342
289
  if (isSomethingVisible()) {
343
290
  this.loadingIndicatorsElement.style.display = "block";
344
291
  } else {
@@ -353,17 +300,10 @@ export default class GenomeSpy {
353
300
  render(indicators, this.loadingIndicatorsElement);
354
301
  }
355
302
 
356
- _prepareContainer() {
357
- this.container.classList.add("genome-spy");
358
- this.container.classList.add("loading");
359
-
360
- this._glHelper = new WebGLHelper(
361
- this.container,
362
- () =>
363
- this.viewRoot
364
- ? calculateCanvasSize(this.viewRoot)
365
- : { width: undefined, height: undefined },
366
- this.spec.background
303
+ #setupDpr() {
304
+ const dprSetter = this.viewRoot.paramMediator.allocateSetter(
305
+ "devicePixelRatio",
306
+ window.devicePixelRatio
367
307
  );
368
308
 
369
309
  const resizeCallback = () => {
@@ -379,9 +319,6 @@ export default class GenomeSpy {
379
319
  resizeObserver.observe(this.container);
380
320
  this._destructionCallbacks.push(() => resizeObserver.disconnect());
381
321
 
382
- const dprSetter = this._paramBroker.allocateSetter("devicePixelRatio");
383
- dprSetter(window.devicePixelRatio);
384
-
385
322
  /** @type {() => void} */
386
323
  let remove = null;
387
324
 
@@ -403,22 +340,48 @@ export default class GenomeSpy {
403
340
  if (remove) {
404
341
  this._destructionCallbacks.push(remove);
405
342
  }
343
+ }
344
+
345
+ #prepareContainer() {
346
+ this.container.classList.add("genome-spy");
347
+
348
+ const styleElement = document.createElement("style");
349
+ styleElement.innerHTML = css;
350
+ this.container.appendChild(styleElement);
351
+
352
+ const canvasWrapper = element("div", {
353
+ class: "canvas-wrapper",
354
+ });
355
+ this.container.appendChild(canvasWrapper);
356
+
357
+ canvasWrapper.classList.add("loading");
358
+
359
+ this._glHelper = new WebGLHelper(
360
+ canvasWrapper,
361
+ () =>
362
+ this.viewRoot
363
+ ? calculateCanvasSize(calculateViewRootSize(this.viewRoot))
364
+ : { width: undefined, height: undefined },
365
+ this.spec.background
366
+ );
406
367
 
407
368
  // The initial loading message that is shown until the first frame is rendered
408
- this.loadingMessageElement = document.createElement("div");
409
- this.loadingMessageElement.className = "loading-message";
410
- this.loadingMessageElement.innerHTML = `<div class="message">Loading<span class="ellipsis">...</span></div>`;
411
- this.container.appendChild(this.loadingMessageElement);
369
+ this.loadingMessageElement = element("div", {
370
+ class: "loading-message",
371
+ innerHTML: `<div class="message">Loading<span class="ellipsis">...</span></div>`,
372
+ });
373
+ canvasWrapper.appendChild(this.loadingMessageElement);
412
374
 
413
375
  // A container for loading indicators (for lazy data sources.)
414
376
  // These could alternatively be included in the view hierarchy,
415
377
  // but it's easier this way – particularly if we want to show
416
378
  // some fancy animated spinners.
417
- this.loadingIndicatorsElement = document.createElement("div");
418
- this.loadingIndicatorsElement.className = "loading-indicators";
419
- this.container.appendChild(this.loadingIndicatorsElement);
379
+ this.loadingIndicatorsElement = element("div", {
380
+ class: "loading-indicators",
381
+ });
382
+ canvasWrapper.appendChild(this.loadingIndicatorsElement);
420
383
 
421
- this.tooltip = new Tooltip(this.container);
384
+ this.tooltip = new Tooltip(canvasWrapper);
422
385
 
423
386
  this.loadingMessageElement
424
387
  .querySelector(".message")
@@ -435,8 +398,10 @@ export default class GenomeSpy {
435
398
  destroy() {
436
399
  // TODO: There's a memory leak somewhere
437
400
 
401
+ const canvasWrapper = this.#canvasWrapper;
402
+
438
403
  this.container.classList.remove("genome-spy");
439
- this.container.classList.remove("loading");
404
+ canvasWrapper.classList.remove("loading");
440
405
 
441
406
  for (const [type, listeners] of this._keyboardListeners) {
442
407
  for (const listener of listeners) {
@@ -448,6 +413,8 @@ export default class GenomeSpy {
448
413
 
449
414
  this._glHelper.finalize();
450
415
 
416
+ this._inputBindingContainer?.remove();
417
+
451
418
  while (this.container.firstChild) {
452
419
  this.container.firstChild.remove();
453
420
  }
@@ -475,8 +442,6 @@ export default class GenomeSpy {
475
442
  return self._glHelper.dpr;
476
443
  },
477
444
 
478
- paramBroker: this._paramBroker,
479
-
480
445
  requestLayoutReflow: () => {
481
446
  // placeholder
482
447
  },
@@ -484,8 +449,8 @@ export default class GenomeSpy {
484
449
  getNamedDataFromProvider: this.getNamedDataFromProvider.bind(this),
485
450
  getCurrentHover: () => this._currentHover,
486
451
 
487
- setDataLoadingStatus: (view, status) => {
488
- this._loadingViews.set(view, status);
452
+ setDataLoadingStatus: (view, status, detail) => {
453
+ this._loadingViews.set(view, { status, detail });
489
454
  this._updateLoadingIndicators();
490
455
  },
491
456
 
@@ -571,6 +536,11 @@ export default class GenomeSpy {
571
536
  VIEW_ROOT_NAME
572
537
  );
573
538
 
539
+ this.#canvasWrapper.style.flexGrow =
540
+ calculateViewRootSize(this.viewRoot).height.grow > 0 ? "1" : "0";
541
+
542
+ this.#initializeParameterBindings();
543
+
574
544
  checkForDuplicateScaleNames(this.viewRoot);
575
545
 
576
546
  setImplicitScaleNames(this.viewRoot);
@@ -585,6 +555,7 @@ export default class GenomeSpy {
585
555
  // We should now have a complete view hierarchy. Let's update the canvas size
586
556
  // and ensure that the loading message is visible.
587
557
  this._glHelper.invalidateSize();
558
+ this.#setupDpr();
588
559
 
589
560
  // Collect all unit views to a list because they need plenty of initialization
590
561
  const unitViews = /** @type {UnitView[]} */ (
@@ -614,12 +585,14 @@ export default class GenomeSpy {
614
585
  view.mark.initializeData();
615
586
  // Update WebGL buffers
616
587
  view.mark.updateGraphicsData();
588
+ context.animator.requestRender();
617
589
  }, view);
618
590
  }
619
591
 
620
592
  // Have to wait until asynchronous font loading is complete.
621
593
  // Text mark's geometry builder needs font metrics before data can be
622
594
  // converted into geometries.
595
+ // TODO: Make updateGraphicsData async and await font loading there.
623
596
  await context.fontManager.waitUntilReady();
624
597
 
625
598
  // Find all data sources and initiate loading
@@ -661,7 +634,7 @@ export default class GenomeSpy {
661
634
  */
662
635
  async launch() {
663
636
  try {
664
- this._prepareContainer();
637
+ this.#prepareContainer();
665
638
 
666
639
  await this._prepareViewsAndData();
667
640
 
@@ -680,7 +653,7 @@ export default class GenomeSpy {
680
653
 
681
654
  return false;
682
655
  } finally {
683
- this.container.classList.remove("loading");
656
+ this.#canvasWrapper.classList.remove("loading");
684
657
  // Transition listener doesn't appear to work on observablehq
685
658
  window.setTimeout(() => {
686
659
  this.loadingMessageElement.style.display = "none";
@@ -959,6 +932,10 @@ export default class GenomeSpy {
959
932
  Rectangle.create(0, 0, canvasSize.width, canvasSize.height)
960
933
  );
961
934
 
935
+ // The view coordinates may have not been known during the initial data loading.
936
+ // Thus, update them so that possible error messages are shown in the correct place.
937
+ this._updateLoadingIndicators();
938
+
962
939
  this.broadcast("layoutComputed");
963
940
  }
964
941
 
@@ -1016,3 +993,19 @@ function createMessageBox(container, message) {
1016
993
  messageBox.appendChild(messageText);
1017
994
  container.appendChild(messageBox);
1018
995
  }
996
+
997
+ /**
998
+ * @param {string} tag
999
+ * @param {Record<string, any>} attrs
1000
+ */
1001
+ function element(tag, attrs) {
1002
+ const el = document.createElement(tag);
1003
+ for (const [key, value] of Object.entries(attrs)) {
1004
+ if (["innerHTML", "innerText", "className"].includes(key)) {
1005
+ // @ts-ignore
1006
+ el[key] = value;
1007
+ }
1008
+ el.setAttribute(key, value);
1009
+ }
1010
+ return el;
1011
+ }
@@ -18,7 +18,7 @@ import {
18
18
  } from "../encoder/encoder.js";
19
19
  import { asArray, peek } from "../utils/arrayUtils.js";
20
20
  import { InternMap } from "internmap";
21
- import { isExprRef } from "../marks/mark.js";
21
+ import { isExprRef } from "../view/paramMediator.js";
22
22
  import scaleNull from "../utils/scaleNull.js";
23
23
 
24
24
  export const ATTRIBUTE_PREFIX = "attr_";
@@ -8,7 +8,7 @@ export function embed(el: string | HTMLElement, spec: string | import("./spec/ro
8
8
  */
9
9
  export function loadSpec(url: string): Promise<any>;
10
10
  import GenomeSpy from "./genomeSpy.js";
11
- import { html } from "lit-html";
11
+ import { html } from "lit";
12
12
  import icon from "./img/bowtie.svg";
13
13
  import favIcon from "./img/genomespy-favicon.svg";
14
14
  export { GenomeSpy, html, icon, favIcon };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":";AAamB,mMAGnB;AAyFA;;;;;GAKG;AACH,8BAFW,MAAM,gBAmBhB;sBA5HqB,gBAAgB;qBAFjB,UAAU;iBAGd,kBAAkB;oBACf,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":";AAawB,mMAGnB;AAyFL;;;;;GAKG;AACH,8BAFW,MAAM,gBAmBhB;sBA5HqB,gBAAgB;qBAFjB,KAAK;iBAGT,kBAAkB;oBACf,6BAA6B"}
package/dist/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isObject, isString } from "vega-util";
2
2
  import { loader as vegaLoader } from "vega-loader";
3
- import { html } from "lit-html";
3
+ import { html } from "lit";
4
4
 
5
5
  import GenomeSpy from "./genomeSpy.js";
6
6
  import icon from "./img/bowtie.svg";
@@ -1,9 +1,4 @@
1
1
  /// <reference types="external-typings/internmap.js" />
2
- /**
3
- * @param {any} x
4
- * @returns {x is import("../spec/parameter.js").ExprRef}
5
- */
6
- export function isExprRef(x: any): x is import("../spec/parameter.js").ExprRef;
7
2
  export const SAMPLE_FACET_UNIFORM: "SAMPLE_FACET_UNIFORM";
8
3
  export const SAMPLE_FACET_TEXTURE: "SAMPLE_FACET_TEXTURE";
9
4
  /**
@@ -90,6 +85,14 @@ export default class Mark {
90
85
  * @returns {Encoding}
91
86
  */
92
87
  fixEncoding(encoding: import("../spec/channel.js").Encoding<string>): import("../spec/channel.js").Encoding<string>;
88
+ /**
89
+ * Handles dynamic properties that are not bound to uniforms but need
90
+ * to trigger a graphics update, i.e., rebuild the vertex buffer.
91
+ *
92
+ * @param {(keyof MarkProps)[]} props
93
+ * @protected
94
+ */
95
+ protected setupExprRefsNeedingGraphicsUpdate(props: (keyof import("../spec/mark.js").MarkProps)[]): void;
93
96
  /**
94
97
  * Returns the encoding spec supplemented with mark's default encodings
95
98
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":";AA4CA,0DAA2D;AAC3D,0DAA2D;AAE3D;;;;;;;;;;;;GAYG;AACH;IAgBI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EAkF/C;IA/EG,gDAAwB;IAExB,oEAAoE;IACpE,UADW,OAAO,MAAM,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC,CACvC;IAIzB,0FAA0F;IAC1F,YADW,OAAO,SAAS,EAAE,UAAU,GAAG;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAC7C;IAE3B,0DAA0D;IAC1D,aADW,OAAO,SAAS,EAAE,WAAW,CACZ;IAE5B,8DAA8D;IAC9D,iBADW,OAAO,SAAS,EAAE,eAAe,CACZ;IAEhC,+DAA+D;IAC/D,mBADW,OAAO,SAAS,EAAE,gBAAgB,CACX;IAElC,+DAA+D;IAC/D,iBADW,OAAO,SAAS,EAAE,gBAAgB,CACb;IAEhC;;;OAGG;IACH,iBAFU,OAAO,SAAS,EAAE,gBAAgB,CAEZ;IAEhC;;;;;OAKG;IACH,uCAA+B;IAE/B,kFAAkF;IAClF,UADW,SAAS,GAAG,CAAC,CACM;IAG9B,wBAAwB;IACxB,uDAqBC;IAED;;;;;;;;OAQG;IACH,kEAKC;IAGL,sBAEC;IAED;;;;;;;OAOG;IACH,iBAFa,MAAM,EAAE,CAKpB;IAED;;OAEG;IACH,+DAWC;IAED;;OAEG;IACH,oEAcC;IAED;;;;;OAKG;IACH,oHAEC;IAED;;;;;;OAMG;IACH,yGAkCC;IAED;;;;OAIG;IACH,8DAiDC;IAED,wDAEC;IAED,8CAEC;IAED,uBAEC;IAED;;;OAGG;IACH,2BAEC;IAED;;OAEG;IACH,oCAEC;IAED;;OAEG;IACH,2BAEC;IAED,sEAeC;IAED;;;;;;OAMG;IAEH,6CANW,MAAM,kBACN,MAAM,iBACN,MAAM,EAAE,QA8NlB;IALG;;;;;;MAIC;IAGL;;;;;;OAMG;IACH,uCA6CC;IAED;;;;;;OAMG;IACH,+CAHW,MAAM,UACK,GAAG,KAAE,IAAI,CAe9B;IAED;;;;;;;;;;OAUG;IACH,mDAJW,MAAM,sFAEsB,GAAG,QA6BzC;IAED;;OAEG;IACH,2BAiBC;IAED;;;OAGG;IACH,6BAFW,GAAG,QAoCb;IAED,yBAAyB;IACzB,uDAEC;IAED,yBAAyB;IACzB,iCAEC;IAED,gCAEC;IAED,+BAEC;IAED,yCAEC;IAED;;;;;OAKG;IACH,gCAcC;IAED;;OAEG;IACH,4CAOC;IAED;;;;;;;;OAQG;IAEH,uBAJW,OAAO,uBAAuB,EAAE,sBAAsB,GACpD,CAAC,MAAM,IAAI,CAAC,EAAE,CAsF1B;IAED;;;;;;OAMG;IACH,qCAJW,oBAAoB,GAClB,OAAO,CAqCnB;IAED;;;;;;;OAOG;IACH,gBAJW,oBAAoB,SACP,IAAI,CAM3B;IAED;;;OAGG;IACH,2BAHW,YAAY,WACZ,OAAO,WAAW,EAAE,oBAAoB,cAiElD;IAED;;;;;;OAMG;IACH,oBAJW,OAAO,6BAA6B,EAAE,OAAO,aAC7C,OAAO,6BAA6B,EAAE,OAAO,GAC3C,OAAO,CAuHnB;IAED;;;;;;;;;OASG;IACH,qBAJW,MAAM,KACN,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAIf;;CACJ;+BAznCY,OAAO,uBAAuB,EAAE,gBAAgB;;;;;;wBAEnD,OAAO;;mCAEJ,gBAAgB,GAAG,qBAAqB;oCAG1C,MAAM,SACN,MAAM;AAmnCjB;;;GAGG;AACH;IACI,cAEC;IAkBD;;;OAGG;IACH,2BAFW,IAAI,CAAC,EAAE,OAAO,yBAAyB,EAAE,UAAU,CAAC,QAiB9D;CACJ;0BAjrCyB,WAAW"}
@@ -40,7 +40,7 @@ import coalesceProperties from "../utils/propertyCoalescer.js";
40
40
  import { isScalar } from "../utils/variableTools.js";
41
41
  import { InternMap } from "internmap";
42
42
  import ViewError from "../view/viewError.js";
43
- import { isString } from "vega-util";
43
+ import { isExprRef } from "../view/paramMediator.js";
44
44
 
45
45
  export const SAMPLE_FACET_UNIFORM = "SAMPLE_FACET_UNIFORM";
46
46
  export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
@@ -221,6 +221,49 @@ export default class Mark {
221
221
  return encoding;
222
222
  }
223
223
 
224
+ /**
225
+ * Handles dynamic properties that are not bound to uniforms but need
226
+ * to trigger a graphics update, i.e., rebuild the vertex buffer.
227
+ *
228
+ * @param {(keyof MarkProps)[]} props
229
+ * @protected
230
+ */
231
+ setupExprRefsNeedingGraphicsUpdate(props) {
232
+ const channels = this.getSupportedChannels();
233
+ /** @type {Partial<MarkProps>} */
234
+ const exprProps = {};
235
+ for (const key of props) {
236
+ const prop = this.properties[key];
237
+ if (prop && isExprRef(prop)) {
238
+ const fn = this.unitView.paramMediator.createExpression(
239
+ prop.expr
240
+ );
241
+ fn.addListener(() => {
242
+ this.updateGraphicsData();
243
+ this.unitView.context.animator.requestRender();
244
+ });
245
+ // @ts-ignore
246
+ if (!channels.includes(key)) {
247
+ Object.defineProperty(exprProps, key, {
248
+ get() {
249
+ return fn();
250
+ },
251
+ });
252
+ } else {
253
+ // Encoder takes care of evaluating the expression
254
+ // N.B.: There are now two expression instances for the
255
+ // same expression, which is no ideal
256
+ }
257
+ }
258
+ }
259
+ const originalProperties = this.properties;
260
+ // @ts-ignore
261
+ this.properties = coalesceProperties(
262
+ () => exprProps,
263
+ () => originalProperties
264
+ );
265
+ }
266
+
224
267
  /**
225
268
  * Returns the encoding spec supplemented with mark's default encodings
226
269
  *
@@ -644,10 +687,20 @@ export default class Mark {
644
687
  * @param {(x: Exclude<T, ExprRef>) => any} adjuster
645
688
  */
646
689
  registerMarkUniformValue(uniformName, propValue, adjuster = (x) => x) {
647
- const setter = this.createMarkUniformSetter(uniformName);
690
+ const rawSetter = this.createMarkUniformSetter(uniformName);
691
+ const setter = (/** @type {any} */ value) => {
692
+ if (value == null) {
693
+ throw new Error(
694
+ `Trying to set null/undefined value for uniform: ${uniformName}${
695
+ isExprRef(propValue) ? `Expr: ${propValue.expr}` : ""
696
+ }`
697
+ );
698
+ }
699
+ rawSetter(value);
700
+ };
648
701
 
649
702
  if (isExprRef(propValue)) {
650
- const fn = this.unitView.context.paramBroker.createExpression(
703
+ const fn = this.unitView.paramMediator.createExpression(
651
704
  propValue.expr
652
705
  );
653
706
 
@@ -1171,17 +1224,19 @@ class RangeMap extends InternMap {
1171
1224
  * @param {Map<K, import("../gl/dataToVertices.js").RangeEntry>} anotherMap
1172
1225
  */
1173
1226
  migrateEntries(anotherMap) {
1227
+ for (const [key, value] of this.entries()) {
1228
+ // Buffered draw calls maintain direct references to the range entries.
1229
+ // Thus, they cannot just be deleted, but instead, their counts and offsets
1230
+ // must be zeroed.
1231
+ if (!anotherMap.has(key)) {
1232
+ value.offset = 0;
1233
+ value.count = 0;
1234
+ value.xIndex = undefined;
1235
+ }
1236
+ }
1237
+
1174
1238
  for (const [key, value] of anotherMap.entries()) {
1175
1239
  Object.assign(this.get(key), value);
1176
1240
  }
1177
1241
  }
1178
1242
  }
1179
-
1180
- // TODO: Find a better place for this function
1181
- /**
1182
- * @param {any} x
1183
- * @returns {x is import("../spec/parameter.js").ExprRef}
1184
- */
1185
- export function isExprRef(x) {
1186
- return typeof x == "object" && x != null && "expr" in x && isString(x.expr);
1187
- }
@@ -1,2 +1,2 @@
1
- const shader = "layout(std140)uniform Mark{/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform lowp float uMaxRelativePointDiameter;uniform mediump float uScaleFactor;uniform mediump float uMaxPointSize;uniform mediump float uZoomLevel;uniform highp float uSemanticThreshold;uniform mediump float uGradientStrength;\n#pragma markUniforms\n};";
1
+ const shader = "layout(std140)uniform Mark{/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform mediump float uScaleFactor;uniform mediump float uZoomLevel;uniform highp float uSemanticThreshold;uniform mediump float uGradientStrength;\n#pragma markUniforms\n};";
2
2
  export default shader;
@@ -1,11 +1,8 @@
1
1
  export default class PointMark extends Mark {
2
2
  sampledSemanticScores: Float32Array;
3
3
  _getGeometricScaleFactor(): number;
4
- /**
5
- * Returns the maximum size of the points in the data, before any scaling
6
- */
7
- _getMaxPointSize(): import("../spec/channel.js").Scalar;
8
4
  getSemanticThreshold(): number;
5
+ #private;
9
6
  }
10
7
  import Mark from "./mark.js";
11
8
  //# sourceMappingURL=point.d.ts.map