@genome-spy/core 0.59.0 → 0.60.1

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 (85) hide show
  1. package/dist/bundle/index.es.js +6100 -5545
  2. package/dist/bundle/index.js +144 -119
  3. package/dist/schema.json +304 -22
  4. package/dist/src/data/collector.d.ts.map +1 -1
  5. package/dist/src/data/collector.js +1 -0
  6. package/dist/src/data/sources/dataUtils.d.ts +2 -1
  7. package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
  8. package/dist/src/data/sources/dataUtils.js +3 -4
  9. package/dist/src/data/sources/inlineSource.d.ts +8 -0
  10. package/dist/src/data/sources/inlineSource.d.ts.map +1 -1
  11. package/dist/src/data/sources/inlineSource.js +17 -1
  12. package/dist/src/data/sources/urlSource.d.ts +1 -0
  13. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  14. package/dist/src/data/sources/urlSource.js +33 -4
  15. package/dist/src/encoder/encoder.d.ts +1 -1
  16. package/dist/src/genomeSpy.d.ts.map +1 -1
  17. package/dist/src/genomeSpy.js +39 -6
  18. package/dist/src/gl/colorUtils.d.ts +4 -0
  19. package/dist/src/gl/colorUtils.d.ts.map +1 -1
  20. package/dist/src/gl/colorUtils.js +8 -0
  21. package/dist/src/gl/glslScaleGenerator.d.ts +1 -1
  22. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  23. package/dist/src/gl/glslScaleGenerator.js +1 -9
  24. package/dist/src/gl/includes/common.glsl.js +1 -1
  25. package/dist/src/marks/link.d.ts.map +1 -1
  26. package/dist/src/marks/link.js +8 -0
  27. package/dist/src/marks/mark.d.ts +8 -0
  28. package/dist/src/marks/mark.d.ts.map +1 -1
  29. package/dist/src/marks/mark.js +101 -3
  30. package/dist/src/marks/point.fragment.glsl.js +1 -1
  31. package/dist/src/marks/point.vertex.glsl.js +1 -1
  32. package/dist/src/marks/rect.common.glsl.js +1 -1
  33. package/dist/src/marks/rect.d.ts.map +1 -1
  34. package/dist/src/marks/rect.fragment.glsl.js +1 -1
  35. package/dist/src/marks/rect.js +41 -0
  36. package/dist/src/marks/rect.vertex.glsl.js +1 -1
  37. package/dist/src/selection/selection.d.ts +27 -2
  38. package/dist/src/selection/selection.d.ts.map +1 -1
  39. package/dist/src/selection/selection.js +53 -3
  40. package/dist/src/spec/data.d.ts +18 -1
  41. package/dist/src/spec/mark.d.ts +58 -1
  42. package/dist/src/spec/parameter.d.ts +71 -31
  43. package/dist/src/spec/view.d.ts +9 -2
  44. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  45. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  46. package/dist/src/styles/genome-spy.css.js +12 -1
  47. package/dist/src/styles/genome-spy.scss +19 -1
  48. package/dist/src/types/selectionTypes.d.ts +4 -7
  49. package/dist/src/utils/expression.d.ts.map +1 -1
  50. package/dist/src/utils/expression.js +4 -0
  51. package/dist/src/utils/ui/tooltip.d.ts +6 -10
  52. package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
  53. package/dist/src/utils/ui/tooltip.js +74 -42
  54. package/dist/src/view/concatView.d.ts +1 -1
  55. package/dist/src/view/concatView.d.ts.map +1 -1
  56. package/dist/src/view/concatView.js +1 -1
  57. package/dist/src/view/gridView/gridChild.d.ts +53 -0
  58. package/dist/src/view/gridView/gridChild.d.ts.map +1 -0
  59. package/dist/src/view/gridView/gridChild.js +758 -0
  60. package/dist/src/view/gridView/gridView.d.ts +64 -0
  61. package/dist/src/view/gridView/gridView.d.ts.map +1 -0
  62. package/dist/src/view/{gridView.js → gridView/gridView.js} +40 -595
  63. package/dist/src/view/gridView/scrollbar.d.ts +32 -0
  64. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -0
  65. package/dist/src/view/gridView/scrollbar.js +186 -0
  66. package/dist/src/view/gridView/selectionRect.d.ts +10 -0
  67. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -0
  68. package/dist/src/view/gridView/selectionRect.js +182 -0
  69. package/dist/src/view/layout/rectangle.d.ts +11 -1
  70. package/dist/src/view/layout/rectangle.d.ts.map +1 -1
  71. package/dist/src/view/layout/rectangle.js +22 -2
  72. package/dist/src/view/layout/rectangle.test.js +12 -0
  73. package/dist/src/view/paramMediator.d.ts.map +1 -1
  74. package/dist/src/view/paramMediator.js +9 -0
  75. package/dist/src/view/scaleResolution.d.ts +1 -0
  76. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  77. package/dist/src/view/scaleResolution.js +43 -33
  78. package/dist/src/view/view.d.ts +6 -0
  79. package/dist/src/view/view.d.ts.map +1 -1
  80. package/dist/src/view/view.js +19 -0
  81. package/dist/src/view/viewFactory.d.ts.map +1 -1
  82. package/dist/src/view/viewFactory.js +13 -1
  83. package/package.json +2 -2
  84. package/dist/src/view/gridView.d.ts +0 -135
  85. package/dist/src/view/gridView.d.ts.map +0 -1
@@ -688,6 +688,8 @@ export default class GenomeSpy {
688
688
 
689
689
  let lastWheelEvent = performance.now();
690
690
 
691
+ let longPressTriggered = false;
692
+
691
693
  /** @param {Event} event */
692
694
  const listener = (event) => {
693
695
  const now = performance.now();
@@ -781,6 +783,10 @@ export default class GenomeSpy {
781
783
 
782
784
  // TODO: Should be handled at the view level, not globally
783
785
  if (event.type == "click") {
786
+ if (longPressTriggered) {
787
+ return;
788
+ }
789
+
784
790
  const e = this._currentHover
785
791
  ? {
786
792
  type: event.type,
@@ -820,17 +826,44 @@ export default class GenomeSpy {
820
826
  "mousemove",
821
827
  "gesturechange",
822
828
  "contextmenu",
829
+ "dblclick",
823
830
  ].forEach((type) => canvas.addEventListener(type, listener));
824
831
 
825
832
  canvas.addEventListener("mousedown", (/** @type {MouseEvent} */ e) => {
826
833
  this._mouseDownCoords = Point.fromMouseEvent(e);
834
+ if (this.tooltip.sticky) {
835
+ this.tooltip.sticky = false;
836
+ this.tooltip.clear();
837
+ // A hack to prevent selection if the tooltip is sticky.
838
+ // Let the tooltip be destickified first.
839
+ longPressTriggered = true;
840
+ } else {
841
+ longPressTriggered = false;
842
+ }
827
843
 
828
- document.addEventListener(
829
- "mouseup",
830
- () => this.tooltip.popEnabledState(),
831
- { once: true }
832
- );
833
- this.tooltip.pushEnabledState(false);
844
+ const disableTooltip = () => {
845
+ document.addEventListener(
846
+ "mouseup",
847
+ () => this.tooltip.popEnabledState(),
848
+ { once: true }
849
+ );
850
+ this.tooltip.pushEnabledState(false);
851
+ };
852
+
853
+ // Opening context menu or using modifier keys disables the tooltip
854
+ if (e.button == 2 || e.shiftKey || e.ctrlKey || e.metaKey) {
855
+ disableTooltip();
856
+ } else if (this.tooltip.visible) {
857
+ // Make tooltip sticky if the user long-presses
858
+ const timeout = setTimeout(() => {
859
+ longPressTriggered = true;
860
+ this.tooltip.sticky = true;
861
+ }, 400);
862
+
863
+ const clear = () => clearTimeout(timeout);
864
+ document.addEventListener("mouseup", clear, { once: true });
865
+ document.addEventListener("mousemove", clear, { once: true });
866
+ }
834
867
  });
835
868
 
836
869
  // Prevent text selections etc while dragging
@@ -31,4 +31,8 @@ export function createDiscreteTexture(range: number[], gl: WebGL2RenderingContex
31
31
  * @param {WebGLTexture} [existingTexture]
32
32
  */
33
33
  export function createDiscreteColorTexture(colors: string[], gl: WebGL2RenderingContext, count?: number, existingTexture?: WebGLTexture): WebGLTexture;
34
+ /**
35
+ * @param {string} color
36
+ */
37
+ export function cssColorToArray(color: string): number[];
34
38
  //# sourceMappingURL=colorUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"colorUtils.d.ts","sourceRoot":"","sources":["../../../src/gl/colorUtils.js"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,kDALW,MAAM,GAAG,OAAO,kBAAkB,EAAE,YAAY,MAChD,sBAAsB,UACtB,MAAM,oBACN,YAAY,gBAqCtB;AAED;;;;;GAKG;AACH,uDALW,MAAM,EAAE,qBACR,OAAO,kBAAkB,EAAE,gBAAgB,GAAG,OAAO,kBAAkB,EAAE,sBAAsB,MAC/F,sBAAsB,oBACtB,YAAY,gBA6BtB;AAED;;;;;;;;GAQG;AACH,6CALW,MAAM,EAAE,MACR,sBAAsB,UACtB,MAAM,oBACN,YAAY,gBAqBtB;AAED;;;;;;;GAOG;AACH,mDALW,MAAM,EAAE,MACR,sBAAsB,UACtB,MAAM,oBACN,YAAY,gBActB"}
1
+ {"version":3,"file":"colorUtils.d.ts","sourceRoot":"","sources":["../../../src/gl/colorUtils.js"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,kDALW,MAAM,GAAG,OAAO,kBAAkB,EAAE,YAAY,MAChD,sBAAsB,UACtB,MAAM,oBACN,YAAY,gBAqCtB;AAED;;;;;GAKG;AACH,uDALW,MAAM,EAAE,qBACR,OAAO,kBAAkB,EAAE,gBAAgB,GAAG,OAAO,kBAAkB,EAAE,sBAAsB,MAC/F,sBAAsB,oBACtB,YAAY,gBA6BtB;AAED;;;;;;;;GAQG;AACH,6CALW,MAAM,EAAE,MACR,sBAAsB,UACtB,MAAM,oBACN,YAAY,gBAqBtB;AAED;;;;;;;GAOG;AACH,mDALW,MAAM,EAAE,MACR,sBAAsB,UACtB,MAAM,oBACN,YAAY,gBActB;AAyDD;;GAEG;AACH,uCAFW,MAAM,YAKhB"}
@@ -189,3 +189,11 @@ function colorArrayToTextureData(scheme, count) {
189
189
  }
190
190
  return textureData;
191
191
  }
192
+
193
+ /**
194
+ * @param {string} color
195
+ */
196
+ export function cssColorToArray(color) {
197
+ const rgb = d3color(color).rgb();
198
+ return [rgb.r, rgb.g, rgb.b].map((x) => x / 255);
199
+ }
@@ -71,7 +71,7 @@ export function generateConditionalEncoderGlsl(channel: Channel, accessors: impo
71
71
  /**
72
72
  * @param {Channel} channel
73
73
  */
74
- export function getScaledDataTypeForChannel(channel: Channel): "float" | "vec3" | "uint";
74
+ export function getScaledDataTypeForChannel(channel: Channel): "vec3" | "uint" | "float";
75
75
  /**
76
76
  *
77
77
  * @param {import("../types/encoder.js").VegaScale} scale
@@ -1 +1 @@
1
- {"version":3,"file":"glslScaleGenerator.d.ts","sourceRoot":"","sources":["../../../src/gl/glslScaleGenerator.js"],"names":[],"mappings":"AAsDA;;;;;GAKG;AACH,kDAJW,OAAO,mBACP,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,mDALW,OAAO,mBACP,MAAM,SACN,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,OAAO,GAClC,aAAa,CA4CzB;AAED;;;;;;;GAOG;AACH,4DAJW,OAAO,mBACP,MAAM,GACJ,aAAa,CAkCzB;AAED;;;;;;GAMG;AACH,0CANW,OAAO,SACP,GAAG,mBACH,MAAM,+BACN,OAAO,EAAE,GACP,aAAa,CA+BzB;AACD;;;;;GAKG;AACH,qDALW,OAAO,SACP,GAAG,mBACH,MAAM,GACJ,aAAa,CAyBzB;AAED;;;;;GAKG;AAEH,2CALW,OAAO,SACP,GAAG,cACH,OAAO,oBAAoB,EAAE,UAAU;;;;;;EAwQjD;AAED;;;;GAIG;AACH,wDAHW,OAAO,aACP,OAAO,qBAAqB,EAAE,QAAQ,EAAE,UA+BlD;AAmED;;GAEG;AACH,qDAFW,OAAO,6BAQjB;AA+CD;;;;GAIG;AACH,iDAHW,OAAO,qBAAqB,EAAE,SAAS,WACvC,OAAO,oBAAoB,EAAE,OAAO;mBAQjB,MAAM;sBAAoB,sBAAsB,GAAG,sBAAsB,GAAG,uBAAuB;;;;;;EAkBhI;AAED;;;;GAIG;AACH,2CAFW,MAAM,6BAIhB;AAED;;;;GAIG;AACH,sCAFW,MAAM,EAAE,WAIlB;AAMD;;;GAGG;AACH,sCAHW,MAAM,QACN,MAAM,EAAE,YAYlB;AAED;;;GAGG;AACH,2CAHW,MAAM,QACN,MAAM,EAAE,YAUlB;AAYD;;GAEG;AACH,qDAFW,MAAM,EAAE,YAIlB;AAED;;GAEG;AAEH;;;;;GAKG;AACH,+CAFW,OAAO,CAAC,MAAM,CAAC,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC,CAAC,+DA4BtG;AAED;;GAEG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,GAAG,OAAO,oBAAoB,EAAE,OAAO,EAAE,UAIvF;AAwBD;;;;GAIG;AACH,uCAJW,MAAM,EAAE,cACR,MAAM,EAAE,GACN,MAAM,CAgClB;AA90BD,+BAAgC,OAAO,CAAC;AACxC,4BAA6B,UAAU,CAAC;AACxC,2BAA4B,QAAQ,CAAC;AACrC,uCAAwC,WAAW,CAAC;AACpD,oCAAqC,QAAQ,CAAC;AAC9C,qCAAsC,YAAY,CAAC;AACnD,mCAAoC,gBAAgB,CAAC;AACrD,2BAA4B,SAAS,CAAC;AACtC,uCAAwC,iBAAiB,CAAC;AA2xBnD,uCAJI,GAAG,WACH,OAAO,GACL,MAAM,EAAE,CAQA;sBA3xBR,OAAO,oBAAoB,EAAE,OAAO;;aA+BvC,OAAO;kBACP,MAAM;0BACN,MAAM;oBACN,MAAM;oBACN,MAAM;kBACN,MAAM;kBACN,MAAM;eACN,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG;;;;;8BAqfZ,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;;;uBAgMhD,CAAC,MAAM,EAAE,OAAO,CAAC;0BA7uBJ,WAAW"}
1
+ {"version":3,"file":"glslScaleGenerator.d.ts","sourceRoot":"","sources":["../../../src/gl/glslScaleGenerator.js"],"names":[],"mappings":"AAsDA;;;;;GAKG;AACH,kDAJW,OAAO,mBACP,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,mDALW,OAAO,mBACP,MAAM,SACN,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,OAAO,GAClC,aAAa,CA4CzB;AAED;;;;;;;GAOG;AACH,4DAJW,OAAO,mBACP,MAAM,GACJ,aAAa,CAkCzB;AAED;;;;;;GAMG;AACH,0CANW,OAAO,SACP,GAAG,mBACH,MAAM,+BACN,OAAO,EAAE,GACP,aAAa,CA+BzB;AACD;;;;;GAKG;AACH,qDALW,OAAO,SACP,GAAG,mBACH,MAAM,GACJ,aAAa,CAyBzB;AAED;;;;;GAKG;AAEH,2CALW,OAAO,SACP,GAAG,cACH,OAAO,oBAAoB,EAAE,UAAU;;;;;;EAwQjD;AAED;;;;GAIG;AACH,wDAHW,OAAO,aACP,OAAO,qBAAqB,EAAE,QAAQ,EAAE,UA+BlD;AAmED;;GAEG;AACH,qDAFW,OAAO,6BAQjB;AAuCD;;;;GAIG;AACH,iDAHW,OAAO,qBAAqB,EAAE,SAAS,WACvC,OAAO,oBAAoB,EAAE,OAAO;mBAQjB,MAAM;sBAAoB,sBAAsB,GAAG,sBAAsB,GAAG,uBAAuB;;;;;;EAkBhI;AAED;;;;GAIG;AACH,2CAFW,MAAM,6BAIhB;AAED;;;;GAIG;AACH,sCAFW,MAAM,EAAE,WAIlB;AAMD;;;GAGG;AACH,sCAHW,MAAM,QACN,MAAM,EAAE,YAYlB;AAED;;;GAGG;AACH,2CAHW,MAAM,QACN,MAAM,EAAE,YAUlB;AAYD;;GAEG;AACH,qDAFW,MAAM,EAAE,YAIlB;AAED;;GAEG;AAEH;;;;;GAKG;AACH,+CAFW,OAAO,CAAC,MAAM,CAAC,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC,CAAC,+DA4BtG;AAED;;GAEG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,GAAG,OAAO,oBAAoB,EAAE,OAAO,EAAE,UAIvF;AAwBD;;;;GAIG;AACH,uCAJW,MAAM,EAAE,cACR,MAAM,EAAE,GACN,MAAM,CAgClB;AAt0BD,+BAAgC,OAAO,CAAC;AACxC,4BAA6B,UAAU,CAAC;AACxC,2BAA4B,QAAQ,CAAC;AACrC,uCAAwC,WAAW,CAAC;AACpD,oCAAqC,QAAQ,CAAC;AAC9C,qCAAsC,YAAY,CAAC;AACnD,mCAAoC,gBAAgB,CAAC;AACrD,2BAA4B,SAAS,CAAC;AACtC,uCAAwC,iBAAiB,CAAC;AAmxBnD,uCAJI,GAAG,WACH,OAAO,GACL,MAAM,EAAE,CAQA;sBAnxBR,OAAO,oBAAoB,EAAE,OAAO;;aA+BvC,OAAO;kBACP,MAAM;0BACN,MAAM;oBACN,MAAM;oBACN,MAAM;kBACN,MAAM;kBACN,MAAM;eACN,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG;;;;;8BAqfZ,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;;;uBAwLhD,CAAC,MAAM,EAAE,OAAO,CAAC;0BAtuBJ,WAAW"}
@@ -5,7 +5,6 @@ import {
5
5
  isInterpolating,
6
6
  } from "vega-scale";
7
7
  import { isArray, isBoolean, isNumber, isString } from "vega-util";
8
- import { color as d3color } from "d3-color";
9
8
 
10
9
  import {
11
10
  getDiscreteRangeMapper,
@@ -18,6 +17,7 @@ import { asArray, peek } from "../utils/arrayUtils.js";
18
17
  import { InternMap } from "internmap";
19
18
  import { isExprRef } from "../view/paramMediator.js";
20
19
  import scaleNull from "../utils/scaleNull.js";
20
+ import { cssColorToArray } from "./colorUtils.js";
21
21
 
22
22
  export const ATTRIBUTE_PREFIX = "attr_";
23
23
  export const DOMAIN_PREFIX = "uDomain_";
@@ -618,14 +618,6 @@ export function getScaledDataTypeForChannel(channel) {
618
618
  : "float";
619
619
  }
620
620
 
621
- /**
622
- * @param {string} color
623
- */
624
- function cssColorToArray(color) {
625
- const rgb = d3color(color).rgb();
626
- return [rgb.r, rgb.g, rgb.b].map((x) => x / 255);
627
- }
628
-
629
621
  /**
630
622
  * @param {string} color
631
623
  */
@@ -1,2 +1,2 @@
1
- const shader = "#define PI 3.141593\nuniform View{mediump vec2 uViewOffset;mediump vec2 uViewScale;mediump vec2 uViewportSize;lowp float uDevicePixelRatio;lowp float uViewOpacity;bool uPickingEnabled;};/***Maps a coordinate on the unit scale to a normalized device coordinate.*(0,0)is at the bottom left corner.*/vec4 unitToNdc(vec2 coord){return vec4((coord*uViewScale+uViewOffset)*2.0-1.0,0.0,1.0);}vec4 unitToNdc(float x,float y){return unitToNdc(vec2(x,y));}vec4 pixelsToNdc(vec2 coord){return unitToNdc(coord/uViewportSize);}vec4 pixelsToNdc(float x,float y){return pixelsToNdc(vec2(x,y));}float linearstep(float edge0,float edge1,float x){return clamp((x-edge0)/(edge1-edge0),0.0,1.0);}bool isEmptyBinarySearchTexture(highp usampler2D s){return textureSize(s,0).x==1&&texelFetch(s,ivec2(0,0),0).r==0u;}bool binarySearchTexture(highp usampler2D s,uint value){int texSize=textureSize(s,0).x;int left=0;int right=texSize-1;while(left<=right){int mid=left+(right-left)/2;uint midValue=texelFetch(s,ivec2(mid,0),0).r;if(midValue==value){return true;}if(midValue<value){left=mid+1;}else{right=mid-1;}}return false;}/***Calculates a gamma for antialiasing opacity based on the color.*/float getGammaForColor(vec3 rgb){return mix(1.25,0.75,smoothstep(0.0,1.0,dot(rgb,vec3(0.299,0.587,0.114))));}/***Specialized linearstep for doing antialiasing*/float distanceToRatio(float d){return clamp(d*uDevicePixelRatio+0.5,0.0,1.0);}vec4 distanceToColor(float d,vec4 fill,vec4 stroke,float halfStrokeWidth){if(halfStrokeWidth>0.0){float sd=abs(d)-halfStrokeWidth;return mix(stroke,d<=0.0 ? fill : vec4(0.0),distanceToRatio(sd));}else{return fill*distanceToRatio(-d);}}";
1
+ const shader = "#define PI 3.141593\nuniform View{mediump vec2 uViewOffset;mediump vec2 uViewScale;mediump vec2 uViewportSize;lowp float uDevicePixelRatio;lowp float uViewOpacity;bool uPickingEnabled;};/***Maps a coordinate on the unit scale to a normalized device coordinate.*(0,0)is at the bottom left corner.*/vec4 unitToNdc(vec2 coord){return vec4((coord*uViewScale+uViewOffset)*2.0-1.0,0.0,1.0);}vec4 unitToNdc(float x,float y){return unitToNdc(vec2(x,y));}vec4 pixelsToNdc(vec2 coord){return unitToNdc(coord/uViewportSize);}vec4 pixelsToNdc(float x,float y){return pixelsToNdc(vec2(x,y));}float linearstep(float edge0,float edge1,float x){return clamp((x-edge0)/(edge1-edge0),0.0,1.0);}bool isEmptyBinarySearchTexture(highp usampler2D s){return textureSize(s,0).x==1&&texelFetch(s,ivec2(0,0),0).r==0u;}bool binarySearchTexture(highp usampler2D s,uint value){int texSize=textureSize(s,0).x;int left=0;int right=texSize-1;while(left<=right){int mid=left+(right-left)/2;uint midValue=texelFetch(s,ivec2(mid,0),0).r;if(midValue==value){return true;}if(midValue<value){left=mid+1;}else{right=mid-1;}}return false;}/***Calculates a gamma for antialiasing opacity based on the color.*/float getGammaForColor(vec3 rgb){return mix(1.25,0.75,smoothstep(0.0,1.0,dot(rgb,vec3(0.299,0.587,0.114))));}/***Specialized linearstep for doing antialiasing*/float distanceToRatio(float d){return clamp(d*uDevicePixelRatio+0.5,0.0,1.0);}vec4 distanceToColor(float d,vec4 fill,vec4 stroke,vec4 background,float halfStrokeWidth){if(halfStrokeWidth>0.0){float sd=abs(d)-halfStrokeWidth;return mix(stroke,d<=0.0 ? fill : background,distanceToRatio(sd));}else{return mix(background,fill,distanceToRatio(-d));}}";
2
2
  export default shader;
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAYA;;GAEG;AACH;IACI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EAoC/C;IATG;;;;;OAKG;IACH,yBAEC;IAsHD;;kBAGiC,GAAG;;;;MAEnC;CA4FR;iBArQgB,WAAW"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAYA;;GAEG;AACH;IACI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EAoC/C;IATG;;;;;OAKG;IACH,yBAEC;IA8HD;;kBAGiC,GAAG;;;;MAEnC;CA4FR;iBA7QgB,WAAW"}
@@ -53,6 +53,14 @@ export default class LinkMark extends Mark {
53
53
  );
54
54
  }
55
55
 
56
+ /**
57
+ * Returns the default hit test mode for this mark.
58
+ * @returns {import("./mark.js").HitTestMode}
59
+ */
60
+ get defaultHitTestMode() {
61
+ return "endpoints";
62
+ }
63
+
56
64
  /**
57
65
  * @returns {import("../spec/channel.js").Channel[]}
58
66
  */
@@ -12,6 +12,8 @@ export const SELECTION_TEXTURE_PREFIX: "uSelectionTexture_";
12
12
  * @callback DrawFunction
13
13
  * @param {number} offset
14
14
  * @param {number} count
15
+ *
16
+ * @typedef {"intersects" | "encloses" | "endpoints"} HitTestMode
15
17
  */
16
18
  /**
17
19
  * @template {MarkProps} [P=MarkProps]
@@ -93,6 +95,11 @@ export default class Mark<P extends import("../spec/mark.js").MarkProps = import
93
95
  */
94
96
  protected augmentDefaultProperties(props: Partial<P>): void;
95
97
  get opaque(): boolean;
98
+ /**
99
+ * Returns the default hit test mode for this mark.
100
+ * @returns {HitTestMode}
101
+ */
102
+ get defaultHitTestMode(): HitTestMode;
96
103
  /**
97
104
  * Returns attribute info for WebGL attributes that match visual channels.
98
105
  *
@@ -277,6 +284,7 @@ export type _MarkRenderingOptions = {
277
284
  };
278
285
  export type MarkRenderingOptions = RenderingOptions & _MarkRenderingOptions;
279
286
  export type DrawFunction = (offset: number, count: number) => any;
287
+ export type HitTestMode = "intersects" | "encloses" | "endpoints";
280
288
  /**
281
289
  * @augments {InternMap<K, import("../gl/dataToVertices.js").RangeEntry>}
282
290
  * @template K
@@ -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":"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"}
@@ -11,6 +11,7 @@ import {
11
11
  } from "twgl.js";
12
12
  import { isContinuous, isDiscrete } from "vega-scale";
13
13
  import createEncoders, {
14
+ getSecondaryChannel,
14
15
  isChannelDefWithScale,
15
16
  isChannelWithScale,
16
17
  isDatumDef,
@@ -50,6 +51,7 @@ import ViewError from "../view/viewError.js";
50
51
  import { isExprRef, validateParameterName } from "../view/paramMediator.js";
51
52
  import { UNIQUE_ID_KEY } from "../data/transforms/identifier.js";
52
53
  import {
54
+ isIntervalSelection,
53
55
  isMultiPointSelection,
54
56
  isSinglePointSelection,
55
57
  } from "../selection/selection.js";
@@ -70,6 +72,8 @@ export const SELECTION_TEXTURE_PREFIX = "uSelectionTexture_";
70
72
  * @callback DrawFunction
71
73
  * @param {number} offset
72
74
  * @param {number} count
75
+ *
76
+ * @typedef {"intersects" | "encloses" | "endpoints"} HitTestMode
73
77
  */
74
78
 
75
79
  /**
@@ -217,6 +221,14 @@ export default class Mark {
217
221
  return false;
218
222
  }
219
223
 
224
+ /**
225
+ * Returns the default hit test mode for this mark.
226
+ * @returns {HitTestMode}
227
+ */
228
+ get defaultHitTestMode() {
229
+ return "intersects";
230
+ }
231
+
220
232
  /**
221
233
  * Returns attribute info for WebGL attributes that match visual channels.
222
234
  *
@@ -464,14 +476,14 @@ export default class Mark {
464
476
 
465
477
  /**
466
478
  * Prevent duplicate registration.
467
- * @type {Map<string, "single" | "multi" | "range">}
479
+ * @type {Map<string, "single" | "multi" | "interval">}
468
480
  */
469
481
  const selectionParameterUniforms = new Map();
470
482
 
471
483
  for (const predicate of paramPredicates) {
472
484
  const param = predicate.param;
473
485
  const paramMediator = this.unitView.paramMediator;
474
- const selection = paramMediator.getValue(param);
486
+ const selection = paramMediator.findValue(param);
475
487
 
476
488
  // The selection is supposed to have an empty value at this point
477
489
  // so that we can figure out the type of the selection.
@@ -487,9 +499,10 @@ export default class Mark {
487
499
  // Register a mark uniform for each param. The uniform will have
488
500
  // the value of uniqueId of the selected datum.
489
501
  if (!selectionParameterUniforms.has(param)) {
502
+ selectionParameterUniforms.set(param, "single");
503
+
490
504
  const uniformName =
491
505
  PARAM_PREFIX + validateParameterName(param);
492
- selectionParameterUniforms.set(param, "single");
493
506
 
494
507
  dynamicMarkUniforms.push(` // Selection parameter`);
495
508
  dynamicMarkUniforms.push(
@@ -561,6 +574,91 @@ export default class Mark {
561
574
  this.getContext().animator.requestRender();
562
575
  });
563
576
  }
577
+ } else if (isIntervalSelection(selection)) {
578
+ if (!selectionParameterUniforms.has(param)) {
579
+ selectionParameterUniforms.set(param, "interval");
580
+
581
+ /** @type {string[]} */
582
+ const testSnippets = [];
583
+
584
+ /** @type {string[]} */
585
+ const emptySnippets = [];
586
+
587
+ // Handle both channels separately
588
+ for (const channel of Object.keys(selection.intervals)) {
589
+ if (!["x", "y"].includes(channel)) {
590
+ continue;
591
+ }
592
+
593
+ const uniformName =
594
+ PARAM_PREFIX +
595
+ validateParameterName(param) +
596
+ `_${channel}`;
597
+
598
+ // TODO: High precision scales
599
+ const { attributeType } = getAttributeAndArrayTypes(
600
+ this.unitView.getScaleResolution(channel).scale,
601
+ channel
602
+ );
603
+
604
+ dynamicMarkUniforms.push(` // Selection parameter`);
605
+ dynamicMarkUniforms.push(
606
+ ` uniform highp ${attributeType}[2] ${uniformName};`
607
+ );
608
+ this.#callAfterShaderCompilation.push(() => {
609
+ this.registerMarkUniformValue(
610
+ uniformName,
611
+ { expr: param },
612
+ (
613
+ /** @type {import("../types/selectionTypes.js").IntervalSelection} */ selection
614
+ ) =>
615
+ selection.intervals[channel] ?? [
616
+ Infinity,
617
+ -Infinity,
618
+ ]
619
+ );
620
+ });
621
+
622
+ const c = ATTRIBUTE_PREFIX + channel;
623
+ const u = uniformName + "[0]";
624
+ const u2 = uniformName + "[1]";
625
+ const secondaryChannel = getSecondaryChannel(channel);
626
+ if (this.encoding[secondaryChannel]) {
627
+ const c2 = ATTRIBUTE_PREFIX + secondaryChannel;
628
+ const mode = this.defaultHitTestMode;
629
+ if (mode == "endpoints") {
630
+ testSnippets.push(
631
+ `((${u} <= ${c} && ${c} <= ${u2}) || (${u} <= ${c2} && ${c2} <= ${u2}))`
632
+ );
633
+ } else if (mode == "encloses") {
634
+ testSnippets.push(
635
+ `(${u} <= ${c} && ${c2} <= ${u2})`
636
+ );
637
+ } else if (mode == "intersects") {
638
+ testSnippets.push(
639
+ `(${u} <= ${c2} && ${c} <= ${u2})`
640
+ );
641
+ } else {
642
+ throw new ViewError(
643
+ `Unsupported hit test mode "${mode}" for interval selection!`,
644
+ this.unitView
645
+ );
646
+ }
647
+ } else {
648
+ testSnippets.push(
649
+ `(${u} <= ${c} && ${c} <= ${u2})`
650
+ );
651
+ }
652
+
653
+ emptySnippets.push(`${u} > ${u2}`);
654
+ }
655
+
656
+ scaleCode.push(
657
+ `bool ${SELECTION_CHECKER_PREFIX}${param}(bool empty) {\n` +
658
+ ` return ${testSnippets.join(" && ")} || (empty && (${emptySnippets.join(" || ")}));\n` +
659
+ `}`
660
+ );
661
+ }
564
662
  }
565
663
  }
566
664
 
@@ -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);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,vec4(0.0),vHalfStrokeWidth);}else if(d-vHalfStrokeWidth<=0.0){fragColor=vPickingColor;}else{discard;}}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
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;}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;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=max((diameter+padding),uPickingEnabled ? uMinPickingSize : 0.0)*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;}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=isPointSelected()? 1.0: 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;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=max((diameter+padding),uPickingEnabled ? uMinPickingSize : 0.0)*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 = "layout(std140)uniform Mark{uniform float uMinWidth;uniform float uMinHeight;uniform float uMinOpacity;uniform float uCornerRadiusTopRight;uniform float uCornerRadiusBottomRight;uniform float uCornerRadiusTopLeft;uniform float uCornerRadiusBottomLeft;\n#pragma markUniforms\n};";
1
+ const shader = "layout(std140)uniform Mark{uniform float uMinWidth;uniform float uMinHeight;uniform float uMinOpacity;uniform float uCornerRadiusTopRight;uniform float uCornerRadiusBottomRight;uniform float uCornerRadiusTopLeft;uniform float uCornerRadiusBottomLeft;uniform int uHatchPattern;uniform vec3 uShadowColor;uniform float uShadowOpacity;uniform float uShadowBlur;uniform float uShadowOffsetX;uniform float uShadowOffsetY;\n#pragma markUniforms\n};";
2
2
  export default shader;
@@ -1 +1 @@
1
- {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAaA;;GAEG;AACH;IACI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EAkB/C;IAuMD;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAvQgB,WAAW"}
1
+ {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AA2BA;;GAEG;AACH;IACI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EAkB/C;IAkOD;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAhTgB,WAAW"}
@@ -1,2 +1,2 @@
1
- const shader = "#if defined(ROUNDED_CORNERS) || defined(STROKED)\nin vec2 vPosInPixels;\n#endif\nin vec2 vHalfSizeInPixels;in lowp vec4 vFillColor;in lowp vec4 vStrokeColor;in float vHalfStrokeWidth;in vec4 vCornerRadii;out lowp vec4 fragColor;float sdRoundedBox(vec2 p,vec2 b,vec4 r){r.xy=p.x>0.0 ? r.xy : r.zw;r.x=p.y>0.0 ? r.x : r.y;vec2 q=abs(p)-b+r.x;return min(max(q.x,q.y),0.0)+length(max(q,0.0))-r.x;}float sdSharpBox(vec2 p,vec2 b){vec2 q=abs(p)-b;return max(q.x,q.y);}void main(void){\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\n#ifdef ROUNDED_CORNERS\nfloat d=sdRoundedBox(vPosInPixels,vHalfSizeInPixels,vCornerRadii);\n#else\nfloat d=sdSharpBox(vPosInPixels,vHalfSizeInPixels);\n#endif\nfragColor=distanceToColor(d,vFillColor,vStrokeColor,vHalfStrokeWidth);if(fragColor.a==0.0){discard;}\n#else\nfragColor=vFillColor;\n#endif\nif(uPickingEnabled){fragColor=vPickingColor;}}";
1
+ const shader = "#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\nin vec2 vPosInPixels;\n#endif\nin vec2 vHalfSizeInPixels;in lowp vec4 vFillColor;in lowp vec4 vStrokeColor;in float vHalfStrokeWidth;in vec4 vCornerRadii;out lowp vec4 fragColor;\n#ifdef SHADOW\nfloat gaussian(float x,float sigma){const float pi=3.141592653589793;return exp(-(x*x)/(2.0*sigma*sigma))/(sqrt(2.0*pi)*sigma);}vec2 erf(vec2 x){vec2 s=sign(x),a=abs(x);x=1.0+(0.278393+(0.230389+0.078108*(a*a))*a)*a;x*=x;return s-s/(x*x);}float roundedBoxShadowX(float x,float y,float sigma,float corner,vec2 halfSize){float delta=min(halfSize.y-corner-abs(y),0.0);float curved=halfSize.x-corner+sqrt(max(0.0,corner*corner-delta*delta));vec2 integral=0.5+0.5*erf((x+vec2(-curved,curved))*(sqrt(0.5)/sigma));return integral.y-integral.x;}float roundedBoxShadow(vec2 lower,vec2 upper,vec2 point,float sigma,float corner){vec2 center=(lower+upper)*0.5;vec2 halfSize=(upper-lower)*0.5;point-=center;float low=point.y-halfSize.y;float high=point.y+halfSize.y;float start=clamp(-3.0*sigma,low,high);float end=clamp(3.0*sigma,low,high);float step=(end-start)/4.0;float y=start+step*0.5;float value=0.0;for(int i=0;i<4;i++){value+=roundedBoxShadowX(point.x,point.y-y,sigma,corner,halfSize)*gaussian(y,sigma)*step;y+=step;}return value;}\n#endif\nfloat sdRoundedBox(vec2 p,vec2 b,vec4 r){r.xy=p.x>0.0 ? r.xy : r.zw;r.x=p.y>0.0 ? r.x : r.y;vec2 q=abs(p)-b+r.x;return min(max(q.x,q.y),0.0)+length(max(q,0.0))-r.x;}float sdSharpBox(vec2 p,vec2 b){vec2 q=abs(p)-b;return max(q.x,q.y);}float diagonalPattern(vec2 uv,float spacing){float divisor=spacing*vHalfStrokeWidth*2.0*1.5;return abs(mod(uv.x-uv.y,divisor)-0.5*divisor)/1.5;}float verticalPattern(float x,float spacing){float divisor=spacing*vHalfStrokeWidth*2.0;return abs(mod(x,divisor))/2.0;}float circle(vec2 p,float r){return length(p)-r;}float masonryCirclePattern(vec2 uv,float spacing,float radius){float halfSpacing=0.5*spacing;float row=floor(uv.y/spacing);float shift=mod(row,2.0)*halfSpacing;vec2 shifted=vec2(uv.x+shift,uv.y+halfSpacing);vec2 cell=mod(shifted+0.5*spacing,spacing)-halfSpacing;return abs(circle(cell,radius));}/***Patterns:*0 none*1 diagonal(/)*2 antiDiagonal(\\)*3 cross(X)*4 vertical(|)*5 horizontal(-)*6 grid(+)*7 dots(.)*8 rings(o)*9 ringsLarge(O)*/float pattern(){\n#ifdef STROKED\nint patternType=uHatchPattern;vec2 uv=vPosInPixels;float spacing=4.0;switch(patternType){case 1:return diagonalPattern(vec2(uv.x,-uv.y),spacing);case 2:return diagonalPattern(uv,spacing);case 3:return min(diagonalPattern(uv,spacing),diagonalPattern(vec2(uv.x,-uv.y),spacing));case 4:return verticalPattern(uv.x,spacing);case 5:return verticalPattern(uv.y,spacing);case 6:return min(verticalPattern(uv.x,spacing),verticalPattern(uv.y,spacing));case 7:case 8:case 9:{float spacing=vHalfStrokeWidth*14.0;float radius=spacing*(patternType==8 ? 0.2 :patternType==9 ? 0.35 :0.07);return masonryCirclePattern(uv,spacing,radius);}default:break;}\n#endif\nreturn 1.0/0.0;}void main(void){\n#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\n#ifdef ROUNDED_CORNERS\nfloat d=sdRoundedBox(vPosInPixels,vHalfSizeInPixels,vCornerRadii);\n#else\nfloat d=sdSharpBox(vPosInPixels,vHalfSizeInPixels);\n#endif\nvec4 backgroundColor=vec4(0.0,0.0,0.0,0.0);\n#ifdef SHADOW\nfloat maxCornerRadius=max(vCornerRadii.x,max(vCornerRadii.y,max(vCornerRadii.z,vCornerRadii.w)));float shadow=0.0;if(d>=vHalfStrokeWidth-1.0&&uShadowOpacity>0.0){shadow=roundedBoxShadow(-vHalfSizeInPixels-vHalfStrokeWidth,vHalfSizeInPixels+vHalfStrokeWidth,vPosInPixels-vec2(uShadowOffsetX,-uShadowOffsetY),max(uShadowBlur/2.5,0.25),maxCornerRadius+vHalfStrokeWidth)*uShadowOpacity*uViewOpacity;}backgroundColor=vec4(uShadowColor*shadow,shadow);\n#endif\nif(vHalfStrokeWidth>0.0&&uHatchPattern>0){d=max(d,-pattern());}fragColor=distanceToColor(d,vFillColor,vStrokeColor,backgroundColor,vHalfStrokeWidth);if(uPickingEnabled){if(d<vHalfStrokeWidth){fragColor=vPickingColor;}}else if(fragColor.a==0.0){discard;}\n#else\nfragColor=vFillColor;if(uPickingEnabled){fragColor=vPickingColor;}\n#endif\n}";
2
2
  export default shader;
@@ -10,6 +10,20 @@ import { asArray } from "../utils/arrayUtils.js";
10
10
  import { isValueDef } from "../encoder/encoder.js";
11
11
  import { getCachedOrCall } from "../utils/propertyCacher.js";
12
12
  import { isDiscrete } from "vega-scale";
13
+ import { cssColorToArray } from "../gl/colorUtils.js";
14
+
15
+ const hatchPatterns = [
16
+ "none",
17
+ "diagonal",
18
+ "antiDiagonal",
19
+ "cross",
20
+ "vertical",
21
+ "horizontal",
22
+ "grid",
23
+ "dots",
24
+ "rings",
25
+ "ringsLarge",
26
+ ];
13
27
 
14
28
  /**
15
29
  * @extends {Mark<import("../spec/mark.js").RectProps>}
@@ -79,6 +93,7 @@ export default class RectMark extends Mark {
79
93
  () =>
80
94
  !this.#isRoundedCorners() &&
81
95
  !this.#isStroked() &&
96
+ !this.properties.shadowOpacity &&
82
97
  isValueDef(this.encoding.fillOpacity) &&
83
98
  this.encoding.fillOpacity.value == 1.0 &&
84
99
  this.properties.minOpacity == 1.0
@@ -141,6 +156,9 @@ export default class RectMark extends Mark {
141
156
  if (this.#isStroked()) {
142
157
  defines.push("STROKED");
143
158
  }
159
+ if (this.properties.shadowOpacity) {
160
+ defines.push("SHADOW");
161
+ }
144
162
 
145
163
  this.createAndLinkShaders(VERTEX_SHADER, FRAGMENT_SHADER, [
146
164
  COMMON_SHADER,
@@ -174,6 +192,29 @@ export default class RectMark extends Mark {
174
192
  "uCornerRadiusBottomLeft",
175
193
  props.cornerRadiusBottomLeft ?? props.cornerRadius ?? 0
176
194
  );
195
+
196
+ this.registerMarkUniformValue("uHatchPattern", props.hatch, (x) =>
197
+ Math.max(0, hatchPatterns.indexOf(x ?? "none"))
198
+ );
199
+
200
+ this.registerMarkUniformValue("uShadowBlur", props.shadowBlur ?? 0);
201
+ this.registerMarkUniformValue(
202
+ "uShadowOpacity",
203
+ props.shadowOpacity ?? 0
204
+ );
205
+ this.registerMarkUniformValue(
206
+ "uShadowOffsetX",
207
+ props.shadowOffsetX ?? 0
208
+ );
209
+ this.registerMarkUniformValue(
210
+ "uShadowOffsetY",
211
+ props.shadowOffsetY ?? 0
212
+ );
213
+ this.registerMarkUniformValue(
214
+ "uShadowColor",
215
+ props.shadowColor ?? "black",
216
+ cssColorToArray
217
+ );
177
218
  }
178
219
 
179
220
  updateGraphicsData() {
@@ -1,2 +1,2 @@
1
- const shader = "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;}}/***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.*/vec2 getVertexPos(){int index=gl_VertexID % 6;return vec2(index==0||index==1||index==3 ? 0.0 : 1.0,index==0||index==1||index==2 ? 0.0 : 1.0);}void main(void){vec2 frac=getVertexPos();vec2 normalizedMinSize=vec2(uMinWidth,uMinHeight)/uViewportSize;vec4 cornerRadii=vec4(uCornerRadiusTopRight,uCornerRadiusBottomRight,uCornerRadiusTopLeft,uCornerRadiusBottomLeft);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();}";
1
+ const shader = "out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out float vHalfStrokeWidth;out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\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;}}/***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.*/vec2 getVertexPos(){int index=gl_VertexID % 6;return vec2(index==0||index==1||index==3 ? 0.0 : 1.0,index==0||index==1||index==2 ? 0.0 : 1.0);}void main(void){vec2 frac=getVertexPos();vec2 normalizedMinSize=vec2(uMinWidth,uMinHeight)/uViewportSize;vec4 cornerRadii=vec4(uCornerRadiusTopRight,uCornerRadiusBottomRight,uCornerRadiusTopLeft,uCornerRadiusBottomLeft);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) || defined(SHADOW)\nfloat aaPadding=1.0/uDevicePixelRatio;float shadowPadding=uShadowBlur+max(abs(uShadowOffsetX),abs(uShadowOffsetY));float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding+shadowPadding*2.0)/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;
@@ -8,6 +8,12 @@ export function createSinglePointSelection(datum: import("../data/flowNode.js").
8
8
  * @returns {import("../types/selectionTypes.js").MultiPointSelection}
9
9
  */
10
10
  export function createMultiPointSelection(data?: import("../data/flowNode.js").Datum[]): import("../types/selectionTypes.js").MultiPointSelection;
11
+ /**
12
+ *
13
+ * @param {import("../spec/channel.js").ChannelWithScale[]} channels
14
+ * @returns {import("../types/selectionTypes.js").IntervalSelection}
15
+ */
16
+ export function createIntervalSelection(channels: import("../spec/channel.js").ChannelWithScale[]): import("../types/selectionTypes.js").IntervalSelection;
11
17
  /**
12
18
  * Updates the backing data and returns a new instance of the selection object.
13
19
  * A new instance is required to trigger reactivity in parameters.
@@ -32,9 +38,9 @@ export function makeSelectionTestExpression(params: {
32
38
  }): string;
33
39
  /**
34
40
  * @param {import("../types/selectionTypes.js").Selection} selection
35
- * @returns {selection is import("../types/selectionTypes.js").RangeSelection}
41
+ * @returns {selection is import("../types/selectionTypes.js").IntervalSelection}
36
42
  */
37
- export function isRangeSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").RangeSelection;
43
+ export function isIntervalSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").IntervalSelection;
38
44
  /**
39
45
  * @param {import("../types/selectionTypes.js").Selection} selection
40
46
  * @returns {selection is import("../types/selectionTypes.js").SinglePointSelection}
@@ -60,4 +66,23 @@ export function asSelectionConfig(typeOrConfig: import("../spec/parameter.js").S
60
66
  * @returns {config is import("../spec/parameter.js").PointSelectionConfig}
61
67
  */
62
68
  export function isPointSelectionConfig(config: import("../spec/parameter.js").SelectionConfig): config is import("../spec/parameter.js").PointSelectionConfig;
69
+ /**
70
+ *
71
+ * @param {import("../spec/parameter.js").SelectionConfig} config
72
+ * @returns {config is import("../spec/parameter.js").IntervalSelectionConfig}
73
+ */
74
+ export function isIntervalSelectionConfig(config: import("../spec/parameter.js").SelectionConfig): config is import("../spec/parameter.js").IntervalSelectionConfig;
75
+ /**
76
+ * @param {import("../types/selectionTypes.js").IntervalSelection} selection
77
+ */
78
+ export function isActiveIntervalSelection(selection: import("../types/selectionTypes.js").IntervalSelection): boolean;
79
+ /**
80
+ * @typedef {import("../types/selectionTypes.js").IntervalSelection} IntervalSelection
81
+ * @typedef {Partial<Record<keyof IntervalSelection["intervals"], number>>} IntervalPoint
82
+ * @param {IntervalSelection} selection
83
+ * @param {IntervalPoint} point
84
+ */
85
+ export function selectionContainsPoint(selection: IntervalSelection, point: IntervalPoint): boolean;
86
+ export type IntervalSelection = import("../types/selectionTypes.js").IntervalSelection;
87
+ export type IntervalPoint = Partial<Record<keyof IntervalSelection["intervals"], number>>;
63
88
  //# sourceMappingURL=selection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection/selection.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,kDAHW,OAAO,qBAAqB,EAAE,KAAK,GACjC,OAAO,4BAA4B,EAAE,oBAAoB,CAQrE;AAED;;;GAGG;AACH,iDAHW,OAAO,qBAAqB,EAAE,KAAK,EAAE,GACnC,OAAO,4BAA4B,EAAE,mBAAmB,CAQpE;AAED;;;;;;;GAOG;AACH,qDAJW,OAAO,4BAA4B,EAAE,mBAAmB,2BACxD,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,QAAQ,GAAG,QAAQ,EAAE,QAAQ,CAAC,OAAO,qBAAqB,EAAE,KAAK,CAAC,CAAC,CAAC,GACzF,OAAO,4BAA4B,EAAE,mBAAmB,CA2BpE;AAED;;;;GAIG;AACH,yCAJW,OAAO,4BAA4B,EAAE,SAAS,SAC9C,OAAO,qBAAqB,EAAE,KAAK,UACnC,OAAO,WAkBjB;AAED;;GAEG;AACH,oDAFW;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,UAM1C;AAED;;;GAGG;AACH,4CAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,cAAc,CAI5E;AAED;;;GAGG;AACH,kDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,oBAAoB,CAIlF;AAED;;;GAGG;AACH,iDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,mBAAmB,CAIjF;AAED;;;GAGG;AACH,gDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,kBAAkB,CAIhF;AAED;;;GAGG;AACH,gDAHW,OAAO,sBAAsB,EAAE,qBAAqB,GAClD,OAAO,sBAAsB,EAAE,eAAe,CAiB1D;AAED;;;GAGG;AACH,+CAHW,OAAO,sBAAsB,EAAE,eAAe,GAC5C,MAAM,IAAI,OAAO,sBAAsB,EAAE,oBAAoB,CAIzE"}
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection/selection.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,kDAHW,OAAO,qBAAqB,EAAE,KAAK,GACjC,OAAO,4BAA4B,EAAE,oBAAoB,CAQrE;AAED;;;GAGG;AACH,iDAHW,OAAO,qBAAqB,EAAE,KAAK,EAAE,GACnC,OAAO,4BAA4B,EAAE,mBAAmB,CAQpE;AAED;;;;GAIG;AACH,kDAHW,OAAO,oBAAoB,EAAE,gBAAgB,EAAE,GAC7C,OAAO,4BAA4B,EAAE,iBAAiB,CASlE;AAED;;;;;;;GAOG;AACH,qDAJW,OAAO,4BAA4B,EAAE,mBAAmB,2BACxD,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,QAAQ,GAAG,QAAQ,EAAE,QAAQ,CAAC,OAAO,qBAAqB,EAAE,KAAK,CAAC,CAAC,CAAC,GACzF,OAAO,4BAA4B,EAAE,mBAAmB,CA2BpE;AAED;;;;GAIG;AACH,yCAJW,OAAO,4BAA4B,EAAE,SAAS,SAC9C,OAAO,qBAAqB,EAAE,KAAK,UACnC,OAAO,WAoBjB;AAED;;GAEG;AACH,oDAFW;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,UAM1C;AAED;;;GAGG;AACH,+CAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,iBAAiB,CAI/E;AAED;;;GAGG;AACH,kDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,oBAAoB,CAIlF;AAED;;;GAGG;AACH,iDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,mBAAmB,CAIjF;AAED;;;GAGG;AACH,gDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,kBAAkB,CAIhF;AAED;;;GAGG;AACH,gDAHW,OAAO,sBAAsB,EAAE,qBAAqB,GAClD,OAAO,sBAAsB,EAAE,eAAe,CAiB1D;AAED;;;GAGG;AACH,+CAHW,OAAO,sBAAsB,EAAE,eAAe,GAC5C,MAAM,IAAI,OAAO,sBAAsB,EAAE,oBAAoB,CAIzE;AAED;;;;GAIG;AACH,kDAHW,OAAO,sBAAsB,EAAE,eAAe,GAC5C,MAAM,IAAI,OAAO,sBAAsB,EAAE,uBAAuB,CAI5E;AAED;;GAEG;AACH,qDAFW,OAAO,4BAA4B,EAAE,iBAAiB,WAMhE;AAED;;;;;GAKG;AACH,kDAHW,iBAAiB,SACjB,aAAa,WAUvB;gCAbY,OAAO,4BAA4B,EAAE,iBAAiB;4BACtD,OAAO,CAAC,MAAM,CAAC,MAAM,iBAAiB,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC"}