@genome-spy/core 0.43.0 → 0.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/{index-d7k3kkin.js → index-noY1e-G6.js} +365 -361
- package/dist/bundle/index.es.js +3294 -3200
- package/dist/bundle/index.js +83 -81
- package/dist/src/data/sources/lazy/bigBedSource.d.ts +6 -0
- package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.js +128 -6
- package/dist/src/gl/arrayBuilder.d.ts +11 -4
- package/dist/src/gl/arrayBuilder.d.ts.map +1 -1
- package/dist/src/gl/arrayBuilder.js +36 -13
- package/dist/src/gl/dataToVertices.d.ts +3 -2
- package/dist/src/gl/dataToVertices.d.ts.map +1 -1
- package/dist/src/gl/dataToVertices.js +45 -14
- package/dist/src/gl/glslScaleGenerator.d.ts +12 -0
- package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
- package/dist/src/gl/glslScaleGenerator.js +38 -4
- package/dist/src/gl/includes/scales.glsl.js +1 -1
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +2 -1
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +3 -1
- package/package.json +3 -3
|
@@ -8,6 +8,12 @@ export default class BigBedSource extends SingleAxisWindowedSource {
|
|
|
8
8
|
parser: import("@gmod/bed").default;
|
|
9
9
|
/** @type {import("@gmod/bbi").BigBed} */
|
|
10
10
|
bbi: import("@gmod/bbi").BigBed;
|
|
11
|
+
/** @type {(chrom: string, fields: { start: number, end: number, rest?: string }) => Record<string, any>} */
|
|
12
|
+
parseLine: (chrom: string, fields: {
|
|
13
|
+
start: number;
|
|
14
|
+
end: number;
|
|
15
|
+
rest?: string;
|
|
16
|
+
}) => Record<string, any>;
|
|
11
17
|
params: import("../../../spec/data.js").BigBedData;
|
|
12
18
|
initializedPromise: Promise<any>;
|
|
13
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bigBedSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/bigBedSource.js"],"names":[],"mappings":"AAGA;
|
|
1
|
+
{"version":3,"file":"bigBedSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/bigBedSource.js"],"names":[],"mappings":"AAGA;IAUI;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,UAAU,QAC1C,OAAO,uBAAuB,EAAE,OAAO,EAsDjD;IAjED,0CAA0C;IAC1C,QADW,OAAO,WAAW,EAAE,OAAO,CAC/B;IAEP,yCAAyC;IACzC,KADW,OAAO,WAAW,EAAE,MAAM,CACjC;IAEJ,4GAA4G;IAC5G,mBADmB,MAAM,UAAU;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,MAAM,EAAE,GAAG,CAAC,CAC9F;IAkBN,mDAAgC;IAQhC,iCA+BE;CAuBT;qCA1FoC,+BAA+B"}
|
|
@@ -8,6 +8,9 @@ export default class BigBedSource extends SingleAxisWindowedSource {
|
|
|
8
8
|
/** @type {import("@gmod/bbi").BigBed} */
|
|
9
9
|
bbi;
|
|
10
10
|
|
|
11
|
+
/** @type {(chrom: string, fields: { start: number, end: number, rest?: string }) => Record<string, any>} */
|
|
12
|
+
parseLine;
|
|
13
|
+
|
|
11
14
|
/**
|
|
12
15
|
* @param {import("../../../spec/data.js").BigBedData} params
|
|
13
16
|
* @param {import("../../../view/view.js").default} view
|
|
@@ -49,6 +52,16 @@ export default class BigBedSource extends SingleAxisWindowedSource {
|
|
|
49
52
|
this.bbi.getHeader().then(async (header) => {
|
|
50
53
|
// @ts-ignore TODO: Fix
|
|
51
54
|
this.parser = new BED({ autoSql: header.autoSql });
|
|
55
|
+
try {
|
|
56
|
+
const fastParser = makeFastParser(this.parser);
|
|
57
|
+
this.parseLine = (chrom, f) =>
|
|
58
|
+
fastParser(chrom, f.start, f.end, f.rest);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
this.parseLine = (chrom, f) =>
|
|
61
|
+
this.parser.parseLine(
|
|
62
|
+
`${chrom}\t${f.start}\t${f.end}\t${f.rest}`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
52
65
|
|
|
53
66
|
resolve();
|
|
54
67
|
});
|
|
@@ -68,12 +81,7 @@ export default class BigBedSource extends SingleAxisWindowedSource {
|
|
|
68
81
|
signal,
|
|
69
82
|
})
|
|
70
83
|
.then((features) =>
|
|
71
|
-
features.map((f) =>
|
|
72
|
-
this.parser.parseLine(
|
|
73
|
-
`${d.chrom}\t${f.start}\t${f.end}\t${f.rest}`,
|
|
74
|
-
{ uniqueId: f.uniqueId }
|
|
75
|
-
)
|
|
76
|
-
)
|
|
84
|
+
features.map((f) => this.parseLine(d.chrom, f))
|
|
77
85
|
)
|
|
78
86
|
);
|
|
79
87
|
|
|
@@ -82,3 +90,117 @@ export default class BigBedSource extends SingleAxisWindowedSource {
|
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A specific optimization for Hautaniemi Lab's Methylation project, where
|
|
96
|
+
* we have hundreds of columns having small integers (0-100).
|
|
97
|
+
* This parser avoids generating piles of garbage to be collected by the GC.
|
|
98
|
+
* We don't split the line into an array of strings, but instead parse the
|
|
99
|
+
* integer fields directly from the original string.
|
|
100
|
+
* This parser doesn't support arrays, etc. at the moment.
|
|
101
|
+
*
|
|
102
|
+
* @param {import("@gmod/bed").default} bed
|
|
103
|
+
*/
|
|
104
|
+
function makeFastParser(bed) {
|
|
105
|
+
// Skip the first three fields: chrom, chromStart, chromEnd
|
|
106
|
+
const fields = bed.autoSql.fields.filter((field) => field.type).slice(3);
|
|
107
|
+
|
|
108
|
+
let i = 0;
|
|
109
|
+
let currentLine = "";
|
|
110
|
+
let lineLength = 0;
|
|
111
|
+
|
|
112
|
+
/** @type {Record<string, any>} */
|
|
113
|
+
let currentObject = {};
|
|
114
|
+
|
|
115
|
+
const delimiter = "\t";
|
|
116
|
+
const delimiterCode = delimiter.charCodeAt(0);
|
|
117
|
+
const zero = "0".charCodeAt(0);
|
|
118
|
+
const minusCode = "-".charCodeAt(0);
|
|
119
|
+
|
|
120
|
+
function parseString() {
|
|
121
|
+
let end = currentLine.indexOf(delimiter, i);
|
|
122
|
+
if (end < 0) {
|
|
123
|
+
end = lineLength;
|
|
124
|
+
}
|
|
125
|
+
const str = currentLine.substring(i, end);
|
|
126
|
+
i = end + 1;
|
|
127
|
+
return str;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function parseInt() {
|
|
131
|
+
let value = 0;
|
|
132
|
+
|
|
133
|
+
let charCode = currentLine.charCodeAt(i);
|
|
134
|
+
let sign = 1;
|
|
135
|
+
|
|
136
|
+
if (charCode === minusCode) {
|
|
137
|
+
sign = -1;
|
|
138
|
+
i++;
|
|
139
|
+
charCode = currentLine.charCodeAt(i);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
do {
|
|
143
|
+
if (charCode === delimiterCode) {
|
|
144
|
+
i++;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
value = value * 10 + charCode - zero;
|
|
148
|
+
charCode = currentLine.charCodeAt(++i);
|
|
149
|
+
} while (i < lineLength);
|
|
150
|
+
|
|
151
|
+
return value * sign;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const fieldParsers = fields.map((field) => {
|
|
155
|
+
const { name, type } = field;
|
|
156
|
+
|
|
157
|
+
if (["ubyte", "int", "uint"].includes(type)) {
|
|
158
|
+
return () => {
|
|
159
|
+
currentObject[name] = parseInt();
|
|
160
|
+
};
|
|
161
|
+
} else if (field.isNumeric) {
|
|
162
|
+
return () => {
|
|
163
|
+
currentObject[name] = Number(parseString());
|
|
164
|
+
};
|
|
165
|
+
} else if (["char", "string", "lstring"].includes(type)) {
|
|
166
|
+
return () => {
|
|
167
|
+
currentObject[name] = parseString();
|
|
168
|
+
};
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error("Unsupported type: " + type);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @param {string} line
|
|
176
|
+
*/
|
|
177
|
+
function setLine(line) {
|
|
178
|
+
currentLine = line;
|
|
179
|
+
lineLength = line.length;
|
|
180
|
+
i = 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @param {string} chrom
|
|
185
|
+
* @param {number} chromStart
|
|
186
|
+
* @param {number} chromEnd
|
|
187
|
+
* @param {string} rest
|
|
188
|
+
*/
|
|
189
|
+
function parseLine(chrom, chromStart, chromEnd, rest) {
|
|
190
|
+
setLine(rest);
|
|
191
|
+
|
|
192
|
+
currentObject = {
|
|
193
|
+
chrom,
|
|
194
|
+
chromStart,
|
|
195
|
+
chromEnd,
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
for (let j = 0, n = fieldParsers.length; j < n; j++) {
|
|
199
|
+
fieldParsers[j]();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return currentObject;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return parseLine;
|
|
206
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @prop {function(object):any} f The converter
|
|
6
6
|
* @prop {number[]} [arrayReference] An optimization for fp64 mainly
|
|
7
7
|
* @prop {number} [numComponents]
|
|
8
|
+
* @prop {typeof Uint16Array | typeof Int16Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array} [targetArrayType] Defaults to Float32Array
|
|
8
9
|
*/
|
|
9
10
|
export default class ArrayBuilder {
|
|
10
11
|
/**
|
|
@@ -13,10 +14,10 @@ export default class ArrayBuilder {
|
|
|
13
14
|
*/
|
|
14
15
|
constructor(size: number);
|
|
15
16
|
size: number;
|
|
16
|
-
/** @type {Object.<string, {data:
|
|
17
|
+
/** @type {Object.<string, {data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array, numComponents: number, divisor?: number}>} */
|
|
17
18
|
arrays: {
|
|
18
19
|
[x: string]: {
|
|
19
|
-
data:
|
|
20
|
+
data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array;
|
|
20
21
|
numComponents: number;
|
|
21
22
|
divisor?: number;
|
|
22
23
|
};
|
|
@@ -26,6 +27,7 @@ export default class ArrayBuilder {
|
|
|
26
27
|
/** @type {(function(any):void)[]} */
|
|
27
28
|
dataUpdaters: ((arg0: any) => void)[];
|
|
28
29
|
vertexCount: number;
|
|
30
|
+
configure(): void;
|
|
29
31
|
/**
|
|
30
32
|
*
|
|
31
33
|
* @param {string} attribute
|
|
@@ -36,13 +38,13 @@ export default class ArrayBuilder {
|
|
|
36
38
|
*
|
|
37
39
|
* @param {string} attributeName
|
|
38
40
|
* @param {number} numComponents
|
|
41
|
+
* @param {typeof Uint16Array | typeof Int16Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array} [targetArrayType]
|
|
39
42
|
* @param {number[]} [arrayReference]
|
|
40
43
|
* @return {function(number|number[])}
|
|
41
44
|
*/
|
|
42
|
-
createUpdater(attributeName: string, numComponents: number, arrayReference?: number[]): (arg0: number | number[]) => any;
|
|
45
|
+
createUpdater(attributeName: string, numComponents: number, targetArrayType?: typeof Uint16Array | typeof Int16Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array, arrayReference?: number[]): (arg0: number | number[]) => any;
|
|
43
46
|
pushAll(): void;
|
|
44
47
|
/**
|
|
45
|
-
*
|
|
46
48
|
* @param {object} datum
|
|
47
49
|
*/
|
|
48
50
|
updateFromDatum(datum: object): void;
|
|
@@ -51,6 +53,7 @@ export default class ArrayBuilder {
|
|
|
51
53
|
* @param {object} datum
|
|
52
54
|
*/
|
|
53
55
|
pushFromDatum(datum: object): void;
|
|
56
|
+
#private;
|
|
54
57
|
}
|
|
55
58
|
/**
|
|
56
59
|
* A function that extracts a raw attribute from a datum (optionally) converts
|
|
@@ -66,5 +69,9 @@ export type ConverterMetadata = {
|
|
|
66
69
|
*/
|
|
67
70
|
arrayReference?: number[];
|
|
68
71
|
numComponents?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Defaults to Float32Array
|
|
74
|
+
*/
|
|
75
|
+
targetArrayType?: typeof Uint16Array | typeof Int16Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array;
|
|
69
76
|
};
|
|
70
77
|
//# sourceMappingURL=arrayBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrayBuilder.d.ts","sourceRoot":"","sources":["../../../src/gl/arrayBuilder.js"],"names":[],"mappings":"AASA
|
|
1
|
+
{"version":3,"file":"arrayBuilder.d.ts","sourceRoot":"","sources":["../../../src/gl/arrayBuilder.js"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH;IAKI;;;OAGG;IACH,kBAFW,MAAM,EAehB;IAZG,aAAgB;IAEhB,mJAAmJ;IACnJ;YADmB,MAAM,GAAE;YAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAC;MAC9H;IAEhB,kCAAkC;IAClC,SADW,OAAY,IAAI,CAAC,EAAE,CACb;IAEjB,qCAAqC;IACrC,cADW,QAAU,GAAG,KAAE,IAAI,CAAC,EAAE,CACX;IAEtB,oBAAoB;IAGxB,kBAOC;IAED;;;;OAIG;IACH,wBAHW,MAAM,YACN,iBAAiB,QAe3B;IAED;;;;;;;OAOG;IACH,6BANW,MAAM,iBACN,MAAM,oBACN,kBAAkB,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,mBAAmB,mBACrG,MAAM,EAAE,UACE,MAAM,GAAC,MAAM,EAAE,SAoFnC;IAED,gBAEC;IAED;;OAEG;IACH,uBAFW,MAAM,QAIhB;IAuDD;;;OAGG;IACH,qBAFW,MAAM,QAKhB;;CACJ;;;;;;;;;cA9NkB,MAAM,KAAE,GAAG;;;;qBACpB,MAAM,EAAE;oBACR,MAAM;;;;sBACN,kBAAkB,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,mBAAmB"}
|
|
@@ -14,10 +14,13 @@ const UNROLL_LIMIT = 10000;
|
|
|
14
14
|
* @prop {function(object):any} f The converter
|
|
15
15
|
* @prop {number[]} [arrayReference] An optimization for fp64 mainly
|
|
16
16
|
* @prop {number} [numComponents]
|
|
17
|
+
* @prop {typeof Uint16Array | typeof Int16Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array} [targetArrayType] Defaults to Float32Array
|
|
17
18
|
*/
|
|
18
19
|
export default class ArrayBuilder {
|
|
19
20
|
// TODO: Support strided layout. May yield better performance or not. No consensus in literature.
|
|
20
21
|
|
|
22
|
+
#configured = false;
|
|
23
|
+
|
|
21
24
|
/**
|
|
22
25
|
*
|
|
23
26
|
* @param {number} size Size if known, uses TypedArray
|
|
@@ -25,7 +28,7 @@ export default class ArrayBuilder {
|
|
|
25
28
|
constructor(size) {
|
|
26
29
|
this.size = size;
|
|
27
30
|
|
|
28
|
-
/** @type {Object.<string, {data:
|
|
31
|
+
/** @type {Object.<string, {data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array, numComponents: number, divisor?: number}>} */
|
|
29
32
|
this.arrays = {};
|
|
30
33
|
|
|
31
34
|
/** @type {(function():void)[]} */
|
|
@@ -37,6 +40,15 @@ export default class ArrayBuilder {
|
|
|
37
40
|
this.vertexCount = 0;
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
configure() {
|
|
44
|
+
if (this.#configured) {
|
|
45
|
+
throw new Error("Already configured!");
|
|
46
|
+
}
|
|
47
|
+
this.#configurePushAll();
|
|
48
|
+
this.#configureUpdateFromDatum();
|
|
49
|
+
this.#configured = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
/**
|
|
41
53
|
*
|
|
42
54
|
* @param {string} attribute
|
|
@@ -46,6 +58,7 @@ export default class ArrayBuilder {
|
|
|
46
58
|
const updater = this.createUpdater(
|
|
47
59
|
ATTRIBUTE_PREFIX + attribute,
|
|
48
60
|
metadata.numComponents || 1,
|
|
61
|
+
metadata.targetArrayType ?? Float32Array,
|
|
49
62
|
metadata.arrayReference
|
|
50
63
|
);
|
|
51
64
|
const f = metadata.f;
|
|
@@ -60,10 +73,16 @@ export default class ArrayBuilder {
|
|
|
60
73
|
*
|
|
61
74
|
* @param {string} attributeName
|
|
62
75
|
* @param {number} numComponents
|
|
76
|
+
* @param {typeof Uint16Array | typeof Int16Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array} [targetArrayType]
|
|
63
77
|
* @param {number[]} [arrayReference]
|
|
64
78
|
* @return {function(number|number[])}
|
|
65
79
|
*/
|
|
66
|
-
createUpdater(
|
|
80
|
+
createUpdater(
|
|
81
|
+
attributeName,
|
|
82
|
+
numComponents,
|
|
83
|
+
targetArrayType = Float32Array,
|
|
84
|
+
arrayReference = undefined
|
|
85
|
+
) {
|
|
67
86
|
if (!isNumber(this.size)) {
|
|
68
87
|
throw new Error("The number of vertices must be defined!");
|
|
69
88
|
}
|
|
@@ -73,7 +92,8 @@ export default class ArrayBuilder {
|
|
|
73
92
|
let updater;
|
|
74
93
|
let i = 0;
|
|
75
94
|
|
|
76
|
-
|
|
95
|
+
// eslint-disable-next-line new-cap
|
|
96
|
+
const array = new targetArrayType(this.size * numComponents);
|
|
77
97
|
|
|
78
98
|
this.arrays[attributeName] = {
|
|
79
99
|
data: array,
|
|
@@ -142,6 +162,17 @@ export default class ArrayBuilder {
|
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
pushAll() {
|
|
165
|
+
throw new Error("Call configure() first!");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @param {object} datum
|
|
170
|
+
*/
|
|
171
|
+
updateFromDatum(datum) {
|
|
172
|
+
throw new Error("Call configure() first!");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#configurePushAll() {
|
|
145
176
|
if (this.size > UNROLL_LIMIT) {
|
|
146
177
|
const preps = this.pushers
|
|
147
178
|
.map((_v, i) => `const p${i} = that.pushers[${i}];`)
|
|
@@ -165,15 +196,9 @@ ${pushs}
|
|
|
165
196
|
this.vertexCount++;
|
|
166
197
|
};
|
|
167
198
|
}
|
|
168
|
-
|
|
169
|
-
this.pushAll();
|
|
170
199
|
}
|
|
171
200
|
|
|
172
|
-
|
|
173
|
-
*
|
|
174
|
-
* @param {object} datum
|
|
175
|
-
*/
|
|
176
|
-
updateFromDatum(datum) {
|
|
201
|
+
#configureUpdateFromDatum() {
|
|
177
202
|
if (this.size > UNROLL_LIMIT) {
|
|
178
203
|
const preps = this.dataUpdaters
|
|
179
204
|
.map((_v, i) => `const u${i} = that.dataUpdaters[${i}];`)
|
|
@@ -192,14 +217,12 @@ ${updates}
|
|
|
192
217
|
};`
|
|
193
218
|
)(this);
|
|
194
219
|
} else {
|
|
195
|
-
this.updateFromDatum = (datum) => {
|
|
220
|
+
this.updateFromDatum = (/** @type {object} */ datum) => {
|
|
196
221
|
for (let i = 0; i < this.dataUpdaters.length; i++) {
|
|
197
222
|
this.dataUpdaters[i](datum);
|
|
198
223
|
}
|
|
199
224
|
};
|
|
200
225
|
}
|
|
201
|
-
|
|
202
|
-
this.updateFromDatum(datum);
|
|
203
226
|
}
|
|
204
227
|
|
|
205
228
|
/**
|
|
@@ -63,9 +63,9 @@ export class GeometryBuilder {
|
|
|
63
63
|
getIndex: () => import("../utils/binnedIndex.js").Lookup;
|
|
64
64
|
};
|
|
65
65
|
toArrays(): {
|
|
66
|
-
/** @type {Record<string, {data:
|
|
66
|
+
/** @type {Record<string, {data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array, numComponents: number, divisor?: number}>} */
|
|
67
67
|
arrays: Record<string, {
|
|
68
|
-
data:
|
|
68
|
+
data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array;
|
|
69
69
|
numComponents: number;
|
|
70
70
|
divisor?: number;
|
|
71
71
|
}>;
|
|
@@ -89,6 +89,7 @@ export class RectVertexBuilder extends GeometryBuilder {
|
|
|
89
89
|
attributes: string[];
|
|
90
90
|
numItems?: number;
|
|
91
91
|
});
|
|
92
|
+
pushAllSixTimes: any;
|
|
92
93
|
}
|
|
93
94
|
export class RuleVertexBuilder extends GeometryBuilder {
|
|
94
95
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataToVertices.d.ts","sourceRoot":"","sources":["../../../src/gl/dataToVertices.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dataToVertices.d.ts","sourceRoot":"","sources":["../../../src/gl/dataToVertices.js"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH;IACI;;;OAGG;IAEH;;;;;;OAMG;IACH;;qBAJW,MAAM,EAAE;sBACR,MAAM;OA6EhB;IAzEG,gEAAwB;IAGxB;;MAKC;IAQD,0BAAoC;IAEpC,8BAAoD;IAmDpD,mBAAmB;IAEnB,yFAAyF;IACzF,UADW,IAAI,GAAG,EAAE,UAAU,CAAC,CACkB;IAGrD;;;;OAIG;IACH,mBAFW,GAAG,QAcb;IAED;;OAEG;IACH,oBAFW,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,QAM5B;IAED;;;OAGG;IACH,cAHW,GAAG,QACH,MAAM,EAAE,kCAYlB;IAED;;;;OAIG;IACH,sBAJW,OAAO,qBAAqB,EAAE,IAAI,OAClC,MAAM,OACN,MAAM,QA+DhB;IAED;;;;;OAKG;IACH,mBAFW,OAAO,qBAAqB,EAAE,KAAK,QAI7C;IA/DO;;;MAAyB;IAiEjC;QAEQ,kJAAkJ;gBAAvI,OAAO,MAAM,EAAE;YAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAC,CAAC;QAE9I,8BAA8B;;QAE9B,8CAA8C;;;MAIrD;CACJ;AAED;IACI;;;;;;OAMG;IACH;;oBAHW,MAAM,EAAE;mBACR,MAAM;OA+BhB;IAnBG,qBAkBW;CA8BlB;AAED;IACI;;;;;;;;;OASG;IACH;;oBANW,MAAM,EAAE;gCACR,MAAM;uBAEN,MAAM,EAAE;mBACR,MAAM;OAwBhB;IARG,uBAAgC;IAEhC,8BAA8D;IAE9D,6CAA+D;IAC/D,4CAA6D;CA6CpE;AAED;IACI;;;;;;OAMG;IACH;;oBAHW,MAAM,EAAE;mBACR,MAAM;OAShB;CACJ;AAED;IACI;;;;;OAKG;IACH;;oBAHW,MAAM,EAAE;mBACR,MAAM;OAShB;CAYJ;AAED;IACI;;;;;;;;;OASG;IACH;;oBANW,MAAM,EAAE;qBACR,OAAO,2BAA2B,EAAE,aAAa;oBACjD,OAAO,MAAM,EAAE,GAAG,CAAC;wBACnB,MAAM;sBACN,OAAO;OA8CjB;IA/BG,4DAA2B;IAC3B,2DAA0B;IAE1B,gCAA4B;IAQ5B,qCAAqC;IACrC,sBADmB,GAAG,KAAK,MAAM,CAMf;IAElB,oDAGC;IACD,qDAGC;IAED,8CAAiE;CAgJxE;;;;;;;;YAvmBS,MAAM;;;;WACN,MAAM;YACN,OAAO,yBAAyB,EAAE,MAAM;;yBAjBzB,mBAAmB"}
|
|
@@ -8,10 +8,11 @@ import { isValueDef } from "../encoder/encoder.js";
|
|
|
8
8
|
import {
|
|
9
9
|
dedupeEncodingFields,
|
|
10
10
|
isHighPrecisionScale,
|
|
11
|
+
isLargeGenome,
|
|
11
12
|
makeAttributeName,
|
|
12
|
-
|
|
13
|
+
splitLargeHighPrecision,
|
|
13
14
|
} from "./glslScaleGenerator.js";
|
|
14
|
-
import { isContinuous } from "vega-scale";
|
|
15
|
+
import { isContinuous, isDiscrete } from "vega-scale";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @typedef {object} RangeEntry Represents a location of a vertex subset
|
|
@@ -67,8 +68,9 @@ export class GeometryBuilder {
|
|
|
67
68
|
|
|
68
69
|
const accessor = ce.accessor;
|
|
69
70
|
|
|
70
|
-
const doubleArray = [0, 0];
|
|
71
71
|
const hp = isHighPrecisionScale(ce.scale.type);
|
|
72
|
+
const largeHp = hp && isLargeGenome(ce.scale.domain());
|
|
73
|
+
const largeHpArray = [0, 0];
|
|
72
74
|
|
|
73
75
|
const indexer = ce.indexer;
|
|
74
76
|
|
|
@@ -81,8 +83,8 @@ export class GeometryBuilder {
|
|
|
81
83
|
*/
|
|
82
84
|
const f = indexer
|
|
83
85
|
? (d) => indexer(accessor(d))
|
|
84
|
-
:
|
|
85
|
-
? (d) =>
|
|
86
|
+
: largeHp
|
|
87
|
+
? (d) => splitLargeHighPrecision(accessor(d), largeHpArray)
|
|
86
88
|
: accessor;
|
|
87
89
|
|
|
88
90
|
const attributeName = sharedChannels
|
|
@@ -91,8 +93,13 @@ export class GeometryBuilder {
|
|
|
91
93
|
|
|
92
94
|
this.variableBuilder.addConverter(attributeName, {
|
|
93
95
|
f,
|
|
94
|
-
numComponents:
|
|
95
|
-
arrayReference:
|
|
96
|
+
numComponents: largeHp ? 2 : 1,
|
|
97
|
+
arrayReference: largeHp ? largeHpArray : undefined,
|
|
98
|
+
targetArrayType: isDiscrete(ce.scale.type)
|
|
99
|
+
? Uint16Array
|
|
100
|
+
: hp
|
|
101
|
+
? Uint32Array
|
|
102
|
+
: Float32Array,
|
|
96
103
|
});
|
|
97
104
|
}
|
|
98
105
|
|
|
@@ -226,7 +233,7 @@ export class GeometryBuilder {
|
|
|
226
233
|
|
|
227
234
|
toArrays() {
|
|
228
235
|
return {
|
|
229
|
-
/** @type {Record<string, {data:
|
|
236
|
+
/** @type {Record<string, {data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array, numComponents: number, divisor?: number}>} */
|
|
230
237
|
arrays: this.variableBuilder.arrays,
|
|
231
238
|
/** Number of vertices used */
|
|
232
239
|
vertexCount: this.variableBuilder.vertexCount,
|
|
@@ -251,6 +258,29 @@ export class RectVertexBuilder extends GeometryBuilder {
|
|
|
251
258
|
attributes,
|
|
252
259
|
numVertices: numItems * 6,
|
|
253
260
|
});
|
|
261
|
+
this.variableBuilder.configure();
|
|
262
|
+
|
|
263
|
+
const pushAll = this.variableBuilder.pushAll;
|
|
264
|
+
|
|
265
|
+
this.pushAllSixTimes =
|
|
266
|
+
// TODO: Don't do this stupid comparison. Instead, reuse the previous GeometryBuilder.
|
|
267
|
+
numItems > 500
|
|
268
|
+
? // Make a new function instance where the JS engine can inline
|
|
269
|
+
// all pushAll calls to avoid the function call overhead.
|
|
270
|
+
new Function(
|
|
271
|
+
"pushAll",
|
|
272
|
+
`return function unrolledPushAllSixTimes() {
|
|
273
|
+
pushAll(); pushAll(); pushAll(); pushAll(); pushAll(); pushAll();
|
|
274
|
+
};`
|
|
275
|
+
)(pushAll)
|
|
276
|
+
: function pushAllSixTimes() {
|
|
277
|
+
pushAll();
|
|
278
|
+
pushAll();
|
|
279
|
+
pushAll();
|
|
280
|
+
pushAll();
|
|
281
|
+
pushAll();
|
|
282
|
+
pushAll();
|
|
283
|
+
};
|
|
254
284
|
}
|
|
255
285
|
|
|
256
286
|
/**
|
|
@@ -273,12 +303,7 @@ export class RectVertexBuilder extends GeometryBuilder {
|
|
|
273
303
|
|
|
274
304
|
// Six vertices per rect. The vertex shader is using gl_VertexID to
|
|
275
305
|
// determine the vertex position within the rect.
|
|
276
|
-
this.
|
|
277
|
-
this.variableBuilder.pushAll();
|
|
278
|
-
this.variableBuilder.pushAll();
|
|
279
|
-
this.variableBuilder.pushAll();
|
|
280
|
-
this.variableBuilder.pushAll();
|
|
281
|
-
this.variableBuilder.pushAll();
|
|
306
|
+
this.pushAllSixTimes();
|
|
282
307
|
|
|
283
308
|
this.addToXIndex(d);
|
|
284
309
|
}
|
|
@@ -318,6 +343,8 @@ export class RuleVertexBuilder extends GeometryBuilder {
|
|
|
318
343
|
|
|
319
344
|
this.updateSide = this.variableBuilder.createUpdater("side", 1);
|
|
320
345
|
this.updatePos = this.variableBuilder.createUpdater("pos", 1);
|
|
346
|
+
|
|
347
|
+
this.variableBuilder.configure();
|
|
321
348
|
}
|
|
322
349
|
|
|
323
350
|
/* eslint-disable complexity */
|
|
@@ -376,6 +403,7 @@ export class PointVertexBuilder extends GeometryBuilder {
|
|
|
376
403
|
attributes,
|
|
377
404
|
numVertices: numItems,
|
|
378
405
|
});
|
|
406
|
+
this.variableBuilder.configure();
|
|
379
407
|
}
|
|
380
408
|
}
|
|
381
409
|
|
|
@@ -392,6 +420,7 @@ export class LinkVertexBuilder extends GeometryBuilder {
|
|
|
392
420
|
attributes,
|
|
393
421
|
numVertices: numItems,
|
|
394
422
|
});
|
|
423
|
+
this.variableBuilder.configure();
|
|
395
424
|
}
|
|
396
425
|
|
|
397
426
|
toArrays() {
|
|
@@ -459,6 +488,8 @@ export class TextVertexBuilder extends GeometryBuilder {
|
|
|
459
488
|
);
|
|
460
489
|
|
|
461
490
|
this.updateWidth = this.variableBuilder.createUpdater("width", 1);
|
|
491
|
+
|
|
492
|
+
this.variableBuilder.configure();
|
|
462
493
|
}
|
|
463
494
|
|
|
464
495
|
/**
|
|
@@ -18,15 +18,27 @@ export function generateScaleGlsl(channel: Channel, scale: any, channelDef: impo
|
|
|
18
18
|
domainUniform: string;
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
|
+
* True if scale needs more than 24 bits (float32) of precision.
|
|
21
22
|
*
|
|
22
23
|
* @param {string} type
|
|
23
24
|
*/
|
|
24
25
|
export function isHighPrecisionScale(type: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* True if Uint32 cannot represent the domain.
|
|
28
|
+
*
|
|
29
|
+
* @param {number[]} domain
|
|
30
|
+
*/
|
|
31
|
+
export function isLargeGenome(domain: number[]): boolean;
|
|
25
32
|
/**
|
|
26
33
|
* @param {number} x Must be an integer
|
|
27
34
|
* @param {number[]} [arr]
|
|
28
35
|
*/
|
|
29
36
|
export function splitHighPrecision(x: number, arr?: number[]): number[];
|
|
37
|
+
/**
|
|
38
|
+
* @param {number} x Must be an integer
|
|
39
|
+
* @param {number[]} [arr]
|
|
40
|
+
*/
|
|
41
|
+
export function splitLargeHighPrecision(x: number, arr?: number[]): number[];
|
|
30
42
|
/**
|
|
31
43
|
* @param {number[]} domain
|
|
32
44
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glslScaleGenerator.d.ts","sourceRoot":"","sources":["../../../src/gl/glslScaleGenerator.js"],"names":[],"mappings":";AAmDA;;;;GAIG;AACH,2CAHW,OAAO,SACP,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,OAAO,UAsC9C;AAED;;;;;;GAMG;AAEH,2CANW,OAAO,SACP,GAAG,cACH,OAAO,oBAAoB,EAAE,UAAU,+BACvC,OAAO,EAAE;;;;
|
|
1
|
+
{"version":3,"file":"glslScaleGenerator.d.ts","sourceRoot":"","sources":["../../../src/gl/glslScaleGenerator.js"],"names":[],"mappings":";AAmDA;;;;GAIG;AACH,2CAHW,OAAO,SACP,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,OAAO,UAsC9C;AAED;;;;;;GAMG;AAEH,2CANW,OAAO,SACP,GAAG,cACH,OAAO,oBAAoB,EAAE,UAAU,+BACvC,OAAO,EAAE;;;;EA8RnB;AA+FD;;;;GAIG;AACH,2CAFW,MAAM,WAIhB;AAED;;;;GAIG;AACH,sCAFW,MAAM,EAAE,WAIlB;AAMD;;;GAGG;AACH,sCAHW,MAAM,QACN,MAAM,EAAE,YAYlB;AAED;;;GAGG;AACH,2CAHW,MAAM,QACN,MAAM,EAAE,YAUlB;AAYD;;GAEG;AACH,qDAFW,MAAM,EAAE,YAIlB;AAED;;GAEG;AAEH;;;;;GAKG;AACH,+CAFW,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC,CAAC,+DA4BtG;AAED;;GAEG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,GAAG,OAAO,oBAAoB,EAAE,OAAO,EAAE,UAIvF;AA3jBD,uCAAwC;AACxC,uCAAwC;AACxC,oCAAqC;AACrC,6CAA8C;AAC9C,kDAAmD;AACnD,oDAAqD;sBAMxC,OAAO,oBAAoB,EAAE,OAAO;;;;8BAiYpC,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;;;uBAqIhD,CAAC,MAAM,EAAE,OAAO,CAAC;0BAnhBJ,WAAW"}
|
|
@@ -122,8 +122,19 @@ export function generateScaleGlsl(
|
|
|
122
122
|
const domainUniformName = DOMAIN_PREFIX + primary;
|
|
123
123
|
const rangeName = RANGE_PREFIX + primary;
|
|
124
124
|
|
|
125
|
+
// The attribute has discrete values
|
|
126
|
+
const discrete = isDiscrete(scale.type);
|
|
127
|
+
|
|
125
128
|
const hp = isHighPrecisionScale(scale.type);
|
|
126
|
-
const
|
|
129
|
+
const largeHp = hp && isLargeGenome(scale.domain());
|
|
130
|
+
|
|
131
|
+
const attributeType = largeHp
|
|
132
|
+
? "uvec2"
|
|
133
|
+
: hp
|
|
134
|
+
? "uint"
|
|
135
|
+
: discrete
|
|
136
|
+
? "uint"
|
|
137
|
+
: "float";
|
|
127
138
|
|
|
128
139
|
const domainLength = scale.domain ? scale.domain().length : undefined;
|
|
129
140
|
|
|
@@ -468,6 +479,7 @@ function makeFunctionCall(name, ...args) {
|
|
|
468
479
|
}
|
|
469
480
|
|
|
470
481
|
/**
|
|
482
|
+
* True if scale needs more than 24 bits (float32) of precision.
|
|
471
483
|
*
|
|
472
484
|
* @param {string} type
|
|
473
485
|
*/
|
|
@@ -475,9 +487,17 @@ export function isHighPrecisionScale(type) {
|
|
|
475
487
|
return type == "index" || type == "locus";
|
|
476
488
|
}
|
|
477
489
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
490
|
+
/**
|
|
491
|
+
* True if Uint32 cannot represent the domain.
|
|
492
|
+
*
|
|
493
|
+
* @param {number[]} domain
|
|
494
|
+
*/
|
|
495
|
+
export function isLargeGenome(domain) {
|
|
496
|
+
return domain[1] > 2 ** 32;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const LOW_BITS = 12;
|
|
500
|
+
const BS = 2 ** LOW_BITS;
|
|
481
501
|
const BM = BS - 1;
|
|
482
502
|
|
|
483
503
|
/**
|
|
@@ -496,6 +516,20 @@ export function splitHighPrecision(x, arr = []) {
|
|
|
496
516
|
return arr;
|
|
497
517
|
}
|
|
498
518
|
|
|
519
|
+
/**
|
|
520
|
+
* @param {number} x Must be an integer
|
|
521
|
+
* @param {number[]} [arr]
|
|
522
|
+
*/
|
|
523
|
+
export function splitLargeHighPrecision(x, arr = []) {
|
|
524
|
+
const lo = x % BS;
|
|
525
|
+
const hi = (x - lo) / BS;
|
|
526
|
+
|
|
527
|
+
arr[0] = hi;
|
|
528
|
+
arr[1] = lo;
|
|
529
|
+
|
|
530
|
+
return arr;
|
|
531
|
+
}
|
|
532
|
+
|
|
499
533
|
/**
|
|
500
534
|
* @param {number} x
|
|
501
535
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "uniform highp float uZero;vec3 getDiscreteColor(sampler2D s,int index){return texelFetch(s,ivec2(index % textureSize(s,0).x,0),0).rgb;}vec3 getInterpolatedColor(sampler2D s,float unitValue){return texture(s,vec2(unitValue,0.0)).rgb;}float clampToRange(float value,vec2 range){return clamp(value,min(range[0],range[1]),max(range[0],range[1]));}float scaleIdentity(float value){return value;}float scaleLinear(float value,vec2 domain,vec2 range){float domainSpan=domain[1]-domain[0];float rangeSpan=range[1]-range[0];return(value-domain[0])/domainSpan*rangeSpan+range[0];}float scaleLog(float value,vec2 domain,vec2 range,float base){return scaleLinear(log(value)/log(base),log(domain)/log(base),range);}float symlog(float value,float constant){return sign(value)*log(abs(value/constant)+1.0);}float scaleSymlog(float value,vec2 domain,vec2 range,float constant){return scaleLinear(symlog(value,constant),vec2(symlog(domain[0],constant),symlog(domain[1],constant)),range);}float scalePow(float value,vec2 domain,vec2 range,float exponent){return scaleLinear(pow(abs(value),exponent)*sign(value),pow(abs(domain),vec2(exponent))*sign(domain),range);}float scaleBand(
|
|
1
|
+
const shader = "uniform highp float uZero;vec3 getDiscreteColor(sampler2D s,int index){return texelFetch(s,ivec2(index % textureSize(s,0).x,0),0).rgb;}vec3 getInterpolatedColor(sampler2D s,float unitValue){return texture(s,vec2(unitValue,0.0)).rgb;}float clampToRange(float value,vec2 range){return clamp(value,min(range[0],range[1]),max(range[0],range[1]));}float scaleIdentity(float value){return value;}float scaleIdentity(uint value){return float(value);}float scaleLinear(float value,vec2 domain,vec2 range){float domainSpan=domain[1]-domain[0];float rangeSpan=range[1]-range[0];return(value-domain[0])/domainSpan*rangeSpan+range[0];}float scaleLog(float value,vec2 domain,vec2 range,float base){return scaleLinear(log(value)/log(base),log(domain)/log(base),range);}float symlog(float value,float constant){return sign(value)*log(abs(value/constant)+1.0);}float scaleSymlog(float value,vec2 domain,vec2 range,float constant){return scaleLinear(symlog(value,constant),vec2(symlog(domain[0],constant),symlog(domain[1],constant)),range);}float scalePow(float value,vec2 domain,vec2 range,float exponent){return scaleLinear(pow(abs(value),exponent)*sign(value),pow(abs(domain),vec2(exponent))*sign(domain),range);}float scaleBand(uint value,vec2 domainExtent,vec2 range,float paddingInner,float paddingOuter,float align,float band){float start=range[0];float stop=range[1];float rangeSpan=stop-start;float n=domainExtent[1]-domainExtent[0];paddingInner=int(n)>1 ? paddingInner : 0.0;float step=rangeSpan/max(1.0,n-paddingInner+paddingOuter*2.0);start+=(rangeSpan-step*(n-paddingInner))*align;float bandwidth=step*(1.0-paddingInner);return start+(float(value)-domainExtent[0])*step+bandwidth*band;}const int lowBits=12;const float lowDivisor=pow(2.0,float(lowBits));const uint lowMask=uint(lowDivisor-1.0);vec2 splitUint(uint value){uint valueLo=value&lowMask;uint valueHi=value-valueLo;return vec2(float(valueHi),float(valueLo));}/***High precision variant of scaleBand for index/locus scales*/float scaleBandHp(uint value,vec3 domainExtent,vec2 range,float paddingInner,float paddingOuter,float align,float band){float start=range[0];float stop=range[1];float rangeSpan=stop-start;vec2 domainStart=domainExtent.xy;float n=domainExtent[2];float step=rangeSpan/max(1.0,n-paddingInner+paddingOuter*2.0);start+=(rangeSpan-step*(n-paddingInner))*align;float bandwidth=step*(1.0-paddingInner);vec2 splitValue=splitUint(value);float inf=1.0/uZero;float hi=max(splitValue[0]-domainStart[0],-inf);float lo=max(splitValue[1]-domainStart[1],-inf);return dot(vec4(start,hi,lo,bandwidth),vec4(1.0,step,step,band));}/***High precision variant of scaleBand for index/locus scales for large*domains where 32bit uints are not sufficient to represent the domain.*/float scaleBandHp(uvec2 value,vec3 domainExtent,vec2 range,float paddingInner,float paddingOuter,float align,float band){float start=range[0];float stop=range[1];float rangeSpan=stop-start;vec2 domainStart=domainExtent.xy;float n=domainExtent[2];float step=rangeSpan/max(1.0,n-paddingInner+paddingOuter*2.0);start+=(rangeSpan-step*(n-paddingInner))*align;float bandwidth=step*(1.0-paddingInner);vec2 splitValue=vec2(float(value[0])*lowDivisor,float(value[1]));float inf=1.0/uZero;float hi=max(splitValue[0]-domainStart[0],-inf);float lo=max(splitValue[1]-domainStart[1],-inf);return dot(vec4(start,hi,lo,bandwidth),vec4(1.0,step,step,band));}";
|
|
2
2
|
export default shader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IA+BQ;;;;;OAKG;IACH,yBAEC;
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IA+BQ;;;;;OAKG;IACH,yBAEC;IAmGD;;;;;;MAKC;CAoFR;iBAzOgB,WAAW"}
|