@genome-spy/core 0.38.0 → 0.39.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/schema.json CHANGED
@@ -2457,6 +2457,10 @@
2457
2457
  "description": "The rotation angle in degrees.\n\n**Default value:** `0`",
2458
2458
  "type": "number"
2459
2459
  },
2460
+ "arcHeightFactor": {
2461
+ "description": "Scaling factor for the `\"arc`\" shape's height. The default value `1.0` produces roughly circular arcs.\n\n**Default value:** `1.0`",
2462
+ "type": "number"
2463
+ },
2460
2464
  "baseline": {
2461
2465
  "$ref": "#/definitions/Baseline",
2462
2466
  "description": "The vertical alignment of the text. One of `\"top\"`, `\"middle\"`, `\"bottom\"`.\n\n**Default value:** `\"bottom\"`"
@@ -2465,6 +2469,10 @@
2465
2469
  "description": "Builds and index for efficient rendering of subsets of the data. The data must be sorted by the x coordinate.\n\nTODO: This should be enabled automatically if the data are sorted.",
2466
2470
  "type": "boolean"
2467
2471
  },
2472
+ "clampApex": {
2473
+ "description": "Whether the apex of the `\"dome\"` shape is clamped to the viewport edge. When over a half of the dome is located outside the viewport, clamping allows for more accurate reading of the value encoded by the apex' position.\n\n**Default value:** `false`",
2474
+ "type": "boolean"
2475
+ },
2468
2476
  "clip": {
2469
2477
  "anyOf": [
2470
2478
  {
@@ -2480,10 +2488,6 @@
2480
2488
  "color": {
2481
2489
  "type": "string"
2482
2490
  },
2483
- "color2": {
2484
- "description": "TODO",
2485
- "type": "string"
2486
- },
2487
2491
  "cornerRadius": {
2488
2492
  "description": "Radius of the rounded corners.\n\n**Default value:** `0`",
2489
2493
  "type": "number"
@@ -2560,10 +2564,24 @@
2560
2564
  "description": "Should the stroke only grow inwards, e.g, the diameter/outline is not affected by the stroke width. Thus, a point that has a zero size has no visible stroke. This allows strokes to be used with geometric zoom, etc.\n\n**Default value:** `false`",
2561
2565
  "type": "boolean"
2562
2566
  },
2567
+ "linkShape": {
2568
+ "description": "The shape of the link path. Either `\"arc\"`, `\"diagonal\"`, `\"line\"`, or `\"dome\"`.\n\n**Default value:** `\"arc\"`",
2569
+ "enum": [
2570
+ "arc",
2571
+ "diagonal",
2572
+ "line",
2573
+ "dome"
2574
+ ],
2575
+ "type": "string"
2576
+ },
2563
2577
  "logoLetters": {
2564
2578
  "description": "Stretch letters so that they can be used with [sequence logos](https://en.wikipedia.org/wiki/Sequence_logo), etc...",
2565
2579
  "type": "boolean"
2566
2580
  },
2581
+ "minArcHeight": {
2582
+ "description": "The minimum height of an `\"arc\"` shape. Makes very short links more clearly visible.\n\n**Default value:** `1.5`",
2583
+ "type": "number"
2584
+ },
2567
2585
  "minBufferSize": {
2568
2586
  "description": "Minimum size for WebGL buffers (number of data items). Allows for using `bufferSubData()` to update graphics.\n\nThis property is intended for internal use.",
2569
2587
  "type": "number"
@@ -2580,8 +2598,8 @@
2580
2598
  "description": "Clamps the minimum size-dependent opacity. The property does not affect the `opacity` channel. Valid values are between `0` and `1`.\n\nWhen a rectangle would be smaller than what is specified in `minHeight` and `minWidth`, it is faded out proportionally. Example: a rectangle would be rendered as one pixel wide, but `minWidth` clamps it to five pixels. The rectangle is actually rendered as five pixels wide, but its opacity is multiplied by 0.2. With this setting, you can limit the factor to, for example, 0.5 to keep the rectangles more clearly visible.\n\n**Default value:** `0`",
2581
2599
  "type": "number"
2582
2600
  },
2583
- "minSagittaLength": {
2584
- "description": "Minimum length of the arc's sagitta. Makes very short links more clearly visible.\n\n**Default value:** `1.5`",
2601
+ "minPickingSize": {
2602
+ "description": "The minimum stroke width of the links when pointing with the mouse cursor. Allows making very thin links easier to point at.\n\n**Default value:** `3.0`",
2585
2603
  "type": "number"
2586
2604
  },
2587
2605
  "minWidth": {
@@ -2591,6 +2609,14 @@
2591
2609
  "opacity": {
2592
2610
  "type": "number"
2593
2611
  },
2612
+ "orient": {
2613
+ "description": "The orientation of the link path. Either `\"vertical\"` or `\"horizontal\"`. Only applies to diagonal links.\n\n**Default value:** `\"vertical\"`",
2614
+ "enum": [
2615
+ "vertical",
2616
+ "horizontal"
2617
+ ],
2618
+ "type": "string"
2619
+ },
2594
2620
  "paddingX": {
2595
2621
  "description": "The horizontal padding, in pixels, when the `x2` channel is used for ranged text.\n\n**Default value:** `0`",
2596
2622
  "type": "number"
@@ -2599,10 +2625,6 @@
2599
2625
  "description": "The vertical padding, in pixels, when the `y2` channel is used for ranged text.\n\n**Default value:** `0`",
2600
2626
  "type": "number"
2601
2627
  },
2602
- "sagittaScaleFactor": {
2603
- "description": "Scaling factor of the arc's sagitta. The default value `1.0` produces roughly circular arcs.\n\n**Default value:** `1.0`",
2604
- "type": "number"
2605
- },
2606
2628
  "sampleFacetPadding": {
2607
2629
  "description": "Padding between sample facet's upper/lower edge and the maximum point size. This property controls how tightly points are squeezed when facet's height is smaller than the maximum point size. The unit is a proportion of facet's height. The value must be between `0` and `0.5`. This property has no effect when sample faceting is not used.\n\n**Default value:** `0.1`",
2608
2630
  "type": "number"
@@ -2623,10 +2645,6 @@
2623
2645
  "description": "The font size in pixels.\n\n**Default value:** `11`",
2624
2646
  "type": "number"
2625
2647
  },
2626
- "size2": {
2627
- "description": "TODO",
2628
- "type": "number"
2629
- },
2630
2648
  "squeeze": {
2631
2649
  "description": "If the `squeeze` property is true and secondary positional channels (`x2` and/or `y2`) are used, the text is scaled to fit mark's width and/or height.\n\n**Default value:** `true`",
2632
2650
  "type": "boolean"
@@ -1 +1 @@
1
- {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/encoder/encoder.js"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,6CAJW,OAAO,kBAAkB,EAAE,OAAO,aAClC,OAAO,oBAAoB,EAAE,QAAQ,gGAsC/C;AAED;;;;;;;GAOG;AACH,0CANW,OAAO,oBAAoB,EAAE,UAAU,SACvC,GAAG,0IAyFb;AAED;;;;;GAKG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,4FAKjD;AAED;;;GAGG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,mEAKjD;AAED;;;GAGG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,uDAKjD;AAED;;;GAGG;AACH,kDAHW,OAAO,oBAAoB,EAAE,UAAU,kEAWjD;AAED;;;GAGG;AACH,6CAHW,OAAO,qBAAqB,EAAE,OAAO,WACrC,OAAO,oBAAoB,EAAE,OAAO,klBAS9C;AAED;;;GAGG;AACH,0CAHW,OAAO,oBAAoB,EAAE,UAAU,0DAKjD;AAED;;;GAGG;AACH,sCAHW,OAAO,oBAAoB,EAAE,UAAU,sDAKjD;AAoBD;;;GAGG;AACH,oDAHW,OAAO,oBAAoB,EAAE,OAAO,oEAM9C;AAED;;;GAGG;AACH,6CAHW,OAAO,oBAAoB,EAAE,OAAO,6DAM9C;AAqBD;;;GAGG;AACH,4CAFW,MAAM,WAIhB;AAED;;;;GAIG;AACH,oDAFW,OAAO,oBAAoB,EAAE,OAAO,2DAS9C;AAED;;;;;GAKG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,wCAI9C;AAED;;;;GAIG;AACH,kDAFW,OAAO,oBAAoB,EAAE,OAAO,0CAM9C;AAED;;GAEG;AACH,wCAFW,OAAO,oBAAoB,EAAE,OAAO,WAI9C;AAED;;;;GAIG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,WAI9C;AAED;;;GAGG;AACH,4CAHW,OAAO,oBAAoB,EAAE,OAAO,4DAuB9C;AAED;;;;;GAKG;AACH,0CAHW,OAAO,oBAAoB,EAAE,OAAO,GAClC,GAAG,EAAE,CAkBjB;AAED;;;GAGG;AACH,gDAHW,OAAO,oBAAoB,EAAE,OAAO,UACzB,GAAG,KAAE,MAAM,CAkBhC;AAxLD;;GAEG;AACH,wCAFU,OAAO,oBAAoB,EAAE,wBAAwB,EAAE,CAEb;AAEpD;;GAEG;AACH,0CAFU,OAAO,oBAAoB,EAAE,0BAA0B,EAAE,CAEX;AAExD;;GAEG;AACH,iCAFU,OAAO,oBAAoB,EAAE,iBAAiB,EAAE,CAKxD;AAoBF;;;;GAIG;AACH,gCAFU,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,oBAAoB,EAAE,0BAA0B,CAAC,CAAC,CAKtH;AAEF;;;;GAIG;AACH,8BAFU,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAInG"}
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/encoder/encoder.js"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,6CAJW,OAAO,kBAAkB,EAAE,OAAO,aAClC,OAAO,oBAAoB,EAAE,QAAQ,gGAsC/C;AAED;;;;;;;GAOG;AACH,0CANW,OAAO,oBAAoB,EAAE,UAAU,SACvC,GAAG,0IAyFb;AAED;;;;;GAKG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,4FAKjD;AAED;;;GAGG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,mEAKjD;AAED;;;GAGG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,uDAKjD;AAED;;;GAGG;AACH,kDAHW,OAAO,oBAAoB,EAAE,UAAU,kEAWjD;AAED;;;GAGG;AACH,6CAHW,OAAO,qBAAqB,EAAE,OAAO,WACrC,OAAO,oBAAoB,EAAE,OAAO,klBAS9C;AAED;;;GAGG;AACH,0CAHW,OAAO,oBAAoB,EAAE,UAAU,0DAKjD;AAED;;;GAGG;AACH,sCAHW,OAAO,oBAAoB,EAAE,UAAU,sDAKjD;AAoBD;;;GAGG;AACH,oDAHW,OAAO,oBAAoB,EAAE,OAAO,oEAM9C;AAED;;;GAGG;AACH,6CAHW,OAAO,oBAAoB,EAAE,OAAO,6DAM9C;AAqBD;;;GAGG;AACH,4CAFW,MAAM,WAIhB;AAED;;;;GAIG;AACH,oDAFW,OAAO,oBAAoB,EAAE,OAAO,2DAS9C;AAED;;;;;GAKG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,wCAI9C;AAED;;;;GAIG;AACH,kDAFW,OAAO,oBAAoB,EAAE,OAAO,0CAM9C;AAED;;GAEG;AACH,wCAFW,OAAO,oBAAoB,EAAE,OAAO,WAI9C;AAED;;;;GAIG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,WAI9C;AAED;;;GAGG;AACH,4CAHW,OAAO,oBAAoB,EAAE,OAAO,4DAuB9C;AAED;;;;;GAKG;AACH,0CAHW,OAAO,oBAAoB,EAAE,OAAO,GAClC,GAAG,EAAE,CAsBjB;AAED;;;GAGG;AACH,gDAHW,OAAO,oBAAoB,EAAE,OAAO,UACzB,GAAG,KAAE,MAAM,CAmBhC;AA7LD;;GAEG;AACH,wCAFU,OAAO,oBAAoB,EAAE,wBAAwB,EAAE,CAEb;AAEpD;;GAEG;AACH,0CAFU,OAAO,oBAAoB,EAAE,0BAA0B,EAAE,CAEX;AAExD;;GAEG;AACH,iCAFU,OAAO,oBAAoB,EAAE,iBAAiB,EAAE,CAKxD;AAoBF;;;;GAIG;AACH,gCAFU,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,oBAAoB,EAAE,0BAA0B,CAAC,CAAC,CAKtH;AAEF;;;;GAIG;AACH,8BAFU,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAInG"}
@@ -366,12 +366,16 @@ export function getDiscreteRange(channel) {
366
366
  return [
367
367
  "circle",
368
368
  "square",
369
- "triangle-up",
370
369
  "cross",
371
370
  "diamond",
372
- "triangle-down",
371
+ "triangle-up",
373
372
  "triangle-right",
373
+ "triangle-down",
374
374
  "triangle-left",
375
+ "tick-up",
376
+ "tick-right",
377
+ "tick-down",
378
+ "tick-left",
375
379
  ];
376
380
  default:
377
381
  }
@@ -391,6 +395,7 @@ export function getDiscreteRangeMapper(channel) {
391
395
  );
392
396
 
393
397
  return (value) => {
398
+ // TODO: Memoize previous
394
399
  const mapped = valueMap.get(value);
395
400
  if (mapped !== undefined) {
396
401
  return mapped;
@@ -135,7 +135,7 @@ export class PointVertexBuilder extends GeometryBuilder {
135
135
  numItems?: number;
136
136
  });
137
137
  }
138
- export class ConnectionVertexBuilder extends GeometryBuilder {
138
+ export class LinkVertexBuilder extends GeometryBuilder {
139
139
  /**
140
140
  * @param {object} object
141
141
  * @param {Record<string, Encoder>} object.encoders
@@ -415,7 +415,7 @@ export class PointVertexBuilder extends GeometryBuilder {
415
415
  }
416
416
  }
417
417
 
418
- export class ConnectionVertexBuilder extends GeometryBuilder {
418
+ export class LinkVertexBuilder extends GeometryBuilder {
419
419
  /**
420
420
  * @param {object} object
421
421
  * @param {Record<string, Encoder>} object.encoders
@@ -1,2 +1,2 @@
1
- const shader = "uniform float uSagittaScaleFactor;uniform float uMinSagittaLength;in vec2 strip;out vec4 vColor;out float vSize;out float vNormalLengthInPixels;void main(void){float pixelSize=1.0/uDevicePixelRatio;float opacity=getScaled_opacity()*uViewOpacity;vec2 a=vec2(getScaled_x(),getScaled_y())*uViewportSize;vec2 b=vec2(getScaled_x2(),getScaled_y2())*uViewportSize;vec2 chordVector=b-a;vec2 unitChordVector=normalize(chordVector);vec2 chordNormal=vec2(-unitChordVector.y,unitChordVector.x);float sagitta=max(length(chordVector)/2.0*uSagittaScaleFactor,uMinSagittaLength);bool compress=false;if(compress){float maxSagittaLen=length(chordNormal*uViewportSize);float maxChordLen=length(unitChordVector*uViewportSize);float threshold=maxSagittaLen*0.5;if(sagitta>threshold){float m=(maxSagittaLen-threshold)/(maxChordLen-threshold);sagitta=(sagitta-threshold)*m+threshold;}}vec2 controlOffset=chordNormal*sagitta/0.75;vec2 p1=a;vec2 p2=a+controlOffset;vec2 p3=b+controlOffset;vec2 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);\n#ifdef size2_DEFINED\nfloat mixedSize=mix(getScaled_size(),getScaled_size2(),t);\n#else\nfloat mixedSize=getScaled_size();\n#endif\nif(mixedSize<pixelSize){opacity*=mixedSize/pixelSize;mixedSize=pixelSize;}float paddedSize=mixedSize+pixelSize;vNormalLengthInPixels=strip.y*paddedSize;p+=normal*vNormalLengthInPixels;gl_Position=pixelsToNdc(p);\n#ifdef color2_DEFINED\nvec3 color=mix(getScaled_color(),getScaled_color2(),t);\n#else\nvec3 color=getScaled_color();\n#endif\nvColor=vec4(color*opacity,opacity);vSize=paddedSize;setupPicking();}";
1
+ const shader = "uniform float uArcHeightFactor;uniform float uMinArcHeight;uniform float uMinPickingSize;uniform int uShape;uniform int uOrient;uniform bool uClampApex;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;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 height=max(length(chordVector)/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;p+=normal*vNormalLengthInPixels;gl_Position=pixelsToNdc(p);vec3 color=getScaled_color();vColor=vec4(color*opacity,opacity);vSize=paddedSize;setupPicking();}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "const lowp vec4 white=vec4(1.0);const lowp vec4 black=vec4(0.0,0.0,0.0,1.0);uniform bool uInwardStroke;uniform float uGradientStrength;in float vRadius;in float vRadiusWithPadding;in lowp vec4 vFillColor;in lowp vec4 vStrokeColor;in lowp float vShape;in lowp float vHalfStrokeWidth;in mat2 vRotationMatrix;out lowp vec4 fragColor;const float CIRCLE=0.0;const float SQUARE=1.0;const float TRIANGLE_UP=2.0;const float CROSS=3.0;const float DIAMOND=4.0;const float TRIANGLE_DOWN=5.0;const float TRIANGLE_RIGHT=6.0;const float TRIANGLE_LEFT=7.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 equilateralTriangle(vec2 p,float r,bool flip,bool swap){if(swap){p.xy=p.yx;}if(flip){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==TRIANGLE_UP){d=equilateralTriangle(p,r,true,false);}else if(vShape==CROSS){d=crossShape(p,r);}else if(vShape==DIAMOND){d=diamond(p,r);}else if(vShape==TRIANGLE_DOWN){d=equilateralTriangle(p,r,false,false);}else if(vShape==TRIANGLE_RIGHT){d=equilateralTriangle(p,r,false,true);}else if(vShape==TRIANGLE_LEFT){d=equilateralTriangle(p,r,true,true);}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);uniform bool uInwardStroke;uniform float uGradientStrength;in float vRadius;in float vRadiusWithPadding;in lowp vec4 vFillColor;in lowp vec4 vStrokeColor;in lowp float vShape;in lowp float vHalfStrokeWidth;in mat2 vRotationMatrix;out lowp vec4 fragColor;const float CIRCLE=0.0;const float SQUARE=1.0;const float CROSS=2.0;const float DIAMOND=3.0;const float TRIANGLE_UP=4.0;const float TICK_UP=8.0;float circle(vec2 p,float r){return length(p)-r;}float square(vec2 p,float r){p=abs(p);return max(p.x,p.y)-r;}float tickUp(vec2 p,float r){float halfR=r*0.5;p.y+=halfR;p=abs(p);return max(p.x-r*0.15,p.y-halfR);}float equilateralTriangle(vec2 p,float r){p.y=-p.y;float k=sqrt(3.0);float kr=k*r;p.y-=kr/2.0;return max((abs(p.x)*k+p.y)/2.0,-p.y-kr);}float crossShape(vec2 p,float r){p=abs(p);vec2 b=vec2(0.4,1.0)*r;vec2 v=abs(p)-b.xy;vec2 h=abs(p)-b.yx;return min(max(v.x,v.y),max(h.x,h.y));}float diamond(vec2 p,float r){p=abs(p);return(max(abs(p.x-p.y),abs(p.x+p.y))-r)/sqrt(2.0);}void main(){float d;vec2 p=vRotationMatrix*(2.0*gl_PointCoord-1.0)*vRadiusWithPadding;float r=vRadius;if(vShape==CIRCLE){d=circle(p,r);}else if(vShape==SQUARE){d=square(p,r);}else if(vShape==CROSS){d=crossShape(p,r);}else if(vShape==DIAMOND){d=diamond(p,r);}else if(vShape==TRIANGLE_UP){d=equilateralTriangle(p,r);}else if(vShape==TICK_UP){d=tickUp(p,r);}else{d=0.0;}if(!uPickingEnabled){lowp vec4 fillColor=mix(vFillColor,white,-d*uGradientStrength/vRadius);fragColor=distanceToColor(d+(uInwardStroke ? vHalfStrokeWidth : 0.0),fillColor,vStrokeColor,vHalfStrokeWidth);}else if(d-vHalfStrokeWidth<=0.0){fragColor=vPickingColor;}else{discard;}}";
2
2
  export default shader;
@@ -1,2 +1,2 @@
1
- const shader = "/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform lowp float uMaxRelativePointDiameter;uniform float uScaleFactor;uniform float uMaxPointSize;uniform float uZoomLevel;uniform float uSemanticThreshold;out float vRadius;out float vRadiusWithPadding;out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out lowp float vShape;out lowp float vHalfStrokeWidth;out mat2 vRotationMatrix;float computeSemanticThresholdFactor(){return getScaled_semanticScore()>=uSemanticThreshold ? 1.0 : 0.0;}/***Computes a scaling factor for the points in a sample-faceted view.*/float getDownscaleFactor(vec2 pos){if(!isFacetedSamples()){return 1.0;}float sampleFacetHeight=getSampleFacetHeight(pos);float maxPointDiameter=sqrt(uMaxPointSize);float factor=sampleFacetHeight*uViewportSize.y*uMaxRelativePointDiameter;return clamp(0.0,maxPointDiameter,factor)/maxPointDiameter;}vec2 getDxDy(){\n#if defined(dx_DEFINED) || defined(dy_DEFINED)\nreturn vec2(getScaled_dx(),getScaled_dy())/uViewportSize;\n#else\nreturn vec2(0.0,0.0);\n#endif\n}void main(void){float semanticThresholdFactor=computeSemanticThresholdFactor();if(semanticThresholdFactor<=0.0){gl_PointSize=0.0;gl_Position=vec4(100.0,0.0,0.0,0.0);return;}float size=getScaled_size();vec2 pos=vec2(getScaled_x(),getScaled_y())+getDxDy();gl_Position=unitToNdc(applySampleFacet(pos));float strokeWidth=getScaled_strokeWidth();float diameter=sqrt(size)*uScaleFactor*semanticThresholdFactor*getDownscaleFactor(pos);float opacity=uViewOpacity;if(strokeWidth<=0.0||uInwardStroke){float minDiameter=1.0/uDevicePixelRatio;if(diameter<minDiameter){opacity*=pow(diameter/minDiameter,2.5);diameter=minDiameter;}}float fillOpa=getScaled_fillOpacity()*opacity;float strokeOpa=getScaled_strokeOpacity()*opacity;vShape=getScaled_shape();bool circle=vShape==0.0;float angleInDegrees=getScaled_angle();float angle=-angleInDegrees*PI/180.0;float sinTheta=sin(angle);float cosTheta=cos(angle);vRotationMatrix=mat2(cosTheta,sinTheta,-sinTheta,cosTheta);float roomForRotation=circle ? 1.0 : sin(mod(angle,PI/2.0)+PI/4.0)/sin(PI/4.0);float aaPadding=1.0/uDevicePixelRatio;float rotationPadding=(diameter*roomForRotation)-diameter;float strokePadding=uInwardStroke ? 0.0 : strokeWidth*(circle ? 1.0 : sqrt(3.0));float padding=rotationPadding+strokePadding+aaPadding;gl_PointSize=(diameter+padding)*uDevicePixelRatio;vRadius=diameter/2.0;vRadiusWithPadding=vRadius+padding/2.0;vHalfStrokeWidth=strokeWidth/2.0;vFillColor=vec4(getScaled_fill()*fillOpa,fillOpa);vStrokeColor=vec4(getScaled_stroke()*strokeOpa,strokeOpa);setupPicking();}";
1
+ const shader = "/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform lowp float uMaxRelativePointDiameter;uniform float uScaleFactor;uniform float uMaxPointSize;uniform float uZoomLevel;uniform float uSemanticThreshold;out float vRadius;out float vRadiusWithPadding;out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out lowp float vShape;out lowp float vHalfStrokeWidth;out mat2 vRotationMatrix;const float CIRCLE=0.0;const float SQUARE=1.0;const float CROSS=2.0;const float DIAMOND=3.0;const float TRIANGLE_UP=4.0;const float TRIANGLE_RIGHT=5.0;const float TRIANGLE_DOWN=6.0;const float TRIANGLE_LEFT=7.0;const float TICK_UP=8.0;const float TICK_RIGHT=9.0;const float TICK_DOWN=10.0;const float TICK_LEFT=11.0;float computeSemanticThresholdFactor(){return getScaled_semanticScore()>=uSemanticThreshold ? 1.0 : 0.0;}/***Computes a scaling factor for the points in a sample-faceted view.*/float getDownscaleFactor(vec2 pos){if(!isFacetedSamples()){return 1.0;}float sampleFacetHeight=getSampleFacetHeight(pos);float maxPointDiameter=sqrt(uMaxPointSize);float factor=sampleFacetHeight*uViewportSize.y*uMaxRelativePointDiameter;return clamp(0.0,maxPointDiameter,factor)/maxPointDiameter;}vec2 getDxDy(){\n#if defined(dx_DEFINED) || defined(dy_DEFINED)\nreturn vec2(getScaled_dx(),getScaled_dy())/uViewportSize;\n#else\nreturn vec2(0.0,0.0);\n#endif\n}void main(void){float shapeAngle=0.0;float semanticThresholdFactor=computeSemanticThresholdFactor();if(semanticThresholdFactor<=0.0){gl_PointSize=0.0;gl_Position=vec4(100.0,0.0,0.0,0.0);return;}float size=getScaled_size();vec2 pos=vec2(getScaled_x(),getScaled_y())+getDxDy();gl_Position=unitToNdc(applySampleFacet(pos));float strokeWidth=getScaled_strokeWidth();float diameter=sqrt(size)*uScaleFactor*semanticThresholdFactor*getDownscaleFactor(pos);float opacity=uViewOpacity;if(strokeWidth<=0.0||uInwardStroke){float minDiameter=1.0/uDevicePixelRatio;if(diameter<minDiameter){opacity*=pow(diameter/minDiameter,2.5);diameter=minDiameter;}}float fillOpa=getScaled_fillOpacity()*opacity;float strokeOpa=getScaled_strokeOpacity()*opacity;vShape=getScaled_shape();bool circle=vShape==0.0;if(vShape>TICK_UP&&vShape<=TICK_LEFT){shapeAngle=(vShape-TICK_UP)*90.0;vShape=TICK_UP;}else if(vShape>TRIANGLE_UP&&vShape<=TRIANGLE_LEFT){shapeAngle=(vShape-TRIANGLE_UP)*90.0;vShape=TRIANGLE_UP;}float angleInDegrees=getScaled_angle();float angle=-(shapeAngle+angleInDegrees)*PI/180.0;float sinTheta=sin(angle);float cosTheta=cos(angle);vRotationMatrix=mat2(cosTheta,sinTheta,-sinTheta,cosTheta);float roomForRotation=circle ? 1.0 : sin(mod(angle,PI/2.0)+PI/4.0)/sin(PI/4.0);float aaPadding=1.0/uDevicePixelRatio;float rotationPadding=(diameter*roomForRotation)-diameter;float strokePadding=uInwardStroke ? 0.0 : strokeWidth*(circle ? 1.0 : sqrt(3.0));float padding=rotationPadding+strokePadding+aaPadding;gl_PointSize=(diameter+padding)*uDevicePixelRatio;vRadius=diameter/2.0;vRadiusWithPadding=vRadius+padding/2.0;vHalfStrokeWidth=strokeWidth/2.0;vFillColor=vec4(getScaled_fill()*fillOpa,fillOpa);vStrokeColor=vec4(getScaled_stroke()*strokeOpa,strokeOpa);setupPicking();}";
2
2
  export default shader;
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAOA;IAqGQ;;;;;;MAKC;CAkDR;iBA9JgB,WAAW"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IAsHQ;;;;;;MAKC;CAkDR;iBAnLgB,WAAW"}
@@ -1,9 +1,13 @@
1
1
  import { drawBufferInfo, setBuffersAndAttributes, setUniforms } from "twgl.js";
2
2
  import VERTEX_SHADER from "../gl/link.vertex.glsl.js";
3
3
  import FRAGMENT_SHADER from "../gl/link.fragment.glsl.js";
4
- import { ConnectionVertexBuilder } from "../gl/dataToVertices.js";
4
+ import { LinkVertexBuilder } from "../gl/dataToVertices.js";
5
5
 
6
6
  import Mark from "./mark.js";
7
+ import { isChannelDefWithScale } from "../encoder/encoder.js";
8
+
9
+ const LINK_SHAPES = ["arc", "dome", "diagonal", "line"];
10
+ const ORIENTS = ["vertical", "horizontal"];
7
11
 
8
12
  export default class LinkMark extends Mark {
9
13
  /**
@@ -24,8 +28,13 @@ export default class LinkMark extends Mark {
24
28
  opacity: 1.0,
25
29
 
26
30
  segments: 101, // Performance is affected more by the fill rate, i.e. number of pixels
27
- sagittaScaleFactor: 1.0,
28
- minSagittaLength: 1.5,
31
+ arcHeightFactor: 1.0,
32
+ minArcHeight: 1.5,
33
+ minPickingSize: 3.0,
34
+ clampApex: false,
35
+
36
+ linkShape: "arc",
37
+ orient: "vertical",
29
38
  })
30
39
  );
31
40
  }
@@ -55,12 +64,20 @@ export default class LinkMark extends Mark {
55
64
  * @returns {import("../spec/channel.js").Encoding}
56
65
  */
57
66
  fixEncoding(encoding) {
58
- if (!encoding.x) {
59
- encoding.x2 = encoding.x;
67
+ if (!encoding.x2) {
68
+ if (isChannelDefWithScale(encoding.x)) {
69
+ encoding.x2 = { datum: 0.0 };
70
+ } else {
71
+ encoding.x2 = encoding.x;
72
+ }
60
73
  }
61
74
 
62
75
  if (!encoding.y2) {
63
- encoding.y2 = encoding.y;
76
+ if (isChannelDefWithScale(encoding.y)) {
77
+ encoding.y2 = { datum: 0.0 };
78
+ } else {
79
+ encoding.y2 = encoding.y;
80
+ }
64
81
  }
65
82
 
66
83
  return encoding;
@@ -80,8 +97,12 @@ export default class LinkMark extends Mark {
80
97
 
81
98
  // TODO: Use uniform block.
82
99
  setUniforms(this.programInfo, {
83
- uSagittaScaleFactor: props.sagittaScaleFactor,
84
- uMinSagittaLength: props.minSagittaLength,
100
+ uArcHeightFactor: props.arcHeightFactor,
101
+ uMinArcHeight: props.minArcHeight,
102
+ uMinPickingSize: props.minPickingSize,
103
+ uShape: LINK_SHAPES.indexOf(props.linkShape),
104
+ uOrient: ORIENTS.indexOf(props.orient),
105
+ uClampApex: !!props.clampApex,
85
106
  });
86
107
  }
87
108
 
@@ -89,7 +110,7 @@ export default class LinkMark extends Mark {
89
110
  const collector = this.unitView.getCollector();
90
111
  const itemCount = collector.getItemCount();
91
112
 
92
- const builder = new ConnectionVertexBuilder({
113
+ const builder = new LinkVertexBuilder({
93
114
  encoders: this.encoders,
94
115
  attributes: this.getAttributes(),
95
116
  numItems: itemCount,
@@ -328,6 +328,30 @@ export interface PointProps extends AngleProps {
328
328
  }
329
329
 
330
330
  export interface LinkProps extends SecondaryPositionProps {
331
+ /**
332
+ * The shape of the link path. Either `"arc"`, `"diagonal"`, `"line"`, or `"dome"`.
333
+ *
334
+ * **Default value:** `"arc"`
335
+ */
336
+ linkShape?: "arc" | "diagonal" | "line" | "dome";
337
+
338
+ /**
339
+ * The orientation of the link path. Either `"vertical"` or `"horizontal"`.
340
+ * Only applies to diagonal links.
341
+ *
342
+ * **Default value:** `"vertical"`
343
+ */
344
+ orient?: "vertical" | "horizontal";
345
+
346
+ /**
347
+ * Whether the apex of the `"dome"` shape is clamped to the viewport edge. When over a
348
+ * half of the dome is located outside the viewport, clamping allows for more accurate
349
+ * reading of the value encoded by the apex' position.
350
+ *
351
+ * **Default value:** `false`
352
+ */
353
+ clampApex?: boolean;
354
+
331
355
  /**
332
356
  * The number of segments in the bézier curve. Affects the rendering quality and performance.
333
357
  * Use a higher value for a smoother curve.
@@ -337,28 +361,26 @@ export interface LinkProps extends SecondaryPositionProps {
337
361
  segments?: number;
338
362
 
339
363
  /**
340
- * Scaling factor of the arc's sagitta. The default value `1.0` produces roughly circular arcs.
364
+ * Scaling factor for the `"arc`" shape's height. The default value `1.0` produces roughly circular arcs.
341
365
  *
342
366
  * **Default value:** `1.0`
343
367
  */
344
- sagittaScaleFactor?: number;
368
+ arcHeightFactor?: number;
345
369
 
346
370
  /**
347
- * Minimum length of the arc's sagitta. Makes very short links more clearly visible.
371
+ * The minimum height of an `"arc"` shape. Makes very short links more clearly visible.
348
372
  *
349
373
  * **Default value:** `1.5`
350
374
  */
351
- minSagittaLength?: number;
375
+ minArcHeight?: number;
352
376
 
353
377
  /**
354
- * TODO
355
- */
356
- color2?: string;
357
-
358
- /**
359
- * TODO
378
+ * The minimum stroke width of the links when pointing with the mouse cursor.
379
+ * Allows making very thin links easier to point at.
380
+ *
381
+ * **Default value:** `3.0`
360
382
  */
361
- size2?: number;
383
+ minPickingSize?: number;
362
384
  }
363
385
 
364
386
  // TODO: Mark-specific configs
@@ -93,7 +93,7 @@ export class GridChild {
93
93
  /** @type {Partial<Record<import("../spec/axis.js").AxisOrient, AxisGridView>>} gridLines */
94
94
  gridLines: Partial<Record<import("../spec/axis.js").AxisOrient, AxisGridView>>;
95
95
  /** @type {Partial<Record<ScrollDirection, Scrollbar>>} */
96
- scrollbars: Partial<Record<"horizontal" | "vertical", Scrollbar>>;
96
+ scrollbars: Partial<Record<"vertical" | "horizontal", Scrollbar>>;
97
97
  /** @type {UnitView} */
98
98
  title: UnitView;
99
99
  /** @type {Rectangle} */
@@ -116,12 +116,12 @@ declare class Scrollbar extends UnitView {
116
116
  * @param {GridChild} gridChild
117
117
  * @param {ScrollDirection} scrollDirection
118
118
  */
119
- constructor(gridChild: GridChild, scrollDirection: "horizontal" | "vertical");
119
+ constructor(gridChild: GridChild, scrollDirection: "vertical" | "horizontal");
120
120
  config: {
121
121
  scrollbarSize: number;
122
122
  scrollbarPadding: number;
123
123
  };
124
- scrollDirection: "horizontal" | "vertical";
124
+ scrollDirection: "vertical" | "horizontal";
125
125
  viewportOffset: number;
126
126
  maxScrollOffset: number;
127
127
  scrollbarCoords: Rectangle;
@@ -1 +1 @@
1
- {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/view/scaleResolution.js"],"names":[],"mappings":"AAy0BA;;;;;;;;;;GAUG;AACH,6CAFW,OAAO,WAAW,EAAE,OAAO,GAAG,OAAO,WAAW,EAAE,OAAO,EAAE,QA4BrE;AA/zBD,0CAA2C;AAC3C,gCAAiC;AACjC,gCAAiC;AACjC,4BAA6B;AAC7B,4BAA6B;AAE7B;;;;GAIG;AACH;;;;;;;GAOG;AACH;IAyBI;;OAEG;IACH,2DASC;IARG,8CAAsB;IACtB,oDAAoD;IACpD,SADW,gBAAgB,EAAE,CACZ;IACjB,+DAA+D;IAC/D,MADW,MAAM,CACD;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAGzB;;;;;;;OAOG;IACH,uBAHW,QAAQ,oFAQlB;IAED;;;OAGG;IACH,0BAHW,QAAQ,oFAQlB;IAWD;;;;;;OAMG;IACH,kHA0BC;IAED;;OAEG;IACH,4BAEC;IAED,+BAiBC;IAuBD;;;;;OAKG;IACH,iBAFa,OAAO,kBAAkB,EAAE,KAAK,CA+D5C;IAYD;;;;OAIG;IACH,qEAMC;IAED;;;;OAIG;IACH,+DAQC;IAED;;OAEG;IACH,oBAkCC;IAED;;OAEG;IACH,oDAmBC;IAED,mBAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAOzC;IAED;;;;OAIG;IACH,oBAKC;IAED;;OAEG;IACH,sBAGC;IAUD;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAwEnB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBAgD1B;IAED;;;;OAIG;IACH,qBAcC;IAED;;;;;OAKG;IACH,uBAOC;IA2DD;;;OAGG;IACH,aAFa,OAAO,qBAAqB,EAAE,OAAO,CAajD;IAID;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAKhB;IAED;;;OAGG;IACH,6EAFa,MAAM,CAQlB;IAED;;;OAGG;IACH,mHAFa,MAAM,EAAE,CAOpB;;CA6BJ;wIA3rBY;IAAC,IAAI,EAAE,OAAO,eAAe,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,CAAC,CAAA;CAAC"}
1
+ {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/view/scaleResolution.js"],"names":[],"mappings":"AA20BA;;;;;;;;;;GAUG;AACH,6CAFW,OAAO,WAAW,EAAE,OAAO,GAAG,OAAO,WAAW,EAAE,OAAO,EAAE,QA4BrE;AAl0BD,0CAA2C;AAC3C,gCAAiC;AACjC,gCAAiC;AACjC,4BAA6B;AAC7B,4BAA6B;AAE7B;;;;GAIG;AACH;;;;;;;GAOG;AACH;IAyBI;;OAEG;IACH,2DASC;IARG,8CAAsB;IACtB,oDAAoD;IACpD,SADW,gBAAgB,EAAE,CACZ;IACjB,+DAA+D;IAC/D,MADW,MAAM,CACD;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAGzB;;;;;;;OAOG;IACH,uBAHW,QAAQ,oFAQlB;IAED;;;OAGG;IACH,0BAHW,QAAQ,oFAQlB;IAWD;;;;;;OAMG;IACH,kHA0BC;IAED;;OAEG;IACH,4BAEC;IAED,+BAiBC;IAuBD;;;;;OAKG;IACH,iBAFa,OAAO,kBAAkB,EAAE,KAAK,CA+D5C;IAYD;;;;OAIG;IACH,qEAMC;IAED;;;;OAIG;IACH,+DAQC;IAED;;OAEG;IACH,oBAkCC;IAED;;OAEG;IACH,oDAmBC;IAED,mBAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAOzC;IAED;;;;OAIG;IACH,oBAKC;IAED;;OAEG;IACH,sBAGC;IAUD;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAwEnB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBAgD1B;IAED;;;;OAIG;IACH,qBAcC;IAED;;;;;OAKG;IACH,uBAOC;IA8DD;;;OAGG;IACH,aAFa,OAAO,qBAAqB,EAAE,OAAO,CAajD;IAID;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAKhB;IAED;;;OAGG;IACH,6EAFa,MAAM,CAQlB;IAED;;;OAGG;IACH,mHAFa,MAAM,EAAE,CAOpB;;CA6BJ;wIA9rBY;IAAC,IAAI,EAAE,OAAO,eAAe,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,CAAC,CAAA;CAAC"}
@@ -23,7 +23,6 @@ import createScale, { configureScale } from "../scale/scale.js";
23
23
  import { invalidate, getCachedOrCall } from "../utils/propertyCacher.js";
24
24
  import {
25
25
  getChannelDefWithScale,
26
- getDiscreteRange,
27
26
  isColorChannel,
28
27
  isDiscreteChannel,
29
28
  isPositionalChannel,
@@ -649,7 +648,10 @@ export default class ScaleResolution {
649
648
  : "viridis";
650
649
  } else if (isDiscreteChannel(channel)) {
651
650
  // Shapes of point mark, for example
652
- props.range = getDiscreteRange(channel);
651
+ props.range =
652
+ channel == "shape"
653
+ ? ["circle", "square", "triangle-up", "cross", "diamond"]
654
+ : [];
653
655
  } else if (channel == "size") {
654
656
  props.range = [0, 400]; // TODO: Configurable default. This is currently optimized for points.
655
657
  } else if (channel == "angle") {
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "contributors": [],
9
9
  "license": "MIT",
10
- "version": "0.38.0",
10
+ "version": "0.39.0",
11
11
  "jsdelivr": "dist/bundle/index.js",
12
12
  "unpkg": "dist/bundle/index.js",
13
13
  "browser": "dist/bundle/index.js",
@@ -65,5 +65,5 @@
65
65
  "vega-scale": "^7.1.1",
66
66
  "vega-util": "^1.16.0"
67
67
  },
68
- "gitHead": "cd0ae7c4bc32d3a8937b04baa14af742b0fab889"
68
+ "gitHead": "62718f51e03f665435dd2f3b557e20b42df1410e"
69
69
  }