@genome-spy/core 0.62.2 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/index.es.js +4568 -4301
- package/dist/bundle/index.js +371 -297
- package/dist/schema.json +84 -12
- package/dist/src/genomeSpy.d.ts +11 -0
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +98 -20
- package/dist/src/gl/includes/common.glsl.js +1 -1
- package/dist/src/gl/webGLHelper.d.ts +18 -14
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +65 -64
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/marks/link.fragment.glsl.js +1 -1
- package/dist/src/marks/link.vertex.glsl.js +1 -1
- package/dist/src/marks/mark.d.ts +6 -1
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +10 -16
- package/dist/src/marks/point.fragment.glsl.js +1 -1
- package/dist/src/marks/point.vertex.glsl.js +1 -1
- package/dist/src/marks/rect.fragment.glsl.js +1 -1
- package/dist/src/marks/rect.vertex.glsl.js +1 -1
- package/dist/src/marks/rule.fragment.glsl.js +1 -1
- package/dist/src/marks/rule.vertex.glsl.js +1 -1
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.fragment.glsl.js +1 -1
- package/dist/src/marks/text.js +7 -15
- package/dist/src/marks/text.vertex.glsl.js +1 -1
- package/dist/src/selection/selection.d.ts +5 -0
- package/dist/src/selection/selection.d.ts.map +1 -1
- package/dist/src/selection/selection.js +43 -6
- package/dist/src/selection/selection.test.d.ts +2 -0
- package/dist/src/selection/selection.test.d.ts.map +1 -0
- package/dist/src/selection/selection.test.js +14 -0
- package/dist/src/spec/parameter.d.ts +28 -2
- package/dist/src/styles/{genome-spy.scss → genome-spy.css} +25 -21
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +264 -195
- package/dist/src/styles/update.sh +14 -4
- package/dist/src/types/embedApi.d.ts +16 -0
- package/dist/src/types/viewContext.d.ts +0 -2
- package/dist/src/utils/expression.d.ts +5 -0
- package/dist/src/utils/expression.d.ts.map +1 -1
- package/dist/src/utils/expression.js +37 -0
- package/dist/src/utils/interactionEvent.d.ts +18 -1
- package/dist/src/utils/interactionEvent.d.ts.map +1 -1
- package/dist/src/utils/interactionEvent.js +101 -1
- package/dist/src/utils/interactionEvent.test.d.ts +2 -0
- package/dist/src/utils/interactionEvent.test.d.ts.map +1 -0
- package/dist/src/utils/interactionEvent.test.js +35 -0
- package/dist/src/view/facetView.d.ts +1 -1
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +1 -1
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts +32 -17
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts.map +1 -1
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.js +85 -39
- package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts.map +1 -1
- package/dist/src/view/renderingContext/simpleViewRenderingContext.js +5 -1
- package/dist/src/view/renderingContext/viewRenderingContext.d.ts +1 -0
- package/dist/src/view/renderingContext/viewRenderingContext.d.ts.map +1 -1
- package/dist/src/view/renderingContext/viewRenderingContext.js +4 -0
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +45 -2
- package/package.json +8 -8
package/dist/schema.json
CHANGED
|
@@ -1654,6 +1654,15 @@
|
|
|
1654
1654
|
}
|
|
1655
1655
|
]
|
|
1656
1656
|
},
|
|
1657
|
+
"DomEventType": {
|
|
1658
|
+
"enum": [
|
|
1659
|
+
"click",
|
|
1660
|
+
"dblclick",
|
|
1661
|
+
"mouseover",
|
|
1662
|
+
"pointerover"
|
|
1663
|
+
],
|
|
1664
|
+
"type": "string"
|
|
1665
|
+
},
|
|
1657
1666
|
"DsvDataFormat": {
|
|
1658
1667
|
"additionalProperties": false,
|
|
1659
1668
|
"properties": {
|
|
@@ -2107,6 +2116,23 @@
|
|
|
2107
2116
|
},
|
|
2108
2117
|
"type": "object"
|
|
2109
2118
|
},
|
|
2119
|
+
"EventConfig": {
|
|
2120
|
+
"additionalProperties": false,
|
|
2121
|
+
"properties": {
|
|
2122
|
+
"filter": {
|
|
2123
|
+
"description": "An optional filter expression to further filter events of the specified type. The expression can only refer to the event object as `event`, and should evaluate to a boolean value indicating whether to include the event. No other data or parameters are in scope.",
|
|
2124
|
+
"type": "string"
|
|
2125
|
+
},
|
|
2126
|
+
"type": {
|
|
2127
|
+
"$ref": "#/definitions/DomEventType",
|
|
2128
|
+
"description": "The type of event to listen to. For example, `\"click\"` or `\"mouseover\"`."
|
|
2129
|
+
}
|
|
2130
|
+
},
|
|
2131
|
+
"required": [
|
|
2132
|
+
"type"
|
|
2133
|
+
],
|
|
2134
|
+
"type": "object"
|
|
2135
|
+
},
|
|
2110
2136
|
"ExprDef": {
|
|
2111
2137
|
"additionalProperties": false,
|
|
2112
2138
|
"properties": {
|
|
@@ -3715,6 +3741,23 @@
|
|
|
3715
3741
|
"IntervalSelectionConfig": {
|
|
3716
3742
|
"additionalProperties": false,
|
|
3717
3743
|
"properties": {
|
|
3744
|
+
"clear": {
|
|
3745
|
+
"anyOf": [
|
|
3746
|
+
{
|
|
3747
|
+
"$ref": "#/definitions/DomEventType"
|
|
3748
|
+
},
|
|
3749
|
+
{
|
|
3750
|
+
"$ref": "#/definitions/EventConfig"
|
|
3751
|
+
},
|
|
3752
|
+
{
|
|
3753
|
+
"type": "string"
|
|
3754
|
+
},
|
|
3755
|
+
{
|
|
3756
|
+
"type": "boolean"
|
|
3757
|
+
}
|
|
3758
|
+
],
|
|
3759
|
+
"description": "A string or object that defines the events that should clear the selection.\n\n__Default value:__ `\"dblclick\"`"
|
|
3760
|
+
},
|
|
3718
3761
|
"encodings": {
|
|
3719
3762
|
"description": "An array of encoding channels that define the interval selection.",
|
|
3720
3763
|
"items": {
|
|
@@ -3727,16 +3770,22 @@
|
|
|
3727
3770
|
"description": "Interval selections display a rectangle mark to show the selected range. Use the `mark` property to adjust the appearance of this rectangle."
|
|
3728
3771
|
},
|
|
3729
3772
|
"on": {
|
|
3730
|
-
"
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3773
|
+
"anyOf": [
|
|
3774
|
+
{
|
|
3775
|
+
"$ref": "#/definitions/DomEventType"
|
|
3776
|
+
},
|
|
3777
|
+
{
|
|
3778
|
+
"$ref": "#/definitions/EventConfig"
|
|
3779
|
+
},
|
|
3780
|
+
{
|
|
3781
|
+
"type": "string"
|
|
3782
|
+
}
|
|
3734
3783
|
],
|
|
3735
|
-
"
|
|
3784
|
+
"description": "A string or object that defines the events to which the selection should listen."
|
|
3736
3785
|
},
|
|
3737
3786
|
"type": {
|
|
3738
3787
|
"const": "interval",
|
|
3739
|
-
"description": "
|
|
3788
|
+
"description": "The selection type.\n\n- `\"point\"` -- to select multiple discrete data values; the first value is selected on `click` and additional values toggled on shift-click.\n- `\"interval\"` -- to select a continuous range of data values on `drag`.",
|
|
3740
3789
|
"type": "string"
|
|
3741
3790
|
}
|
|
3742
3791
|
},
|
|
@@ -4978,13 +5027,36 @@
|
|
|
4978
5027
|
"PointSelectionConfig": {
|
|
4979
5028
|
"additionalProperties": false,
|
|
4980
5029
|
"properties": {
|
|
5030
|
+
"clear": {
|
|
5031
|
+
"anyOf": [
|
|
5032
|
+
{
|
|
5033
|
+
"$ref": "#/definitions/DomEventType"
|
|
5034
|
+
},
|
|
5035
|
+
{
|
|
5036
|
+
"$ref": "#/definitions/EventConfig"
|
|
5037
|
+
},
|
|
5038
|
+
{
|
|
5039
|
+
"type": "string"
|
|
5040
|
+
},
|
|
5041
|
+
{
|
|
5042
|
+
"type": "boolean"
|
|
5043
|
+
}
|
|
5044
|
+
],
|
|
5045
|
+
"description": "A string or object that defines the events that should clear the selection.\n\n__Default value:__ `\"dblclick\"`"
|
|
5046
|
+
},
|
|
4981
5047
|
"on": {
|
|
4982
|
-
"
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
5048
|
+
"anyOf": [
|
|
5049
|
+
{
|
|
5050
|
+
"$ref": "#/definitions/DomEventType"
|
|
5051
|
+
},
|
|
5052
|
+
{
|
|
5053
|
+
"$ref": "#/definitions/EventConfig"
|
|
5054
|
+
},
|
|
5055
|
+
{
|
|
5056
|
+
"type": "string"
|
|
5057
|
+
}
|
|
4986
5058
|
],
|
|
4987
|
-
"
|
|
5059
|
+
"description": "A string or object that defines the events to which the selection should listen."
|
|
4988
5060
|
},
|
|
4989
5061
|
"toggle": {
|
|
4990
5062
|
"description": "Controls whether data values should be toggled (inserted or removed from a point selection) when clicking with the shift key pressed.\n\n- `true` -- additional values can be selected by shift-clicking.\n- `false` -- only a single value can be selected at a time.\n\n__Default value:__ `true`",
|
|
@@ -4992,7 +5064,7 @@
|
|
|
4992
5064
|
},
|
|
4993
5065
|
"type": {
|
|
4994
5066
|
"const": "point",
|
|
4995
|
-
"description": "
|
|
5067
|
+
"description": "The selection type.\n\n- `\"point\"` -- to select multiple discrete data values; the first value is selected on `click` and additional values toggled on shift-click.\n- `\"interval\"` -- to select a continuous range of data values on `drag`.",
|
|
4996
5068
|
"type": "string"
|
|
4997
5069
|
}
|
|
4998
5070
|
},
|
package/dist/src/genomeSpy.d.ts
CHANGED
|
@@ -84,6 +84,7 @@ export default class GenomeSpy {
|
|
|
84
84
|
_inputBindingContainer: HTMLElement;
|
|
85
85
|
/** @type {Point} */
|
|
86
86
|
_mouseDownCoords: Point;
|
|
87
|
+
dpr: number;
|
|
87
88
|
/**
|
|
88
89
|
*
|
|
89
90
|
* @param {(name: string) => any[]} provider
|
|
@@ -141,6 +142,16 @@ export default class GenomeSpy {
|
|
|
141
142
|
* @template T
|
|
142
143
|
*/
|
|
143
144
|
updateTooltip<T>(datum: T, converter?: (arg0: T) => Promise<string | HTMLElement | import("lit").TemplateResult>): void;
|
|
145
|
+
/**
|
|
146
|
+
* Returns a PNG data URL of the current canvas.
|
|
147
|
+
*
|
|
148
|
+
* @param {number} [logicalWidth] defaults to canvas width
|
|
149
|
+
* @param {number} [logicalHeight] defaults to canvas height
|
|
150
|
+
* @param {number} [devicePixelRatio] defaults to window.devicePixelRatio
|
|
151
|
+
* @param {string} [clearColor] null for transparent
|
|
152
|
+
* @returns A PNG data Url
|
|
153
|
+
*/
|
|
154
|
+
exportCanvas(logicalWidth?: number, logicalHeight?: number, devicePixelRatio?: number, clearColor?: string): string;
|
|
144
155
|
computeLayout(): void;
|
|
145
156
|
renderAll(): void;
|
|
146
157
|
renderPickingFramebuffer(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"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"}
|
package/dist/src/genomeSpy.js
CHANGED
|
@@ -13,7 +13,10 @@ import {
|
|
|
13
13
|
} from "./view/viewUtils.js";
|
|
14
14
|
import UnitView from "./view/unitView.js";
|
|
15
15
|
|
|
16
|
-
import WebGLHelper
|
|
16
|
+
import WebGLHelper, {
|
|
17
|
+
framebufferToDataUrl,
|
|
18
|
+
readPickingPixel,
|
|
19
|
+
} from "./gl/webGLHelper.js";
|
|
17
20
|
import Rectangle from "./view/layout/rectangle.js";
|
|
18
21
|
import BufferedViewRenderingContext from "./view/renderingContext/bufferedViewRenderingContext.js";
|
|
19
22
|
import CompositeViewRenderingContext from "./view/renderingContext/compositeViewRenderingContext.js";
|
|
@@ -35,6 +38,7 @@ import { VIEW_ROOT_NAME, ViewFactory } from "./view/viewFactory.js";
|
|
|
35
38
|
import { reconfigureScales } from "./view/scaleResolution.js";
|
|
36
39
|
import createBindingInputs from "./utils/inputBinding.js";
|
|
37
40
|
import { isStillZooming } from "./view/zoom.js";
|
|
41
|
+
import { createFramebufferInfo } from "twgl.js";
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
44
|
* Events that are broadcasted to all views.
|
|
@@ -148,6 +152,8 @@ export default class GenomeSpy {
|
|
|
148
152
|
|
|
149
153
|
/** @type {Point} */
|
|
150
154
|
this._mouseDownCoords = undefined;
|
|
155
|
+
|
|
156
|
+
this.dpr = window.devicePixelRatio;
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
get #canvasWrapper() {
|
|
@@ -307,12 +313,13 @@ export default class GenomeSpy {
|
|
|
307
313
|
#setupDpr() {
|
|
308
314
|
const dprSetter = this.viewRoot.paramMediator.allocateSetter(
|
|
309
315
|
"devicePixelRatio",
|
|
310
|
-
|
|
316
|
+
this.dpr
|
|
311
317
|
);
|
|
312
318
|
|
|
313
319
|
const resizeCallback = () => {
|
|
314
320
|
this._glHelper.invalidateSize();
|
|
315
|
-
|
|
321
|
+
this.dpr = window.devicePixelRatio;
|
|
322
|
+
dprSetter(this.dpr);
|
|
316
323
|
this.computeLayout();
|
|
317
324
|
// Render immediately, without RAF
|
|
318
325
|
this.renderAll();
|
|
@@ -368,7 +375,6 @@ export default class GenomeSpy {
|
|
|
368
375
|
this.viewRoot
|
|
369
376
|
? calculateCanvasSize(this.viewRoot)
|
|
370
377
|
: { width: undefined, height: undefined },
|
|
371
|
-
this.spec.background,
|
|
372
378
|
{ powerPreference: this.options.powerPreference ?? "default" }
|
|
373
379
|
);
|
|
374
380
|
|
|
@@ -444,10 +450,6 @@ export default class GenomeSpy {
|
|
|
444
450
|
genomeStore: this.genomeStore,
|
|
445
451
|
fontManager: new BmFontManager(this._glHelper),
|
|
446
452
|
|
|
447
|
-
get devicePixelRatio() {
|
|
448
|
-
return self._glHelper.dpr;
|
|
449
|
-
},
|
|
450
|
-
|
|
451
453
|
requestLayoutReflow: () => {
|
|
452
454
|
// placeholder
|
|
453
455
|
},
|
|
@@ -877,13 +879,15 @@ export default class GenomeSpy {
|
|
|
877
879
|
* @param {number} y
|
|
878
880
|
*/
|
|
879
881
|
_handlePicking(x, y) {
|
|
880
|
-
const
|
|
882
|
+
const dpr = this.dpr;
|
|
883
|
+
const pp = readPickingPixel(
|
|
884
|
+
this._glHelper.gl,
|
|
885
|
+
this._glHelper._pickingBufferInfo,
|
|
886
|
+
x * dpr,
|
|
887
|
+
y * dpr
|
|
888
|
+
);
|
|
881
889
|
|
|
882
|
-
const uniqueId =
|
|
883
|
-
pixelValue[0] |
|
|
884
|
-
(pixelValue[1] << 8) |
|
|
885
|
-
(pixelValue[2] << 16) |
|
|
886
|
-
(pixelValue[3] << 24);
|
|
890
|
+
const uniqueId = pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24);
|
|
887
891
|
|
|
888
892
|
if (uniqueId == 0) {
|
|
889
893
|
this._currentHover = null;
|
|
@@ -964,6 +968,72 @@ export default class GenomeSpy {
|
|
|
964
968
|
}
|
|
965
969
|
}
|
|
966
970
|
|
|
971
|
+
/**
|
|
972
|
+
* Returns a PNG data URL of the current canvas.
|
|
973
|
+
*
|
|
974
|
+
* @param {number} [logicalWidth] defaults to canvas width
|
|
975
|
+
* @param {number} [logicalHeight] defaults to canvas height
|
|
976
|
+
* @param {number} [devicePixelRatio] defaults to window.devicePixelRatio
|
|
977
|
+
* @param {string} [clearColor] null for transparent
|
|
978
|
+
* @returns A PNG data Url
|
|
979
|
+
*/
|
|
980
|
+
exportCanvas(
|
|
981
|
+
logicalWidth,
|
|
982
|
+
logicalHeight,
|
|
983
|
+
devicePixelRatio,
|
|
984
|
+
clearColor = "white"
|
|
985
|
+
) {
|
|
986
|
+
const helper = this._glHelper;
|
|
987
|
+
|
|
988
|
+
logicalWidth ??= helper.getLogicalCanvasSize().width;
|
|
989
|
+
logicalHeight ??= helper.getLogicalCanvasSize().height;
|
|
990
|
+
devicePixelRatio ??= window.devicePixelRatio ?? 1;
|
|
991
|
+
|
|
992
|
+
const gl = helper.gl;
|
|
993
|
+
|
|
994
|
+
const width = Math.floor(logicalWidth * devicePixelRatio);
|
|
995
|
+
const height = Math.floor(logicalHeight * devicePixelRatio);
|
|
996
|
+
|
|
997
|
+
const framebufferInfo = createFramebufferInfo(
|
|
998
|
+
gl,
|
|
999
|
+
[
|
|
1000
|
+
{
|
|
1001
|
+
format: gl.RGBA,
|
|
1002
|
+
type: gl.UNSIGNED_BYTE,
|
|
1003
|
+
minMag: gl.LINEAR,
|
|
1004
|
+
wrap: gl.CLAMP_TO_EDGE,
|
|
1005
|
+
},
|
|
1006
|
+
],
|
|
1007
|
+
width,
|
|
1008
|
+
height
|
|
1009
|
+
);
|
|
1010
|
+
|
|
1011
|
+
const renderingContext = new BufferedViewRenderingContext(
|
|
1012
|
+
{ picking: false },
|
|
1013
|
+
{
|
|
1014
|
+
webGLHelper: this._glHelper,
|
|
1015
|
+
canvasSize: { width: logicalWidth, height: logicalHeight },
|
|
1016
|
+
devicePixelRatio,
|
|
1017
|
+
clearColor,
|
|
1018
|
+
framebufferInfo,
|
|
1019
|
+
}
|
|
1020
|
+
);
|
|
1021
|
+
|
|
1022
|
+
this.viewRoot.render(
|
|
1023
|
+
renderingContext,
|
|
1024
|
+
Rectangle.create(0, 0, logicalWidth, logicalHeight)
|
|
1025
|
+
);
|
|
1026
|
+
renderingContext.render();
|
|
1027
|
+
|
|
1028
|
+
const pngUrl = framebufferToDataUrl(gl, framebufferInfo, "image/png");
|
|
1029
|
+
|
|
1030
|
+
// Clean up
|
|
1031
|
+
this.computeLayout();
|
|
1032
|
+
this.renderAll();
|
|
1033
|
+
|
|
1034
|
+
return pngUrl;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
967
1037
|
computeLayout() {
|
|
968
1038
|
const root = this.viewRoot;
|
|
969
1039
|
if (!root) {
|
|
@@ -982,17 +1052,25 @@ export default class GenomeSpy {
|
|
|
982
1052
|
return;
|
|
983
1053
|
}
|
|
984
1054
|
|
|
1055
|
+
const commonOptions = {
|
|
1056
|
+
webGLHelper: this._glHelper,
|
|
1057
|
+
canvasSize,
|
|
1058
|
+
devicePixelRatio: window.devicePixelRatio ?? 1,
|
|
1059
|
+
};
|
|
1060
|
+
|
|
985
1061
|
this._renderingContext = new BufferedViewRenderingContext(
|
|
1062
|
+
{ picking: false },
|
|
986
1063
|
{
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1064
|
+
...commonOptions,
|
|
1065
|
+
clearColor: this.spec.background,
|
|
1066
|
+
}
|
|
990
1067
|
);
|
|
991
1068
|
this._pickingContext = new BufferedViewRenderingContext(
|
|
1069
|
+
{ picking: true },
|
|
992
1070
|
{
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1071
|
+
...commonOptions,
|
|
1072
|
+
framebufferInfo: this._glHelper._pickingBufferInfo,
|
|
1073
|
+
}
|
|
996
1074
|
);
|
|
997
1075
|
|
|
998
1076
|
root.render(
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "#define PI 3.141593\nuniform View{mediump vec2 uViewOffset;mediump vec2 uViewScale;mediump vec2 uViewportSize;lowp float uDevicePixelRatio;lowp float uViewOpacity;bool uPickingEnabled;};/***Maps a coordinate on the unit scale to a normalized device coordinate.*(0,0)is at the bottom left corner.*/vec4 unitToNdc(vec2 coord){return vec4((coord*uViewScale+uViewOffset)*2.0-1.0,0.0,1.0);}vec4 unitToNdc(float x,float y){return unitToNdc(vec2(x,y));}vec4 pixelsToNdc(vec2 coord){return unitToNdc(coord/uViewportSize);}vec4 pixelsToNdc(float x,float y){return pixelsToNdc(vec2(x,y));}float linearstep(float edge0,float edge1,float x){return clamp((x-edge0)/(edge1-edge0),0.0,1.0);}bool isEmptyBinarySearchTexture(highp usampler2D s){return textureSize(s,0).x==1&&texelFetch(s,ivec2(0,0),0).r==0u;}bool binarySearchTexture(highp usampler2D s,uint value){int texSize=textureSize(s,0).x;int left=0;int right=texSize-1;while(left<=right){int mid=left+(right-left)/2;uint midValue=texelFetch(s,ivec2(mid,0),0).r;if(midValue==value){return true;}if(midValue<value){left=mid+1;}else{right=mid-1;}}return false;}/***Calculates a gamma for antialiasing opacity based on the color.*/float getGammaForColor(vec3 rgb){return mix(1.25,0.75,smoothstep(0.0,1.0,dot(rgb,vec3(0.299,0.587,0.114))));}/***Specialized linearstep for doing antialiasing*/float distanceToRatio(float d){return clamp(d*uDevicePixelRatio+0.5,0.0,1.0);}vec4 distanceToColor(float d,vec4 fill,vec4 stroke,vec4 background,float halfStrokeWidth){if(halfStrokeWidth>0.0){float sd=abs(d)-halfStrokeWidth;return mix(stroke,d<=0.0 ? fill : background,distanceToRatio(sd));}else{return mix(background,fill,distanceToRatio(-d));}}";
|
|
1
|
+
const shader = "#define PI 3.141593\nuniform View{mediump vec2 uViewOffset;mediump vec2 uViewScale;mediump vec2 uViewportSize;lowp float uDevicePixelRatio;lowp float uViewOpacity;bool uPickingEnabled;};/***Maps a coordinate on the unit scale to a normalized device coordinate.*(0,0)is at the bottom left corner.*/vec4 unitToNdc(vec2 coord){return vec4((coord*uViewScale+uViewOffset)*2.0-1.0,0.0,1.0);}vec4 unitToNdc(float x,float y){return unitToNdc(vec2(x,y));}vec4 pixelsToNdc(vec2 coord){return unitToNdc(coord/uViewportSize);}vec4 pixelsToNdc(float x,float y){return pixelsToNdc(vec2(x,y));}float linearstep(float edge0,float edge1,float x){return clamp((x-edge0)/(edge1-edge0),0.0,1.0);}bool isEmptyBinarySearchTexture(highp usampler2D s){return textureSize(s,0).x==1&&texelFetch(s,ivec2(0,0),0).r==0u;}bool binarySearchTexture(highp usampler2D s,uint value){int texSize=textureSize(s,0).x;if(texSize==1&&texelFetch(s,ivec2(0,0),0).r==0u){return false;}int left=0;int right=texSize-1;while(left<=right){int mid=left+(right-left)/2;uint midValue=texelFetch(s,ivec2(mid,0),0).r;if(midValue==value){return true;}if(midValue<value){left=mid+1;}else{right=mid-1;}}return false;}/***Calculates a gamma for antialiasing opacity based on the color.*/float getGammaForColor(vec3 rgb){return mix(1.25,0.75,smoothstep(0.0,1.0,dot(rgb,vec3(0.299,0.587,0.114))));}/***Specialized linearstep for doing antialiasing*/float distanceToRatio(float d){return clamp(d*uDevicePixelRatio+0.5,0.0,1.0);}vec4 distanceToColor(float d,vec4 fill,vec4 stroke,vec4 background,float halfStrokeWidth){if(halfStrokeWidth>0.0){float sd=abs(d)-halfStrokeWidth;return mix(stroke,d<=0.0 ? fill : background,distanceToRatio(sd));}else{return mix(background,fill,distanceToRatio(-d));}}";
|
|
2
2
|
export default shader;
|
|
@@ -17,6 +17,21 @@ export function createProgram(gl: WebGL2RenderingContext, vertexShader: WebGLSha
|
|
|
17
17
|
* @param {WebGLTexture} [texture]
|
|
18
18
|
*/
|
|
19
19
|
export function createOrUpdateTexture(gl: WebGLRenderingContext, options: Omit<import("twgl.js").TextureOptions, "src">, src: number[] | ArrayBufferView, texture?: WebGLTexture): WebGLTexture;
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param {WebGL2RenderingContext} gl
|
|
23
|
+
* @param {import("twgl.js").FramebufferInfo} framebufferInfo
|
|
24
|
+
* @param {number} x
|
|
25
|
+
* @param {number} y
|
|
26
|
+
*/
|
|
27
|
+
export function readPickingPixel(gl: WebGL2RenderingContext, framebufferInfo: import("twgl.js").FramebufferInfo, x: number, y: number): Uint8Array<ArrayBuffer>;
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {WebGL2RenderingContext} gl
|
|
31
|
+
* @param {import("twgl.js").FramebufferInfo} framebufferInfo
|
|
32
|
+
* @param {string} [type]
|
|
33
|
+
*/
|
|
34
|
+
export function framebufferToDataUrl(gl: WebGL2RenderingContext, framebufferInfo: import("twgl.js").FramebufferInfo, type?: string): string;
|
|
20
35
|
export default class WebGLHelper {
|
|
21
36
|
/**
|
|
22
37
|
*
|
|
@@ -24,13 +39,12 @@ export default class WebGLHelper {
|
|
|
24
39
|
* @param {() => {width: number, height: number}} [sizeSource]
|
|
25
40
|
* A function that returns the content size. If a dimension is undefined,
|
|
26
41
|
* the canvas fills the container, otherwise the canvas is adjusted to the content size.
|
|
27
|
-
* @param {string} [clearColor]
|
|
28
42
|
* @param {WebGLContextAttributes} [webglContextAttributes]
|
|
29
43
|
*/
|
|
30
44
|
constructor(container: HTMLElement, sizeSource?: () => {
|
|
31
45
|
width: number;
|
|
32
46
|
height: number;
|
|
33
|
-
},
|
|
47
|
+
}, webglContextAttributes?: WebGLContextAttributes);
|
|
34
48
|
_container: HTMLElement;
|
|
35
49
|
_sizeSource: () => {
|
|
36
50
|
width: any;
|
|
@@ -49,15 +63,11 @@ export default class WebGLHelper {
|
|
|
49
63
|
/** @type {import("twgl.js").AttachmentOptions[]} */
|
|
50
64
|
_pickingAttachmentOptions: import("twgl.js").AttachmentOptions[];
|
|
51
65
|
_pickingBufferInfo: import("twgl.js").FramebufferInfo;
|
|
52
|
-
/** @type {[number, number, number, number]} */
|
|
53
|
-
_clearColor: [number, number, number, number];
|
|
54
66
|
invalidateSize(): void;
|
|
55
67
|
_logicalCanvasSize: {
|
|
56
68
|
width: any;
|
|
57
69
|
height: any;
|
|
58
70
|
};
|
|
59
|
-
_updateDpr(): void;
|
|
60
|
-
dpr: number;
|
|
61
71
|
/**
|
|
62
72
|
* Compiles and caches a shader. The shader source is used as a cache key.
|
|
63
73
|
*
|
|
@@ -80,19 +90,13 @@ export default class WebGLHelper {
|
|
|
80
90
|
height: number;
|
|
81
91
|
};
|
|
82
92
|
/**
|
|
83
|
-
* Returns the canvas size in logical pixels
|
|
93
|
+
* Returns the size of the canvas canvas container size in logical pixels,
|
|
94
|
+
* without devicePixelRatio correction.
|
|
84
95
|
*/
|
|
85
96
|
getLogicalCanvasSize(): {
|
|
86
97
|
width: any;
|
|
87
98
|
height: any;
|
|
88
99
|
};
|
|
89
|
-
/**
|
|
90
|
-
*
|
|
91
|
-
* @param {number} x
|
|
92
|
-
* @param {number} y
|
|
93
|
-
*/
|
|
94
|
-
readPickingPixel(x: number, y: number): Uint8Array<ArrayBuffer>;
|
|
95
|
-
clearAll(): void;
|
|
96
100
|
/**
|
|
97
101
|
* Creates textures for color schemes and discrete/discretizing ranges.
|
|
98
102
|
* N.B. Discrete range textures need domain. Thus, this cannot be called
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"AAwZA;;;;GAIG;AACH,kCAJW,sBAAsB,gBACtB,WAAW,kBACX,WAAW;;;;;;EA8CrB;AAED;;;;;GAKG;AACH,0CALW,qBAAqB,WACrB,IAAI,CAAC,OAAO,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,OAC7C,MAAM,EAAE,GAAG,eAAe,YAC1B,YAAY,gBAYtB;AAED;;;;;;GAMG;AACH,qCALW,sBAAsB,mBACtB,OAAO,SAAS,EAAE,eAAe,KACjC,MAAM,KACN,MAAM,2BAWhB;AAED;;;;;GAKG;AACH,yCAJW,sBAAsB,mBACtB,OAAO,SAAS,EAAE,eAAe,SACjC,MAAM,UA4BhB;AAjfD;IACI;;;;;;;OAOG;IACH,uBANW,WAAW,eACX,MAAM;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,2BAGrC,sBAAsB,EAsFhC;IAnFG,wBAA2B;IAC3B;;;MAKO;IAEP,uCAAuC;IACvC,cADW,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CACN;IAE7B,6EAA6E;IAC7E,eADW,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,EAAE,YAAY,CAAC,CACvC;IAElC;;OAEG;IACH,mBAFU,OAAO,CAAC,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAEnD;IA8CtC,0BAAoB;IACpB,2BAAY;IAGZ,oDAAoD;IACpD,2BADW,OAAO,SAAS,EAAE,iBAAiB,EAAE,CAQ/C;IACD,sDAGC;IAML,uBAGC;IAFG;;;MAAmC;IAIvC;;;;;OAKG;IACH,oBAHW,MAAM,QACN,MAAM,GAAG,MAAM,EAAE,eA2B3B;IAED,iBAcC;IAED,iBAEC;IAED;;;;OAIG;IACH,oCAFW;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;MAS3C;IAED;;;OAGG;IACH;;;MAuBC;IAED;;;;;;;;;OASG;IACH,+BAHW,OAAO,4BAA4B,EAAE,OAAO,WAC5C,OAAO,QA0GjB;IAED;;OAEG;IACH,kCAFW,OAAO,4BAA4B,EAAE,mBAAmB,0BA+BlE;CACJ"}
|
|
@@ -26,7 +26,6 @@ import {
|
|
|
26
26
|
isColorChannel,
|
|
27
27
|
isDiscreteChannel,
|
|
28
28
|
} from "../encoder/encoder.js";
|
|
29
|
-
import { color } from "d3-color";
|
|
30
29
|
import { isMultiPointSelection } from "../selection/selection.js";
|
|
31
30
|
|
|
32
31
|
export default class WebGLHelper {
|
|
@@ -36,15 +35,9 @@ export default class WebGLHelper {
|
|
|
36
35
|
* @param {() => {width: number, height: number}} [sizeSource]
|
|
37
36
|
* A function that returns the content size. If a dimension is undefined,
|
|
38
37
|
* the canvas fills the container, otherwise the canvas is adjusted to the content size.
|
|
39
|
-
* @param {string} [clearColor]
|
|
40
38
|
* @param {WebGLContextAttributes} [webglContextAttributes]
|
|
41
39
|
*/
|
|
42
|
-
constructor(
|
|
43
|
-
container,
|
|
44
|
-
sizeSource,
|
|
45
|
-
clearColor,
|
|
46
|
-
webglContextAttributes = {}
|
|
47
|
-
) {
|
|
40
|
+
constructor(container, sizeSource, webglContextAttributes = {}) {
|
|
48
41
|
this._container = container;
|
|
49
42
|
this._sizeSource =
|
|
50
43
|
sizeSource ??
|
|
@@ -97,7 +90,13 @@ export default class WebGLHelper {
|
|
|
97
90
|
|
|
98
91
|
addExtensionsToContext(gl);
|
|
99
92
|
|
|
100
|
-
//
|
|
93
|
+
// Make flat shading fast. All flat vertices have the same values, so
|
|
94
|
+
// it doesn't matter which one is the provoking vertex.
|
|
95
|
+
// https://registry.khronos.org/webgl/extensions/WEBGL_provoking_vertex/
|
|
96
|
+
const epv = gl.getExtension("WEBGL_provoking_vertex");
|
|
97
|
+
if (epv) {
|
|
98
|
+
epv.provokingVertexWEBGL(epv.FIRST_VERTEX_CONVENTION_WEBGL);
|
|
99
|
+
}
|
|
101
100
|
|
|
102
101
|
// Always use pre-multiplied alpha
|
|
103
102
|
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
@@ -122,27 +121,13 @@ export default class WebGLHelper {
|
|
|
122
121
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
123
122
|
|
|
124
123
|
this.adjustGl();
|
|
125
|
-
|
|
126
|
-
this._updateDpr();
|
|
127
|
-
|
|
128
|
-
/** @type {[number, number, number, number]} */
|
|
129
|
-
this._clearColor = [0, 0, 0, 0];
|
|
130
|
-
if (clearColor) {
|
|
131
|
-
const c = color(clearColor).rgb();
|
|
132
|
-
this._clearColor = [c.r / 255, c.g / 255, c.b / 255, c.opacity];
|
|
133
|
-
}
|
|
134
124
|
}
|
|
135
125
|
|
|
136
126
|
invalidateSize() {
|
|
137
127
|
this._logicalCanvasSize = undefined;
|
|
138
|
-
this._updateDpr();
|
|
139
128
|
this.adjustGl();
|
|
140
129
|
}
|
|
141
130
|
|
|
142
|
-
_updateDpr() {
|
|
143
|
-
this.dpr = window.devicePixelRatio;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
131
|
/**
|
|
147
132
|
* Compiles and caches a shader. The shader source is used as a cache key.
|
|
148
133
|
*
|
|
@@ -202,15 +187,17 @@ export default class WebGLHelper {
|
|
|
202
187
|
* @param {{ width: number, height: number }} [logicalSize]
|
|
203
188
|
*/
|
|
204
189
|
getPhysicalCanvasSize(logicalSize) {
|
|
190
|
+
const dpr = window.devicePixelRatio ?? 1;
|
|
205
191
|
logicalSize = logicalSize || this.getLogicalCanvasSize();
|
|
206
192
|
return {
|
|
207
|
-
width: logicalSize.width *
|
|
208
|
-
height: logicalSize.height *
|
|
193
|
+
width: logicalSize.width * dpr,
|
|
194
|
+
height: logicalSize.height * dpr,
|
|
209
195
|
};
|
|
210
196
|
}
|
|
211
197
|
|
|
212
198
|
/**
|
|
213
|
-
* Returns the canvas size in logical pixels
|
|
199
|
+
* Returns the size of the canvas canvas container size in logical pixels,
|
|
200
|
+
* without devicePixelRatio correction.
|
|
214
201
|
*/
|
|
215
202
|
getLogicalCanvasSize() {
|
|
216
203
|
if (this._logicalCanvasSize) {
|
|
@@ -237,44 +224,6 @@ export default class WebGLHelper {
|
|
|
237
224
|
return this._logicalCanvasSize;
|
|
238
225
|
}
|
|
239
226
|
|
|
240
|
-
/**
|
|
241
|
-
*
|
|
242
|
-
* @param {number} x
|
|
243
|
-
* @param {number} y
|
|
244
|
-
*/
|
|
245
|
-
readPickingPixel(x, y) {
|
|
246
|
-
const gl = this.gl;
|
|
247
|
-
|
|
248
|
-
x *= this.dpr;
|
|
249
|
-
y *= this.dpr;
|
|
250
|
-
|
|
251
|
-
const height = this.getPhysicalCanvasSize().height;
|
|
252
|
-
|
|
253
|
-
const pixel = new Uint8Array(4);
|
|
254
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, this._pickingBufferInfo.framebuffer);
|
|
255
|
-
gl.readPixels(
|
|
256
|
-
x,
|
|
257
|
-
height - y - 1,
|
|
258
|
-
1,
|
|
259
|
-
1,
|
|
260
|
-
gl.RGBA,
|
|
261
|
-
gl.UNSIGNED_BYTE,
|
|
262
|
-
pixel
|
|
263
|
-
);
|
|
264
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
265
|
-
|
|
266
|
-
return pixel;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
clearAll() {
|
|
270
|
-
const gl = this.gl;
|
|
271
|
-
const { width, height } = this.getPhysicalCanvasSize();
|
|
272
|
-
gl.viewport(0, 0, width, height);
|
|
273
|
-
gl.disable(gl.SCISSOR_TEST);
|
|
274
|
-
gl.clearColor(...this._clearColor);
|
|
275
|
-
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
227
|
/**
|
|
279
228
|
* Creates textures for color schemes and discrete/discretizing ranges.
|
|
280
229
|
* N.B. Discrete range textures need domain. Thus, this cannot be called
|
|
@@ -525,3 +474,55 @@ export function createOrUpdateTexture(gl, options, src, texture) {
|
|
|
525
474
|
}
|
|
526
475
|
return texture;
|
|
527
476
|
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
*
|
|
480
|
+
* @param {WebGL2RenderingContext} gl
|
|
481
|
+
* @param {import("twgl.js").FramebufferInfo} framebufferInfo
|
|
482
|
+
* @param {number} x
|
|
483
|
+
* @param {number} y
|
|
484
|
+
*/
|
|
485
|
+
export function readPickingPixel(gl, framebufferInfo, x, y) {
|
|
486
|
+
const { height, framebuffer } = framebufferInfo;
|
|
487
|
+
|
|
488
|
+
const pixel = new Uint8Array(4);
|
|
489
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
490
|
+
gl.readPixels(x, height - y - 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
|
|
491
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
492
|
+
|
|
493
|
+
return pixel;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
*
|
|
498
|
+
* @param {WebGL2RenderingContext} gl
|
|
499
|
+
* @param {import("twgl.js").FramebufferInfo} framebufferInfo
|
|
500
|
+
* @param {string} [type]
|
|
501
|
+
*/
|
|
502
|
+
export function framebufferToDataUrl(gl, framebufferInfo, type = "image/png") {
|
|
503
|
+
const { width, height } = framebufferInfo;
|
|
504
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
505
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferInfo.framebuffer);
|
|
506
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
507
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
508
|
+
|
|
509
|
+
const exportCanvas = document.createElement("canvas");
|
|
510
|
+
exportCanvas.width = width;
|
|
511
|
+
exportCanvas.height = height;
|
|
512
|
+
const ctx = exportCanvas.getContext("2d");
|
|
513
|
+
const imageData = ctx.createImageData(width, height);
|
|
514
|
+
|
|
515
|
+
// Flip Y axis (WebGL's origin is bottom-left, canvas is top-left)
|
|
516
|
+
for (let y = 0; y < height; y++) {
|
|
517
|
+
const srcStart = (height - 1 - y) * width * 4;
|
|
518
|
+
const destStart = y * width * 4;
|
|
519
|
+
imageData.data.set(
|
|
520
|
+
pixels.subarray(srcStart, srcStart + width * 4),
|
|
521
|
+
destStart
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
ctx.putImageData(imageData, 0, 0);
|
|
526
|
+
|
|
527
|
+
return exportCanvas.toDataURL(type);
|
|
528
|
+
}
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":";AAyGA;;;;;GAKG;AACH,8BAFW,MAAM,gBAuBhB;sBAjIqB,gBAAgB;qBAFjB,KAAK;iBAGT,kBAAkB;oBACf,6BAA6B"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "in vec4 vColor;in float vSize;in float vNormalLengthInPixels;in float vGamma;out lowp vec4 fragColor;void main(void){float dpr=uDevicePixelRatio;float distance=abs(vNormalLengthInPixels);float opacity=clamp(((vSize/2.0-distance)*dpr),0.0,1.0);opacity=pow(opacity,vGamma);fragColor=vColor*opacity;if(uPickingEnabled){fragColor=vPickingColor;}}";
|
|
1
|
+
const shader = "flat in vec4 vColor;flat in float vSize;in float vNormalLengthInPixels;flat in float vGamma;out lowp vec4 fragColor;void main(void){float dpr=uDevicePixelRatio;float distance=abs(vNormalLengthInPixels);float opacity=clamp(((vSize/2.0-distance)*dpr),0.0,1.0);opacity=pow(opacity,vGamma);fragColor=vColor*opacity;if(uPickingEnabled){fragColor=vPickingColor;}}";
|
|
2
2
|
export default shader;
|