@genome-spy/core 0.14.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/index.js +224 -0
- package/dist/style.css +1 -0
- package/package.json +54 -0
- package/src/data/collector.js +178 -0
- package/src/data/collector.test.js +82 -0
- package/src/data/dataFlow.js +109 -0
- package/src/data/dataFlow.test.js +3 -0
- package/src/data/facetNode.js +17 -0
- package/src/data/flow.test.js +71 -0
- package/src/data/flowBatch.d.ts +40 -0
- package/src/data/flowNode.js +283 -0
- package/src/data/flowNode.test.js +49 -0
- package/src/data/flowOptimizer.js +117 -0
- package/src/data/flowOptimizer.test.js +192 -0
- package/src/data/flowTestUtils.js +63 -0
- package/src/data/formats/fasta.js +32 -0
- package/src/data/formats/fasta.test.js +26 -0
- package/src/data/sources/dataSource.js +22 -0
- package/src/data/sources/dataSourceFactory.js +24 -0
- package/src/data/sources/dataUtils.js +31 -0
- package/src/data/sources/dynamicCallbackSource.js +56 -0
- package/src/data/sources/dynamicSource.js +36 -0
- package/src/data/sources/inlineSource.js +69 -0
- package/src/data/sources/inlineSource.test.js +55 -0
- package/src/data/sources/namedSource.js +74 -0
- package/src/data/sources/sequenceSource.js +46 -0
- package/src/data/sources/sequenceSource.test.js +45 -0
- package/src/data/sources/urlSource.js +74 -0
- package/src/data/transforms/aggregate.js +69 -0
- package/src/data/transforms/clone.js +40 -0
- package/src/data/transforms/clone.test.js +10 -0
- package/src/data/transforms/coverage.js +187 -0
- package/src/data/transforms/coverage.test.js +122 -0
- package/src/data/transforms/filter.js +37 -0
- package/src/data/transforms/filter.test.js +17 -0
- package/src/data/transforms/filterScoredLabels.js +134 -0
- package/src/data/transforms/flattenCompressedExons.js +57 -0
- package/src/data/transforms/flattenDelimited.js +68 -0
- package/src/data/transforms/flattenDelimited.test.js +86 -0
- package/src/data/transforms/flattenSequence.js +39 -0
- package/src/data/transforms/flattenSequence.test.js +33 -0
- package/src/data/transforms/formula.js +39 -0
- package/src/data/transforms/formula.test.js +18 -0
- package/src/data/transforms/identifier.js +108 -0
- package/src/data/transforms/identifier.test.js +82 -0
- package/src/data/transforms/linearizeGenomicCoordinate.js +101 -0
- package/src/data/transforms/measureText.js +44 -0
- package/src/data/transforms/pileup.js +128 -0
- package/src/data/transforms/pileup.test.js +69 -0
- package/src/data/transforms/project.js +41 -0
- package/src/data/transforms/project.test.js +31 -0
- package/src/data/transforms/regexExtract.js +61 -0
- package/src/data/transforms/regexExtract.test.js +66 -0
- package/src/data/transforms/regexFold.js +141 -0
- package/src/data/transforms/regexFold.test.js +159 -0
- package/src/data/transforms/sample.js +101 -0
- package/src/data/transforms/sample.test.js +37 -0
- package/src/data/transforms/stack.js +137 -0
- package/src/data/transforms/stack.test.js +90 -0
- package/src/data/transforms/transformFactory.js +60 -0
- package/src/encoder/accessor.js +82 -0
- package/src/encoder/accessor.test.js +46 -0
- package/src/encoder/encoder.js +369 -0
- package/src/encoder/encoder.test.js +97 -0
- package/src/fonts/Lato-Regular.json +1267 -0
- package/src/fonts/Lato-Regular.png +0 -0
- package/src/fonts/OFL.txt +93 -0
- package/src/fonts/README.md +3 -0
- package/src/fonts/bmFont.d.ts +58 -0
- package/src/fonts/bmFontManager.js +357 -0
- package/src/fonts/bmFontMetrics.js +108 -0
- package/src/genome/genome.js +305 -0
- package/src/genome/genome.test.js +152 -0
- package/src/genome/genomeStore.js +54 -0
- package/src/genome/locusFormat.js +31 -0
- package/src/genome/scaleIndex.js +199 -0
- package/src/genome/scaleIndex.test.js +61 -0
- package/src/genome/scaleLocus.js +112 -0
- package/src/genome/scaleLocus.test.js +3 -0
- package/src/genomeSpy.js +753 -0
- package/src/gl/arrayBuilder.js +199 -0
- package/src/gl/dataToVertices.js +621 -0
- package/src/gl/includes/common.glsl +63 -0
- package/src/gl/includes/fp64-arithmetic.glsl +187 -0
- package/src/gl/includes/fp64-utils.js +132 -0
- package/src/gl/includes/picking.fragment.glsl +3 -0
- package/src/gl/includes/picking.vertex.glsl +29 -0
- package/src/gl/includes/sampleFacet.glsl +107 -0
- package/src/gl/includes/scales.glsl +79 -0
- package/src/gl/includes/scales_fp64.glsl +30 -0
- package/src/gl/link.fragment.glsl +18 -0
- package/src/gl/link.vertex.glsl +111 -0
- package/src/gl/point.fragment.glsl +123 -0
- package/src/gl/point.vertex.glsl +128 -0
- package/src/gl/rect.fragment.glsl +51 -0
- package/src/gl/rect.vertex.glsl +114 -0
- package/src/gl/rule.fragment.glsl +52 -0
- package/src/gl/rule.vertex.glsl +89 -0
- package/src/gl/text.fragment.glsl +31 -0
- package/src/gl/text.vertex.glsl +246 -0
- package/src/gl/webGLHelper.js +490 -0
- package/src/img/bowtie.svg +1 -0
- package/src/img/genomespy-favicon.svg +34 -0
- package/src/index.html +11 -0
- package/src/index.js +151 -0
- package/src/marks/link.js +189 -0
- package/src/marks/mark.js +867 -0
- package/src/marks/markUtils.js +109 -0
- package/src/marks/pointMark.js +279 -0
- package/src/marks/rectMark.js +236 -0
- package/src/marks/rule.js +231 -0
- package/src/marks/text.js +274 -0
- package/src/options.d.ts +9 -0
- package/src/scale/colorUtils.js +184 -0
- package/src/scale/glslScaleGenerator.js +462 -0
- package/src/scale/scale.js +441 -0
- package/src/scale/scale.test.js +323 -0
- package/src/scale/ticks.js +198 -0
- package/src/scale/ticks.test.js +39 -0
- package/src/singlePageApp.js +13 -0
- package/src/spec/axis.d.ts +296 -0
- package/src/spec/channel.d.ts +127 -0
- package/src/spec/data.d.ts +185 -0
- package/src/spec/font.d.ts +15 -0
- package/src/spec/genome.d.ts +35 -0
- package/src/spec/mark.d.ts +432 -0
- package/src/spec/root.d.ts +22 -0
- package/src/spec/scale.d.ts +265 -0
- package/src/spec/tooltip.d.ts +9 -0
- package/src/spec/transform.d.ts +479 -0
- package/src/spec/view.d.ts +215 -0
- package/src/styles/genome-spy.scss +153 -0
- package/src/tooltip/dataTooltipHandler.js +59 -0
- package/src/tooltip/refseqGeneTooltipHandler.js +77 -0
- package/src/tooltip/tooltipHandler.ts +12 -0
- package/src/types/filetypes.d.ts +4 -0
- package/src/types/flatqueue.d.ts +53 -0
- package/src/types/glsl.d.ts +4 -0
- package/src/types/object.d.ts +21 -0
- package/src/types/vega-scale.d.ts +60 -0
- package/src/utils/animator.js +83 -0
- package/src/utils/arrayUtils.js +55 -0
- package/src/utils/binnedRangeIndex.js +83 -0
- package/src/utils/clamp.js +8 -0
- package/src/utils/cloner.js +32 -0
- package/src/utils/cloner.test.js +23 -0
- package/src/utils/coalesce.js +11 -0
- package/src/utils/coalesce.test.js +15 -0
- package/src/utils/concatIterables.js +26 -0
- package/src/utils/concatIterables.test.js +7 -0
- package/src/utils/debounce.js +37 -0
- package/src/utils/domainArray.js +224 -0
- package/src/utils/domainArray.test.js +129 -0
- package/src/utils/eerp.js +13 -0
- package/src/utils/expression.js +32 -0
- package/src/utils/field.js +28 -0
- package/src/utils/fisheye.js +60 -0
- package/src/utils/formatObject.js +31 -0
- package/src/utils/html.js +23 -0
- package/src/utils/html.test.js +13 -0
- package/src/utils/indexer.js +43 -0
- package/src/utils/indexer.test.js +46 -0
- package/src/utils/inertia.js +124 -0
- package/src/utils/interactionEvent.js +33 -0
- package/src/utils/iterateNestedMaps.js +21 -0
- package/src/utils/iterateNestedMaps.test.js +32 -0
- package/src/utils/kWayMerge.js +42 -0
- package/src/utils/kWayMerge.test.js +25 -0
- package/src/utils/layout/flexLayout.js +336 -0
- package/src/utils/layout/flexLayout.test.js +296 -0
- package/src/utils/layout/padding.js +107 -0
- package/src/utils/layout/point.js +23 -0
- package/src/utils/layout/rectangle.js +282 -0
- package/src/utils/layout/rectangle.test.js +171 -0
- package/src/utils/mergeObjects.js +99 -0
- package/src/utils/mergeObjects.test.js +41 -0
- package/src/utils/numberExtractor.js +24 -0
- package/src/utils/numberExtractor.test.js +5 -0
- package/src/utils/point.js +14 -0
- package/src/utils/propertyCacher.js +70 -0
- package/src/utils/propertyCacher.test.js +84 -0
- package/src/utils/propertyCoalescer.js +37 -0
- package/src/utils/propertyCoalescer.test.js +21 -0
- package/src/utils/reservationMap.js +103 -0
- package/src/utils/reservationMap.test.js +19 -0
- package/src/utils/scaleNull.js +19 -0
- package/src/utils/setOperations.js +75 -0
- package/src/utils/smoothstep.js +10 -0
- package/src/utils/throttle.js +34 -0
- package/src/utils/topK.js +76 -0
- package/src/utils/topK.test.js +63 -0
- package/src/utils/transition.js +74 -0
- package/src/utils/ui/tooltip.js +189 -0
- package/src/utils/url.js +22 -0
- package/src/utils/variableTools.js +24 -0
- package/src/utils/variableTools.test.js +12 -0
- package/src/view/axisResolution.js +135 -0
- package/src/view/axisResolution.test.js +200 -0
- package/src/view/axisView.js +746 -0
- package/src/view/channel.js +5 -0
- package/src/view/concatView.js +296 -0
- package/src/view/containerView.js +141 -0
- package/src/view/decoratorView.js +510 -0
- package/src/view/facetView.js +488 -0
- package/src/view/flowBuilder.js +362 -0
- package/src/view/flowBuilder.test.js +124 -0
- package/src/view/importView.js +19 -0
- package/src/view/layerView.js +60 -0
- package/src/view/rendering.d.ts +44 -0
- package/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
- package/src/view/renderingContext/deferredViewRenderingContext.js +174 -0
- package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
- package/src/view/renderingContext/simpleViewRenderingContext.js +62 -0
- package/src/view/renderingContext/svgViewRenderingContext.js +121 -0
- package/src/view/renderingContext/viewRenderingContext.js +41 -0
- package/src/view/scaleResolution.js +756 -0
- package/src/view/scaleResolution.test.js +571 -0
- package/src/view/scaleResolutionApi.d.ts +40 -0
- package/src/view/testUtils.js +48 -0
- package/src/view/unitView.js +368 -0
- package/src/view/view.js +589 -0
- package/src/view/view.test.js +213 -0
- package/src/view/viewContext.d.ts +57 -0
- package/src/view/viewFactory.js +179 -0
- package/src/view/viewFactory.test.js +16 -0
- package/src/view/viewUtils.js +420 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const lowp vec4 white = vec4(1.0);
|
|
2
|
+
const lowp vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
|
|
3
|
+
|
|
4
|
+
uniform bool uInwardStroke;
|
|
5
|
+
uniform float uGradientStrength;
|
|
6
|
+
|
|
7
|
+
flat in float vRadius;
|
|
8
|
+
flat in float vRadiusWithPadding;
|
|
9
|
+
|
|
10
|
+
flat in lowp vec4 vFillColor;
|
|
11
|
+
flat in lowp vec4 vStrokeColor;
|
|
12
|
+
flat in lowp float vShape;
|
|
13
|
+
flat in lowp float vHalfStrokeWidth;
|
|
14
|
+
|
|
15
|
+
flat in mat2 vRotationMatrix;
|
|
16
|
+
|
|
17
|
+
out lowp vec4 fragColor;
|
|
18
|
+
|
|
19
|
+
const float CIRCLE = 0.0;
|
|
20
|
+
const float SQUARE = 1.0;
|
|
21
|
+
const float TRIANGLE_UP = 2.0;
|
|
22
|
+
const float CROSS = 3.0;
|
|
23
|
+
const float DIAMOND = 4.0;
|
|
24
|
+
const float TRIANGLE_DOWN = 5.0;
|
|
25
|
+
const float TRIANGLE_RIGHT = 6.0;
|
|
26
|
+
const float TRIANGLE_LEFT = 7.0;
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
// The distance functions are inspired by:
|
|
30
|
+
// http://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
|
|
31
|
+
// However, these are not true distance functions, because the corners need to be sharp.
|
|
32
|
+
|
|
33
|
+
float circle(vec2 p, float r) {
|
|
34
|
+
return length(p) - r;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
float square(vec2 p, float r) {
|
|
38
|
+
p = abs(p);
|
|
39
|
+
return max(p.x, p.y) - r;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
float equilateralTriangle(vec2 p, float r, bool flip, bool swap) {
|
|
43
|
+
if (swap) {
|
|
44
|
+
p.xy = p.yx;
|
|
45
|
+
}
|
|
46
|
+
if (flip) {
|
|
47
|
+
p.y = -p.y;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
float k = sqrt(3.0);
|
|
51
|
+
float kr = k * r;
|
|
52
|
+
//p.y -= kr * 2.0 / 3.0;
|
|
53
|
+
p.y -= kr / 2.0;
|
|
54
|
+
return max((abs(p.x) * k + p.y) / 2.0, -p.y - kr);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
float crossShape(vec2 p, float r) {
|
|
58
|
+
p = abs(p);
|
|
59
|
+
|
|
60
|
+
vec2 b = vec2(0.4, 1.0) * r;
|
|
61
|
+
vec2 v = abs(p) - b.xy;
|
|
62
|
+
vec2 h = abs(p) - b.yx;
|
|
63
|
+
return min(max(v.x, v.y), max(h.x, h.y));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
float diamond(vec2 p, float r) {
|
|
67
|
+
p = abs(p);
|
|
68
|
+
return (max(abs(p.x - p.y), abs(p.x + p.y)) - r) / sqrt(2.0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void main() {
|
|
72
|
+
float d;
|
|
73
|
+
|
|
74
|
+
/** Normalized point coord */
|
|
75
|
+
vec2 p = vRotationMatrix * (2.0 * gl_PointCoord - 1.0) * vRadiusWithPadding;
|
|
76
|
+
float r = vRadius;
|
|
77
|
+
|
|
78
|
+
// We could also use textures here. Could even be faster, because we have plenty of branching here.
|
|
79
|
+
if (vShape == CIRCLE) {
|
|
80
|
+
d = circle(p, r);
|
|
81
|
+
|
|
82
|
+
} else if (vShape == SQUARE) {
|
|
83
|
+
d = square(p, r);
|
|
84
|
+
|
|
85
|
+
} else if (vShape == TRIANGLE_UP) {
|
|
86
|
+
d = equilateralTriangle(p, r, true, false);
|
|
87
|
+
|
|
88
|
+
} else if (vShape == CROSS) {
|
|
89
|
+
d = crossShape(p, r);
|
|
90
|
+
|
|
91
|
+
} else if (vShape == DIAMOND) {
|
|
92
|
+
d = diamond(p, r);
|
|
93
|
+
|
|
94
|
+
} else if (vShape == TRIANGLE_DOWN) {
|
|
95
|
+
d = equilateralTriangle(p, r, false, false);
|
|
96
|
+
|
|
97
|
+
} else if (vShape == TRIANGLE_RIGHT) {
|
|
98
|
+
d = equilateralTriangle(p, r, false, true);
|
|
99
|
+
|
|
100
|
+
} else if (vShape == TRIANGLE_LEFT) {
|
|
101
|
+
d = equilateralTriangle(p, r, true, true);
|
|
102
|
+
|
|
103
|
+
} else {
|
|
104
|
+
d = 0.0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!uPickingEnabled) {
|
|
108
|
+
lowp vec4 fillColor = mix(vFillColor, white, -d * uGradientStrength / vRadius);
|
|
109
|
+
|
|
110
|
+
fragColor = distanceToColor(
|
|
111
|
+
d + (uInwardStroke ? vHalfStrokeWidth : 0.0),
|
|
112
|
+
fillColor,
|
|
113
|
+
vStrokeColor,
|
|
114
|
+
vHalfStrokeWidth);
|
|
115
|
+
|
|
116
|
+
} else if (d - vHalfStrokeWidth <= 0.0) {
|
|
117
|
+
fragColor = vPickingColor;
|
|
118
|
+
|
|
119
|
+
} else {
|
|
120
|
+
discard;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
precision mediump float;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The stroke should only grow inwards, e.g, the diameter/outline is not affected by the stroke width.
|
|
5
|
+
* Thus, a point that has a zero size has no visible stroke. This allows strokes to be used with
|
|
6
|
+
* geometric zoom, etc.
|
|
7
|
+
*/
|
|
8
|
+
uniform bool uInwardStroke;
|
|
9
|
+
|
|
10
|
+
/** Maximum size of the largest point as the fraction of the height of the (faceted) view */
|
|
11
|
+
uniform lowp float uMaxRelativePointDiameter;
|
|
12
|
+
|
|
13
|
+
/** Scale factor for geometric zoom */
|
|
14
|
+
uniform float uScaleFactor;
|
|
15
|
+
|
|
16
|
+
/** The size of the largest point in the data */
|
|
17
|
+
uniform float uMaxPointSize;
|
|
18
|
+
|
|
19
|
+
uniform float uZoomLevel;
|
|
20
|
+
uniform float uSemanticThreshold;
|
|
21
|
+
|
|
22
|
+
flat out float vRadius;
|
|
23
|
+
flat out float vRadiusWithPadding;
|
|
24
|
+
flat out lowp vec4 vFillColor;
|
|
25
|
+
flat out lowp vec4 vStrokeColor;
|
|
26
|
+
flat out lowp float vShape;
|
|
27
|
+
flat out lowp float vHalfStrokeWidth;
|
|
28
|
+
flat out mat2 vRotationMatrix;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
float computeSemanticThresholdFactor() {
|
|
32
|
+
// TODO: add smooth transition
|
|
33
|
+
return getScaled_semanticScore() >= uSemanticThreshold ? 1.0 : 0.0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Computes a scaling factor for the points in a sample-faceted view.
|
|
38
|
+
*/
|
|
39
|
+
float getDownscaleFactor(vec2 pos) {
|
|
40
|
+
if (!isFacetedSamples()) {
|
|
41
|
+
return 1.0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
float sampleFacetHeight = getSampleFacetHeight(pos);
|
|
45
|
+
float maxPointDiameter = sqrt(uMaxPointSize);
|
|
46
|
+
|
|
47
|
+
float factor = sampleFacetHeight *
|
|
48
|
+
uViewportSize.y *
|
|
49
|
+
uMaxRelativePointDiameter;
|
|
50
|
+
|
|
51
|
+
return clamp(0.0, maxPointDiameter, factor) / maxPointDiameter;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// TODO: Move this into common.glsl or something
|
|
55
|
+
vec2 getDxDy() {
|
|
56
|
+
#if defined(dx_DEFINED) || defined(dy_DEFINED)
|
|
57
|
+
return vec2(getScaled_dx(), getScaled_dy()) / uViewportSize;
|
|
58
|
+
#else
|
|
59
|
+
return vec2(0.0, 0.0);
|
|
60
|
+
#endif
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void main(void) {
|
|
64
|
+
|
|
65
|
+
float semanticThresholdFactor = computeSemanticThresholdFactor();
|
|
66
|
+
if (semanticThresholdFactor <= 0.0) {
|
|
67
|
+
gl_PointSize = 0.0;
|
|
68
|
+
// Exit early. MAY prevent some unnecessary calculations.
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
float size = getScaled_size();
|
|
73
|
+
vec2 pos = vec2(getScaled_x(), getScaled_y()) + getDxDy();
|
|
74
|
+
|
|
75
|
+
gl_Position = unitToNdc(applySampleFacet(pos));
|
|
76
|
+
|
|
77
|
+
float strokeWidth = getScaled_strokeWidth();
|
|
78
|
+
|
|
79
|
+
float diameter = sqrt(size) *
|
|
80
|
+
uScaleFactor *
|
|
81
|
+
semanticThresholdFactor *
|
|
82
|
+
getDownscaleFactor(pos);
|
|
83
|
+
|
|
84
|
+
// Clamp minimum size and adjust opacity instead. Yields more pleasing result,
|
|
85
|
+
// no flickering etc.
|
|
86
|
+
float opacity = uViewOpacity;
|
|
87
|
+
if (strokeWidth <= 0.0 || uInwardStroke) {
|
|
88
|
+
float minDiameter = 1.0 / uDevicePixelRatio;
|
|
89
|
+
if (diameter < minDiameter) {
|
|
90
|
+
// We do some "cheap" gamma correction here. It breaks on dark background, though.
|
|
91
|
+
// First we take a square of the size and then apply "gamma" of 1.5.
|
|
92
|
+
opacity *= pow(diameter / minDiameter, 2.5);
|
|
93
|
+
diameter = minDiameter;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
float fillOpa = getScaled_fillOpacity() * opacity;
|
|
98
|
+
float strokeOpa = getScaled_strokeOpacity() * opacity;
|
|
99
|
+
|
|
100
|
+
vShape = getScaled_shape();
|
|
101
|
+
|
|
102
|
+
// Circle doesn't have sharp corners. Do some special optimizations to minimize the point size.
|
|
103
|
+
bool circle = vShape == 0.0;
|
|
104
|
+
|
|
105
|
+
float angleInDegrees = getScaled_angle();
|
|
106
|
+
float angle = -angleInDegrees * PI / 180.0;
|
|
107
|
+
float sinTheta = sin(angle);
|
|
108
|
+
float cosTheta = cos(angle);
|
|
109
|
+
vRotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta);
|
|
110
|
+
float roomForRotation = circle ? 1.0 : sin(mod(angle, PI / 2.0) + PI / 4.0) / sin(PI / 4.0);
|
|
111
|
+
|
|
112
|
+
float aaPadding = 1.0 / uDevicePixelRatio;
|
|
113
|
+
float rotationPadding = (diameter * roomForRotation) - diameter;
|
|
114
|
+
// sqrt(3.0) ensures that the angles of equilateral triangles have enough room
|
|
115
|
+
float strokePadding = uInwardStroke ? 0.0 : strokeWidth * (circle ? 1.0 : sqrt(3.0));
|
|
116
|
+
float padding = rotationPadding + strokePadding + aaPadding;
|
|
117
|
+
gl_PointSize = (diameter + padding) * uDevicePixelRatio;
|
|
118
|
+
|
|
119
|
+
vRadius = diameter / 2.0;
|
|
120
|
+
vRadiusWithPadding = vRadius + padding / 2.0;
|
|
121
|
+
|
|
122
|
+
vHalfStrokeWidth = strokeWidth / 2.0;
|
|
123
|
+
|
|
124
|
+
vFillColor = vec4(getScaled_fill() * fillOpa, fillOpa);
|
|
125
|
+
vStrokeColor = vec4(getScaled_stroke() * strokeOpa, strokeOpa);
|
|
126
|
+
|
|
127
|
+
setupPicking();
|
|
128
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#if defined(ROUNDED_CORNERS) || defined(STROKED)
|
|
2
|
+
in vec2 vPosInPixels;
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
flat in vec2 vHalfSizeInPixels;
|
|
6
|
+
|
|
7
|
+
flat in lowp vec4 vFillColor;
|
|
8
|
+
flat in lowp vec4 vStrokeColor;
|
|
9
|
+
flat in float vHalfStrokeWidth;
|
|
10
|
+
flat in vec4 vCornerRadii;
|
|
11
|
+
|
|
12
|
+
out lowp vec4 fragColor;
|
|
13
|
+
|
|
14
|
+
// Source: https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
|
|
15
|
+
float sdRoundedBox(vec2 p, vec2 b, vec4 r) {
|
|
16
|
+
r.xy = p.x > 0.0 ? r.xy : r.zw;
|
|
17
|
+
r.x = p.y > 0.0 ? r.x : r.y;
|
|
18
|
+
vec2 q = abs(p) - b + r.x;
|
|
19
|
+
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r.x;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Not a true SDF. Makes the corners of strokes sharp and is faster.
|
|
23
|
+
float sdSharpBox(vec2 p, vec2 b) {
|
|
24
|
+
vec2 q = abs(p) - b;
|
|
25
|
+
return max(q.x, q.y);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
void main(void) {
|
|
29
|
+
|
|
30
|
+
#if defined(ROUNDED_CORNERS) || defined(STROKED)
|
|
31
|
+
#ifdef ROUNDED_CORNERS
|
|
32
|
+
// Distance from rectangle's edge in pixels. Negative inside the rectangle.
|
|
33
|
+
float d = sdRoundedBox(vPosInPixels, vHalfSizeInPixels, vCornerRadii);
|
|
34
|
+
#else
|
|
35
|
+
float d = sdSharpBox(vPosInPixels, vHalfSizeInPixels);
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
fragColor = distanceToColor(d, vFillColor, vStrokeColor, vHalfStrokeWidth);
|
|
39
|
+
|
|
40
|
+
if (fragColor.a == 0.0) {
|
|
41
|
+
discard;
|
|
42
|
+
}
|
|
43
|
+
#else
|
|
44
|
+
// The trivial, non-decorated case
|
|
45
|
+
fragColor = vFillColor;
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
if (uPickingEnabled) {
|
|
49
|
+
fragColor = vPickingColor;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vertex position wrt the rectangle specified by (x, x2, y, y2).
|
|
3
|
+
* [0, 0] = [x, y], [1, 1] = [x2, y2].
|
|
4
|
+
* The x or y component may contain fractional values if the rectangle
|
|
5
|
+
* have been tessellated.
|
|
6
|
+
*/
|
|
7
|
+
in vec2 frac;
|
|
8
|
+
|
|
9
|
+
/** Minimum size (width, height) of the displayed rectangle in pixels */
|
|
10
|
+
uniform vec2 uMinSize;
|
|
11
|
+
|
|
12
|
+
/** Minimum opacity for the size size clamping */
|
|
13
|
+
uniform float uMinOpacity;
|
|
14
|
+
|
|
15
|
+
/** top-right, bottom-right, top-left, bottom-left */
|
|
16
|
+
uniform vec4 uCornerRadii;
|
|
17
|
+
|
|
18
|
+
flat out lowp vec4 vFillColor;
|
|
19
|
+
flat out lowp vec4 vStrokeColor;
|
|
20
|
+
flat out float vHalfStrokeWidth;
|
|
21
|
+
flat out vec4 vCornerRadii;
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
#if defined(ROUNDED_CORNERS) || defined(STROKED)
|
|
25
|
+
/** Position for SDF-strokes */
|
|
26
|
+
out vec2 vPosInPixels;
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
/** Size of the rect in pixels */
|
|
30
|
+
flat out vec2 vHalfSizeInPixels;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Clamps the minimumSize and returns an opacity that reflects the amount of clamping.
|
|
34
|
+
*/
|
|
35
|
+
float clampMinSize(inout float pos, float frac, float size, float minSize) {
|
|
36
|
+
if (minSize > 0.0 && abs(size) < minSize) {
|
|
37
|
+
pos += (frac - 0.5) * (minSize * sign(size) - size);
|
|
38
|
+
return abs(size) / minSize;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return 1.0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void sort(inout float a, inout float b) {
|
|
45
|
+
if (a > b) {
|
|
46
|
+
float tmp = b;
|
|
47
|
+
b = a;
|
|
48
|
+
a = tmp;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void main(void) {
|
|
53
|
+
vec2 normalizedMinSize = uMinSize / uViewportSize;
|
|
54
|
+
|
|
55
|
+
float x = getScaled_x();
|
|
56
|
+
float x2 = getScaled_x2();
|
|
57
|
+
float y = getScaled_y();
|
|
58
|
+
float y2 = getScaled_y2();
|
|
59
|
+
|
|
60
|
+
sort(x, x2);
|
|
61
|
+
sort(y, y2);
|
|
62
|
+
|
|
63
|
+
// Clamp x to prevent precision artifacts when the scale is zoomed very close.
|
|
64
|
+
// TODO: clamp y as well
|
|
65
|
+
float clampMargin = 1.0;
|
|
66
|
+
vec2 pos1 = vec2(clamp(x, 0.0 - clampMargin, 1.0 + clampMargin), y);
|
|
67
|
+
vec2 pos2 = vec2(clamp(x2, 0.0 - clampMargin, 1.0 + clampMargin), y2);
|
|
68
|
+
|
|
69
|
+
vec2 size = pos2 - pos1;
|
|
70
|
+
|
|
71
|
+
if (size.x <= 0.0 || size.y <= 0.0) {
|
|
72
|
+
// Early exit. May increase performance or not...
|
|
73
|
+
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
vec2 pos = pos1 + frac * size;
|
|
78
|
+
|
|
79
|
+
size.y *= getSampleFacetHeight(pos);
|
|
80
|
+
|
|
81
|
+
// Clamp to minimum size, optionally compensate with opacity
|
|
82
|
+
float opaFactor = uViewOpacity * max(uMinOpacity,
|
|
83
|
+
clampMinSize(pos.x, frac.x, size.x, normalizedMinSize.x) *
|
|
84
|
+
clampMinSize(pos.y, frac.y, size.y, normalizedMinSize.y));
|
|
85
|
+
|
|
86
|
+
pos = applySampleFacet(pos);
|
|
87
|
+
|
|
88
|
+
#if defined(ROUNDED_CORNERS) || defined(STROKED)
|
|
89
|
+
// Add an extra pixel to stroke width to accommodate edge antialiasing
|
|
90
|
+
float aaPadding = 1.0 / uDevicePixelRatio;
|
|
91
|
+
float strokeWidth = getScaled_strokeWidth();
|
|
92
|
+
float strokeOpacity = getScaled_strokeOpacity() * opaFactor;
|
|
93
|
+
|
|
94
|
+
vec2 centeredFrac = frac - 0.5;
|
|
95
|
+
vec2 expand = centeredFrac * (strokeWidth + aaPadding) / uViewportSize;
|
|
96
|
+
pos += expand;
|
|
97
|
+
|
|
98
|
+
vec2 sizeInPixels = size * uViewportSize;
|
|
99
|
+
vPosInPixels = (centeredFrac + expand / size) * sizeInPixels;
|
|
100
|
+
|
|
101
|
+
vHalfSizeInPixels = sizeInPixels / 2.0;
|
|
102
|
+
|
|
103
|
+
vCornerRadii = min(uCornerRadii, min(vHalfSizeInPixels.x, vHalfSizeInPixels.y));
|
|
104
|
+
vHalfStrokeWidth = strokeWidth / 2.0;
|
|
105
|
+
vStrokeColor = vec4(getScaled_stroke() * strokeOpacity, strokeOpacity);
|
|
106
|
+
#endif
|
|
107
|
+
|
|
108
|
+
gl_Position = unitToNdc(pos);
|
|
109
|
+
|
|
110
|
+
float fillOpacity = getScaled_fillOpacity() * opaFactor;
|
|
111
|
+
vFillColor = vec4(getScaled_fill() * fillOpacity, fillOpacity);
|
|
112
|
+
|
|
113
|
+
setupPicking();
|
|
114
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Line ending
|
|
2
|
+
const int BUTT = 0;
|
|
3
|
+
const int SQUARE = 1;
|
|
4
|
+
const int ROUND = 2;
|
|
5
|
+
|
|
6
|
+
uniform sampler2D uDashTexture;
|
|
7
|
+
uniform float uDashTextureSize;
|
|
8
|
+
uniform float uStrokeDashOffset;
|
|
9
|
+
uniform lowp int uStrokeCap;
|
|
10
|
+
|
|
11
|
+
flat in vec4 vColor;
|
|
12
|
+
flat in float vSize;
|
|
13
|
+
|
|
14
|
+
/** Position on the rule along its length in pixels */
|
|
15
|
+
in vec2 vPosInPixels;
|
|
16
|
+
in float vNormalLengthInPixels;
|
|
17
|
+
|
|
18
|
+
out lowp vec4 fragColor;
|
|
19
|
+
|
|
20
|
+
void main(void) {
|
|
21
|
+
float dpr = uDevicePixelRatio;
|
|
22
|
+
|
|
23
|
+
float distanceFromEnd = -min(vPosInPixels[0], vPosInPixels[1]);
|
|
24
|
+
float distance; // from the rule centerline or end
|
|
25
|
+
if (distanceFromEnd > 0.0 && uStrokeCap == ROUND) {
|
|
26
|
+
// round cap
|
|
27
|
+
distance = length(vec2(distanceFromEnd, vNormalLengthInPixels));
|
|
28
|
+
} else {
|
|
29
|
+
distance = abs(vNormalLengthInPixels);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Use a signed distance field to implement edge antialiasing
|
|
33
|
+
float opacity = clamp(((vSize / 2.0 - distance) * dpr), -0.5, 0.5) + 0.5;
|
|
34
|
+
|
|
35
|
+
if (uDashTextureSize > 0.0) {
|
|
36
|
+
float pos = (vPosInPixels[0] + uStrokeDashOffset) * dpr;
|
|
37
|
+
float floored = floor(pos);
|
|
38
|
+
vec2 texelPositions = (floored + vec2(0.5, 1.5)) / dpr / uDashTextureSize;
|
|
39
|
+
|
|
40
|
+
// Do antialiasing
|
|
41
|
+
opacity *= mix(
|
|
42
|
+
texture(uDashTexture, vec2(texelPositions[0], 0)).r,
|
|
43
|
+
texture(uDashTexture, vec2(texelPositions[1], 0)).r,
|
|
44
|
+
clamp((pos - floored), 0.0, 1.0));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fragColor = vColor * opacity;
|
|
48
|
+
|
|
49
|
+
if (uPickingEnabled) {
|
|
50
|
+
fragColor = vPickingColor;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Line caps
|
|
2
|
+
const int BUTT = 0;
|
|
3
|
+
const int SQUARE = 1;
|
|
4
|
+
const int ROUND = 2;
|
|
5
|
+
|
|
6
|
+
/** Position along the rule */
|
|
7
|
+
in float pos;
|
|
8
|
+
|
|
9
|
+
/** Which side of the stroke: -0.5 or 0.5 */
|
|
10
|
+
in float side;
|
|
11
|
+
|
|
12
|
+
/** Minimum rule length in pixels */
|
|
13
|
+
uniform float uMinLength;
|
|
14
|
+
|
|
15
|
+
uniform float uDashTextureSize;
|
|
16
|
+
uniform lowp int uStrokeCap;
|
|
17
|
+
|
|
18
|
+
flat out vec4 vColor;
|
|
19
|
+
|
|
20
|
+
/** Stroke width */
|
|
21
|
+
flat out float vSize;
|
|
22
|
+
|
|
23
|
+
/** The distance from the line center to the direction of normal in pixels */
|
|
24
|
+
out float vNormalLengthInPixels;
|
|
25
|
+
|
|
26
|
+
/** Distances from the line endings. Used for rendering the round caps and dashes */
|
|
27
|
+
out highp vec2 vPosInPixels;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
void main(void) {
|
|
31
|
+
float pixelSize = 1.0 / uDevicePixelRatio;
|
|
32
|
+
|
|
33
|
+
// Stroke width in pixels
|
|
34
|
+
float size = getScaled_size();
|
|
35
|
+
float opacity = getScaled_opacity() * uViewOpacity;
|
|
36
|
+
|
|
37
|
+
// Avoid artifacts in very thin lines by clamping the size and adjusting opacity respectively
|
|
38
|
+
if (size < pixelSize) {
|
|
39
|
+
opacity *= size / pixelSize;
|
|
40
|
+
size = pixelSize;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
vec2 a = applySampleFacet(vec2(getScaled_x(), getScaled_y()));
|
|
44
|
+
vec2 b = applySampleFacet(vec2(getScaled_x2(), getScaled_y2()));
|
|
45
|
+
|
|
46
|
+
vec2 tangent = b - a;
|
|
47
|
+
|
|
48
|
+
float offset = 0.0;
|
|
49
|
+
float relativeDiff = 0.0;
|
|
50
|
+
if (uMinLength > 0.0 || uStrokeCap != BUTT) {
|
|
51
|
+
float len = length(tangent * uViewportSize);
|
|
52
|
+
|
|
53
|
+
// Elongate to reach the minimum length.
|
|
54
|
+
// The length difference in pixels
|
|
55
|
+
float diff = max(0.0, uMinLength - len);
|
|
56
|
+
|
|
57
|
+
// Add line caps
|
|
58
|
+
if (uStrokeCap != BUTT) {
|
|
59
|
+
diff += size;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
relativeDiff = diff / len;
|
|
63
|
+
offset = relativeDiff * (pos - 0.5);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Apply caps and minimum length by spreading the vertices along the tangent
|
|
67
|
+
vec2 p = pos < 1.0
|
|
68
|
+
? a + tangent * (pos + offset)
|
|
69
|
+
: b + tangent * offset;
|
|
70
|
+
|
|
71
|
+
// Add an extra pixel to stroke width to accommodate edge antialiasing
|
|
72
|
+
float aaPadding = pixelSize;
|
|
73
|
+
|
|
74
|
+
// Extrude
|
|
75
|
+
vec2 normal = normalize(vec2(-tangent.y, tangent.x) / uViewportSize);
|
|
76
|
+
p += normal * side * (size + aaPadding) / uViewportSize;
|
|
77
|
+
|
|
78
|
+
gl_Position = unitToNdc(p);
|
|
79
|
+
|
|
80
|
+
vColor = vec4(getScaled_color() * opacity, opacity);
|
|
81
|
+
vSize = size;
|
|
82
|
+
vNormalLengthInPixels = side * (size + aaPadding);
|
|
83
|
+
|
|
84
|
+
// TODO: Here's a precision problem that breaks round caps when zoomed in enough
|
|
85
|
+
vPosInPixels = vec2(pos, (1.0 - pos)) * (1.0 + relativeDiff) * length(tangent * uViewportSize) -
|
|
86
|
+
vec2(uStrokeCap != BUTT ? size / 2.0 : 0.0);
|
|
87
|
+
|
|
88
|
+
setupPicking();
|
|
89
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
uniform sampler2D uTexture;
|
|
2
|
+
|
|
3
|
+
in vec2 vTexCoord;
|
|
4
|
+
in float vEdgeFadeOpacity;
|
|
5
|
+
flat in vec4 vColor;
|
|
6
|
+
flat in float vSlope;
|
|
7
|
+
|
|
8
|
+
out lowp vec4 fragColor;
|
|
9
|
+
|
|
10
|
+
float median(float r, float g, float b) {
|
|
11
|
+
return max(min(r, g), min(max(r, g), b));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
void main() {
|
|
15
|
+
// TODO: Really small text should fall back to normal (non-SDF) texture that can be mip-mapped.
|
|
16
|
+
// Currently small text has severe aliasing artifacts.
|
|
17
|
+
|
|
18
|
+
vec3 c = texture(uTexture, vTexCoord).rgb;
|
|
19
|
+
|
|
20
|
+
float sigDist = 1.0 - median(c.r, c.g, c.b);
|
|
21
|
+
float opa = clamp((sigDist - 0.5) * vSlope + 0.5, 0.0, 1.0);
|
|
22
|
+
|
|
23
|
+
// Raise to the power of 2.2 to do some cheap gamma correction
|
|
24
|
+
opa *= pow(clamp(vEdgeFadeOpacity, 0.0, 1.0), 2.2);
|
|
25
|
+
|
|
26
|
+
fragColor = vColor * opa;
|
|
27
|
+
|
|
28
|
+
if (uPickingEnabled) {
|
|
29
|
+
fragColor = vPickingColor;
|
|
30
|
+
}
|
|
31
|
+
}
|