gladly-plot 0.0.4 → 0.0.6

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.
Files changed (60) hide show
  1. package/README.md +9 -2
  2. package/package.json +10 -11
  3. package/src/axes/Axis.js +401 -0
  4. package/src/{AxisLink.js → axes/AxisLink.js} +6 -2
  5. package/src/{AxisQuantityKindRegistry.js → axes/AxisQuantityKindRegistry.js} +7 -0
  6. package/src/axes/AxisRegistry.js +179 -0
  7. package/src/axes/Camera.js +47 -0
  8. package/src/axes/ColorAxisRegistry.js +101 -0
  9. package/src/{FilterAxisRegistry.js → axes/FilterAxisRegistry.js} +63 -0
  10. package/src/axes/TickLabelAtlas.js +99 -0
  11. package/src/axes/ZoomController.js +463 -0
  12. package/src/colorscales/BivariateColorscales.js +205 -0
  13. package/src/colorscales/ColorscaleRegistry.js +144 -0
  14. package/src/compute/ComputationRegistry.js +179 -0
  15. package/src/compute/axisFilter.js +59 -0
  16. package/src/compute/conv.js +286 -0
  17. package/src/compute/elementwise.js +72 -0
  18. package/src/compute/fft.js +378 -0
  19. package/src/compute/filter.js +229 -0
  20. package/src/compute/hist.js +285 -0
  21. package/src/compute/kde.js +120 -0
  22. package/src/compute/scatter2dInterpolate.js +277 -0
  23. package/src/compute/util.js +196 -0
  24. package/src/core/ComputePipeline.js +153 -0
  25. package/src/core/GlBase.js +141 -0
  26. package/src/core/Layer.js +59 -0
  27. package/src/core/LayerType.js +433 -0
  28. package/src/core/Plot.js +1213 -0
  29. package/src/core/PlotGroup.js +204 -0
  30. package/src/core/ShaderQueue.js +73 -0
  31. package/src/data/ColumnData.js +269 -0
  32. package/src/data/Computation.js +95 -0
  33. package/src/data/Data.js +270 -0
  34. package/src/{Colorbar.js → floats/Colorbar.js} +19 -5
  35. package/src/floats/Colorbar2d.js +77 -0
  36. package/src/{Filterbar.js → floats/Filterbar.js} +18 -4
  37. package/src/{FilterbarFloat.js → floats/Float.js} +73 -30
  38. package/src/{EpsgUtils.js → geo/EpsgUtils.js} +1 -1
  39. package/src/index.js +47 -22
  40. package/src/layers/BarsLayer.js +168 -0
  41. package/src/{ColorbarLayer.js → layers/ColorbarLayer.js} +12 -16
  42. package/src/layers/ColorbarLayer2d.js +86 -0
  43. package/src/{FilterbarLayer.js → layers/FilterbarLayer.js} +6 -5
  44. package/src/layers/LinesLayer.js +185 -0
  45. package/src/layers/PointsLayer.js +118 -0
  46. package/src/layers/ScatterShared.js +98 -0
  47. package/src/{TileLayer.js → layers/TileLayer.js} +24 -20
  48. package/src/math/mat4.js +100 -0
  49. package/src/Axis.js +0 -48
  50. package/src/AxisRegistry.js +0 -54
  51. package/src/ColorAxisRegistry.js +0 -49
  52. package/src/ColorscaleRegistry.js +0 -52
  53. package/src/Data.js +0 -67
  54. package/src/Float.js +0 -159
  55. package/src/Layer.js +0 -44
  56. package/src/LayerType.js +0 -209
  57. package/src/Plot.js +0 -1073
  58. package/src/ScatterLayer.js +0 -287
  59. /package/src/{MatplotlibColorscales.js → colorscales/MatplotlibColorscales.js} +0 -0
  60. /package/src/{LayerTypeRegistry.js → core/LayerTypeRegistry.js} +0 -0
@@ -0,0 +1,433 @@
1
+ import { Layer } from "./Layer.js"
2
+ import { buildColorGlsl } from "../colorscales/ColorscaleRegistry.js"
3
+ import { buildFilterGlsl } from "../axes/FilterAxisRegistry.js"
4
+ import { resolveAttributeExpr } from "../compute/ComputationRegistry.js"
5
+ import { SAMPLE_COLUMN_GLSL, SAMPLE_COLUMN_ND_GLSL } from "../data/ColumnData.js"
6
+
7
+ function buildSpatialGlsl() {
8
+ return `uniform vec2 xDomain;
9
+ uniform vec2 yDomain;
10
+ uniform vec2 zDomain;
11
+ uniform float xScaleType;
12
+ uniform float yScaleType;
13
+ uniform float zScaleType;
14
+ uniform float u_is3D;
15
+ uniform mat4 u_mvp;
16
+ out vec3 v_clip_pos;
17
+ float normalize_axis(float v, vec2 domain, float scaleType) {
18
+ float vt = scaleType > 0.5 ? log(v) : v;
19
+ float d0 = scaleType > 0.5 ? log(domain.x) : domain.x;
20
+ float d1 = scaleType > 0.5 ? log(domain.y) : domain.y;
21
+ return (vt - d0) / (d1 - d0);
22
+ }
23
+ vec4 plot_pos_3d(vec3 pos) {
24
+ float nx = normalize_axis(pos.x, xDomain, xScaleType);
25
+ float ny = normalize_axis(pos.y, yDomain, yScaleType);
26
+ float nz = normalize_axis(pos.z, zDomain, zScaleType);
27
+ v_clip_pos = vec3(nx, ny, nz);
28
+ return u_mvp * vec4(nx*2.0-1.0, ny*2.0-1.0, nz*2.0-1.0, 1.0);
29
+ }
30
+ vec4 plot_pos(vec2 pos) {
31
+ float nx = normalize_axis(pos.x, xDomain, xScaleType);
32
+ float ny = normalize_axis(pos.y, yDomain, yScaleType);
33
+ if (u_is3D > 0.5) {
34
+ return plot_pos_3d(vec3(pos, zDomain.x));
35
+ }
36
+ v_clip_pos = vec3(nx, ny, 0.5);
37
+ return u_mvp * vec4(nx*2.0-1.0, ny*2.0-1.0, 0.0, 1.0);
38
+ }`
39
+ }
40
+
41
+ function buildClipFragGlsl() {
42
+ return `in vec3 v_clip_pos;
43
+ uniform float u_is3D;`
44
+ }
45
+
46
+ function buildApplyColorGlsl() {
47
+ return `out vec4 fragColor;
48
+ uniform float u_pickingMode;
49
+ uniform float u_pickLayerIndex;
50
+ in float v_pickId;
51
+ vec4 gladly_apply_color(vec4 color) {
52
+ if (u_pickingMode > 0.5) {
53
+ float layerIdx = u_pickLayerIndex + 1.0;
54
+ float dataIdx = floor(v_pickId + 0.5);
55
+ return vec4(
56
+ layerIdx / 255.0,
57
+ floor(dataIdx / 65536.0) / 255.0,
58
+ floor(mod(dataIdx, 65536.0) / 256.0) / 255.0,
59
+ mod(dataIdx, 256.0) / 255.0
60
+ );
61
+ }
62
+ return color;
63
+ }`
64
+ }
65
+
66
+ function removeAttributeDecl(src, varName) {
67
+ return src.replace(
68
+ new RegExp(`[ \\t]*in\\s+(?:(?:lowp|mediump|highp)\\s+)?\\w+\\s+${varName}\\s*;[ \\t]*\\n?`, 'g'),
69
+ ''
70
+ )
71
+ }
72
+
73
+ function removeUniformDecl(src, varName) {
74
+ return src.replace(
75
+ new RegExp(`[ \\t]*uniform\\s+(?:(?:lowp|mediump|highp)\\s+)?\\w+\\s+${varName}\\s*;[ \\t]*\\n?`, 'g'),
76
+ ''
77
+ )
78
+ }
79
+
80
+ function injectIntoMainStart(src, code) {
81
+ return src.replace(
82
+ /void\s+main\s*\(\s*(?:void\s*)?\)\s*\{/,
83
+ match => `${match}\n ${code}`
84
+ )
85
+ }
86
+
87
+ function injectPickIdAssignment(src) {
88
+ const lastBrace = src.lastIndexOf('}')
89
+ if (lastBrace === -1) return src
90
+ return src.slice(0, lastBrace) + ' v_pickId = a_pickId;\n}'
91
+ }
92
+
93
+ function injectInto(src, helpers) {
94
+ const injected = helpers.filter(Boolean).join('\n')
95
+ if (!injected) return src
96
+ const versionRe = /^[ \t]*#version[^\n]*\n?/
97
+ const versionMatch = src.match(versionRe)
98
+ const version = versionMatch ? versionMatch[0] : ''
99
+ const rest = version ? src.slice(version.length) : src
100
+ const precisionRe = /^\s*precision\s+\S+\s+\S+\s*;\s*$/mg
101
+ const precisions = rest.match(precisionRe) ?? []
102
+ const body = rest.replace(precisionRe, '')
103
+ return version + precisions.join('\n') + '\n' + injected + '\n' + body
104
+ }
105
+
106
+ export class LayerType {
107
+ constructor({
108
+ name,
109
+ xAxis, xAxisQuantityKind,
110
+ yAxis, yAxisQuantityKind,
111
+ zAxis, zAxisQuantityKind,
112
+ colorAxisQuantityKinds,
113
+ colorAxis2dQuantityKinds,
114
+ filterAxisQuantityKinds,
115
+ getAxisConfig,
116
+ vert, frag, schema, createLayer, createDrawCommand,
117
+ suppressWarnings = false
118
+ }) {
119
+ this.name = name
120
+ this.suppressWarnings = suppressWarnings
121
+ this.xAxis = xAxis
122
+ this.xAxisQuantityKind = xAxisQuantityKind
123
+ this.yAxis = yAxis
124
+ this.yAxisQuantityKind = yAxisQuantityKind
125
+ this.zAxis = zAxis ?? null
126
+ this.zAxisQuantityKind = zAxisQuantityKind ?? null
127
+ this.colorAxisQuantityKinds = colorAxisQuantityKinds ?? {}
128
+ this.colorAxis2dQuantityKinds = colorAxis2dQuantityKinds ?? {}
129
+ this.filterAxisQuantityKinds = filterAxisQuantityKinds ?? {}
130
+ this.vert = vert
131
+ this.frag = frag
132
+
133
+ if (schema) this._schema = schema
134
+ if (createLayer) this._createLayer = createLayer
135
+ if (getAxisConfig) this._getAxisConfig = getAxisConfig
136
+ if (createDrawCommand) this.createDrawCommand = createDrawCommand
137
+ }
138
+
139
+ async createDrawCommand(regl, layer, plot) {
140
+ // --- Resolve attributes ---
141
+ let vertSrc = this.vert
142
+ const bufferAttrs = {} // name → Float32Array (fixed geometry)
143
+ const allTextures = {} // uniformName → () => texture
144
+ const allDataColumns = [] // ColumnData instances for refresh()
145
+ const mainInjections = [] // float name = expr; injected inside main()
146
+
147
+ const ndTextures = {} // sampler2D textures for nD columns only (also in allTextures)
148
+ const ndColumnHelperLines = [] // shape uniform decls + typed wrapper fns
149
+ const ndShapeUniforms = {} // { u_col_name_shape: [x, y, z, w] }
150
+
151
+ for (const [key, expr] of Object.entries(layer.attributes)) {
152
+ const result = await resolveAttributeExpr(regl, expr, key, plot)
153
+ if (result.kind === 'buffer') {
154
+ bufferAttrs[key] = result.value
155
+ } else {
156
+ vertSrc = removeAttributeDecl(vertSrc, key)
157
+ Object.assign(allTextures, result.textures)
158
+ allDataColumns.push(result.col)
159
+
160
+ if (result.col.ndim === 1) {
161
+ mainInjections.push(`float ${key} = ${result.glslExpr};`)
162
+ } else {
163
+ // nD column: inject shape uniform + typed wrapper; skip auto-assignment
164
+ const uName = `u_col_${key}`
165
+ const s = result.col.shape
166
+ ndShapeUniforms[`${uName}_shape`] = [s[0] ?? 1, s[1] ?? 1, s[2] ?? 1, s[3] ?? 1]
167
+ Object.assign(ndTextures, result.textures)
168
+ const ndim = result.col.ndim
169
+ const ivecType = ndim <= 2 ? 'ivec2' : ndim === 3 ? 'ivec3' : 'ivec4'
170
+ const idxExpand = ndim <= 2 ? `ivec4(idx, 0, 0)` : ndim === 3 ? `ivec4(idx, 0)` : `idx`
171
+ ndColumnHelperLines.push(
172
+ `uniform ivec4 ${uName}_shape;`,
173
+ `float sample_${key}(${ivecType} idx) {`,
174
+ ` return sampleColumnND(${uName}, ${uName}_shape, ${idxExpand});`,
175
+ `}`
176
+ )
177
+ }
178
+ }
179
+ }
180
+
181
+ layer._dataColumns = allDataColumns
182
+
183
+ if (mainInjections.length > 0) {
184
+ vertSrc = injectIntoMainStart(vertSrc, mainInjections.join('\n '))
185
+ }
186
+
187
+ // Validate buffer attributes
188
+ if (!this.suppressWarnings) {
189
+ for (const [key, buf] of Object.entries(bufferAttrs)) {
190
+ if (buf instanceof Float32Array && buf.length === 0) {
191
+ console.warn(`[gladly] Layer '${this.name}': buffer attribute '${key}' is an empty Float32Array — this layer may draw nothing`)
192
+ }
193
+ }
194
+ }
195
+
196
+ // Pick IDs
197
+ const isInstanced = layer.instanceCount !== null
198
+ const pickCount = isInstanced ? layer.instanceCount :
199
+ (layer.vertexCount ??
200
+ Object.values(bufferAttrs).find(v => v instanceof Float32Array)?.length ?? 0)
201
+ if (pickCount === 0 && !this.suppressWarnings) {
202
+ console.warn(
203
+ `[gladly] Layer '${this.name}': ` +
204
+ `${isInstanced ? 'instanceCount' : 'vertex count'} resolved to 0 — ` +
205
+ `this layer will draw nothing. Check that data columns are non-empty.`
206
+ )
207
+ }
208
+ const pickIds = new Float32Array(pickCount)
209
+ for (let i = 0; i < pickCount; i++) pickIds[i] = i
210
+
211
+ // Sampler declarations for column textures
212
+ const samplerDecls = Object.keys(allTextures)
213
+ .map(n => `uniform sampler2D ${n};`)
214
+ .join('\n')
215
+
216
+ // Build regl attributes
217
+ const attributes = {
218
+ ...Object.fromEntries(
219
+ Object.entries(bufferAttrs).map(([key, buffer]) => {
220
+ const divisor = layer.attributeDivisors[key]
221
+ return [key, divisor !== undefined ? { buffer, divisor } : { buffer }]
222
+ })
223
+ ),
224
+ a_pickId: isInstanced ? { buffer: pickIds, divisor: 1 } : { buffer: pickIds }
225
+ }
226
+
227
+ // Build uniforms
228
+ const uniforms = {
229
+ ...ndShapeUniforms,
230
+ xDomain: regl.prop("xDomain"),
231
+ yDomain: regl.prop("yDomain"),
232
+ zDomain: regl.prop("zDomain"),
233
+ xScaleType: regl.prop("xScaleType"),
234
+ yScaleType: regl.prop("yScaleType"),
235
+ zScaleType: regl.prop("zScaleType"),
236
+ u_is3D: regl.prop("u_is3D"),
237
+ u_mvp: regl.prop("u_mvp"),
238
+ u_pickingMode: regl.prop('u_pickingMode'),
239
+ u_pickLayerIndex: regl.prop('u_pickLayerIndex'),
240
+ ...layer.uniforms,
241
+ ...Object.fromEntries(Object.entries(allTextures).map(([k, fn]) => [k, fn]))
242
+ }
243
+
244
+ for (const [suffix, qk] of Object.entries(layer.colorAxes)) {
245
+ uniforms[`colorscale${suffix}`] = regl.prop(`colorscale_${qk}`)
246
+ uniforms[`color_range${suffix}`] = regl.prop(`color_range_${qk}`)
247
+ uniforms[`color_scale_type${suffix}`] = regl.prop(`color_scale_type_${qk}`)
248
+ uniforms[`alpha_blend${suffix}`] = regl.prop(`alpha_blend_${qk}`)
249
+ }
250
+
251
+ for (const [suffix, qk] of Object.entries(layer.filterAxes)) {
252
+ uniforms[`filter_range${suffix}`] = regl.prop(`filter_range_${qk}`)
253
+ uniforms[`filter_scale_type${suffix}`] = regl.prop(`filter_scale_type_${qk}`)
254
+ }
255
+
256
+ // Strip spatial uniforms from vert (re-declared in buildSpatialGlsl)
257
+ vertSrc = removeUniformDecl(vertSrc, 'xDomain')
258
+ vertSrc = removeUniformDecl(vertSrc, 'yDomain')
259
+ vertSrc = removeUniformDecl(vertSrc, 'zDomain')
260
+ vertSrc = removeUniformDecl(vertSrc, 'xScaleType')
261
+ vertSrc = removeUniformDecl(vertSrc, 'yScaleType')
262
+ vertSrc = removeUniformDecl(vertSrc, 'zScaleType')
263
+ vertSrc = removeUniformDecl(vertSrc, 'u_is3D')
264
+ vertSrc = removeUniformDecl(vertSrc, 'u_mvp')
265
+
266
+ const spatialGlsl = buildSpatialGlsl()
267
+ const colorGlsl = (Object.keys(layer.colorAxes).length > 0 || Object.keys(layer.colorAxes2d).length > 0) ? buildColorGlsl() : ''
268
+ const filterGlsl = Object.keys(layer.filterAxes).length > 0 ? buildFilterGlsl() : ''
269
+ const pickVertDecls = `in float a_pickId;\nout float v_pickId;`
270
+
271
+ const hasNdColumns = ndColumnHelperLines.length > 0
272
+ const ndColumnHelpersStr = ndColumnHelperLines.join('\n')
273
+
274
+ // Column helpers for vert: precision + all samplers + sampleColumn + sampleColumnND + wrappers
275
+ const columnHelpers = allDataColumns.length > 0
276
+ ? [
277
+ 'precision highp sampler2D;',
278
+ samplerDecls,
279
+ SAMPLE_COLUMN_GLSL,
280
+ hasNdColumns ? SAMPLE_COLUMN_ND_GLSL : '',
281
+ ndColumnHelpersStr,
282
+ ].filter(Boolean).join('\n')
283
+ : ''
284
+
285
+ // Column helpers for frag: only nD column samplers + sampleColumnND + wrappers
286
+ // (1D columns stay in vert; their a_pickId is a vertex attribute)
287
+ const ndFragHelpers = hasNdColumns
288
+ ? [
289
+ 'precision highp sampler2D;',
290
+ ...Object.keys(ndTextures).map(n => `uniform sampler2D ${n};`),
291
+ SAMPLE_COLUMN_ND_GLSL,
292
+ ndColumnHelpersStr,
293
+ ].join('\n')
294
+ : ''
295
+
296
+ const fnSuffix = (s) => s.replace(/^_+/, '')
297
+
298
+ const colorHelperLines = []
299
+ let fragSrc = this.frag
300
+ for (const [suffix] of Object.entries(layer.colorAxes)) {
301
+ colorHelperLines.push(
302
+ `uniform int colorscale${suffix};`,
303
+ `uniform vec2 color_range${suffix};`,
304
+ `uniform float color_scale_type${suffix};`,
305
+ `uniform float alpha_blend${suffix};`,
306
+ `vec4 map_color_${fnSuffix(suffix)}(float value) {`,
307
+ ` return map_color_s(colorscale${suffix}, color_range${suffix}, value, color_scale_type${suffix}, alpha_blend${suffix});`,
308
+ `}`,
309
+ `vec4 map_color_2d_x_${fnSuffix(suffix)}(float value) {`,
310
+ ` return map_color_s_2d(colorscale${suffix}, color_range${suffix}, value, color_scale_type${suffix}, alpha_blend${suffix},`,
311
+ ` colorscale${suffix}, color_range${suffix}, 0.0/0.0, color_scale_type${suffix}, 0.0);`,
312
+ `}`,
313
+ `vec4 map_color_2d_y_${fnSuffix(suffix)}(float value) {`,
314
+ ` return map_color_s_2d(colorscale${suffix}, color_range${suffix}, 0.0/0.0, color_scale_type${suffix}, 0.0,`,
315
+ ` colorscale${suffix}, color_range${suffix}, value, color_scale_type${suffix}, alpha_blend${suffix});`,
316
+ `}`
317
+ )
318
+ fragSrc = removeUniformDecl(fragSrc, `colorscale${suffix}`)
319
+ fragSrc = removeUniformDecl(fragSrc, `color_range${suffix}`)
320
+ fragSrc = removeUniformDecl(fragSrc, `color_scale_type${suffix}`)
321
+ fragSrc = removeUniformDecl(fragSrc, `alpha_blend${suffix}`)
322
+ }
323
+ const colorHelpers = colorHelperLines.join('\n')
324
+
325
+ const color2dHelperLines = []
326
+ for (const [suffix2d, [s1, s2]] of Object.entries(layer.colorAxes2d)) {
327
+ color2dHelperLines.push(
328
+ `vec4 map_color_2d_${fnSuffix(suffix2d)}(vec2 values) {`,
329
+ ` return map_color_s_2d(colorscale${s1}, color_range${s1}, values.x, color_scale_type${s1}, alpha_blend${s1},`,
330
+ ` colorscale${s2}, color_range${s2}, values.y, color_scale_type${s2}, alpha_blend${s2});`,
331
+ `}`
332
+ )
333
+ }
334
+ const color2dHelpers = color2dHelperLines.join('\n')
335
+
336
+ const filterHelperLines = []
337
+ for (const [suffix] of Object.entries(layer.filterAxes)) {
338
+ filterHelperLines.push(
339
+ `uniform vec4 filter_range${suffix};`,
340
+ `bool filter_${fnSuffix(suffix)}(float value) {`,
341
+ ` return filter_in_range(filter_range${suffix}, value);`,
342
+ `}`
343
+ )
344
+ vertSrc = removeUniformDecl(vertSrc, `filter_range${suffix}`)
345
+ }
346
+ const filterHelpers = filterHelperLines.join('\n')
347
+
348
+ const clipFragDiscard = `if (u_is3D > 0.5 && (v_clip_pos.x < 0.0 || v_clip_pos.x > 1.0 || v_clip_pos.y < 0.0 || v_clip_pos.y > 1.0 || v_clip_pos.z < 0.0 || v_clip_pos.z > 1.0)) discard;`
349
+ const drawConfig = {
350
+ vert: injectPickIdAssignment(injectInto(vertSrc, [spatialGlsl, filterGlsl, filterHelpers, columnHelpers, pickVertDecls])),
351
+ frag: injectIntoMainStart(injectInto(fragSrc, [buildApplyColorGlsl(), buildClipFragGlsl(), colorGlsl, colorHelpers, color2dHelpers, filterGlsl, filterHelpers, ndFragHelpers]), clipFragDiscard),
352
+ attributes,
353
+ uniforms,
354
+ viewport: regl.prop("viewport"),
355
+ primitive: layer.primitive,
356
+ lineWidth: layer.lineWidth,
357
+ count: regl.prop("count"),
358
+ ...(Object.keys(layer.colorAxes).length > 0 || Object.keys(layer.colorAxes2d).length > 0
359
+ ? { blend: { enable: true, func: { srcRGB: 'src alpha', dstRGB: 'one minus src alpha', srcAlpha: 0, dstAlpha: 1 } } }
360
+ : layer.blend ? { blend: layer.blend } : {})
361
+ }
362
+
363
+ if (layer.instanceCount !== null) {
364
+ drawConfig.instances = regl.prop("instances")
365
+ }
366
+
367
+ return drawConfig
368
+ }
369
+
370
+ schema(data) {
371
+ if (this._schema) return this._schema(data)
372
+ throw new Error(`LayerType '${this.name}' does not implement schema()`)
373
+ }
374
+
375
+ resolveAxisConfig(parameters, data) {
376
+ const resolved = {
377
+ xAxis: this.xAxis,
378
+ xAxisQuantityKind: this.xAxisQuantityKind,
379
+ yAxis: this.yAxis,
380
+ yAxisQuantityKind: this.yAxisQuantityKind,
381
+ zAxis: this.zAxis,
382
+ zAxisQuantityKind: this.zAxisQuantityKind,
383
+ colorAxisQuantityKinds: { ...this.colorAxisQuantityKinds },
384
+ colorAxis2dQuantityKinds: { ...this.colorAxis2dQuantityKinds },
385
+ filterAxisQuantityKinds: { ...this.filterAxisQuantityKinds },
386
+ }
387
+
388
+ if (this._getAxisConfig) {
389
+ const dynamic = this._getAxisConfig.call(this, parameters, data)
390
+ if (dynamic.xAxis !== undefined) resolved.xAxis = dynamic.xAxis
391
+ if (dynamic.xAxisQuantityKind !== undefined) resolved.xAxisQuantityKind = dynamic.xAxisQuantityKind
392
+ if (dynamic.yAxis !== undefined) resolved.yAxis = dynamic.yAxis
393
+ if (dynamic.yAxisQuantityKind !== undefined) resolved.yAxisQuantityKind = dynamic.yAxisQuantityKind
394
+ if (dynamic.zAxis !== undefined) resolved.zAxis = dynamic.zAxis
395
+ if (dynamic.zAxisQuantityKind !== undefined) resolved.zAxisQuantityKind = dynamic.zAxisQuantityKind
396
+ if (dynamic.colorAxisQuantityKinds !== undefined) resolved.colorAxisQuantityKinds = dynamic.colorAxisQuantityKinds
397
+ if (dynamic.colorAxis2dQuantityKinds !== undefined) resolved.colorAxis2dQuantityKinds = dynamic.colorAxis2dQuantityKinds
398
+ if (dynamic.filterAxisQuantityKinds !== undefined) resolved.filterAxisQuantityKinds = dynamic.filterAxisQuantityKinds
399
+ }
400
+
401
+ return resolved
402
+ }
403
+
404
+ async createLayer(regl, parameters, data, plot) {
405
+ if (!this._createLayer) {
406
+ throw new Error(`LayerType '${this.name}' does not implement createLayer()`)
407
+ }
408
+ const gpuConfigs = await this._createLayer.call(this, regl, parameters, data, plot)
409
+ const axisConfig = this.resolveAxisConfig(parameters, data)
410
+
411
+ return gpuConfigs.map(gpuConfig => new Layer({
412
+ type: this,
413
+ attributes: gpuConfig.attributes ?? {},
414
+ uniforms: gpuConfig.uniforms ?? {},
415
+ domains: gpuConfig.domains ?? {},
416
+ lineWidth: gpuConfig.lineWidth ?? 1,
417
+ primitive: gpuConfig.primitive ?? "points",
418
+ vertexCount: gpuConfig.vertexCount ?? null,
419
+ instanceCount: gpuConfig.instanceCount ?? null,
420
+ attributeDivisors: gpuConfig.attributeDivisors ?? {},
421
+ blend: gpuConfig.blend ?? null,
422
+ xAxis: axisConfig.xAxis,
423
+ yAxis: axisConfig.yAxis,
424
+ zAxis: axisConfig.zAxis,
425
+ xAxisQuantityKind: axisConfig.xAxisQuantityKind,
426
+ yAxisQuantityKind: axisConfig.yAxisQuantityKind,
427
+ zAxisQuantityKind: axisConfig.zAxisQuantityKind,
428
+ colorAxes: axisConfig.colorAxisQuantityKinds,
429
+ colorAxes2d: axisConfig.colorAxis2dQuantityKinds,
430
+ filterAxes: axisConfig.filterAxisQuantityKinds,
431
+ }))
432
+ }
433
+ }