@genome-spy/core 0.46.1 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/index.es.js +5184 -5086
- package/dist/bundle/index.js +104 -93
- package/dist/schema.json +38 -0
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +23 -15
- package/dist/src/gl/webGLHelper.d.ts +2 -1
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +8 -1
- package/dist/src/marks/mark.d.ts +24 -12
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +27 -13
- package/dist/src/marks/point.d.ts +0 -1
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +6 -2
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +4 -1
- package/dist/src/scale/scale.js +2 -0
- package/dist/src/spec/parameter.d.ts +20 -1
- package/dist/src/types/embedApi.d.ts +7 -0
- package/dist/src/types/rendering.d.ts +6 -0
- package/dist/src/utils/animator.d.ts +15 -0
- package/dist/src/utils/animator.d.ts.map +1 -1
- package/dist/src/utils/animator.js +66 -0
- package/dist/src/utils/inertia.d.ts +4 -15
- package/dist/src/utils/inertia.d.ts.map +1 -1
- package/dist/src/utils/inertia.js +28 -63
- package/dist/src/utils/inputBinding.d.ts.map +1 -1
- package/dist/src/utils/inputBinding.js +26 -2
- package/dist/src/view/gridView.d.ts +4 -6
- package/dist/src/view/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView.js +45 -27
- package/dist/src/view/unitView.d.ts +3 -14
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +26 -8
- package/dist/src/view/view.d.ts +14 -5
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +26 -7
- package/dist/src/view/zoom.d.ts +2 -2
- package/dist/src/view/zoom.d.ts.map +1 -1
- package/dist/src/view/zoom.js +1 -1
- package/package.json +2 -2
- package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts +0 -60
- package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts.map +0 -1
- package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
package/dist/schema.json
CHANGED
|
@@ -507,6 +507,41 @@
|
|
|
507
507
|
],
|
|
508
508
|
"type": "object"
|
|
509
509
|
},
|
|
510
|
+
"BindInput": {
|
|
511
|
+
"additionalProperties": false,
|
|
512
|
+
"properties": {
|
|
513
|
+
"autocomplete": {
|
|
514
|
+
"description": "A hint for form autofill. See the [HTML autocomplete attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for additional information.",
|
|
515
|
+
"type": "string"
|
|
516
|
+
},
|
|
517
|
+
"debounce": {
|
|
518
|
+
"description": "If defined, delays event handling until the specified milliseconds have elapsed since the last event was fired.",
|
|
519
|
+
"type": "number"
|
|
520
|
+
},
|
|
521
|
+
"description": {
|
|
522
|
+
"description": "An optional description or help text that is shown below the input element.",
|
|
523
|
+
"type": "string"
|
|
524
|
+
},
|
|
525
|
+
"input": {
|
|
526
|
+
"description": "The type of input element to use. The valid values are `\"checkbox\"`, `\"radio\"`, `\"range\"`, `\"select\"`, `\"text\"`, `\"number\"`, and `\"color\"`.",
|
|
527
|
+
"enum": [
|
|
528
|
+
"text",
|
|
529
|
+
"number",
|
|
530
|
+
"color"
|
|
531
|
+
],
|
|
532
|
+
"type": "string"
|
|
533
|
+
},
|
|
534
|
+
"name": {
|
|
535
|
+
"description": "By default, the parameter name is used to label input elements. This `name` property can be used instead to specify a custom label for the bound parameter.",
|
|
536
|
+
"type": "string"
|
|
537
|
+
},
|
|
538
|
+
"placeholder": {
|
|
539
|
+
"description": "Text that appears in the form control when it has no value set.",
|
|
540
|
+
"type": "string"
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
"type": "object"
|
|
544
|
+
},
|
|
510
545
|
"BindRadioSelect": {
|
|
511
546
|
"additionalProperties": false,
|
|
512
547
|
"properties": {
|
|
@@ -595,6 +630,9 @@
|
|
|
595
630
|
},
|
|
596
631
|
{
|
|
597
632
|
"$ref": "#/definitions/BindRange"
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
"$ref": "#/definitions/BindInput"
|
|
598
636
|
}
|
|
599
637
|
]
|
|
600
638
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA8CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA2FpD;IAxFG,uBAA0B;IAC1B,oDAAsB;IAItB,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAE/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB;;;;OAIG;IACH;gBAF8B,OAAO,wBAAwB,EAAE,iBAAiB;iBAAW,MAAM;OAEnE;IAE9B;;OAEG;IACH,wBAFU,WAAW,CAEkB;IA2C3C;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAqDC;IA0DG,
|
|
1
|
+
{"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA8CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA2FpD;IAxFG,uBAA0B;IAC1B,oDAAsB;IAItB,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAE/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB;;;;OAIG;IACH;gBAF8B,OAAO,wBAAwB,EAAE,iBAAiB;iBAAW,MAAM;OAEnE;IAE9B;;OAEG;IACH,wBAFU,WAAW,CAEkB;IA2C3C;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAqDC;IA0DG,uBAQC;IAGD,mCAGE;IAOF,sCAEE;IAGF,iBAAyC;IAW7C;;OAEG;IACH,gBAuBC;IAED,sCA8MC;IAED;;;OAGG;IACH,UAFa,QAAQ,OAAO,CAAC,CA6B5B;IAED,4BA+IC;IAxHe,iCAAoC;IA0HpD;;;OAGG;IACH,kBAHW,MAAM,KACN,MAAM,QAsEhB;IAED;;;;;;;OAOG;IACH,oDAHuB,QAAQ,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;IAED,sBA6CC;IAED,kBAIC;IAED,iCAOC;IAED,iCASC;IAED,qFAWC;;CACJ;;;;iCAl7BY,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,gBAAgB;4BAjC7C,uBAAuB;4BA2BP,uBAAuB;qBAZ9C,qBAAqB;wBAIlB,yBAAyB;yCARR,yDAAyD;oBAYvD,oBAAoB;wBAdvC,qBAAqB;oBAXzB,uBAAuB;qBAStB,oBAAoB"}
|
package/dist/src/genomeSpy.js
CHANGED
|
@@ -362,7 +362,8 @@ export default class GenomeSpy {
|
|
|
362
362
|
this.viewRoot
|
|
363
363
|
? calculateCanvasSize(calculateViewRootSize(this.viewRoot))
|
|
364
364
|
: { width: undefined, height: undefined },
|
|
365
|
-
this.spec.background
|
|
365
|
+
this.spec.background,
|
|
366
|
+
{ powerPreference: this.options.powerPreference ?? "default" }
|
|
366
367
|
);
|
|
367
368
|
|
|
368
369
|
// The initial loading message that is shown until the first frame is rendered
|
|
@@ -668,25 +669,31 @@ export default class GenomeSpy {
|
|
|
668
669
|
// that would also contain state-related stuff that currently pollute the
|
|
669
670
|
// GenomeSpy class.
|
|
670
671
|
|
|
672
|
+
let lastWheelEvent = performance.now();
|
|
673
|
+
|
|
671
674
|
/** @param {Event} event */
|
|
672
675
|
const listener = (event) => {
|
|
676
|
+
const now = performance.now();
|
|
677
|
+
const wheeling = now - lastWheelEvent < 200;
|
|
678
|
+
|
|
673
679
|
if (event instanceof MouseEvent) {
|
|
674
|
-
|
|
680
|
+
const rect = canvas.getBoundingClientRect();
|
|
681
|
+
const point = new Point(
|
|
682
|
+
event.clientX - rect.left - canvas.clientLeft,
|
|
683
|
+
event.clientY - rect.top - canvas.clientTop
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
if (event.type == "mousemove" && !wheeling) {
|
|
675
687
|
this.tooltip.handleMouseMove(event);
|
|
676
688
|
this._tooltipUpdateRequested = false;
|
|
677
689
|
|
|
678
690
|
if (event.buttons == 0) {
|
|
679
691
|
// Disable during dragging
|
|
680
692
|
this.renderPickingFramebuffer();
|
|
693
|
+
this._handlePicking(point.x, point.y);
|
|
681
694
|
}
|
|
682
695
|
}
|
|
683
696
|
|
|
684
|
-
const rect = canvas.getBoundingClientRect();
|
|
685
|
-
const point = new Point(
|
|
686
|
-
event.clientX - rect.left - canvas.clientLeft,
|
|
687
|
-
event.clientY - rect.top - canvas.clientTop
|
|
688
|
-
);
|
|
689
|
-
|
|
690
697
|
/**
|
|
691
698
|
* @param {MouseEvent} event
|
|
692
699
|
*/
|
|
@@ -704,14 +711,10 @@ export default class GenomeSpy {
|
|
|
704
711
|
this._wheelInertia.cancel();
|
|
705
712
|
}
|
|
706
713
|
|
|
707
|
-
if (event.type == "
|
|
708
|
-
this._handlePicking(point.x, point.y);
|
|
709
|
-
} else if (
|
|
710
|
-
event.type == "mousedown" ||
|
|
711
|
-
event.type == "mouseup"
|
|
712
|
-
) {
|
|
714
|
+
if (event.type == "mousedown" || event.type == "mouseup") {
|
|
713
715
|
this.renderPickingFramebuffer();
|
|
714
716
|
} else if (event.type == "wheel") {
|
|
717
|
+
lastWheelEvent = now;
|
|
715
718
|
this._tooltipUpdateRequested = false;
|
|
716
719
|
|
|
717
720
|
const wheelEvent = /** @type {WheelEvent} */ (event);
|
|
@@ -830,7 +833,12 @@ export default class GenomeSpy {
|
|
|
830
833
|
|
|
831
834
|
this.viewRoot.visit((view) => {
|
|
832
835
|
if (view instanceof UnitView) {
|
|
833
|
-
if (
|
|
836
|
+
if (
|
|
837
|
+
view.mark.isPickingParticipant() &&
|
|
838
|
+
[...view.facetCoords.values()].some((coords) =>
|
|
839
|
+
coords.containsPoint(x, y)
|
|
840
|
+
)
|
|
841
|
+
) {
|
|
834
842
|
const accessor = view.mark.encoders.uniqueId.accessor;
|
|
835
843
|
view.getCollector().visitData((d) => {
|
|
836
844
|
if (accessor(d) == uniqueId) {
|
|
@@ -25,11 +25,12 @@ export default class WebGLHelper {
|
|
|
25
25
|
* A function that returns the content size. If a dimension is undefined,
|
|
26
26
|
* the canvas fills the container, otherwise the canvas is adjusted to the content size.
|
|
27
27
|
* @param {string} [clearColor]
|
|
28
|
+
* @param {WebGLContextAttributes} [webglContextAttributes]
|
|
28
29
|
*/
|
|
29
30
|
constructor(container: HTMLElement, sizeSource?: () => {
|
|
30
31
|
width: number;
|
|
31
32
|
height: number;
|
|
32
|
-
}, clearColor?: string);
|
|
33
|
+
}, clearColor?: string, webglContextAttributes?: WebGLContextAttributes);
|
|
33
34
|
_container: HTMLElement;
|
|
34
35
|
_sizeSource: () => {
|
|
35
36
|
width: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"AAmaA;;;;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;AAxcD;IACI;;;;;;;;OAQG;IACH,uBAPW,WAAW,eACX,MAAM;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,eAGrC,MAAM,2BACN,sBAAsB,EAyFhC;IAjFG,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;IAwClC,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,QA0GjB;CACJ"}
|
|
@@ -36,8 +36,14 @@ export default class WebGLHelper {
|
|
|
36
36
|
* A function that returns the content size. If a dimension is undefined,
|
|
37
37
|
* the canvas fills the container, otherwise the canvas is adjusted to the content size.
|
|
38
38
|
* @param {string} [clearColor]
|
|
39
|
+
* @param {WebGLContextAttributes} [webglContextAttributes]
|
|
39
40
|
*/
|
|
40
|
-
constructor(
|
|
41
|
+
constructor(
|
|
42
|
+
container,
|
|
43
|
+
sizeSource,
|
|
44
|
+
clearColor,
|
|
45
|
+
webglContextAttributes = {}
|
|
46
|
+
) {
|
|
41
47
|
this._container = container;
|
|
42
48
|
this._sizeSource =
|
|
43
49
|
sizeSource ??
|
|
@@ -67,6 +73,7 @@ export default class WebGLHelper {
|
|
|
67
73
|
// Disable depth writes. We don't use depth testing.
|
|
68
74
|
depth: false,
|
|
69
75
|
premultipliedAlpha: true,
|
|
76
|
+
...webglContextAttributes,
|
|
70
77
|
})
|
|
71
78
|
);
|
|
72
79
|
|
package/dist/src/marks/mark.d.ts
CHANGED
|
@@ -22,27 +22,39 @@ export default class Mark {
|
|
|
22
22
|
unitView: import("../view/unitView.js").default;
|
|
23
23
|
/** @type {Record<string, import("../types/encoder.js").Encoder>} */
|
|
24
24
|
encoders: Record<string, import("../types/encoder.js").Encoder>;
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* @type {import("twgl.js").BufferInfo & { allocatedVertices?: number }}
|
|
27
|
+
* @protected
|
|
28
|
+
*/
|
|
29
|
+
protected bufferInfo: import("twgl.js").BufferInfo & {
|
|
27
30
|
allocatedVertices?: number;
|
|
28
31
|
};
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
/**
|
|
33
|
+
* @type {import("twgl.js").ProgramInfo}
|
|
34
|
+
* @protected
|
|
35
|
+
*/
|
|
36
|
+
protected programInfo: import("twgl.js").ProgramInfo;
|
|
37
|
+
/**
|
|
38
|
+
* @type {import("twgl.js").VertexArrayInfo}
|
|
39
|
+
* @protected
|
|
40
|
+
*/
|
|
41
|
+
protected vertexArrayInfo: import("twgl.js").VertexArrayInfo;
|
|
42
|
+
/**
|
|
43
|
+
* @type {import("twgl.js").UniformBlockInfo}
|
|
44
|
+
* @protected
|
|
45
|
+
*/
|
|
46
|
+
protected viewUniformInfo: import("twgl.js").UniformBlockInfo;
|
|
37
47
|
/**
|
|
38
48
|
* Uniforms related to the specific mark type.
|
|
49
|
+
*
|
|
39
50
|
* @type {import("twgl.js").UniformBlockInfo}
|
|
51
|
+
* @protected
|
|
40
52
|
*/
|
|
41
|
-
markUniformInfo: import("twgl.js").UniformBlockInfo;
|
|
53
|
+
protected markUniformInfo: import("twgl.js").UniformBlockInfo;
|
|
42
54
|
/**
|
|
43
55
|
* Indicates whether the mark's uniforms have been altered since the last rendering.
|
|
44
56
|
* If set to true, the uniforms will be sent to the GPU before rendering the next frame.
|
|
45
|
-
|
|
57
|
+
*
|
|
46
58
|
* @protected
|
|
47
59
|
*/
|
|
48
60
|
protected markUniformsAltered: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":";AA4CA,0DAA2D;AAC3D,0DAA2D;AAE3D;;;;;;;;;;;;GAYG;AACH;IAgBI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":";AA4CA,0DAA2D;AAC3D,0DAA2D;AAE3D;;;;;;;;;;;;GAYG;AACH;IAgBI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EA6F/C;IA1FG,gDAAwB;IAExB,oEAAoE;IACpE,UADW,OAAO,MAAM,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC,CACvC;IAIzB;;;OAGG;IACH,sBAHU,OAAO,SAAS,EAAE,UAAU,GAAG;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAG5C;IAE3B;;;OAGG;IACH,uBAHU,OAAO,SAAS,EAAE,WAAW,CAGX;IAE5B;;;OAGG;IACH,2BAHU,OAAO,SAAS,EAAE,eAAe,CAGX;IAEhC;;;OAGG;IACH,2BAHU,OAAO,SAAS,EAAE,gBAAgB,CAGZ;IAEhC;;;;;OAKG;IACH,2BAHU,OAAO,SAAS,EAAE,gBAAgB,CAGZ;IAEhC;;;;;OAKG;IACH,uCAA+B;IAE/B,kFAAkF;IAClF,UADW,SAAS,GAAG,CAAC,CACM;IAG9B,wBAAwB;IACxB,uDAqBC;IAED;;;;;;;;OAQG;IACH,kEAKC;IAGL,sBAEC;IAED;;;;;;;OAOG;IACH,iBAFa,MAAM,EAAE,CAKpB;IAED;;OAEG;IACH,+DAWC;IAED;;OAEG;IACH,oEAcC;IAED;;;;;OAKG;IACH,oHAEC;IAED;;;;;;OAMG;IACH,yGAkCC;IAED;;;;OAIG;IACH,8DAiDC;IAED,wDAEC;IAED,8CAEC;IAED,uBAEC;IAED;;;OAGG;IACH,2BAEC;IAED;;OAEG;IACH,oCAEC;IAED;;OAEG;IACH,2BAEC;IAED,sEAeC;IAED;;;;;;OAMG;IAEH,6CANW,MAAM,kBACN,MAAM,iBACN,MAAM,EAAE,QA8NlB;IALG;;;;;;MAIC;IAGL;;;;;;OAMG;IACH,uCA6CC;IAED;;;;;;OAMG;IACH,+CAHW,MAAM,UACK,GAAG,KAAE,IAAI,CAe9B;IAED;;;;;;;;;;OAUG;IACH,mDAJW,MAAM,sFAEsB,GAAG,QA6BzC;IAED;;OAEG;IACH,2BAwBC;IAED;;;OAGG;IACH,6BAFW,GAAG,QAgCb;IAED,yBAAyB;IACzB,uDAEC;IAED,yBAAyB;IACzB,iCAEC;IAED,gCAEC;IAED,+BAEC;IAED,yCAEC;IAED;;;;;OAKG;IACH,gCAcC;IAED;;OAEG;IACH,4CAOC;IAED;;;;;;;;OAQG;IAEH,uBAJW,OAAO,uBAAuB,EAAE,sBAAsB,GACpD,CAAC,MAAM,IAAI,CAAC,EAAE,CAsF1B;IAED;;;;;;OAMG;IACH,qCAJW,oBAAoB,GAClB,OAAO,CAqCnB;IAED;;;;;;;OAOG;IACH,gBAJW,oBAAoB,SACP,IAAI,CAM3B;IAED;;;OAGG;IACH,2BAHW,YAAY,WACZ,OAAO,WAAW,EAAE,oBAAoB,cAiElD;IAED;;;;;;OAMG;IACH,oBAJW,OAAO,6BAA6B,EAAE,OAAO,aAC7C,OAAO,6BAA6B,EAAE,OAAO,GAC3C,OAAO,CAuHnB;IAED;;;;;;;;;OASG;IACH,qBAJW,MAAM,KACN,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAIf;;CACJ;+BAvoCY,OAAO,uBAAuB,EAAE,gBAAgB;;;;;;wBAEnD,OAAO;;mCAEJ,gBAAgB,GAAG,qBAAqB;oCAG1C,MAAM,SACN,MAAM;AAioCjB;;;GAGG;AACH;IACI,cAEC;IAkBD;;;OAGG;IACH,2BAFW,IAAI,CAAC,EAAE,OAAO,yBAAyB,EAAE,UAAU,CAAC,QAiB9D;CACJ;0BA/rCyB,WAAW"}
|
package/dist/src/marks/mark.js
CHANGED
|
@@ -85,31 +85,42 @@ export default class Mark {
|
|
|
85
85
|
|
|
86
86
|
// TODO: Consolidate the following webgl stuff into a single object
|
|
87
87
|
|
|
88
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* @type {import("twgl.js").BufferInfo & { allocatedVertices?: number }}
|
|
90
|
+
* @protected
|
|
91
|
+
*/
|
|
89
92
|
this.bufferInfo = undefined;
|
|
90
93
|
|
|
91
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* @type {import("twgl.js").ProgramInfo}
|
|
96
|
+
* @protected
|
|
97
|
+
*/
|
|
92
98
|
this.programInfo = undefined;
|
|
93
99
|
|
|
94
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* @type {import("twgl.js").VertexArrayInfo}
|
|
102
|
+
* @protected
|
|
103
|
+
*/
|
|
95
104
|
this.vertexArrayInfo = undefined;
|
|
96
105
|
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
/**
|
|
107
|
+
* @type {import("twgl.js").UniformBlockInfo}
|
|
108
|
+
* @protected
|
|
109
|
+
*/
|
|
101
110
|
this.viewUniformInfo = undefined;
|
|
102
111
|
|
|
103
112
|
/**
|
|
104
113
|
* Uniforms related to the specific mark type.
|
|
114
|
+
*
|
|
105
115
|
* @type {import("twgl.js").UniformBlockInfo}
|
|
116
|
+
* @protected
|
|
106
117
|
*/
|
|
107
118
|
this.markUniformInfo = undefined;
|
|
108
119
|
|
|
109
120
|
/**
|
|
110
121
|
* Indicates whether the mark's uniforms have been altered since the last rendering.
|
|
111
122
|
* If set to true, the uniforms will be sent to the GPU before rendering the next frame.
|
|
112
|
-
|
|
123
|
+
*
|
|
113
124
|
* @protected
|
|
114
125
|
*/
|
|
115
126
|
this.markUniformsAltered = true;
|
|
@@ -719,8 +730,15 @@ export default class Mark {
|
|
|
719
730
|
* Delete WebGL buffers etc.
|
|
720
731
|
*/
|
|
721
732
|
deleteGraphicsData() {
|
|
733
|
+
const gl = this.gl;
|
|
734
|
+
|
|
735
|
+
if (this.vertexArrayInfo) {
|
|
736
|
+
this.gl.bindVertexArray(null);
|
|
737
|
+
gl.deleteVertexArray(this.vertexArrayInfo.vertexArrayObject);
|
|
738
|
+
this.vertexArrayInfo = undefined;
|
|
739
|
+
}
|
|
740
|
+
|
|
722
741
|
if (this.bufferInfo) {
|
|
723
|
-
const gl = this.gl;
|
|
724
742
|
// A hack to prevent WebGL: INVALID_OPERATION: drawArrays: no buffer is bound to enabled attribute
|
|
725
743
|
// TODO: Consider using bufferSubData or DYNAMIC_DRAW etc...
|
|
726
744
|
for (let i = 0; i < 8; i++) {
|
|
@@ -742,7 +760,6 @@ export default class Mark {
|
|
|
742
760
|
* @param {any} vertexData TODO: Extract type from VertexBuilder
|
|
743
761
|
*/
|
|
744
762
|
updateBufferInfo(vertexData) {
|
|
745
|
-
// Ensure that no VAOs are inadvertently altered
|
|
746
763
|
this.gl.bindVertexArray(null);
|
|
747
764
|
|
|
748
765
|
if (
|
|
@@ -761,8 +778,6 @@ export default class Mark {
|
|
|
761
778
|
attributeData.data,
|
|
762
779
|
0
|
|
763
780
|
);
|
|
764
|
-
// TODO: Consider double buffering:
|
|
765
|
-
// https://community.khronos.org/t/texture-buffers-are-much-slower-than-uniform-buffers/77139
|
|
766
781
|
}
|
|
767
782
|
}
|
|
768
783
|
} else {
|
|
@@ -773,7 +788,6 @@ export default class Mark {
|
|
|
773
788
|
{ numElements: vertexData.vertexCount }
|
|
774
789
|
);
|
|
775
790
|
this.bufferInfo.allocatedVertices = vertexData.allocatedVertices;
|
|
776
|
-
this.vertexArrayInfo = undefined;
|
|
777
791
|
}
|
|
778
792
|
}
|
|
779
793
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAmBA;IA0HY,oCAMC;
|
|
1
|
+
{"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAmBA;IA0HY,oCAMC;IA6DT,+BAkBC;;CAgDJ;iBAvQgB,WAAW"}
|
package/dist/src/marks/point.js
CHANGED
|
@@ -192,7 +192,11 @@ export default class PointMark extends Mark {
|
|
|
192
192
|
this.updateBufferInfo(vertexData);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
/**
|
|
196
|
+
* This and `geometricZoomBound` should be deprecated once params (zoomLevel) and
|
|
197
|
+
* expressions are documented.
|
|
198
|
+
*/
|
|
199
|
+
#getGeometricScaleFactor() {
|
|
196
200
|
const zoomLevel = Math.pow(2, this.properties.geometricZoomBound || 0);
|
|
197
201
|
|
|
198
202
|
return Math.pow(
|
|
@@ -231,7 +235,7 @@ export default class PointMark extends Mark {
|
|
|
231
235
|
ops.push(() => {
|
|
232
236
|
// TODO: Use bindUniformBlock if none of the uniform has changed
|
|
233
237
|
setBlockUniforms(this.markUniformInfo, {
|
|
234
|
-
uScaleFactor: this
|
|
238
|
+
uScaleFactor: this.#getGeometricScaleFactor(),
|
|
235
239
|
uSemanticThreshold: this.getSemanticThreshold(),
|
|
236
240
|
});
|
|
237
241
|
this.markUniformsAltered = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAyDQ,oDAMmD;
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAyDQ,oDAMmD;CAwM1D;iBAlSgB,WAAW"}
|
package/dist/src/marks/text.js
CHANGED
|
@@ -243,7 +243,10 @@ export default class TextMark extends Mark {
|
|
|
243
243
|
fontMetrics: this.font.metrics,
|
|
244
244
|
numCharacters: Math.max(
|
|
245
245
|
charCount,
|
|
246
|
-
|
|
246
|
+
// There's some mysterious bug with growing the buffer –
|
|
247
|
+
// old buffer is rendered instead of the new one.
|
|
248
|
+
// TODO: Figure it out
|
|
249
|
+
this.properties.minBufferSize || 1024
|
|
247
250
|
),
|
|
248
251
|
});
|
|
249
252
|
|
package/dist/src/scale/scale.js
CHANGED
|
@@ -274,6 +274,8 @@ function rawDomain(scale, raw, logger) {
|
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
function padDomain(type, domain, range, pad, exponent, constant) {
|
|
277
|
+
range ??= [0, 1]; // default to unit range. TODO: Fix this when we have pixel-based ranges.
|
|
278
|
+
|
|
277
279
|
var span = Math.abs(peek(range) - range[0]),
|
|
278
280
|
frac = span / (span - 2 * pad),
|
|
279
281
|
d =
|
|
@@ -60,6 +60,25 @@ export interface BindBase {
|
|
|
60
60
|
description?: string;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
export interface BindInput extends BindBase {
|
|
64
|
+
/**
|
|
65
|
+
* The type of input element to use.
|
|
66
|
+
* The valid values are `"checkbox"`, `"radio"`, `"range"`, `"select"`, `"text"`, `"number"`, and `"color"`.
|
|
67
|
+
*/
|
|
68
|
+
input?: "text" | "number" | "color";
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Text that appears in the form control when it has no value set.
|
|
72
|
+
*/
|
|
73
|
+
placeholder?: string;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A hint for form autofill.
|
|
77
|
+
* See the [HTML autocomplete attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for additional information.
|
|
78
|
+
*/
|
|
79
|
+
autocomplete?: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
63
82
|
export interface BindCheckbox extends BindBase {
|
|
64
83
|
input: "checkbox";
|
|
65
84
|
}
|
|
@@ -124,4 +143,4 @@ export interface BindDirect {
|
|
|
124
143
|
debounce?: number;
|
|
125
144
|
}
|
|
126
145
|
|
|
127
|
-
export type Binding = BindCheckbox | BindRadioSelect | BindRange;
|
|
146
|
+
export type Binding = BindCheckbox | BindRadioSelect | BindRange | BindInput;
|
|
@@ -33,6 +33,13 @@ export interface EmbedOptions {
|
|
|
33
33
|
* the input binding elements are placed in the same container as the GenomeSpy instance.
|
|
34
34
|
*/
|
|
35
35
|
inputBindingContainer?: HTMLElement | "none" | "default";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A suggestion for the browser on the appropriate GPU setup for the WebGL environment.
|
|
39
|
+
* Defaults to "default" in the @genome-spy/core package and "high-performance" in the
|
|
40
|
+
* @genome-spy/app package.
|
|
41
|
+
*/
|
|
42
|
+
powerPreference?: "default" | "high-performance" | "low-power";
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
/**
|
|
@@ -24,6 +24,12 @@ export interface RenderingOptions {
|
|
|
24
24
|
*/
|
|
25
25
|
facetId?: any;
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* If rendering facets, this is the first facet. Allows for
|
|
29
|
+
* cleanup, etc.
|
|
30
|
+
*/
|
|
31
|
+
firstFacet?: boolean;
|
|
32
|
+
|
|
27
33
|
sampleFacetRenderingOptions?: SampleFacetRenderingOptions;
|
|
28
34
|
|
|
29
35
|
/**
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a lerp smoother that animates a value towards a target value. Lerp smoothing
|
|
3
|
+
* is conceptually similar to easing, but can be used when the current and target
|
|
4
|
+
* values are not known in advance.
|
|
5
|
+
*
|
|
6
|
+
* Read more at: https://www.gamedeveloper.com/programming/improved-lerp-smoothing-
|
|
7
|
+
*
|
|
8
|
+
* @param {import("../utils/animator.js").default} animator
|
|
9
|
+
* @param {(value: number) => void} callback Function to be called with the interpolated value
|
|
10
|
+
* @param {number} halfLife Time until half of the value is reached, in milliseconds
|
|
11
|
+
* @param {number} stopAt Stop animation when the value is within this distance from the target
|
|
12
|
+
* @param {number} [initialValue] Initial value
|
|
13
|
+
* @returns {(target: number) => void} Function that activates the transition with a new target value
|
|
14
|
+
*/
|
|
15
|
+
export function makeLerpSmoother(animator: import("../utils/animator.js").default, callback: (value: number) => void, halfLife: number, stopAt: number, initialValue?: number): (target: number) => void;
|
|
1
16
|
export default class Animator {
|
|
2
17
|
/**
|
|
3
18
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animator.d.ts","sourceRoot":"","sources":["../../../src/utils/animator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"animator.d.ts","sourceRoot":"","sources":["../../../src/utils/animator.js"],"names":[],"mappings":"AAoFA;;;;;;;;;;;;;GAaG;AACH,2CAPW,OAAO,sBAAsB,EAAE,OAAO,oBAC9B,MAAM,KAAK,IAAI,YACvB,MAAM,UACN,MAAM,iBACN,MAAM,YACK,MAAM,KAAK,IAAI,CAoDpC;AAlJD;IACI;;;OAGG;IACH,mCAFoB,MAAM,KAAE,IAAI,EAS/B;IANG,wBAHgB,MAAM,KAAE,IAAI,CAGS;IACrC,0BAA6B;IAC7B,eAAkB;IAElB,wCAAwC;IACxC,aADW,QAAU,MAAM,KAAE,IAAI,CAAC,EAAE,CACf;IAGzB;;;;;;;;;OASG;IACH,mCAFoB,MAAM,KAAE,IAAI,QAM/B;IAED;;OAEG;IACH,kCAFoB,MAAM,KAAE,IAAI,QAO/B;IAED;;;;OAIG;IACH,sBAoBC;IAED;;;;;OAKG;IACH,oBAFW,OAAO,iBAAiB,EAAE,iBAAiB,gBAQrD;CACJ"}
|
|
@@ -81,3 +81,69 @@ export default class Animator {
|
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns a lerp smoother that animates a value towards a target value. Lerp smoothing
|
|
87
|
+
* is conceptually similar to easing, but can be used when the current and target
|
|
88
|
+
* values are not known in advance.
|
|
89
|
+
*
|
|
90
|
+
* Read more at: https://www.gamedeveloper.com/programming/improved-lerp-smoothing-
|
|
91
|
+
*
|
|
92
|
+
* @param {import("../utils/animator.js").default} animator
|
|
93
|
+
* @param {(value: number) => void} callback Function to be called with the interpolated value
|
|
94
|
+
* @param {number} halfLife Time until half of the value is reached, in milliseconds
|
|
95
|
+
* @param {number} stopAt Stop animation when the value is within this distance from the target
|
|
96
|
+
* @param {number} [initialValue] Initial value
|
|
97
|
+
* @returns {(target: number) => void} Function that activates the transition with a new target value
|
|
98
|
+
*/
|
|
99
|
+
export function makeLerpSmoother(
|
|
100
|
+
animator,
|
|
101
|
+
callback,
|
|
102
|
+
halfLife,
|
|
103
|
+
stopAt,
|
|
104
|
+
initialValue = 0
|
|
105
|
+
) {
|
|
106
|
+
let lastTimeStamp = 0;
|
|
107
|
+
let settled = true;
|
|
108
|
+
|
|
109
|
+
let current = initialValue;
|
|
110
|
+
let target = current;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {number} [timestamp]
|
|
114
|
+
*/
|
|
115
|
+
function smoothUpdate(timestamp) {
|
|
116
|
+
timestamp ??= +document.timeline.currentTime;
|
|
117
|
+
|
|
118
|
+
// If settled, the animation loop may have been stopped, so we need to
|
|
119
|
+
// wait until the next frame to get a proper time delta.
|
|
120
|
+
const tD = settled ? 0 : timestamp - lastTimeStamp;
|
|
121
|
+
lastTimeStamp = timestamp;
|
|
122
|
+
|
|
123
|
+
settled = false;
|
|
124
|
+
|
|
125
|
+
// Lerp smoothing: https://twitter.com/FreyaHolmer/status/1757836988495847568
|
|
126
|
+
current = target + (current - target) * Math.pow(2, -tD / halfLife);
|
|
127
|
+
|
|
128
|
+
callback(current);
|
|
129
|
+
|
|
130
|
+
if (Math.abs(target - current) < stopAt) {
|
|
131
|
+
current = target;
|
|
132
|
+
callback(current);
|
|
133
|
+
settled = true;
|
|
134
|
+
animator.requestRender();
|
|
135
|
+
} else {
|
|
136
|
+
animator.requestTransition((t) => smoothUpdate(t));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {number} value
|
|
142
|
+
*/
|
|
143
|
+
return function setTarget(value) {
|
|
144
|
+
target = value;
|
|
145
|
+
if (settled) {
|
|
146
|
+
smoothUpdate();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -14,18 +14,12 @@ export default class Inertia {
|
|
|
14
14
|
constructor(animator: import("./animator.js").default, disabled?: boolean);
|
|
15
15
|
animator: import("./animator.js").default;
|
|
16
16
|
disabled: boolean;
|
|
17
|
-
|
|
18
|
-
acceleration: number;
|
|
19
|
-
/** Use acceleration if the momentum step is greater than X */
|
|
20
|
-
accelerationThreshold: number;
|
|
21
|
-
lowerLimit: number;
|
|
22
|
-
loop: boolean;
|
|
23
|
-
momentum: number;
|
|
24
|
-
timestamp: number;
|
|
17
|
+
maxDistance: number;
|
|
25
18
|
/** @type {function(number):void} */
|
|
26
19
|
callback: (arg0: number) => void;
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
targetValue: number;
|
|
21
|
+
lastValue: number;
|
|
22
|
+
smoother: (target: number) => void;
|
|
29
23
|
cancel(): void;
|
|
30
24
|
/**
|
|
31
25
|
*
|
|
@@ -33,10 +27,5 @@ export default class Inertia {
|
|
|
33
27
|
* @param {function(number):void} callback
|
|
34
28
|
*/
|
|
35
29
|
setMomentum(value: number, callback: (arg0: number) => void): void;
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
* @param {number} [timestamp]
|
|
39
|
-
*/
|
|
40
|
-
animate(timestamp?: number): void;
|
|
41
30
|
}
|
|
42
31
|
//# sourceMappingURL=inertia.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inertia.d.ts","sourceRoot":"","sources":["../../../src/utils/inertia.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"inertia.d.ts","sourceRoot":"","sources":["../../../src/utils/inertia.js"],"names":[],"mappings":"AAmEA;;;GAGG;AACH,8EAiBC;AApFD;;GAEG;AACH;IACI;;;OAGG;IACH,sBAHW,OAAO,eAAe,EAAE,OAAO,aAC/B,OAAO,EAyBjB;IAtBG,0CAAwB;IACxB,kBAA0B;IAG1B,oBAAsB;IAEtB,oCAAoC;IACpC,iBADoB,MAAM,KAAE,IAAI,CACZ;IAEpB,oBAAoB;IACpB,kBAAkB;IAElB,mCASC;IAGL,eAIC;IAED;;;;OAIG;IACH,mBAHW,MAAM,mBACG,MAAM,KAAE,IAAI,QAkB/B;CACJ"}
|