@genome-spy/core 0.48.0 → 0.48.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.
package/dist/schema.json CHANGED
@@ -3471,8 +3471,15 @@
3471
3471
  "description": "The vertical padding, in pixels, when the `y2` channel is used for ranged text.\n\n**Default value:** `0`"
3472
3472
  },
3473
3473
  "segments": {
3474
- "description": "The number of segments in the bézier curve. Affects the rendering quality and performance. Use a higher value for a smoother curve.\n\n**Default value:* `101`",
3475
- "type": "number"
3474
+ "anyOf": [
3475
+ {
3476
+ "type": "number"
3477
+ },
3478
+ {
3479
+ "$ref": "#/definitions/ExprRef"
3480
+ }
3481
+ ],
3482
+ "description": "The number of segments in the bézier curve. Affects the rendering quality and performance. Use a higher value for a smoother curve.\n\n**Default value:* `101`"
3476
3483
  },
3477
3484
  "semanticZoomFraction": {
3478
3485
  "anyOf": [
@@ -1,2 +1,2 @@
1
- const shader = "layout(std140)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;\n#pragma markUniforms\n};";
1
+ const shader = "layout(std140)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;uniform int uSegmentBreaks;\n#pragma markUniforms\n};";
2
2
  export default shader;
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAYA;IA+BQ;;;;;OAKG;IACH,yBAEC;IA4GD;;;;;;MAKC;CAoFR;iBAlPgB,WAAW"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAYA;IA+BQ;;;;;OAKG;IACH,yBAEC;IA2GD;;;;;;MAKC;CAwFR;iBArPgB,WAAW"}
@@ -133,6 +133,11 @@ export default class LinkMark extends Mark {
133
133
  (x) => !!x
134
134
  );
135
135
  this.registerMarkUniformValue("uMaxChordLength", props.maxChordLength);
136
+ this.registerMarkUniformValue(
137
+ "uSegmentBreaks",
138
+ props.segments,
139
+ (x) => x + 1
140
+ );
136
141
  }
137
142
 
138
143
  updateGraphicsData() {
@@ -149,12 +154,6 @@ export default class LinkMark extends Mark {
149
154
 
150
155
  const vertexData = builder.toArrays();
151
156
 
152
- // TODO: Use gl_VertexID to calculate the strip in the vertex shader
153
- vertexData.arrays.strip = {
154
- data: createStrip(this.properties.segments),
155
- numComponents: 2,
156
- };
157
-
158
157
  this.rangeMap.migrateEntries(vertexData.rangeMap);
159
158
 
160
159
  this.arrays = Object.fromEntries(
@@ -196,8 +195,6 @@ export default class LinkMark extends Mark {
196
195
  render(options) {
197
196
  const gl = this.gl;
198
197
 
199
- const arcVertexCount = (this.properties.segments + 1) * 2;
200
-
201
198
  return this._baseInstanceExt
202
199
  ? this.createRenderCallback((offset, count) => {
203
200
  // Using the following extension, which, however, is only a draft and
@@ -207,7 +204,9 @@ export default class LinkMark extends Mark {
207
204
  this._baseInstanceExt.drawArraysInstancedBaseInstanceWEBGL(
208
205
  gl.TRIANGLE_STRIP,
209
206
  0,
210
- arcVertexCount,
207
+ /** @type {Float32Array} */ (
208
+ this.markUniformInfo.uniforms.uSegmentBreaks
209
+ )[0] * 2,
211
210
  count,
212
211
  offset
213
212
  );
@@ -229,7 +228,9 @@ export default class LinkMark extends Mark {
229
228
  attribInfo.divisor
230
229
  ) {
231
230
  attribInfo.offset =
232
- offset * this.arrays[attribute].numComponents * 4; // gl.FLOAT in bytes
231
+ offset *
232
+ this.arrays[attribute].numComponents *
233
+ this.bytesPerElement.get(attribute);
233
234
  }
234
235
  }
235
236
  setBuffersAndAttributes(
@@ -241,20 +242,11 @@ export default class LinkMark extends Mark {
241
242
  gl.drawArraysInstanced(
242
243
  gl.TRIANGLE_STRIP,
243
244
  0,
244
- arcVertexCount,
245
+ /** @type {Float32Array} */ (
246
+ this.markUniformInfo.uniforms.uSegmentBreaks
247
+ )[0] * 2,
245
248
  count
246
249
  );
247
250
  }, options);
248
251
  }
249
252
  }
250
-
251
- function createStrip(/** @type number */ segments) {
252
- let i = 0;
253
- const coords = [];
254
-
255
- for (; i <= segments; i++) {
256
- coords.push(i / segments, 0.5);
257
- coords.push(i / segments, -0.5);
258
- }
259
- return new Float32Array(coords);
260
- }
@@ -1,2 +1,2 @@
1
- const shader = "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 = "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;}vec2 strip=vec2(float(gl_VertexID/2)/float(uSegmentBreaks),float(gl_VertexID % 2)-0.5);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;
@@ -29,6 +29,15 @@ export default class Mark {
29
29
  protected bufferInfo: import("twgl.js").BufferInfo & {
30
30
  allocatedVertices?: number;
31
31
  };
32
+ /**
33
+ * TWGL's BufferInfo doesn't contain the number of bytes per element,
34
+ * so we need to keep track of it separately. This is mainly used by
35
+ * the instancing hack in the link mark.
36
+ *
37
+ * @type {Map<string, number>}
38
+ * @protected
39
+ */
40
+ protected bytesPerElement: Map<string, number>;
32
41
  /**
33
42
  * @type {import("twgl.js").ProgramInfo}
34
43
  * @protected
@@ -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,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"}
1
+ {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":"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"}
@@ -91,6 +91,16 @@ export default class Mark {
91
91
  */
92
92
  this.bufferInfo = undefined;
93
93
 
94
+ /**
95
+ * TWGL's BufferInfo doesn't contain the number of bytes per element,
96
+ * so we need to keep track of it separately. This is mainly used by
97
+ * the instancing hack in the link mark.
98
+ *
99
+ * @type {Map<string, number>}
100
+ * @protected
101
+ */
102
+ this.bytesPerElement = new Map();
103
+
94
104
  /**
95
105
  * @type {import("twgl.js").ProgramInfo}
96
106
  * @protected
@@ -788,6 +798,15 @@ export default class Mark {
788
798
  { numElements: vertexData.vertexCount }
789
799
  );
790
800
  this.bufferInfo.allocatedVertices = vertexData.allocatedVertices;
801
+
802
+ for (const [attribute, attributeData] of Object.entries(
803
+ vertexData.arrays
804
+ )) {
805
+ this.bytesPerElement.set(
806
+ attribute,
807
+ attributeData.data.BYTES_PER_ELEMENT
808
+ );
809
+ }
791
810
  }
792
811
  }
793
812
 
@@ -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,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();}";
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();}";
2
2
  export default shader;
@@ -349,7 +349,7 @@ export interface LinkProps extends SecondaryPositionProps {
349
349
  *
350
350
  * **Default value:* `101`
351
351
  */
352
- segments?: number;
352
+ segments?: number | ExprRef;
353
353
 
354
354
  /**
355
355
  * Scaling factor for the `"arc`" shape's height. The default value `1.0` produces roughly circular arcs.
@@ -6,13 +6,14 @@
6
6
  * Read more at: https://www.gamedeveloper.com/programming/improved-lerp-smoothing-
7
7
  *
8
8
  * @param {import("../utils/animator.js").default} animator
9
- * @param {(value: number) => void} callback Function to be called with the interpolated value
9
+ * @param {(value: T) => void} callback Function to be called with the interpolated value
10
10
  * @param {number} halfLife Time until half of the value is reached, in milliseconds
11
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) & { stop: () => void}} Function that activates the transition with a new target value
12
+ * @param {T} initialValue Initial value
13
+ * @returns {((target: T) => void) & { stop: () => void}} Function that activates the transition with a new target value
14
+ * @template {Record<string, number>} T
14
15
  */
15
- export function makeLerpSmoother(animator: import("../utils/animator.js").default, callback: (value: number) => void, halfLife: number, stopAt: number, initialValue?: number): ((target: number) => void) & {
16
+ export function makeLerpSmoother<T extends Record<string, number>>(animator: import("../utils/animator.js").default, callback: (value: T) => void, halfLife: number, stopAt: number, initialValue: T): ((target: T) => void) & {
16
17
  stop: () => void;
17
18
  };
18
19
  export default class Animator {
@@ -1 +1 @@
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,aACM,MAAM,KAAK,IAAI;UAAY,MAAM,IAAI;EA0D3D;AAxJD;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"}
1
+ {"version":3,"file":"animator.d.ts","sourceRoot":"","sources":["../../../src/utils/animator.js"],"names":[],"mappings":"AAoFA;;;;;;;;;;;;;;GAcG;AACH,6EARW,OAAO,sBAAsB,EAAE,OAAO,0BACxB,IAAI,YAClB,MAAM,UACN,MAAM,oCAEY,IAAI;UAAY,MAAM,IAAI;EAgFtD;AA9KD;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"}
@@ -90,25 +90,39 @@ export default class Animator {
90
90
  * Read more at: https://www.gamedeveloper.com/programming/improved-lerp-smoothing-
91
91
  *
92
92
  * @param {import("../utils/animator.js").default} animator
93
- * @param {(value: number) => void} callback Function to be called with the interpolated value
93
+ * @param {(value: T) => void} callback Function to be called with the interpolated value
94
94
  * @param {number} halfLife Time until half of the value is reached, in milliseconds
95
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) & { stop: () => void}} Function that activates the transition with a new target value
96
+ * @param {T} initialValue Initial value
97
+ * @returns {((target: T) => void) & { stop: () => void}} Function that activates the transition with a new target value
98
+ * @template {Record<string, number>} T
98
99
  */
99
100
  export function makeLerpSmoother(
100
101
  animator,
101
102
  callback,
102
103
  halfLife,
103
104
  stopAt,
104
- initialValue = 0
105
+ initialValue
105
106
  ) {
106
107
  let lastTimeStamp = 0;
107
108
  let settled = true;
108
109
 
109
- let current = initialValue;
110
+ let current = structuredClone(initialValue);
110
111
  let target = current;
111
112
 
113
+ /**
114
+ * Smoother for a scalar.
115
+ * Based on: https://twitter.com/FreyaHolmer/status/1757836988495847568
116
+ *
117
+ * @param {number} current
118
+ * @param {number} target
119
+ * @param {number} tD
120
+ * @param {number} halfLife
121
+ */
122
+ function lerpSmooth(current, target, tD, halfLife) {
123
+ return target + (current - target) * Math.pow(2, -tD / halfLife);
124
+ }
125
+
112
126
  /**
113
127
  * @param {number} [timestamp]
114
128
  */
@@ -120,12 +134,20 @@ export function makeLerpSmoother(
120
134
  const tD = timestamp - lastTimeStamp;
121
135
  lastTimeStamp = timestamp;
122
136
 
123
- // Lerp smoothing: https://twitter.com/FreyaHolmer/status/1757836988495847568
124
- current = target + (current - target) * Math.pow(2, -tD / halfLife);
137
+ for (const key of /** @type {(keyof T)[]} */ (Object.keys(target))) {
138
+ current[key] = /** @type {T[keyof T]}*/ (
139
+ lerpSmooth(current[key], target[key], tD, halfLife)
140
+ );
141
+ }
125
142
 
126
143
  callback(current);
127
144
 
128
- if (Math.abs(target - current) < stopAt) {
145
+ let maxDiff = -Infinity;
146
+ for (const key of Object.keys(target)) {
147
+ maxDiff = Math.max(maxDiff, Math.abs(target[key] - current[key]));
148
+ }
149
+
150
+ if (maxDiff < stopAt) {
129
151
  current = target;
130
152
  callback(current);
131
153
  settled = true;
@@ -136,7 +158,7 @@ export function makeLerpSmoother(
136
158
  }
137
159
 
138
160
  /**
139
- * @param {number} value
161
+ * @param {T} value
140
162
  */
141
163
  function setTarget(value) {
142
164
  target = value;
@@ -19,7 +19,9 @@ export default class Inertia {
19
19
  callback: (arg0: number) => void;
20
20
  targetValue: number;
21
21
  lastValue: number;
22
- smoother: ((target: number) => void) & {
22
+ smoother: ((target: {
23
+ x: number;
24
+ }) => void) & {
23
25
  stop: () => void;
24
26
  };
25
27
  cancel(): void;
@@ -1 +1 @@
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;;MASC;IAGL,eAIC;IAED;;;;OAIG;IACH,mBAHW,MAAM,mBACG,MAAM,KAAE,IAAI,QAkB/B;CACJ"}
1
+ {"version":3,"file":"inertia.d.ts","sourceRoot":"","sources":["../../../src/utils/inertia.js"],"names":[],"mappings":"AAoEA;;;GAGG;AACH,8EAiBC;AArFD;;GAEG;AACH;IACI;;;OAGG;IACH,sBAHW,OAAO,eAAe,EAAE,OAAO,aAC/B,OAAO,EA0BjB;IAvBG,0CAAwB;IACxB,kBAA0B;IAG1B,oBAAsB;IAEtB,oCAAoC;IACpC,iBADoB,MAAM,KAAE,IAAI,CACZ;IAEpB,oBAAoB;IACpB,kBAAkB;IAElB;;;;MAUC;IAGL,eAIC;IAED;;;;OAIG;IACH,mBAHW,MAAM,mBACG,MAAM,KAAE,IAAI,QAkB/B;CACJ"}
@@ -26,19 +26,20 @@ export default class Inertia {
26
26
  this.smoother = makeLerpSmoother(
27
27
  animator,
28
28
  (value) => {
29
- const delta = value - this.lastValue;
30
- this.lastValue = value;
29
+ const delta = value.x - this.lastValue;
30
+ this.lastValue = value.x;
31
31
  this.callback?.(delta);
32
32
  },
33
33
  40,
34
- 0.1
34
+ 0.1,
35
+ { x: 0 }
35
36
  );
36
37
  }
37
38
 
38
39
  cancel() {
39
40
  // decelelerate rapidly
40
41
  this.targetValue = lerp([this.lastValue, this.targetValue], 0.3);
41
- this.smoother(this.targetValue);
42
+ this.smoother({ x: this.targetValue });
42
43
  }
43
44
 
44
45
  /**
@@ -61,7 +62,7 @@ export default class Inertia {
61
62
  );
62
63
  this.targetValue = this.lastValue + delta;
63
64
 
64
- this.smoother(this.targetValue);
65
+ this.smoother({ x: this.targetValue });
65
66
  }
66
67
  }
67
68
 
@@ -122,7 +122,9 @@ declare class Scrollbar extends UnitView {
122
122
  scrollbarSize: number;
123
123
  scrollbarPadding: number;
124
124
  };
125
- interpolateViewportOffset: ((target: number) => void) & {
125
+ interpolateViewportOffset: ((target: {
126
+ x: number;
127
+ }) => void) & {
126
128
  stop: () => void;
127
129
  };
128
130
  get scrollOffset(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAswBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA53BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;IA2OD;;;;OAIG;IAEH,gBALW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QA6O1D;;CAoGJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAlrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAqrC5C;IAeI;;;OAGG;IACH,uBAHW,SAAS,8CA4FnB;IA/FD,uBAAmB;IAsCf;;;MAAoB;IAIpB;;MAQC;IA+CL,2BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;;CACJ;oBAv2CmB,qBAAqB"}
1
+ {"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAswBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA53BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;IA2OD;;;;OAIG;IAEH,gBALW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QA6O1D;;CAoGJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAlrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAqrC5C;IAeI;;;OAGG;IACH,uBAHW,SAAS,8CA6FnB;IAhGD,uBAAmB;IAsCf;;;MAAoB;IAIpB;;;;MAQC;IAgDL,2BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;;CACJ;oBAx2CmB,qBAAqB"}
@@ -1273,11 +1273,11 @@ class Scrollbar extends UnitView {
1273
1273
  this.interpolateViewportOffset = makeLerpSmoother(
1274
1274
  this.context.animator,
1275
1275
  (value) => {
1276
- this.viewportOffset = value;
1276
+ this.viewportOffset = value.x;
1277
1277
  },
1278
1278
  50,
1279
1279
  0.4,
1280
- this.viewportOffset
1280
+ { x: this.viewportOffset }
1281
1281
  );
1282
1282
 
1283
1283
  this.addInteractionEventListener("mousedown", (coords, event) => {
@@ -1309,10 +1309,11 @@ class Scrollbar extends UnitView {
1309
1309
  this.#maxScrollOffset
1310
1310
  );
1311
1311
 
1312
- this.interpolateViewportOffset(
1313
- (scrollOffset / this.#maxScrollOffset) *
1314
- this.#maxViewportOffset
1315
- );
1312
+ this.interpolateViewportOffset({
1313
+ x:
1314
+ (scrollOffset / this.#maxScrollOffset) *
1315
+ this.#maxViewportOffset,
1316
+ });
1316
1317
  };
1317
1318
 
1318
1319
  const onMouseup = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../../src/view/zoom.js"],"names":[],"mappings":"AAkBA,0CAGC;AAgBD;;;;;;GAMG;AACH,yCANW,OAAO,8BAA8B,EAAE,OAAO,UAC9C,OAAO,uBAAuB,EAAE,OAAO,0BAC3B,SAAS,KAAK,IAAI,UAC9B,OAAO,yBAAyB,EAAE,KAAK,aACvC,OAAO,sBAAsB,EAAE,OAAO,QA0IhD;;OAlLS,MAAM;OACN,MAAM;YACN,MAAM;YACN,MAAM;YACN,MAAM"}
1
+ {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../../src/view/zoom.js"],"names":[],"mappings":"AAkBA,0CAGC;AAgBD;;;;;;GAMG;AACH,yCANW,OAAO,8BAA8B,EAAE,OAAO,UAC9C,OAAO,uBAAuB,EAAE,OAAO,0BAC3B,SAAS,KAAK,IAAI,UAC9B,OAAO,yBAAyB,EAAE,KAAK,aACvC,OAAO,sBAAsB,EAAE,OAAO,QAkJhD;;OA1LS,MAAM;OACN,MAAM;YACN,MAAM;YACN,MAAM;YACN,MAAM"}
@@ -46,15 +46,21 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
46
46
  handleZoom = recordTimeStamp(handleZoom);
47
47
 
48
48
  if (event.type == "wheel") {
49
+ // TODO: Wheel-zoom inertia should probably be moved here and the faked wheel
50
+ // events in genomeSpy.js and inertia.js should be retired.
51
+
49
52
  event.uiEvent.preventDefault(); // TODO: Only if there was something zoomable
50
53
 
51
54
  const wheelEvent = /** @type {WheelEvent} */ (event.uiEvent);
52
55
  const wheelMultiplier = wheelEvent.deltaMode ? 120 : 1;
53
56
 
54
- if (wheelEvent.deltaX === 0 && wheelEvent.deltaY === 0) {
57
+ if (!wheelEvent.deltaX && !wheelEvent.deltaY) {
55
58
  return;
56
59
  }
57
60
 
61
+ // Stop drag-to-pan inertia
62
+ smoother?.stop();
63
+
58
64
  let { x, y } = event.point;
59
65
 
60
66
  // Snapping to the hovered item:
@@ -63,9 +69,6 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
63
69
  // This allows the user to rapidly zoom closer without having to
64
70
  // continuously adjust the cursor position.
65
71
 
66
- // Stop drag-to-pan inertia
67
- smoother?.stop();
68
-
69
72
  if (hover) {
70
73
  const e = hover.mark.encoders;
71
74
  if (e.x && !e.x2 && !e.x.constantValue) {
@@ -102,7 +105,7 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
102
105
  }
103
106
 
104
107
  /** @type {RingBuffer<{point: Point, timestamp: number}>} */
105
- const buffer = new RingBuffer(30);
108
+ const eventBuffer = new RingBuffer(30);
106
109
 
107
110
  const mouseEvent = /** @type {MouseEvent} */ (event.uiEvent);
108
111
  mouseEvent.preventDefault();
@@ -113,7 +116,7 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
113
116
  moveEvent
114
117
  ) => {
115
118
  const point = Point.fromMouseEvent(moveEvent);
116
- buffer.push({ point, timestamp: performance.now() });
119
+ eventBuffer.push({ point, timestamp: performance.now() });
117
120
 
118
121
  const delta = point.subtract(prevPoint);
119
122
 
@@ -132,7 +135,7 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
132
135
  const lastMillisToInclude = 160;
133
136
 
134
137
  const now = performance.now();
135
- const arr = buffer
138
+ const arr = eventBuffer
136
139
  .get()
137
140
  .filter((p) => now - p.timestamp < lastMillisToInclude);
138
141
 
@@ -148,25 +151,30 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
148
151
  .multiply(1 / (a.timestamp - b.timestamp));
149
152
 
150
153
  let x = prevPoint.x;
154
+ let y = prevPoint.y;
151
155
 
152
156
  smoother = makeLerpSmoother(
153
157
  animator,
154
- (a) => {
158
+ (p) => {
155
159
  handleZoom({
156
- x: a,
157
- y: prevPoint.y,
158
- xDelta: x - a,
159
- yDelta: 0,
160
+ x: p.x,
161
+ y: p.y,
162
+ xDelta: x - p.x,
163
+ yDelta: y - p.y,
160
164
  zDelta: 0,
161
165
  });
162
- x = a;
166
+ x = p.x;
167
+ y = p.y;
163
168
  },
164
169
  150,
165
170
  0.5,
166
- x
171
+ { x, y }
167
172
  );
168
173
 
169
- smoother(prevPoint.x - v.x * 250);
174
+ smoother({
175
+ x: prevPoint.x - v.x * 250,
176
+ y: prevPoint.y - v.y * 250,
177
+ });
170
178
  };
171
179
 
172
180
  const onMouseup = () => {
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "contributors": [],
9
9
  "license": "MIT",
10
- "version": "0.48.0",
10
+ "version": "0.48.1",
11
11
  "jsdelivr": "dist/bundle/index.js",
12
12
  "unpkg": "dist/bundle/index.js",
13
13
  "browser": "dist/bundle/index.js",
@@ -64,5 +64,5 @@
64
64
  "vega-scale": "^7.3.1",
65
65
  "vega-util": "^1.17.2"
66
66
  },
67
- "gitHead": "64cd3335607b2608db3c85c74a4fb571302e77d0"
67
+ "gitHead": "f2e023ce43cf18091cb81140f5be1f59887271df"
68
68
  }