@genome-spy/core 0.40.0 → 0.42.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 (104) hide show
  1. package/dist/bundle/index--cKb-dKG.js +615 -0
  2. package/dist/bundle/{index-gn8bhQ8w.js → index-d7k3kkin.js} +365 -366
  3. package/dist/bundle/index.es.js +4260 -3928
  4. package/dist/bundle/index.js +115 -80
  5. package/dist/schema.json +254 -52
  6. package/dist/src/data/sources/dynamic/axisGenomeSource.js +1 -1
  7. package/dist/src/data/sources/dynamic/axisTickSource.js +3 -3
  8. package/dist/src/data/sources/dynamic/bamSource.d.ts +3 -21
  9. package/dist/src/data/sources/dynamic/bamSource.d.ts.map +1 -1
  10. package/dist/src/data/sources/dynamic/bamSource.js +38 -55
  11. package/dist/src/data/sources/dynamic/bigBedSource.d.ts +2 -38
  12. package/dist/src/data/sources/dynamic/bigBedSource.d.ts.map +1 -1
  13. package/dist/src/data/sources/dynamic/bigBedSource.js +14 -71
  14. package/dist/src/data/sources/dynamic/bigWigSource.d.ts +4 -42
  15. package/dist/src/data/sources/dynamic/bigWigSource.d.ts.map +1 -1
  16. package/dist/src/data/sources/dynamic/bigWigSource.js +23 -60
  17. package/dist/src/data/sources/dynamic/gff3Source.d.ts.map +1 -1
  18. package/dist/src/data/sources/dynamic/gff3Source.js +1 -0
  19. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts +2 -20
  20. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts.map +1 -1
  21. package/dist/src/data/sources/dynamic/indexedFastaSource.js +23 -41
  22. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts +23 -4
  23. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts.map +1 -1
  24. package/dist/src/data/sources/dynamic/singleAxisLazySource.js +29 -4
  25. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts +60 -0
  26. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts.map +1 -0
  27. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.js +152 -0
  28. package/dist/src/data/sources/dynamic/tabixSource.d.ts +6 -40
  29. package/dist/src/data/sources/dynamic/tabixSource.d.ts.map +1 -1
  30. package/dist/src/data/sources/dynamic/tabixSource.js +29 -78
  31. package/dist/src/data/transforms/regexFold.d.ts.map +1 -1
  32. package/dist/src/data/transforms/regexFold.js +8 -0
  33. package/dist/src/data/transforms/regexFold.test.js +28 -0
  34. package/dist/src/encoder/accessor.js +4 -2
  35. package/dist/src/genomeSpy.d.ts +16 -0
  36. package/dist/src/genomeSpy.d.ts.map +1 -1
  37. package/dist/src/genomeSpy.js +119 -8
  38. package/dist/src/gl/link.vertex.glsl.js +1 -1
  39. package/dist/src/gl/point.common.glsl.js +2 -0
  40. package/dist/src/gl/point.fragment.glsl.js +1 -1
  41. package/dist/src/gl/point.vertex.glsl.js +1 -1
  42. package/dist/src/gl/rect.vertex.glsl.js +1 -1
  43. package/dist/src/gl/rule.common.glsl.js +2 -0
  44. package/dist/src/gl/rule.fragment.glsl.js +1 -1
  45. package/dist/src/gl/rule.vertex.glsl.js +1 -1
  46. package/dist/src/gl/text.common.glsl.js +2 -0
  47. package/dist/src/gl/text.fragment.glsl.js +1 -1
  48. package/dist/src/gl/text.vertex.glsl.js +1 -1
  49. package/dist/src/gl/webGLHelper.d.ts +6 -21
  50. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  51. package/dist/src/gl/webGLHelper.js +7 -38
  52. package/dist/src/img/90-ring-with-bg.svg +1 -0
  53. package/dist/src/img/README.md +5 -0
  54. package/dist/src/marks/link.d.ts +7 -0
  55. package/dist/src/marks/link.d.ts.map +1 -1
  56. package/dist/src/marks/link.js +99 -50
  57. package/dist/src/marks/mark.d.ts +34 -0
  58. package/dist/src/marks/mark.d.ts.map +1 -1
  59. package/dist/src/marks/mark.js +83 -1
  60. package/dist/src/marks/pointMark.d.ts.map +1 -1
  61. package/dist/src/marks/pointMark.js +21 -9
  62. package/dist/src/marks/rectMark.d.ts +1 -2
  63. package/dist/src/marks/rectMark.d.ts.map +1 -1
  64. package/dist/src/marks/rectMark.js +28 -17
  65. package/dist/src/marks/rule.d.ts.map +1 -1
  66. package/dist/src/marks/rule.js +17 -6
  67. package/dist/src/marks/text.d.ts.map +1 -1
  68. package/dist/src/marks/text.js +32 -18
  69. package/dist/src/paramBroker.d.ts +30 -0
  70. package/dist/src/paramBroker.d.ts.map +1 -0
  71. package/dist/src/paramBroker.js +102 -0
  72. package/dist/src/spec/data.d.ts +28 -13
  73. package/dist/src/spec/mark.d.ts +27 -26
  74. package/dist/src/spec/view.d.ts +2 -1
  75. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  76. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  77. package/dist/src/styles/genome-spy.css.js +33 -4
  78. package/dist/src/styles/genome-spy.scss +40 -4
  79. package/dist/src/types/viewContext.d.ts +11 -0
  80. package/dist/src/utils/binnedIndex.d.ts +2 -0
  81. package/dist/src/utils/binnedIndex.d.ts.map +1 -1
  82. package/dist/src/utils/binnedIndex.js +59 -10
  83. package/dist/src/utils/binnedIndex.test.js +46 -0
  84. package/dist/src/utils/expression.d.ts +12 -2
  85. package/dist/src/utils/expression.d.ts.map +1 -1
  86. package/dist/src/utils/expression.js +68 -9
  87. package/dist/src/utils/linearstep.d.ts +7 -0
  88. package/dist/src/utils/linearstep.d.ts.map +1 -0
  89. package/dist/src/utils/linearstep.js +10 -0
  90. package/dist/src/view/gridView.d.ts.map +1 -1
  91. package/dist/src/view/gridView.js +2 -0
  92. package/dist/src/view/layerView.d.ts.map +1 -1
  93. package/dist/src/view/layerView.js +2 -0
  94. package/dist/src/view/unitView.d.ts +0 -6
  95. package/dist/src/view/unitView.d.ts.map +1 -1
  96. package/dist/src/view/unitView.js +2 -9
  97. package/dist/src/view/view.d.ts +6 -0
  98. package/dist/src/view/view.d.ts.map +1 -1
  99. package/dist/src/view/view.js +17 -0
  100. package/package.json +3 -3
  101. package/dist/bundle/index-Cbz74kpR.js +0 -638
  102. package/dist/src/data/sources/dynamic/windowedMixin.d.ts +0 -32
  103. package/dist/src/data/sources/dynamic/windowedMixin.d.ts.map +0 -1
  104. package/dist/src/data/sources/dynamic/windowedMixin.js +0 -53
@@ -1,4 +1,7 @@
1
1
  import { formats as vegaFormats } from "vega-loader";
2
+ import { html, render } from "lit-html";
3
+ import { styleMap } from "lit/directives/style-map.js";
4
+ import SPINNER from "./img/90-ring-with-bg.svg";
2
5
 
3
6
  import css from "./styles/genome-spy.css.js";
4
7
  import Tooltip from "./utils/ui/tooltip.js";
@@ -31,6 +34,7 @@ import dataTooltipHandler from "./tooltip/dataTooltipHandler.js";
31
34
  import { invalidatePrefix } from "./utils/propertyCacher.js";
32
35
  import { VIEW_ROOT_NAME, ViewFactory } from "./view/viewFactory.js";
33
36
  import { reconfigureScales } from "./view/scaleResolution.js";
37
+ import ParamBroker from "./paramBroker.js";
34
38
 
35
39
  /**
36
40
  * Events that are broadcasted to all views.
@@ -56,6 +60,9 @@ export default class GenomeSpy {
56
60
  constructor(container, spec, options = {}) {
57
61
  this.container = container;
58
62
 
63
+ /** @type {(() => void)[]} */
64
+ this._destructionCallbacks = [];
65
+
59
66
  const styleElement = document.createElement("style");
60
67
  styleElement.innerHTML = css;
61
68
  container.appendChild(styleElement);
@@ -128,6 +135,15 @@ export default class GenomeSpy {
128
135
 
129
136
  /** @type {View} */
130
137
  this.viewRoot = undefined;
138
+
139
+ this._paramBroker = new ParamBroker();
140
+
141
+ /**
142
+ * Views that are currently loading data using lazy sources.
143
+ *
144
+ * @type {Map<View, boolean>}
145
+ */
146
+ this._loadingViews = new Map();
131
147
  }
132
148
 
133
149
  /**
@@ -182,6 +198,53 @@ export default class GenomeSpy {
182
198
  ?.forEach((listener) => listener(message));
183
199
  }
184
200
 
201
+ /**
202
+ * Draw some layers on top of the canvas. It's easier to do fancy spinning
203
+ * animations with html elements than with WebGL.
204
+ */
205
+ _updateLoadingIndicators() {
206
+ /** @type {import("lit-html").TemplateResult[]} */
207
+ const indicators = [];
208
+
209
+ const isSomethingVisible = () =>
210
+ [...this._loadingViews.values()].some((v) => v);
211
+
212
+ for (const [view, status] of this._loadingViews) {
213
+ const c = view.coords;
214
+ if (c) {
215
+ const style = {
216
+ left: `${c.x}px`,
217
+ top: `${c.y}px`,
218
+ width: `${c.width}px`,
219
+ height: `${c.height}px`,
220
+ };
221
+ indicators.push(
222
+ html`<div style=${styleMap(style)}>
223
+ <div class=${status ? "loading" : ""}>
224
+ <img src="${SPINNER}" alt="" />
225
+ <span>Loading...</span>
226
+ </div>
227
+ </div>`
228
+ );
229
+ }
230
+ }
231
+
232
+ // Do some hacks to stop css animations of the loading indicators.
233
+ // Otherwise they fire animation frames even when their opacity is zero.
234
+ if (isSomethingVisible()) {
235
+ this.loadingIndicatorsElement.style.display = "block";
236
+ } else {
237
+ // TODO: Clear previous timeout
238
+ setTimeout(() => {
239
+ if (!isSomethingVisible()) {
240
+ this.loadingIndicatorsElement.style.display = "none";
241
+ }
242
+ }, 3000);
243
+ }
244
+
245
+ render(indicators, this.loadingIndicatorsElement);
246
+ }
247
+
185
248
  _prepareContainer() {
186
249
  this.container.classList.add("genome-spy");
187
250
  this.container.classList.add("loading");
@@ -195,11 +258,58 @@ export default class GenomeSpy {
195
258
  this.spec.background
196
259
  );
197
260
 
261
+ const resizeCallback = () => {
262
+ this._glHelper.invalidateSize();
263
+ dprSetter(window.devicePixelRatio);
264
+ this.computeLayout();
265
+ // Render immediately, without RAF
266
+ this.renderAll();
267
+ };
268
+
269
+ // TODO: Size should be observed only if the content is not absolutely sized
270
+ const resizeObserver = new ResizeObserver(resizeCallback);
271
+ resizeObserver.observe(this.container);
272
+ this._destructionCallbacks.push(() => resizeObserver.disconnect());
273
+
274
+ const dprSetter = this._paramBroker.allocateSetter("devicePixelRatio");
275
+ dprSetter(window.devicePixelRatio);
276
+
277
+ /** @type {() => void} */
278
+ let remove = null;
279
+
280
+ const updatePixelRatio = () => {
281
+ if (remove != null) {
282
+ remove();
283
+ resizeCallback();
284
+ }
285
+ const media = matchMedia(
286
+ `(resolution: ${window.devicePixelRatio}dppx)`
287
+ );
288
+ media.addEventListener("change", updatePixelRatio);
289
+ remove = () => {
290
+ media.removeEventListener("change", updatePixelRatio);
291
+ };
292
+ };
293
+ updatePixelRatio();
294
+
295
+ if (remove) {
296
+ this._destructionCallbacks.push(remove);
297
+ }
298
+
299
+ // The initial loading message that is shown until the first frame is rendered
198
300
  this.loadingMessageElement = document.createElement("div");
199
301
  this.loadingMessageElement.className = "loading-message";
200
302
  this.loadingMessageElement.innerHTML = `<div class="message">Loading<span class="ellipsis">...</span></div>`;
201
303
  this.container.appendChild(this.loadingMessageElement);
202
304
 
305
+ // A container for loading indicators (for lazy data sources.)
306
+ // These could alternatively be included in the view hierarchy,
307
+ // but it's easier this way – particularly if we want to show
308
+ // some fancy animated spinners.
309
+ this.loadingIndicatorsElement = document.createElement("div");
310
+ this.loadingIndicatorsElement.className = "loading-indicators";
311
+ this.container.appendChild(this.loadingIndicatorsElement);
312
+
203
313
  this.tooltip = new Tooltip(this.container);
204
314
 
205
315
  this.loadingMessageElement
@@ -226,6 +336,8 @@ export default class GenomeSpy {
226
336
  }
227
337
  }
228
338
 
339
+ this._destructionCallbacks.forEach((callback) => callback());
340
+
229
341
  this._glHelper.finalize();
230
342
 
231
343
  while (this.container.firstChild) {
@@ -255,6 +367,8 @@ export default class GenomeSpy {
255
367
  return self._glHelper.dpr;
256
368
  },
257
369
 
370
+ paramBroker: this._paramBroker,
371
+
258
372
  requestLayoutReflow: () => {
259
373
  // placeholder
260
374
  },
@@ -262,6 +376,11 @@ export default class GenomeSpy {
262
376
  getNamedDataFromProvider: this.getNamedDataFromProvider.bind(this),
263
377
  getCurrentHover: () => this._currentHover,
264
378
 
379
+ setDataLoadingStatus: (view, status) => {
380
+ this._loadingViews.set(view, status);
381
+ this._updateLoadingIndicators();
382
+ },
383
+
265
384
  addKeyboardListener: (type, listener) => {
266
385
  // TODO: Listeners should be called only when the mouse pointer is inside the
267
386
  // container or the app covers the full document.
@@ -449,14 +568,6 @@ export default class GenomeSpy {
449
568
  this.computeLayout();
450
569
  this.animator.requestRender();
451
570
 
452
- // Register resize listener after the initial layout computation to prevent
453
- // incomplete layouts from accidentally polluting any caches related to sizes.
454
- this._glHelper.addEventListener("resize", () => {
455
- this.computeLayout();
456
- // Render immediately, without RAF
457
- this.renderAll();
458
- });
459
-
460
571
  return true;
461
572
  } catch (reason) {
462
573
  const message = `${
@@ -1,2 +1,2 @@
1
- const shader = "uniform float uArcHeightFactor;uniform float uMinArcHeight;uniform float uMinPickingSize;uniform int uShape;uniform int uOrient;uniform bool uClampApex;uniform float uMaxChordLength;uniform vec2 uArcFadingDistance;in vec2 strip;out vec4 vColor;out float vSize;out float vNormalLengthInPixels;const int SHAPE_ARC=0;const int SHAPE_DOME=1;const int SHAPE_DIAGONAL=2;const int SHAPE_LINE=3;const int ORIENT_VERTICAL=0;const int ORIENT_HORIZONTAL=1;float distanceFromLine(vec2 pointOnLine1,vec2 pointOnLine2,vec2 point){vec2 a=point-pointOnLine1;vec2 b=pointOnLine2-pointOnLine1;vec2 proj=dot(a,b)/dot(b,b)*b;return length(a-proj);}bool isInsideViewport(vec2 point,float marginFactor){vec2 margin=uViewportSize*vec2(marginFactor);return point.x>=-margin.x&&point.x<=uViewportSize.x+margin.x&&point.y>=-margin.y&&point.y<=uViewportSize.y+margin.y;}void main(void){float pixelSize=1.0/uDevicePixelRatio;float opacity=getScaled_opacity()*uViewOpacity;vec2 p1,p2,p3,p4;vec2 a=applySampleFacet(vec2(getScaled_x(),getScaled_y()))*uViewportSize;vec2 b=applySampleFacet(vec2(getScaled_x2(),getScaled_y2()))*uViewportSize;if(uShape<=SHAPE_DOME){if(uShape==SHAPE_DOME){vec2 height=vec2(0.0);if(uOrient==ORIENT_VERTICAL){p1=vec2(min(a.x,b.x),b.y);p4=vec2(max(a.x,b.x),b.y);height=vec2(0.0,a.y-b.y);if(uClampApex){if(p4.x>0.0){p1.x=max(p1.x,-p4.x);}if(p1.x<uViewportSize.x){p4.x=min(p4.x,2.0*uViewportSize.x-p1.x);}}}else{p1=vec2(b.x,min(a.y,b.y));p4=vec2(b.x,max(a.y,b.y));height=vec2(a.x-b.x,0.0);if(uClampApex){if(p4.y>0.0){p1.y=max(p1.y,-p4.y);}if(p1.y<uViewportSize.y){p4.y=min(p4.y,2.0*uViewportSize.y-p1.y);}}}vec2 controlOffset=height/0.75;p2=p1+controlOffset;p3=p4+controlOffset;}if(uShape==SHAPE_ARC){p1=a;p4=b;vec2 chordVector=p4-p1;vec2 unitChordVector=normalize(chordVector);vec2 chordNormal=vec2(-unitChordVector.y,unitChordVector.x);float chordLength=length(chordVector);if(chordLength>uMaxChordLength){if(isInsideViewport(p1,2.0)){chordLength=uMaxChordLength;p4=p1+unitChordVector*uMaxChordLength;}else if(isInsideViewport(p4,2.0)){chordLength=uMaxChordLength;p1=p4-unitChordVector*uMaxChordLength;}}float height=max(chordLength/2.0*uArcHeightFactor,uMinArcHeight);vec2 controlOffset=chordNormal*height/0.75;p2=p1+controlOffset;p3=p4+controlOffset;}}else if(uShape==SHAPE_DIAGONAL){if(uOrient==ORIENT_VERTICAL){p1=a;p2=vec2(a.x,(a.y+b.y)/2.0);p3=vec2(b.x,(a.y+b.y)/2.0);p4=b;}else{p1=a;p2=vec2((a.x+b.x)/2.0,a.y);p3=vec2((a.x+b.x)/2.0,b.y);p4=b;}}else if(uShape==SHAPE_LINE){p1=a;p2=(a+b)/2.0;p3=p2;p4=b;}float t=smoothstep(0.0,1.0,strip.x);vec2 C1=p4-3.0*p3+3.0*p2-p1;vec2 C2=3.0*p3-6.0*p2+3.0*p1;vec2 C3=3.0*p2-3.0*p1;vec2 C4=p1;vec2 p;if(t==0.0){p=p1;}else if(t==1.0){p=p4;}else{p=C1*t*t*t+C2*t*t+C3*t+C4;}vec2 tangent=normalize(3.0*C1*t*t+2.0*C2*t+C3);vec2 normal=vec2(-tangent.y,tangent.x);float size=getScaled_size();if(size<pixelSize){opacity*=size/pixelSize;size=pixelSize;}float paddedSize=uPickingEnabled? max(size,uMinPickingSize): size+pixelSize;vNormalLengthInPixels=strip.y*paddedSize;if(uShape==SHAPE_ARC&&uArcFadingDistance[0]>0.0&&uArcFadingDistance[1]>0.0){float d=distanceFromLine(p1,p4,p);float distanceOpacity=smoothstep(uArcFadingDistance[1],uArcFadingDistance[0],d);opacity*=distanceOpacity;if(distanceOpacity<=0.0){vNormalLengthInPixels=0.0;}}p+=normal*vNormalLengthInPixels;gl_Position=pixelsToNdc(p);vec3 color=getScaled_color();vColor=vec4(color*opacity,opacity);vSize=paddedSize;setupPicking();}";
1
+ const shader = "uniform Mark{uniform float uArcHeightFactor;uniform float uMinArcHeight;uniform float uMinPickingSize;uniform int uShape;uniform int uOrient;uniform bool uClampApex;uniform float uMaxChordLength;uniform vec2 uArcFadingDistance;};in vec2 strip;out vec4 vColor;out float vSize;out float vNormalLengthInPixels;const int SHAPE_ARC=0;const int SHAPE_DOME=1;const int SHAPE_DIAGONAL=2;const int SHAPE_LINE=3;const int ORIENT_VERTICAL=0;const int ORIENT_HORIZONTAL=1;float distanceFromLine(vec2 pointOnLine1,vec2 pointOnLine2,vec2 point){vec2 a=point-pointOnLine1;vec2 b=pointOnLine2-pointOnLine1;vec2 proj=dot(a,b)/dot(b,b)*b;return length(a-proj);}bool isInsideViewport(vec2 point,float marginFactor){vec2 margin=uViewportSize*vec2(marginFactor);return point.x>=-margin.x&&point.x<=uViewportSize.x+margin.x&&point.y>=-margin.y&&point.y<=uViewportSize.y+margin.y;}void main(void){float pixelSize=1.0/uDevicePixelRatio;float opacity=getScaled_opacity()*uViewOpacity;vec2 p1,p2,p3,p4;vec2 a=applySampleFacet(vec2(getScaled_x(),getScaled_y()))*uViewportSize;vec2 b=applySampleFacet(vec2(getScaled_x2(),getScaled_y2()))*uViewportSize;if(uShape<=SHAPE_DOME){if(uShape==SHAPE_DOME){vec2 height=vec2(0.0);if(uOrient==ORIENT_VERTICAL){p1=vec2(min(a.x,b.x),b.y);p4=vec2(max(a.x,b.x),b.y);height=vec2(0.0,a.y-b.y);if(uClampApex){if(p4.x>0.0){p1.x=max(p1.x,-p4.x);}if(p1.x<uViewportSize.x){p4.x=min(p4.x,2.0*uViewportSize.x-p1.x);}}}else{p1=vec2(b.x,min(a.y,b.y));p4=vec2(b.x,max(a.y,b.y));height=vec2(a.x-b.x,0.0);if(uClampApex){if(p4.y>0.0){p1.y=max(p1.y,-p4.y);}if(p1.y<uViewportSize.y){p4.y=min(p4.y,2.0*uViewportSize.y-p1.y);}}}vec2 controlOffset=height/0.75;p2=p1+controlOffset;p3=p4+controlOffset;}if(uShape==SHAPE_ARC){p1=a;p4=b;vec2 chordVector=p4-p1;vec2 unitChordVector=normalize(chordVector);vec2 chordNormal=vec2(-unitChordVector.y,unitChordVector.x);float chordLength=length(chordVector);if(chordLength>uMaxChordLength){if(isInsideViewport(p1,2.0)){chordLength=uMaxChordLength;p4=p1+unitChordVector*uMaxChordLength;}else if(isInsideViewport(p4,2.0)){chordLength=uMaxChordLength;p1=p4-unitChordVector*uMaxChordLength;}}float height=max(chordLength/2.0*uArcHeightFactor,uMinArcHeight);vec2 controlOffset=chordNormal*height/0.75;p2=p1+controlOffset;p3=p4+controlOffset;}}else if(uShape==SHAPE_DIAGONAL){if(uOrient==ORIENT_VERTICAL){p1=a;p2=vec2(a.x,(a.y+b.y)/2.0);p3=vec2(b.x,(a.y+b.y)/2.0);p4=b;}else{p1=a;p2=vec2((a.x+b.x)/2.0,a.y);p3=vec2((a.x+b.x)/2.0,b.y);p4=b;}}else if(uShape==SHAPE_LINE){p1=a;p2=(a+b)/2.0;p3=p2;p4=b;}float t=smoothstep(0.0,1.0,strip.x);vec2 C1=p4-3.0*p3+3.0*p2-p1;vec2 C2=3.0*p3-6.0*p2+3.0*p1;vec2 C3=3.0*p2-3.0*p1;vec2 C4=p1;vec2 p;if(t==0.0){p=p1;}else if(t==1.0){p=p4;}else{p=C1*t*t*t+C2*t*t+C3*t+C4;}vec2 tangent=normalize(3.0*C1*t*t+2.0*C2*t+C3);vec2 normal=vec2(-tangent.y,tangent.x);float size=getScaled_size();if(size<pixelSize){opacity*=size/pixelSize;size=pixelSize;}float paddedSize=uPickingEnabled? max(size,uMinPickingSize): size+pixelSize;vNormalLengthInPixels=strip.y*paddedSize;if(uShape==SHAPE_ARC&&uArcFadingDistance[0]>0.0&&uArcFadingDistance[1]>0.0){float d=distanceFromLine(p1,p4,p);float distanceOpacity=smoothstep(uArcFadingDistance[1],uArcFadingDistance[0],d);opacity*=distanceOpacity;if(distanceOpacity<=0.0){vNormalLengthInPixels=0.0;}}p+=normal*vNormalLengthInPixels;gl_Position=pixelsToNdc(p);vec3 color=getScaled_color();vColor=vec4(color*opacity,opacity);vSize=paddedSize;setupPicking();}";
2
2
  export default shader;
@@ -0,0 +1,2 @@
1
+ const shader = "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;};";
2
+ export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "const lowp vec4 white=vec4(1.0);const lowp vec4 black=vec4(0.0,0.0,0.0,1.0);uniform bool uInwardStroke;uniform float uGradientStrength;in float vRadius;in float vRadiusWithPadding;in lowp vec4 vFillColor;in lowp vec4 vStrokeColor;in lowp float vShape;in lowp float vHalfStrokeWidth;in mat2 vRotationMatrix;out lowp vec4 fragColor;const float CIRCLE=0.0;const float SQUARE=1.0;const float CROSS=2.0;const float DIAMOND=3.0;const float TRIANGLE_UP=4.0;const float TICK_UP=8.0;float circle(vec2 p,float r){return length(p)-r;}float square(vec2 p,float r){p=abs(p);return max(p.x,p.y)-r;}float tickUp(vec2 p,float r){float halfR=r*0.5;p.y+=halfR;p=abs(p);return max(p.x-r*0.15,p.y-halfR);}float equilateralTriangle(vec2 p,float r){p.y=-p.y;float k=sqrt(3.0);float kr=k*r;p.y-=kr/2.0;return max((abs(p.x)*k+p.y)/2.0,-p.y-kr);}float crossShape(vec2 p,float r){p=abs(p);vec2 b=vec2(0.4,1.0)*r;vec2 v=abs(p)-b.xy;vec2 h=abs(p)-b.yx;return min(max(v.x,v.y),max(h.x,h.y));}float diamond(vec2 p,float r){p=abs(p);return(max(abs(p.x-p.y),abs(p.x+p.y))-r)/sqrt(2.0);}void main(){float d;vec2 p=vRotationMatrix*(2.0*gl_PointCoord-1.0)*vRadiusWithPadding;float r=vRadius;if(vShape==CIRCLE){d=circle(p,r);}else if(vShape==SQUARE){d=square(p,r);}else if(vShape==CROSS){d=crossShape(p,r);}else if(vShape==DIAMOND){d=diamond(p,r);}else if(vShape==TRIANGLE_UP){d=equilateralTriangle(p,r);}else if(vShape==TICK_UP){d=tickUp(p,r);}else{d=0.0;}if(!uPickingEnabled){lowp vec4 fillColor=mix(vFillColor,white,-d*uGradientStrength/vRadius);fragColor=distanceToColor(d+(uInwardStroke ? vHalfStrokeWidth : 0.0),fillColor,vStrokeColor,vHalfStrokeWidth);}else if(d-vHalfStrokeWidth<=0.0){fragColor=vPickingColor;}else{discard;}}";
1
+ const shader = "const lowp vec4 white=vec4(1.0);const lowp vec4 black=vec4(0.0,0.0,0.0,1.0);in float vRadius;in float vRadiusWithPadding;in lowp vec4 vFillColor;in lowp vec4 vStrokeColor;in lowp float vShape;in lowp float vHalfStrokeWidth;in mat2 vRotationMatrix;out lowp vec4 fragColor;const float CIRCLE=0.0;const float SQUARE=1.0;const float CROSS=2.0;const float DIAMOND=3.0;const float TRIANGLE_UP=4.0;const float TICK_UP=8.0;float circle(vec2 p,float r){return length(p)-r;}float square(vec2 p,float r){p=abs(p);return max(p.x,p.y)-r;}float tickUp(vec2 p,float r){float halfR=r*0.5;p.y+=halfR;p=abs(p);return max(p.x-r*0.15,p.y-halfR);}float equilateralTriangle(vec2 p,float r){p.y=-p.y;float k=sqrt(3.0);float kr=k*r;p.y-=kr/2.0;return max((abs(p.x)*k+p.y)/2.0,-p.y-kr);}float crossShape(vec2 p,float r){p=abs(p);vec2 b=vec2(0.4,1.0)*r;vec2 v=abs(p)-b.xy;vec2 h=abs(p)-b.yx;return min(max(v.x,v.y),max(h.x,h.y));}float diamond(vec2 p,float r){p=abs(p);return(max(abs(p.x-p.y),abs(p.x+p.y))-r)/sqrt(2.0);}void main(){float d;vec2 p=vRotationMatrix*(2.0*gl_PointCoord-1.0)*vRadiusWithPadding;float r=vRadius;if(vShape==CIRCLE){d=circle(p,r);}else if(vShape==SQUARE){d=square(p,r);}else if(vShape==CROSS){d=crossShape(p,r);}else if(vShape==DIAMOND){d=diamond(p,r);}else if(vShape==TRIANGLE_UP){d=equilateralTriangle(p,r);}else if(vShape==TICK_UP){d=tickUp(p,r);}else{d=0.0;}if(!uPickingEnabled){lowp vec4 fillColor=mix(vFillColor,white,-d*uGradientStrength/vRadius);fragColor=distanceToColor(d+(uInwardStroke ? vHalfStrokeWidth : 0.0),fillColor,vStrokeColor,vHalfStrokeWidth);}else if(d-vHalfStrokeWidth<=0.0){fragColor=vPickingColor;}else{discard;}}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "/***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 float uScaleFactor;uniform float uMaxPointSize;uniform float uZoomLevel;uniform float uSemanticThreshold;out float vRadius;out float vRadiusWithPadding;out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out lowp float vShape;out lowp float vHalfStrokeWidth;out mat2 vRotationMatrix;const float CIRCLE=0.0;const float SQUARE=1.0;const float CROSS=2.0;const float DIAMOND=3.0;const float TRIANGLE_UP=4.0;const float TRIANGLE_RIGHT=5.0;const float TRIANGLE_DOWN=6.0;const float TRIANGLE_LEFT=7.0;const float TICK_UP=8.0;const float TICK_RIGHT=9.0;const float TICK_DOWN=10.0;const float TICK_LEFT=11.0;float computeSemanticThresholdFactor(){return getScaled_semanticScore()>=uSemanticThreshold ? 1.0 : 0.0;}/***Computes a scaling factor for the points in a sample-faceted view.*/float getDownscaleFactor(vec2 pos){if(!isFacetedSamples()){return 1.0;}float sampleFacetHeight=getSampleFacetHeight(pos);float maxPointDiameter=sqrt(uMaxPointSize);float factor=sampleFacetHeight*uViewportSize.y*uMaxRelativePointDiameter;return clamp(0.0,maxPointDiameter,factor)/maxPointDiameter;}vec2 getDxDy(){\n#if defined(dx_DEFINED) || defined(dy_DEFINED)\nreturn vec2(getScaled_dx(),getScaled_dy())/uViewportSize;\n#else\nreturn vec2(0.0,0.0);\n#endif\n}void main(void){float shapeAngle=0.0;float semanticThresholdFactor=computeSemanticThresholdFactor();if(semanticThresholdFactor<=0.0){gl_PointSize=0.0;gl_Position=vec4(100.0,0.0,0.0,0.0);return;}float size=getScaled_size();vec2 pos=vec2(getScaled_x(),getScaled_y())+getDxDy();gl_Position=unitToNdc(applySampleFacet(pos));float strokeWidth=getScaled_strokeWidth();float diameter=sqrt(size)*uScaleFactor*semanticThresholdFactor*getDownscaleFactor(pos);float opacity=uViewOpacity;if(strokeWidth<=0.0||uInwardStroke){float minDiameter=1.0/uDevicePixelRatio;if(diameter<minDiameter){opacity*=pow(diameter/minDiameter,2.5);diameter=minDiameter;}}float fillOpa=getScaled_fillOpacity()*opacity;float strokeOpa=getScaled_strokeOpacity()*opacity;vShape=getScaled_shape();bool circle=vShape==0.0;if(vShape>TICK_UP&&vShape<=TICK_LEFT){shapeAngle=(vShape-TICK_UP)*90.0;vShape=TICK_UP;}else if(vShape>TRIANGLE_UP&&vShape<=TRIANGLE_LEFT){shapeAngle=(vShape-TRIANGLE_UP)*90.0;vShape=TRIANGLE_UP;}float angleInDegrees=getScaled_angle();float angle=-(shapeAngle+angleInDegrees)*PI/180.0;float sinTheta=sin(angle);float cosTheta=cos(angle);vRotationMatrix=mat2(cosTheta,sinTheta,-sinTheta,cosTheta);float roomForRotation=circle ? 1.0 : sin(mod(angle,PI/2.0)+PI/4.0)/sin(PI/4.0);float aaPadding=1.0/uDevicePixelRatio;float rotationPadding=(diameter*roomForRotation)-diameter;float strokePadding=uInwardStroke ? 0.0 : strokeWidth*(circle ? 1.0 : sqrt(3.0));float padding=rotationPadding+strokePadding+aaPadding;gl_PointSize=(diameter+padding)*uDevicePixelRatio;vRadius=diameter/2.0;vRadiusWithPadding=vRadius+padding/2.0;vHalfStrokeWidth=strokeWidth/2.0;vFillColor=vec4(getScaled_fill()*fillOpa,fillOpa);vStrokeColor=vec4(getScaled_stroke()*strokeOpa,strokeOpa);setupPicking();}";
1
+ const shader = "out float vRadius;out float vRadiusWithPadding;out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out lowp float vShape;out lowp float vHalfStrokeWidth;out mat2 vRotationMatrix;const float CIRCLE=0.0;const float SQUARE=1.0;const float CROSS=2.0;const float DIAMOND=3.0;const float TRIANGLE_UP=4.0;const float TRIANGLE_RIGHT=5.0;const float TRIANGLE_DOWN=6.0;const float TRIANGLE_LEFT=7.0;const float TICK_UP=8.0;const float TICK_RIGHT=9.0;const float TICK_DOWN=10.0;const float TICK_LEFT=11.0;float computeSemanticThresholdFactor(){return getScaled_semanticScore()>=uSemanticThreshold ? 1.0 : 0.0;}/***Computes a scaling factor for the points in a sample-faceted view.*/float getDownscaleFactor(vec2 pos){if(!isFacetedSamples()){return 1.0;}float sampleFacetHeight=getSampleFacetHeight(pos);float maxPointDiameter=sqrt(uMaxPointSize);float factor=sampleFacetHeight*uViewportSize.y*uMaxRelativePointDiameter;return clamp(0.0,maxPointDiameter,factor)/maxPointDiameter;}vec2 getDxDy(){\n#if defined(dx_DEFINED) || defined(dy_DEFINED)\nreturn vec2(getScaled_dx(),getScaled_dy())/uViewportSize;\n#else\nreturn vec2(0.0,0.0);\n#endif\n}void main(void){float shapeAngle=0.0;float semanticThresholdFactor=computeSemanticThresholdFactor();if(semanticThresholdFactor<=0.0){gl_PointSize=0.0;gl_Position=vec4(100.0,0.0,0.0,0.0);return;}float size=getScaled_size();vec2 pos=vec2(getScaled_x(),getScaled_y())+getDxDy();gl_Position=unitToNdc(applySampleFacet(pos));float strokeWidth=getScaled_strokeWidth();float diameter=sqrt(size)*uScaleFactor*semanticThresholdFactor*getDownscaleFactor(pos);float opacity=uViewOpacity;if(strokeWidth<=0.0||uInwardStroke){float minDiameter=1.0/uDevicePixelRatio;if(diameter<minDiameter){opacity*=pow(diameter/minDiameter,2.5);diameter=minDiameter;}}float fillOpa=getScaled_fillOpacity()*opacity;float strokeOpa=getScaled_strokeOpacity()*opacity;vShape=getScaled_shape();bool circle=vShape==0.0;if(vShape>TICK_UP&&vShape<=TICK_LEFT){shapeAngle=(vShape-TICK_UP)*90.0;vShape=TICK_UP;}else if(vShape>TRIANGLE_UP&&vShape<=TRIANGLE_LEFT){shapeAngle=(vShape-TRIANGLE_UP)*90.0;vShape=TRIANGLE_UP;}float angleInDegrees=getScaled_angle();float angle=-(shapeAngle+angleInDegrees)*PI/180.0;float sinTheta=sin(angle);float cosTheta=cos(angle);vRotationMatrix=mat2(cosTheta,sinTheta,-sinTheta,cosTheta);float roomForRotation=circle ? 1.0 : sin(mod(angle,PI/2.0)+PI/4.0)/sin(PI/4.0);float aaPadding=1.0/uDevicePixelRatio;float rotationPadding=(diameter*roomForRotation)-diameter;float strokePadding=uInwardStroke ? 0.0 : strokeWidth*(circle ? 1.0 : sqrt(3.0));float padding=rotationPadding+strokePadding+aaPadding;gl_PointSize=(diameter+padding)*uDevicePixelRatio;vRadius=diameter/2.0;vRadiusWithPadding=vRadius+padding/2.0;vHalfStrokeWidth=strokeWidth/2.0;vFillColor=vec4(getScaled_fill()*fillOpa,fillOpa);vStrokeColor=vec4(getScaled_stroke()*strokeOpa,strokeOpa);setupPicking();}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "/***The vertex position wrt the rectangle specified by(x,x2,y,y2).*[0,0]=[x,y],[1,1]=[x2,y2].*The x or y component may contain fractional values if the rectangle*have been tessellated.*/in vec2 frac;uniform vec2 uMinSize;uniform float uMinOpacity;uniform vec4 uCornerRadii;out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out float vHalfStrokeWidth;out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nout vec2 vPosInPixels;\n#endif\nout vec2 vHalfSizeInPixels;/***Clamps the minimumSize and returns an opacity that reflects the amount of clamping.*/float clampMinSize(inout float pos,float frac,float size,float minSize){if(minSize>0.0&&abs(size)<minSize){pos+=(frac-0.5)*(minSize*sign(size)-size);return abs(size)/minSize;}return 1.0;}void sort(inout float a,inout float b){if(a>b){float tmp=b;b=a;a=tmp;}}void main(void){vec2 normalizedMinSize=uMinSize/uViewportSize;float x=getScaled_x();float x2=getScaled_x2();float y=getScaled_y();float y2=getScaled_y2();sort(x,x2);sort(y,y2);float clampMargin=1.0;vec2 pos1=vec2(clamp(x,0.0-clampMargin,1.0+clampMargin),y);vec2 pos2=vec2(clamp(x2,0.0-clampMargin,1.0+clampMargin),y2);vec2 size=pos2-pos1;if(size.x<=0.0||size.y<=0.0){gl_Position=vec4(0.0,0.0,0.0,1.0);return;}vec2 pos=pos1+frac*size;size.y*=getSampleFacetHeight(pos);float opaFactor=uViewOpacity*max(uMinOpacity,clampMinSize(pos.x,frac.x,size.x,normalizedMinSize.x)*clampMinSize(pos.y,frac.y,size.y,normalizedMinSize.y));pos=applySampleFacet(pos);\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nfloat aaPadding=1.0/uDevicePixelRatio;float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding)/uViewportSize;pos+=expand;vec2 sizeInPixels=size*uViewportSize;vPosInPixels=(centeredFrac+expand/size)*sizeInPixels;vHalfSizeInPixels=sizeInPixels/2.0;vCornerRadii=min(uCornerRadii,min(vHalfSizeInPixels.x,vHalfSizeInPixels.y));vHalfStrokeWidth=strokeWidth/2.0;vStrokeColor=vec4(getScaled_stroke()*strokeOpacity,strokeOpacity);\n#endif\ngl_Position=unitToNdc(pos);float fillOpacity=getScaled_fillOpacity()*opaFactor;vFillColor=vec4(getScaled_fill()*fillOpacity,fillOpacity);setupPicking();}";
1
+ const shader = "uniform Mark{uniform float uMinWidth;uniform float uMinHeight;uniform float uMinOpacity;uniform float uCornerRadiusTopRight;uniform float uCornerRadiusBottomRight;uniform float uCornerRadiusTopLeft;uniform float uCornerRadiusBottomLeft;};/***The vertex position wrt the rectangle specified by(x,x2,y,y2).*[0,0]=[x,y],[1,1]=[x2,y2].*The x or y component may contain fractional values if the rectangle*have been tessellated.*/in vec2 frac;out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out float vHalfStrokeWidth;out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nout vec2 vPosInPixels;\n#endif\nout vec2 vHalfSizeInPixels;/***Clamps the minimumSize and returns an opacity that reflects the amount of clamping.*/float clampMinSize(inout float pos,float frac,float size,float minSize){if(minSize>0.0&&abs(size)<minSize){pos+=(frac-0.5)*(minSize*sign(size)-size);return abs(size)/minSize;}return 1.0;}void sort(inout float a,inout float b){if(a>b){float tmp=b;b=a;a=tmp;}}void main(void){vec2 normalizedMinSize=vec2(uMinWidth,uMinHeight)/uViewportSize;vec4 cornerRadii=vec4(uCornerRadiusTopRight,uCornerRadiusBottomRight,uCornerRadiusBottomLeft,uCornerRadiusTopLeft);float x=getScaled_x();float x2=getScaled_x2();float y=getScaled_y();float y2=getScaled_y2();sort(x,x2);sort(y,y2);float clampMargin=1.0;vec2 pos1=vec2(clamp(x,0.0-clampMargin,1.0+clampMargin),y);vec2 pos2=vec2(clamp(x2,0.0-clampMargin,1.0+clampMargin),y2);vec2 size=pos2-pos1;if(size.x<=0.0||size.y<=0.0){gl_Position=vec4(0.0,0.0,0.0,1.0);return;}vec2 pos=pos1+frac*size;size.y*=getSampleFacetHeight(pos);float opaFactor=uViewOpacity*max(uMinOpacity,clampMinSize(pos.x,frac.x,size.x,normalizedMinSize.x)*clampMinSize(pos.y,frac.y,size.y,normalizedMinSize.y));pos=applySampleFacet(pos);\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nfloat aaPadding=1.0/uDevicePixelRatio;float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding)/uViewportSize;pos+=expand;vec2 sizeInPixels=size*uViewportSize;vPosInPixels=(centeredFrac+expand/size)*sizeInPixels;vHalfSizeInPixels=sizeInPixels/2.0;vCornerRadii=min(cornerRadii,min(vHalfSizeInPixels.x,vHalfSizeInPixels.y));vHalfStrokeWidth=strokeWidth/2.0;vStrokeColor=vec4(getScaled_stroke()*strokeOpacity,strokeOpacity);\n#endif\ngl_Position=unitToNdc(pos);float fillOpacity=getScaled_fillOpacity()*opaFactor;vFillColor=vec4(getScaled_fill()*fillOpacity,fillOpacity);setupPicking();}";
2
2
  export default shader;
@@ -0,0 +1,2 @@
1
+ const shader = "uniform Mark{uniform mediump float uMinLength;uniform mediump float uDashTextureSize;uniform lowp int uStrokeCap;uniform mediump float uStrokeDashOffset;};";
2
+ export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "const int BUTT=0;const int SQUARE=1;const int ROUND=2;uniform sampler2D uDashTexture;uniform float uDashTextureSize;uniform float uStrokeDashOffset;uniform lowp int uStrokeCap;in vec4 vColor;in float vSize;in vec2 vPosInPixels;in float vNormalLengthInPixels;out lowp vec4 fragColor;void main(void){float dpr=uDevicePixelRatio;float distanceFromEnd=-min(vPosInPixels[0],vPosInPixels[1]);float distance;if(distanceFromEnd>0.0&&uStrokeCap==ROUND){distance=length(vec2(distanceFromEnd,vNormalLengthInPixels));}else{distance=abs(vNormalLengthInPixels);}float opacity=clamp(((vSize/2.0-distance)*dpr),-0.5,0.5)+0.5;if(uDashTextureSize>0.0){float pos=(vPosInPixels[0]+uStrokeDashOffset)*dpr;float floored=floor(pos);vec2 texelPositions=(floored+vec2(0.5,1.5))/dpr/uDashTextureSize;opacity*=mix(texture(uDashTexture,vec2(texelPositions[0],0)).r,texture(uDashTexture,vec2(texelPositions[1],0)).r,clamp((pos-floored),0.0,1.0));}fragColor=vColor*opacity;if(uPickingEnabled){fragColor=vPickingColor;}}";
1
+ const shader = "const int BUTT=0;const int SQUARE=1;const int ROUND=2;uniform sampler2D uDashTexture;in vec4 vColor;in float vSize;in vec2 vPosInPixels;in float vNormalLengthInPixels;out lowp vec4 fragColor;void main(void){float dpr=uDevicePixelRatio;float distanceFromEnd=-min(vPosInPixels[0],vPosInPixels[1]);float distance;if(distanceFromEnd>0.0&&uStrokeCap==ROUND){distance=length(vec2(distanceFromEnd,vNormalLengthInPixels));}else{distance=abs(vNormalLengthInPixels);}float opacity=clamp(((vSize/2.0-distance)*dpr),-0.5,0.5)+0.5;if(uDashTextureSize>0.0){float pos=(vPosInPixels[0]+uStrokeDashOffset)*dpr;float floored=floor(pos);vec2 texelPositions=(floored+vec2(0.5,1.5))/dpr/uDashTextureSize;opacity*=mix(texture(uDashTexture,vec2(texelPositions[0],0)).r,texture(uDashTexture,vec2(texelPositions[1],0)).r,clamp((pos-floored),0.0,1.0));}fragColor=vColor*opacity;if(uPickingEnabled){fragColor=vPickingColor;}}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "const int BUTT=0;const int SQUARE=1;const int ROUND=2;in float pos;in float side;uniform float uMinLength;uniform mediump float uDashTextureSize;uniform lowp int uStrokeCap;out vec4 vColor;out float vSize;out float vNormalLengthInPixels;out highp vec2 vPosInPixels;void main(void){float pixelSize=1.0/uDevicePixelRatio;float size=getScaled_size();float opacity=getScaled_opacity()*uViewOpacity;if(size<pixelSize){opacity*=size/pixelSize;size=pixelSize;}vec2 a=applySampleFacet(vec2(getScaled_x(),getScaled_y()));vec2 b=applySampleFacet(vec2(getScaled_x2(),getScaled_y2()));vec2 tangent=b-a;float offset=0.0;float relativeDiff=0.0;if(uMinLength>0.0||uStrokeCap!=BUTT){float len=length(tangent*uViewportSize);float diff=max(0.0,uMinLength-len);if(uStrokeCap!=BUTT){diff+=size;}relativeDiff=diff/len;offset=relativeDiff*(pos-0.5);}vec2 p=pos<1.0? a+tangent*(pos+offset): b+tangent*offset;float aaPadding=pixelSize;vec2 normal=normalize(vec2(-tangent.y,tangent.x)/uViewportSize);p+=normal*side*(size+aaPadding)/uViewportSize;gl_Position=unitToNdc(p);vColor=vec4(getScaled_color()*opacity,opacity);vSize=size;vNormalLengthInPixels=side*(size+aaPadding);vPosInPixels=vec2(pos,(1.0-pos))*(1.0+relativeDiff)*length(tangent*uViewportSize)-vec2(uStrokeCap!=BUTT ? size/2.0 : 0.0);setupPicking();}";
1
+ const shader = "const int BUTT=0;const int SQUARE=1;const int ROUND=2;in float pos;in float side;out vec4 vColor;out float vSize;out float vNormalLengthInPixels;out highp vec2 vPosInPixels;void main(void){float pixelSize=1.0/uDevicePixelRatio;float size=getScaled_size();float opacity=getScaled_opacity()*uViewOpacity;if(size<pixelSize){opacity*=size/pixelSize;size=pixelSize;}vec2 a=applySampleFacet(vec2(getScaled_x(),getScaled_y()));vec2 b=applySampleFacet(vec2(getScaled_x2(),getScaled_y2()));vec2 tangent=b-a;float offset=0.0;float relativeDiff=0.0;if(uMinLength>0.0||uStrokeCap!=BUTT){float len=length(tangent*uViewportSize);float diff=max(0.0,uMinLength-len);if(uStrokeCap!=BUTT){diff+=size;}relativeDiff=diff/len;offset=relativeDiff*(pos-0.5);}vec2 p=pos<1.0? a+tangent*(pos+offset): b+tangent*offset;float aaPadding=pixelSize;vec2 normal=normalize(vec2(-tangent.y,tangent.x)/uViewportSize);p+=normal*side*(size+aaPadding)/uViewportSize;gl_Position=unitToNdc(p);vColor=vec4(getScaled_color()*opacity,opacity);vSize=size;vNormalLengthInPixels=side*(size+aaPadding);vPosInPixels=vec2(pos,(1.0-pos))*(1.0+relativeDiff)*length(tangent*uViewportSize)-vec2(uStrokeCap!=BUTT ? size/2.0 : 0.0);setupPicking();}";
2
2
  export default shader;
@@ -0,0 +1,2 @@
1
+ const shader = "uniform Mark{uniform mediump float uSdfNumerator;uniform mediump vec2 uD;uniform mediump vec4 uViewportEdgeFadeWidth;uniform mediump vec4 uViewportEdgeFadeDistance;uniform bool uSqueeze;uniform bool uLogoLetter;uniform lowp ivec2 uAlign;uniform mediump float uPaddingX;uniform bool uFlushX;uniform mediump float uPaddingY;uniform bool uFlushY;};";
2
+ export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "uniform sampler2D uTexture;uniform bool uLogoLetter;in vec2 vTexCoord;in float vEdgeFadeOpacity;in vec4 vColor;in float vSlope;out lowp vec4 fragColor;float median(float r,float g,float b){return max(min(r,g),min(max(r,g),b));}void main(){vec3 c=texture(uTexture,vTexCoord).rgb;float sigDist=1.0-median(c.r,c.g,c.b);float slope=uLogoLetter? 0.7/length(vec2(dFdy(sigDist),dFdx(sigDist))): vSlope;float opa=clamp((sigDist-0.5)*slope+0.5,0.0,1.0);opa*=pow(clamp(vEdgeFadeOpacity,0.0,1.0),2.2);fragColor=vColor*opa;if(uPickingEnabled){fragColor=vPickingColor;}}";
1
+ const shader = "uniform sampler2D uTexture;in vec2 vTexCoord;in float vEdgeFadeOpacity;in vec4 vColor;in float vSlope;out lowp vec4 fragColor;float median(float r,float g,float b){return max(min(r,g),min(max(r,g),b));}void main(){vec3 c=texture(uTexture,vTexCoord).rgb;float sigDist=1.0-median(c.r,c.g,c.b);float slope=uLogoLetter? 0.7/length(vec2(dFdy(sigDist),dFdx(sigDist))): vSlope;float opa=clamp((sigDist-0.5)*slope+0.5,0.0,1.0);opa*=pow(clamp(vEdgeFadeOpacity,0.0,1.0),2.2);fragColor=vColor*opa;if(uPickingEnabled){fragColor=vPickingColor;}}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "uniform float uSdfNumerator;uniform vec2 uD;in mediump vec2 vertexCoord;in lowp vec2 textureCoord;uniform vec4 uViewportEdgeFadeWidth;uniform vec4 uViewportEdgeFadeDistance;uniform bool uSqueeze;uniform bool uLogoLetter;in float width;uniform ivec2 uAlign;\n#ifdef x2_DEFINED\nuniform float uPaddingX;uniform bool uFlushX;\n#endif\n#ifdef y2_DEFINED\nuniform float uPaddingY;uniform bool uFlushY;\n#endif\nout vec2 vTexCoord;out vec4 vColor;out float vSlope;out float vEdgeFadeOpacity;struct RangeResult{float pos;float scale;};float minValue(vec4 v){return min(min(v.x,v.y),min(v.z,v.w));}float maxValue(vec4 v){return max(max(v.x,v.y),max(v.z,v.w));}/***All measures are in[0,1]*/RangeResult positionInsideRange(float a,float b,float width,float padding,int align,bool flush){float span=b-a;float paddedWidth=width+2.0*padding;if(a>1.0||b<0.0){return RangeResult(0.0,0.0);}float extra=max(0.0,span-paddedWidth);float pos;if(align==0){float centre=a+b;if(flush){float leftOver=max(0.0,paddedWidth-centre);centre+=min(leftOver,extra);float rightOver=max(0.0,paddedWidth+centre-2.0);centre-=min(rightOver,extra);}pos=centre/2.0;}else if(align<0){float edge=a;if(flush){float over=max(0.0,-edge);edge+=min(over,extra);}pos=edge+padding;}else{float edge=b;if(flush){float over=max(0.0,edge-1.0);edge-=min(over,extra);}pos=edge-padding;}float scale=clamp((span-padding)/paddedWidth,0.0,1.0);return RangeResult(pos,scale);}vec2 calculateRotatedDimensions(float width,mat2 rotationMatrix){vec2 a=abs(rotationMatrix*vec2(width/2.0,0.5));vec2 b=abs(rotationMatrix*vec2(width/2.0,-0.5));return vec2(max(a.x,b.x),max(a.y,b.y))*2.0;}ivec2 fixAlignForAngle(ivec2 align,float angleInDegrees){float a=mod(angleInDegrees+45.0,360.0);int x=align.x;int y=-align.y;if(a<90.0){return ivec2(x,y);}else if(a<180.0){return ivec2(y,-x);}else if(a<270.0){return ivec2(-x,y);}else{return ivec2(-y,x);}}void main(void){float opacity=getScaled_opacity()*uViewOpacity;vec2 size=vec2(getScaled_size());float x=getScaled_x();float y=getScaled_y();float scale=1.0;float angleInDegrees=getScaled_angle();float angle=-angleInDegrees*PI/180.0;float sinTheta=sin(angle);float cosTheta=cos(angle);mat2 rotationMatrix=mat2(cosTheta,sinTheta,-sinTheta,cosTheta);vec2 flushSize=calculateRotatedDimensions(width,rotationMatrix);\n#if defined(x2_DEFINED) || defined(y2_DEFINED)\nivec2 align=fixAlignForAngle(uAlign,angleInDegrees);\n#else\nivec2 align=uAlign;\n#endif\n#ifdef x2_DEFINED\nfloat x2=getScaled_x2();if(uLogoLetter){size.x=(x2-x)*uViewportSize.x;x+=(x2-x)/2.0;}else{float x2=getScaled_x2();RangeResult result=positionInsideRange(min(x,x2),max(x,x2),size.x*scale*flushSize.x/uViewportSize.x,uPaddingX/uViewportSize.x,align.x,uFlushX);x=result.pos;scale*=result.scale;}\n#endif\nvec2 pos=applySampleFacet(vec2(x,y));\n#ifdef y2_DEFINED\nfloat y2=getScaled_y2();vec2 pos2=applySampleFacet(vec2(x,y2));if(uLogoLetter){size.y=(pos2.y-pos.y)*uViewportSize.y;pos.y+=(pos2.y-pos.y)/2.0;}else{RangeResult result=positionInsideRange(min(pos.y,pos2.y),max(pos.y,pos2.y),size.y*scale*flushSize.y/uViewportSize.y,uPaddingY/uViewportSize.y,align.y,uFlushY);pos.y=result.pos;scale*=result.scale;}\n#endif\nif(scale<1.0){if(uSqueeze){vec2 scaleFadeExtent=vec2(3.0,6.0)/size;if(scale<scaleFadeExtent[0]){gl_Position=vec4(0.0);return;}size*=scale;opacity*=linearstep(scaleFadeExtent[0],scaleFadeExtent[1],scale);}else if(scale<1.0){gl_Position=vec4(0.0);return;}}vec2 charPos=rotationMatrix*(vertexCoord*size+uD);vec2 unitPos=pos+charPos/uViewportSize;gl_Position=unitToNdc(unitPos);vSlope=max(1.0,min(size.x,size.y)/uSdfNumerator);vColor=vec4(getScaled_color()*opacity,opacity);vTexCoord=textureCoord;if(maxValue(uViewportEdgeFadeDistance)>-pow(10.0,10.0)){vEdgeFadeOpacity=minValue(((vec4(1.0,1.0,0.0,0.0)+vec4(-1.0,-1.0,1.0,1.0)*unitPos.yxyx)*uViewportSize.yxyx-uViewportEdgeFadeDistance)/uViewportEdgeFadeWidth);}else{vEdgeFadeOpacity=1.0;}setupPicking();}";
1
+ const shader = "in mediump vec2 vertexCoord;in lowp vec2 textureCoord;in float width;out vec2 vTexCoord;out vec4 vColor;out float vSlope;out float vEdgeFadeOpacity;struct RangeResult{float pos;float scale;};float minValue(vec4 v){return min(min(v.x,v.y),min(v.z,v.w));}float maxValue(vec4 v){return max(max(v.x,v.y),max(v.z,v.w));}/***All measures are in[0,1]*/RangeResult positionInsideRange(float a,float b,float width,float padding,int align,bool flush){float span=b-a;float paddedWidth=width+2.0*padding;if(a>1.0||b<0.0){return RangeResult(0.0,0.0);}float extra=max(0.0,span-paddedWidth);float pos;if(align==0){float centre=a+b;if(flush){float leftOver=max(0.0,paddedWidth-centre);centre+=min(leftOver,extra);float rightOver=max(0.0,paddedWidth+centre-2.0);centre-=min(rightOver,extra);}pos=centre/2.0;}else if(align<0){float edge=a;if(flush){float over=max(0.0,-edge);edge+=min(over,extra);}pos=edge+padding;}else{float edge=b;if(flush){float over=max(0.0,edge-1.0);edge-=min(over,extra);}pos=edge-padding;}float scale=clamp((span-padding)/paddedWidth,0.0,1.0);return RangeResult(pos,scale);}vec2 calculateRotatedDimensions(float width,mat2 rotationMatrix){vec2 a=abs(rotationMatrix*vec2(width/2.0,0.5));vec2 b=abs(rotationMatrix*vec2(width/2.0,-0.5));return vec2(max(a.x,b.x),max(a.y,b.y))*2.0;}ivec2 fixAlignForAngle(ivec2 align,float angleInDegrees){float a=mod(angleInDegrees+45.0,360.0);int x=align.x;int y=-align.y;if(a<90.0){return ivec2(x,y);}else if(a<180.0){return ivec2(y,-x);}else if(a<270.0){return ivec2(-x,y);}else{return ivec2(-y,x);}}void main(void){float opacity=getScaled_opacity()*uViewOpacity;vec2 size=vec2(getScaled_size());float x=getScaled_x();float y=getScaled_y();float scale=1.0;float angleInDegrees=getScaled_angle();float angle=-angleInDegrees*PI/180.0;float sinTheta=sin(angle);float cosTheta=cos(angle);mat2 rotationMatrix=mat2(cosTheta,sinTheta,-sinTheta,cosTheta);vec2 flushSize=calculateRotatedDimensions(width,rotationMatrix);\n#if defined(x2_DEFINED) || defined(y2_DEFINED)\nivec2 align=fixAlignForAngle(uAlign,angleInDegrees);\n#else\nivec2 align=uAlign;\n#endif\n#ifdef x2_DEFINED\nfloat x2=getScaled_x2();if(uLogoLetter){size.x=(x2-x)*uViewportSize.x;x+=(x2-x)/2.0;}else{float x2=getScaled_x2();RangeResult result=positionInsideRange(min(x,x2),max(x,x2),size.x*scale*flushSize.x/uViewportSize.x,uPaddingX/uViewportSize.x,align.x,uFlushX);x=result.pos;scale*=result.scale;}\n#endif\nvec2 pos=applySampleFacet(vec2(x,y));\n#ifdef y2_DEFINED\nfloat y2=getScaled_y2();vec2 pos2=applySampleFacet(vec2(x,y2));if(uLogoLetter){size.y=(pos2.y-pos.y)*uViewportSize.y;pos.y+=(pos2.y-pos.y)/2.0;}else{RangeResult result=positionInsideRange(min(pos.y,pos2.y),max(pos.y,pos2.y),size.y*scale*flushSize.y/uViewportSize.y,uPaddingY/uViewportSize.y,align.y,uFlushY);pos.y=result.pos;scale*=result.scale;}\n#endif\nif(scale<1.0){if(uSqueeze){vec2 scaleFadeExtent=vec2(3.0,6.0)/size;if(scale<scaleFadeExtent[0]){gl_Position=vec4(0.0);return;}size*=scale;opacity*=linearstep(scaleFadeExtent[0],scaleFadeExtent[1],scale);}else if(scale<1.0){gl_Position=vec4(0.0);return;}}vec2 charPos=rotationMatrix*(vertexCoord*size+uD);vec2 unitPos=pos+charPos/uViewportSize;gl_Position=unitToNdc(unitPos);vSlope=max(1.0,min(size.x,size.y)/uSdfNumerator);vColor=vec4(getScaled_color()*opacity,opacity);vTexCoord=textureCoord;if(maxValue(uViewportEdgeFadeDistance)>-pow(10.0,10.0)){vEdgeFadeOpacity=minValue(((vec4(1.0,1.0,0.0,0.0)+vec4(-1.0,-1.0,1.0,1.0)*unitPos.yxyx)*uViewportSize.yxyx-uViewportEdgeFadeDistance)/uViewportEdgeFadeWidth);}else{vEdgeFadeOpacity=1.0;}setupPicking();}";
2
2
  export default shader;
@@ -32,16 +32,11 @@ export default class WebGLHelper {
32
32
  }, clearColor?: string);
33
33
  _container: HTMLElement;
34
34
  _sizeSource: () => {
35
- width: number;
36
- height: number;
35
+ width: any;
36
+ height: any;
37
37
  };
38
38
  /** @type {Map<string, WebGLShader>} */
39
39
  _shaderCache: Map<string, WebGLShader>;
40
- /** @type {{ type: string, listener: function}[]} */
41
- _listeners: {
42
- type: string;
43
- listener: Function;
44
- }[];
45
40
  /** @type {WeakMap<import("../view/scaleResolution.js").default, WebGLTexture>} */
46
41
  rangeTextures: WeakMap<import("../view/scaleResolution.js").default, WebGLTexture>;
47
42
  canvas: HTMLCanvasElement;
@@ -49,13 +44,12 @@ export default class WebGLHelper {
49
44
  /** @type {import("twgl.js").AttachmentOptions[]} */
50
45
  _pickingAttachmentOptions: import("twgl.js").AttachmentOptions[];
51
46
  _pickingBufferInfo: import("twgl.js").FramebufferInfo;
52
- _resizeObserver: ResizeObserver;
53
47
  /** @type {[number, number, number, number]} */
54
48
  _clearColor: [number, number, number, number];
55
49
  invalidateSize(): void;
56
50
  _logicalCanvasSize: {
57
- width: number;
58
- height: number;
51
+ width: any;
52
+ height: any;
59
53
  };
60
54
  _updateDpr(): void;
61
55
  dpr: number;
@@ -84,18 +78,9 @@ export default class WebGLHelper {
84
78
  * Returns the canvas size in logical pixels (without devicePixelRatio correction)
85
79
  */
86
80
  getLogicalCanvasSize(): {
87
- width: number;
88
- height: number;
81
+ width: any;
82
+ height: any;
89
83
  };
90
- /**
91
- * @param {"render"|"resize"} eventType
92
- * @param {function} listener
93
- */
94
- addEventListener(eventType: "render" | "resize", listener: Function): void;
95
- /**
96
- * @param {string} eventType
97
- */
98
- _emit(eventType: string): void;
99
84
  /**
100
85
  *
101
86
  * @param {number} x
@@ -1 +1 @@
1
- {"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"AA6bA;;;;GAIG;AACH,kCAJW,sBAAsB,gBACtB,WAAW,kBACX,WAAW;;;;;;EA8CrB;AAED;;;;;GAKG;AACH,0CALW,qBAAqB,WACrB,KAAK,OAAO,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,OAC7C,MAAM,EAAE,GAAG,eAAe,YAC1B,YAAY,gBAYtB;AAleD;IACI;;;;;;;OAOG;IACH,uBANW,WAAW,eACX,MAAM;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,eAGrC,MAAM,EA2FhB;IAxFG,wBAA2B;IAC3B,mBAPa;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAOf;IAE7B,uCAAuC;IACvC,cADW,IAAI,MAAM,EAAE,WAAW,CAAC,CACN;IAE7B,oDAAoD;IACpD,YADW;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,WAAU;KAAC,EAAE,CAC5B;IAEpB,kFAAkF;IAClF,eADW,QAAQ,OAAO,4BAA4B,EAAE,OAAO,EAAE,YAAY,CAAC,CAC5C;IAuClC,0BAAoB;IACpB,2BAAY;IAGZ,oDAAoD;IACpD,2BADW,OAAO,SAAS,EAAE,iBAAiB,EAAE,CAQ/C;IACD,sDAGC;IAMD,gCAGE;IAQF,+CAA+C;IAC/C,aADW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CACZ;IAOnC,uBAIC;IAHG;;;MAAmC;IAKvC,mBAEC;IADG,YAAkC;IAGtC;;;;;OAKG;IACH,oBAHW,MAAM,QACN,MAAM,GAAG,MAAM,EAAE,eA2B3B;IAED,iBAcC;IAED,iBAGC;IAED;;;;OAIG;IACH,oCAFW;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;MAQ3C;IAED;;OAEG;IACH;;;MA0BC;IAED;;;OAGG;IACH,4BAHW,QAAQ,GAAC,QAAQ,4BAK3B;IAED;;OAEG;IACH,iBAFW,MAAM,QAQhB;IAED;;;;OAIG;IACH,oBAHW,MAAM,KACN,MAAM,cAwBhB;IAED,iBAOC;IAED;;;;;;;;;OASG;IACH,+BAHW,OAAO,4BAA4B,EAAE,OAAO,WAC5C,OAAO,QA4GjB;CACJ"}
1
+ {"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"AA8ZA;;;;GAIG;AACH,kCAJW,sBAAsB,gBACtB,WAAW,kBACX,WAAW;;;;;;EA8CrB;AAED;;;;;GAKG;AACH,0CALW,qBAAqB,WACrB,KAAK,OAAO,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,OAC7C,MAAM,EAAE,GAAG,eAAe,YAC1B,YAAY,gBAYtB;AAncD;IACI;;;;;;;OAOG;IACH,uBANW,WAAW,eACX,MAAM;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,eAGrC,MAAM,EAmFhB;IAhFG,wBAA2B;IAC3B;;;MAKO;IAEP,uCAAuC;IACvC,cADW,IAAI,MAAM,EAAE,WAAW,CAAC,CACN;IAE7B,kFAAkF;IAClF,eADW,QAAQ,OAAO,4BAA4B,EAAE,OAAO,EAAE,YAAY,CAAC,CAC5C;IAuClC,0BAAoB;IACpB,2BAAY;IAGZ,oDAAoD;IACpD,2BADW,OAAO,SAAS,EAAE,iBAAiB,EAAE,CAQ/C;IACD,sDAGC;IAOD,+CAA+C;IAC/C,aADW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CACZ;IAOnC,uBAIC;IAHG;;;MAAmC;IAKvC,mBAEC;IADG,YAAkC;IAGtC;;;;;OAKG;IACH,oBAHW,MAAM,QACN,MAAM,GAAG,MAAM,EAAE,eA2B3B;IAED,iBAcC;IAED,iBAEC;IAED;;;;OAIG;IACH,oCAFW;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;MAQ3C;IAED;;OAEG;IACH;;;MAuBC;IAED;;;;OAIG;IACH,oBAHW,MAAM,KACN,MAAM,cAwBhB;IAED,iBAOC;IAED;;;;;;;;;OASG;IACH,+BAHW,OAAO,4BAA4B,EAAE,OAAO,WAC5C,OAAO,QA4GjB;CACJ"}
@@ -39,14 +39,16 @@ export default class WebGLHelper {
39
39
  */
40
40
  constructor(container, sizeSource, clearColor) {
41
41
  this._container = container;
42
- this._sizeSource = sizeSource;
42
+ this._sizeSource =
43
+ sizeSource ??
44
+ (() => ({
45
+ width: undefined,
46
+ height: undefined,
47
+ }));
43
48
 
44
49
  /** @type {Map<string, WebGLShader>} */
45
50
  this._shaderCache = new Map();
46
51
 
47
- /** @type {{ type: string, listener: function}[]} */
48
- this._listeners = [];
49
-
50
52
  /** @type {WeakMap<import("../view/scaleResolution.js").default, WebGLTexture>} */
51
53
  this.rangeTextures = new WeakMap();
52
54
 
@@ -108,16 +110,6 @@ export default class WebGLHelper {
108
110
 
109
111
  this.adjustGl();
110
112
 
111
- // TODO: Size should be observed only if the content is not absolutely sized
112
- this._resizeObserver = new ResizeObserver((entries) => {
113
- this.invalidateSize();
114
- this._emit("resize");
115
- });
116
- this._resizeObserver.observe(this._container);
117
-
118
- // TODO: Observe devicePixelRatio
119
- // https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes
120
-
121
113
  this._updateDpr();
122
114
 
123
115
  /** @type {[number, number, number, number]} */
@@ -188,7 +180,6 @@ export default class WebGLHelper {
188
180
  }
189
181
 
190
182
  finalize() {
191
- this._resizeObserver.unobserve(this._container);
192
183
  this.canvas.remove();
193
184
  }
194
185
 
@@ -214,10 +205,7 @@ export default class WebGLHelper {
214
205
  }
215
206
 
216
207
  // TODO: The size should never be smaller than the minimum content size!
217
- const contentSize = this._sizeSource?.() ?? {
218
- width: undefined,
219
- height: undefined,
220
- };
208
+ const contentSize = this._sizeSource();
221
209
 
222
210
  const cs = window.getComputedStyle(this._container, null);
223
211
  const width =
@@ -236,25 +224,6 @@ export default class WebGLHelper {
236
224
  return this._logicalCanvasSize;
237
225
  }
238
226
 
239
- /**
240
- * @param {"render"|"resize"} eventType
241
- * @param {function} listener
242
- */
243
- addEventListener(eventType, listener) {
244
- this._listeners.push({ type: eventType, listener });
245
- }
246
-
247
- /**
248
- * @param {string} eventType
249
- */
250
- _emit(eventType) {
251
- for (const entry of this._listeners) {
252
- if (entry.type === eventType) {
253
- entry.listener();
254
- }
255
- }
256
- }
257
-
258
227
  /**
259
228
  *
260
229
  * @param {number} x
@@ -0,0 +1 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_ajPY{transform-origin:center;animation:spinner_AtaB .75s infinite linear}@keyframes spinner_AtaB{100%{transform:rotate(360deg)}}</style><path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25"/><path d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z" class="spinner_ajPY"/></svg>
@@ -0,0 +1,5 @@
1
+ # Image assets
2
+
3
+ ## Spinner svg
4
+
5
+ Spinner: 90-ring-with-bg.svg, MIT License, https://github.com/n3r4zzurr0/svg-spinners
@@ -1,4 +1,11 @@
1
1
  export default class LinkMark extends Mark {
2
+ /**
3
+ * Only available if "WebGL Draft Extensions" is enabled in chrome://flags
4
+ * But seems to work.
5
+ *
6
+ * @private
7
+ */
8
+ private _baseInstanceExt;
2
9
  arrays: {
3
10
  [k: string]: {
4
11
  data: any;
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IA0HQ;;;;;;MAKC;CAkDR;iBAvLgB,WAAW"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IA+BQ;;;;;OAKG;IACH,yBAEC;IAkGD;;;;;;MAKC;CAoFR;iBAxOgB,WAAW"}