@genome-spy/core 0.43.0 → 0.43.2

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.
@@ -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;IAOI;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,UAAU,QAC1C,OAAO,uBAAuB,EAAE,OAAO,EA4CjD;IApDD,0CAA0C;IAC1C,QADW,OAAO,WAAW,EAAE,OAAO,CAC/B;IAEP,yCAAyC;IACzC,KADW,OAAO,WAAW,EAAE,MAAM,CACjC;IAkBA,mDAAgC;IAQhC,iCAqBE;CA4BT;qCAlFoC,+BAA+B"}
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,138 @@ 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. This could, however,
101
+ * be extended into a fully-featured parser.
102
+ *
103
+ * @param {import("@gmod/bed").default} bed
104
+ */
105
+ function makeFastParser(bed) {
106
+ // Skip the first three fields: chrom, chromStart, chromEnd
107
+ const fields = bed.autoSql.fields.filter((field) => field.type).slice(3);
108
+
109
+ let i = 0;
110
+ let currentLine = "";
111
+ let lineLength = 0;
112
+
113
+ /** @type {Record<string, any>} */
114
+ let currentObject = {};
115
+
116
+ const delimiter = "\t";
117
+ const delimiterCode = delimiter.charCodeAt(0);
118
+ const zero = "0".charCodeAt(0);
119
+ const minusCode = "-".charCodeAt(0);
120
+
121
+ function parseString() {
122
+ let end = currentLine.indexOf(delimiter, i);
123
+ if (end < 0) {
124
+ end = lineLength;
125
+ }
126
+ const str = currentLine.substring(i, end);
127
+ i = end + 1;
128
+ return str;
129
+ }
130
+
131
+ function parseInt() {
132
+ let value = 0;
133
+
134
+ let charCode = currentLine.charCodeAt(i);
135
+ let sign = 1;
136
+
137
+ if (charCode === minusCode) {
138
+ sign = -1;
139
+ i++;
140
+ charCode = currentLine.charCodeAt(i);
141
+ }
142
+
143
+ do {
144
+ if (charCode === delimiterCode) {
145
+ i++;
146
+ break;
147
+ }
148
+ value = value * 10 + charCode - zero;
149
+ charCode = currentLine.charCodeAt(++i);
150
+ } while (i < lineLength);
151
+
152
+ return value * sign;
153
+ }
154
+
155
+ const fieldParsers = fields.map((field) => {
156
+ const { name, type } = field;
157
+
158
+ if (["ubyte", "int", "uint"].includes(type)) {
159
+ return () => {
160
+ currentObject[name] = parseInt();
161
+ };
162
+ } else if (field.isNumeric) {
163
+ return () => {
164
+ currentObject[name] = Number(parseString());
165
+ };
166
+ } else if (["char", "string", "lstring"].includes(type)) {
167
+ return () => {
168
+ currentObject[name] = parseString();
169
+ };
170
+ } else {
171
+ throw new Error("Unsupported type: " + type);
172
+ }
173
+ });
174
+
175
+ const templateFields = fields.map(
176
+ (field) => `"${field.name}": ${field.isNumeric ? "0" : "emptyString"}`
177
+ );
178
+
179
+ /**
180
+ * Make a template object with all fields to avoid the JavaScript VM's
181
+ * hidden class to be changed after each property assignment. Transitions
182
+ * between hidden classes generate plenty of garbage to be collected.
183
+ *
184
+ * Ideally, the parsed values would be assigned directly in this function,
185
+ * but for some reason, it results in abysmally slow performance on Chrome,
186
+ * but not on Firefox, where it would be super fast.
187
+ */
188
+ const makeTemplate = new Function(`
189
+ const emptyString = "";
190
+ return function makeTemplate(chrom, chromStart, chromEnd) {
191
+ return {
192
+ chrom,
193
+ chromStart,
194
+ chromEnd,
195
+ ${templateFields.join(",\n")}
196
+ }
197
+ };`)();
198
+
199
+ /**
200
+ * @param {string} line
201
+ */
202
+ function setLine(line) {
203
+ currentLine = line;
204
+ lineLength = line.length;
205
+ i = 0;
206
+ }
207
+
208
+ /**
209
+ * @param {string} chrom
210
+ * @param {number} chromStart
211
+ * @param {number} chromEnd
212
+ * @param {string} rest
213
+ */
214
+ function parseLine(chrom, chromStart, chromEnd, rest) {
215
+ setLine(rest);
216
+
217
+ currentObject = makeTemplate(chrom, chromStart, chromEnd);
218
+
219
+ for (let j = 0, n = fieldParsers.length; j < n; j++) {
220
+ fieldParsers[j]();
221
+ }
222
+
223
+ return currentObject;
224
+ }
225
+
226
+ return parseLine;
227
+ }
@@ -2,7 +2,10 @@
2
2
  /**
3
3
  * Computes coverage for sorted segments
4
4
  *
5
- * TODO: Binned coverage
5
+ * TODO: Binned coverage, e.g., don't emit a new segment for every
6
+ * coverage change, but only every n bases or so. The most straightforward
7
+ * way to implement it is a separate transform that bins the coverage
8
+ * segments and calculates weighted averages.
6
9
  */
7
10
  export default class CoverageTransform extends FlowNode {
8
11
  /**
@@ -23,7 +26,12 @@ export default class CoverageTransform extends FlowNode {
23
26
  chrom: string;
24
27
  };
25
28
  createSegment: Function;
26
- ends: FlatQueue<any>;
29
+ /**
30
+ * End pos as priority, weight as value
31
+ *
32
+ * @type {FlatQueue<number>}
33
+ */
34
+ ends: FlatQueue<number>;
27
35
  }
28
36
  import FlowNode from "../flowNode.js";
29
37
  import FlatQueue from "flatqueue";
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/coverage.js"],"names":[],"mappings":";AAKA;;;;GAIG;AACH;IAKI;;OAEG;IACH,oBAFW,OAAO,yBAAyB,EAAE,cAAc,EA4C1D;IAxCG,yDAAoB;IAEpB,mDAAwC;IACxC,iDAAoC;IAEpC,mCAAmC;IACnC,sBADoB,GAAG,KAAE,MAAM,CAGT;IACtB,mCAAmC;IACnC,uBADoB,GAAG,KAAE,MAAM,CACsC;IAErE;;;;;MAKC;IAGD,wBAgBC;IAGD,qBAA2B;CA2HlC;qBAnLyC,gBAAgB;sBAHpC,WAAW"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/coverage.js"],"names":[],"mappings":";AAKA;;;;;;;GAOG;AACH;IAKI;;OAEG;IACH,oBAFW,OAAO,yBAAyB,EAAE,cAAc,EAgD1D;IA5CG,yDAAoB;IAEpB,mDAAwC;IACxC,iDAAoC;IAEpC,mCAAmC;IACnC,sBADoB,GAAG,KAAE,MAAM,CAGT;IACtB,mCAAmC;IACnC,uBADoB,GAAG,KAAE,MAAM,CACsC;IAErE;;;;;MAKC;IAGD,wBAgBC;IAED;;;;OAIG;IACH,MAFU,UAAU,MAAM,CAAC,CAEA;CAiIlC;qBAhMyC,gBAAgB;sBAHpC,WAAW"}
@@ -6,7 +6,10 @@ import FlowNode, { BEHAVIOR_CLONES } from "../flowNode.js";
6
6
  /**
7
7
  * Computes coverage for sorted segments
8
8
  *
9
- * TODO: Binned coverage
9
+ * TODO: Binned coverage, e.g., don't emit a new segment for every
10
+ * coverage change, but only every n bases or so. The most straightforward
11
+ * way to implement it is a separate transform that bins the coverage
12
+ * segments and calculates weighted averages.
10
13
  */
11
14
  export default class CoverageTransform extends FlowNode {
12
15
  get behavior() {
@@ -56,7 +59,11 @@ export default class CoverageTransform extends FlowNode {
56
59
  )
57
60
  );
58
61
 
59
- // End pos as priority, weight as value
62
+ /**
63
+ * End pos as priority, weight as value
64
+ *
65
+ * @type {FlatQueue<number>}
66
+ */
60
67
  this.ends = new FlatQueue();
61
68
  }
62
69
 
@@ -75,7 +82,7 @@ export default class CoverageTransform extends FlowNode {
75
82
  const chromAccessor = this.chromAccessor;
76
83
  const weightAccessor = this.weightAccessor;
77
84
 
78
- /** @type {Record<string, number|string>} used for merging adjacent segment */
85
+ /** @type {import("../flowNode.js").Datum} used for merging adjacent segment */
79
86
  let bufferedSegment;
80
87
 
81
88
  /** @type {string} */
@@ -91,7 +98,7 @@ export default class CoverageTransform extends FlowNode {
91
98
  /** @type {number} */
92
99
  let prevEdge;
93
100
 
94
- // End pos as priority, weight as value
101
+ /** End pos as priority, weight as value */
95
102
  const ends = this.ends;
96
103
  ends.clear();
97
104
 
@@ -127,9 +134,7 @@ export default class CoverageTransform extends FlowNode {
127
134
  };
128
135
 
129
136
  const flushQueue = () => {
130
- // Flush queue
131
- /** @type {number} */
132
- let edge;
137
+ let edge = 0;
133
138
  while ((edge = ends.peekValue()) !== undefined) {
134
139
  pushSegment(prevEdge, edge, coverage);
135
140
  prevEdge = edge;
@@ -147,8 +152,7 @@ export default class CoverageTransform extends FlowNode {
147
152
  this.handle = (datum) => {
148
153
  const start = startAccessor(datum);
149
154
 
150
- /** @type {number} */
151
- let edge;
155
+ let edge = 0;
152
156
  while ((edge = ends.peekValue()) !== undefined && edge < start) {
153
157
  pushSegment(prevEdge, edge, coverage);
154
158
  prevEdge = edge;
@@ -179,5 +183,14 @@ export default class CoverageTransform extends FlowNode {
179
183
  flushQueue();
180
184
  super.complete();
181
185
  };
186
+
187
+ /**
188
+ * @param {import("../../types/flowBatch.js").FlowBatch} flowBatch
189
+ */
190
+ this.beginBatch = (flowBatch) => {
191
+ flushQueue();
192
+ prevChrom = undefined;
193
+ super.beginBatch(flowBatch);
194
+ };
182
195
  }
183
196
  }
@@ -1,4 +1,4 @@
1
- import { expect, test } from "vitest";
1
+ import { describe, expect, test } from "vitest";
2
2
  import CoverageTransform from "./coverage.js";
3
3
  import { processData } from "../flowTestUtils.js";
4
4
 
@@ -16,108 +16,223 @@ function transform(params, data) {
16
16
  return processData(t, data);
17
17
  }
18
18
 
19
- test("Coverage transform produces correct coverage segments", () => {
20
- const reads = [
21
- [0, 4],
22
- [1, 3],
23
- [2, 6],
24
- [4, 8],
25
- [8, 10],
26
- [11, 14],
27
- [11, 13],
28
- [11, 12],
29
- [15, 18],
30
- [16, 18],
31
- [17, 18],
32
- ].map((d) => ({
33
- start: d[0],
34
- end: d[1],
35
- }));
36
-
37
- const coverageSegments = [
38
- [0, 1, 1],
39
- [1, 2, 2],
40
- [2, 3, 3],
41
- [3, 6, 2],
42
- [6, 10, 1],
43
- [11, 12, 3],
44
- [12, 13, 2],
45
- [13, 14, 1],
46
- [15, 16, 1],
47
- [16, 17, 2],
48
- [17, 18, 3],
49
- ].map((d) => ({
50
- start: d[0],
51
- end: d[1],
52
- coverage: d[2],
53
- }));
54
-
19
+ /**
20
+ *
21
+ * @param {[number, number][]} reads Start, end
22
+ * @param {[number, number, number][]} coverageSegments Start, end, coverage
23
+ */
24
+ function testSimpleCoverage(reads, coverageSegments) {
55
25
  /** @type {CoverageParams} */
56
26
  const coverageConfig = {
57
27
  type: "coverage",
58
28
  start: "start",
59
29
  end: "end",
60
30
  };
61
- expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
62
- });
63
-
64
- test("Coverage transform handles chromosomes", () => {
65
- const reads = [
66
- { chrom: "chr1", start: 0, end: 1 },
67
- { chrom: "chr2", start: 0, end: 1 },
68
- { chrom: "chr3", start: 1, end: 3 },
69
- ];
70
-
71
- const coverageSegments = [
72
- { chrom: "chr1", start: 0, end: 1, coverage: 1 },
73
- { chrom: "chr2", start: 0, end: 1, coverage: 1 },
74
- { chrom: "chr3", start: 1, end: 3, coverage: 1 },
75
- ];
31
+ expect(
32
+ transform(
33
+ coverageConfig,
34
+ reads.map((d) => ({
35
+ start: d[0],
36
+ end: d[1],
37
+ }))
38
+ )
39
+ ).toEqual(
40
+ coverageSegments.map((d) => ({
41
+ start: d[0],
42
+ end: d[1],
43
+ coverage: d[2],
44
+ }))
45
+ );
46
+ }
76
47
 
48
+ /**
49
+ *
50
+ * @param {[number, number, number][]} reads Start, end, weight
51
+ * @param {[number, number, number][]} coverageSemgments Start, end, coverage
52
+ */
53
+ function testWeightedCoverage(reads, coverageSegments) {
77
54
  /** @type {CoverageParams} */
78
55
  const coverageConfig = {
79
56
  type: "coverage",
80
- chrom: "chrom",
81
57
  start: "start",
82
58
  end: "end",
59
+ weight: "weight",
83
60
  };
61
+ expect(
62
+ transform(
63
+ coverageConfig,
64
+ reads.map((d) => ({
65
+ start: d[0],
66
+ end: d[1],
67
+ weight: d[2],
68
+ }))
69
+ )
70
+ ).toEqual(
71
+ coverageSegments.map((d) => ({
72
+ start: d[0],
73
+ end: d[1],
74
+ coverage: d[2],
75
+ }))
76
+ );
77
+ }
84
78
 
85
- expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
86
- });
79
+ describe("Coverage transform", () => {
80
+ test("Typical case", () =>
81
+ testSimpleCoverage(
82
+ [
83
+ [0, 4],
84
+ [1, 3],
85
+ [2, 6],
86
+ [4, 8],
87
+ [8, 10],
88
+ [11, 14],
89
+ [11, 13],
90
+ [11, 12],
91
+ [15, 18],
92
+ [16, 18],
93
+ [17, 18],
94
+ ],
95
+ [
96
+ [0, 1, 1],
97
+ [1, 2, 2],
98
+ [2, 3, 3],
99
+ [3, 6, 2],
100
+ [6, 10, 1],
101
+ [11, 12, 3],
102
+ [12, 13, 2],
103
+ [13, 14, 1],
104
+ [15, 16, 1],
105
+ [16, 17, 2],
106
+ [17, 18, 3],
107
+ ]
108
+ ));
87
109
 
88
- test("Coverage transform handles weights", () => {
89
- const reads = [
90
- [0, 4, 1],
91
- [1, 3, 2],
92
- [2, 6, 3],
93
- [8, 10, -1],
94
- ].map((d) => ({
95
- start: d[0],
96
- end: d[1],
97
- weight: d[2],
98
- }));
110
+ test("Multiple identical overlapping segments", () =>
111
+ testSimpleCoverage(
112
+ [
113
+ [1, 2],
114
+ [3, 4],
115
+ [3, 4],
116
+ [5, 6],
117
+ [5, 6],
118
+ [5, 6],
119
+ ],
120
+ [
121
+ [1, 2, 1],
122
+ [3, 4, 2],
123
+ [5, 6, 3],
124
+ ]
125
+ ));
99
126
 
100
- const coverageSegments = [
101
- [0, 1, 1],
102
- [1, 2, 3],
103
- [2, 3, 6],
104
- [3, 4, 4],
105
- [4, 6, 3],
106
- [8, 10, -1],
107
- ].map((d) => ({
108
- start: d[0],
109
- end: d[1],
110
- coverage: d[2],
111
- }));
127
+ test("Adjacent segments with equal coverage are merged", () =>
128
+ testSimpleCoverage(
129
+ [
130
+ [1, 2],
131
+ [2, 3],
132
+ [3, 4],
133
+ [5, 6],
134
+ [6, 7],
135
+ [7, 8],
136
+ ],
137
+ [
138
+ [1, 4, 1],
139
+ [5, 8, 1],
140
+ ]
141
+ ));
112
142
 
113
- /** @type {CoverageParams} */
114
- const coverageConfig = {
115
- type: "coverage",
116
- chrom: "chrom",
117
- start: "start",
118
- end: "end",
119
- weight: "weight",
120
- };
143
+ test("Chromosomes pass through", () => {
144
+ const reads = [
145
+ { chrom: "chr1", start: 0, end: 1 },
146
+ { chrom: "chr2", start: 0, end: 1 },
147
+ { chrom: "chr3", start: 1, end: 3 },
148
+ ];
149
+
150
+ const coverageSegments = [
151
+ { chrom: "chr1", start: 0, end: 1, coverage: 1 },
152
+ { chrom: "chr2", start: 0, end: 1, coverage: 1 },
153
+ { chrom: "chr3", start: 1, end: 3, coverage: 1 },
154
+ ];
155
+
156
+ /** @type {CoverageParams} */
157
+ const coverageConfig = {
158
+ type: "coverage",
159
+ chrom: "chrom",
160
+ start: "start",
161
+ end: "end",
162
+ };
163
+
164
+ expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
165
+ });
166
+
167
+ test("Typical weighted coverage", () =>
168
+ testWeightedCoverage(
169
+ [
170
+ [0, 4, 1],
171
+ [1, 3, 2],
172
+ [2, 6, 3],
173
+ [8, 10, -1],
174
+ ],
175
+ [
176
+ [0, 1, 1],
177
+ [1, 2, 3],
178
+ [2, 3, 6],
179
+ [3, 4, 4],
180
+ [4, 6, 3],
181
+ [8, 10, -1],
182
+ ]
183
+ ));
184
+
185
+ test("Multiple weights at a single locus", () =>
186
+ testWeightedCoverage(
187
+ [
188
+ // -- Locus 1
189
+ [1, 2, 1],
190
+ [1, 2, 2],
191
+ [1, 2, 3],
192
+ [1, 2, 4],
193
+ [1, 2, 5],
194
+ // -- Locus 2
195
+ [2, 3, 2],
196
+ [2, 3, 3],
197
+ [2, 3, 4],
198
+ [2, 3, 5],
199
+ [2, 3, 6],
200
+ ],
201
+ [
202
+ // -- Locus 1
203
+ [1, 2, 15],
204
+ // -- Locus 2
205
+ [2, 3, 20],
206
+ ]
207
+ ));
121
208
 
122
- expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
209
+ test("Adjacent segments with different weights produce separated segments", () =>
210
+ testWeightedCoverage(
211
+ [
212
+ // -- Cluster 1
213
+ [1, 2, 2],
214
+ [2, 3, 1],
215
+ [3, 4, 1],
216
+ // -- Cluster 2
217
+ [5, 6, 1],
218
+ [6, 7, 2],
219
+ [7, 8, 1],
220
+ // -- Cluster 3
221
+ [9, 10, 1],
222
+ [10, 11, 1],
223
+ [11, 12, 2],
224
+ ],
225
+ [
226
+ // -- Cluster 1
227
+ [1, 2, 2],
228
+ [2, 4, 1],
229
+ // -- Cluster 2
230
+ [5, 6, 1],
231
+ [6, 7, 2],
232
+ [7, 8, 1],
233
+ // -- Cluster 3
234
+ [9, 11, 1],
235
+ [11, 12, 2],
236
+ ]
237
+ ));
123
238
  });
@@ -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: number[] | Float32Array, numComponents: number, divisor?: number}>} */
17
+ /** @type {Object.<string, {data: Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array, numComponents: number, divisor?: number}>} */
17
18
  arrays: {
18
19
  [x: string]: {
19
- data: number[] | Float32Array;
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