gladly-plot 0.0.5 → 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.
- package/README.md +9 -2
- package/package.json +10 -11
- package/src/axes/Axis.js +320 -172
- package/src/axes/AxisLink.js +6 -2
- package/src/axes/AxisRegistry.js +116 -39
- package/src/axes/Camera.js +47 -0
- package/src/axes/ColorAxisRegistry.js +10 -2
- package/src/axes/FilterAxisRegistry.js +1 -1
- package/src/axes/TickLabelAtlas.js +99 -0
- package/src/axes/ZoomController.js +446 -124
- package/src/colorscales/ColorscaleRegistry.js +30 -10
- package/src/compute/ComputationRegistry.js +126 -184
- package/src/compute/axisFilter.js +21 -9
- package/src/compute/conv.js +64 -8
- package/src/compute/elementwise.js +72 -0
- package/src/compute/fft.js +106 -20
- package/src/compute/filter.js +105 -103
- package/src/compute/hist.js +247 -142
- package/src/compute/kde.js +64 -46
- package/src/compute/scatter2dInterpolate.js +277 -0
- package/src/compute/util.js +196 -0
- package/src/core/ComputePipeline.js +153 -0
- package/src/core/GlBase.js +141 -0
- package/src/core/Layer.js +22 -8
- package/src/core/LayerType.js +251 -92
- package/src/core/Plot.js +630 -152
- package/src/core/PlotGroup.js +204 -0
- package/src/core/ShaderQueue.js +73 -0
- package/src/data/ColumnData.js +269 -0
- package/src/data/Computation.js +95 -0
- package/src/data/Data.js +270 -0
- package/src/floats/Float.js +56 -0
- package/src/index.js +16 -4
- package/src/layers/BarsLayer.js +168 -0
- package/src/layers/ColorbarLayer.js +10 -14
- package/src/layers/ColorbarLayer2d.js +13 -24
- package/src/layers/FilterbarLayer.js +4 -3
- package/src/layers/LinesLayer.js +108 -122
- package/src/layers/PointsLayer.js +73 -69
- package/src/layers/ScatterShared.js +62 -106
- package/src/layers/TileLayer.js +20 -16
- package/src/math/mat4.js +100 -0
- package/src/core/Data.js +0 -67
- package/src/layers/HistogramLayer.js +0 -212
package/src/core/LayerType.js
CHANGED
|
@@ -2,20 +2,52 @@ import { Layer } from "./Layer.js"
|
|
|
2
2
|
import { buildColorGlsl } from "../colorscales/ColorscaleRegistry.js"
|
|
3
3
|
import { buildFilterGlsl } from "../axes/FilterAxisRegistry.js"
|
|
4
4
|
import { resolveAttributeExpr } from "../compute/ComputationRegistry.js"
|
|
5
|
+
import { SAMPLE_COLUMN_GLSL, SAMPLE_COLUMN_ND_GLSL } from "../data/ColumnData.js"
|
|
5
6
|
|
|
6
7
|
function buildSpatialGlsl() {
|
|
7
|
-
return `
|
|
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) {
|
|
8
18
|
float vt = scaleType > 0.5 ? log(v) : v;
|
|
9
19
|
float d0 = scaleType > 0.5 ? log(domain.x) : domain.x;
|
|
10
20
|
float d1 = scaleType > 0.5 ? log(domain.y) : domain.y;
|
|
11
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);
|
|
12
38
|
}`
|
|
13
39
|
}
|
|
14
40
|
|
|
41
|
+
function buildClipFragGlsl() {
|
|
42
|
+
return `in vec3 v_clip_pos;
|
|
43
|
+
uniform float u_is3D;`
|
|
44
|
+
}
|
|
45
|
+
|
|
15
46
|
function buildApplyColorGlsl() {
|
|
16
|
-
return `
|
|
47
|
+
return `out vec4 fragColor;
|
|
48
|
+
uniform float u_pickingMode;
|
|
17
49
|
uniform float u_pickLayerIndex;
|
|
18
|
-
|
|
50
|
+
in float v_pickId;
|
|
19
51
|
vec4 gladly_apply_color(vec4 color) {
|
|
20
52
|
if (u_pickingMode > 0.5) {
|
|
21
53
|
float layerIdx = u_pickLayerIndex + 1.0;
|
|
@@ -31,15 +63,20 @@ vec4 gladly_apply_color(vec4 color) {
|
|
|
31
63
|
}`
|
|
32
64
|
}
|
|
33
65
|
|
|
34
|
-
// Removes `attribute [precision] type varName;` from GLSL source.
|
|
35
66
|
function removeAttributeDecl(src, varName) {
|
|
36
67
|
return src.replace(
|
|
37
|
-
new RegExp(`[ \\t]*
|
|
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'),
|
|
38
76
|
''
|
|
39
77
|
)
|
|
40
78
|
}
|
|
41
79
|
|
|
42
|
-
// Injects code immediately after `void main() {`.
|
|
43
80
|
function injectIntoMainStart(src, code) {
|
|
44
81
|
return src.replace(
|
|
45
82
|
/void\s+main\s*\(\s*(?:void\s*)?\)\s*\{/,
|
|
@@ -69,24 +106,27 @@ function injectInto(src, helpers) {
|
|
|
69
106
|
export class LayerType {
|
|
70
107
|
constructor({
|
|
71
108
|
name,
|
|
72
|
-
// Optional static axis declarations (for schema/introspection — no function call needed)
|
|
73
109
|
xAxis, xAxisQuantityKind,
|
|
74
110
|
yAxis, yAxisQuantityKind,
|
|
111
|
+
zAxis, zAxisQuantityKind,
|
|
75
112
|
colorAxisQuantityKinds,
|
|
113
|
+
colorAxis2dQuantityKinds,
|
|
76
114
|
filterAxisQuantityKinds,
|
|
77
|
-
// Optional dynamic resolver — overrides statics wherever it returns a non-undefined value
|
|
78
115
|
getAxisConfig,
|
|
79
|
-
|
|
80
|
-
|
|
116
|
+
vert, frag, schema, createLayer, createDrawCommand,
|
|
117
|
+
suppressWarnings = false
|
|
81
118
|
}) {
|
|
82
119
|
this.name = name
|
|
83
|
-
|
|
120
|
+
this.suppressWarnings = suppressWarnings
|
|
84
121
|
this.xAxis = xAxis
|
|
85
122
|
this.xAxisQuantityKind = xAxisQuantityKind
|
|
86
123
|
this.yAxis = yAxis
|
|
87
124
|
this.yAxisQuantityKind = yAxisQuantityKind
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
125
|
+
this.zAxis = zAxis ?? null
|
|
126
|
+
this.zAxisQuantityKind = zAxisQuantityKind ?? null
|
|
127
|
+
this.colorAxisQuantityKinds = colorAxisQuantityKinds ?? {}
|
|
128
|
+
this.colorAxis2dQuantityKinds = colorAxis2dQuantityKinds ?? {}
|
|
129
|
+
this.filterAxisQuantityKinds = filterAxisQuantityKinds ?? {}
|
|
90
130
|
this.vert = vert
|
|
91
131
|
this.frag = frag
|
|
92
132
|
|
|
@@ -96,122 +136,235 @@ export class LayerType {
|
|
|
96
136
|
if (createDrawCommand) this.createDrawCommand = createDrawCommand
|
|
97
137
|
}
|
|
98
138
|
|
|
99
|
-
createDrawCommand(regl, layer, plot) {
|
|
100
|
-
|
|
101
|
-
// Rename an internal name to the shader-visible name via nameMap (identity if absent).
|
|
102
|
-
const shaderName = (internalName) => nm[internalName] ?? internalName
|
|
103
|
-
// Build a single-entry uniform object with renamed key reading from the internal prop name.
|
|
104
|
-
const u = (internalName) => ({ [shaderName(internalName)]: regl.prop(internalName) })
|
|
105
|
-
|
|
106
|
-
// --- Resolve computed attributes ---
|
|
139
|
+
async createDrawCommand(regl, layer, plot) {
|
|
140
|
+
// --- Resolve attributes ---
|
|
107
141
|
let vertSrc = this.vert
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
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] }
|
|
115
150
|
|
|
116
151
|
for (const [key, expr] of Object.entries(layer.attributes)) {
|
|
117
|
-
const result = resolveAttributeExpr(regl, expr,
|
|
152
|
+
const result = await resolveAttributeExpr(regl, expr, key, plot)
|
|
118
153
|
if (result.kind === 'buffer') {
|
|
119
|
-
|
|
154
|
+
bufferAttrs[key] = result.value
|
|
120
155
|
} else {
|
|
121
|
-
vertSrc = removeAttributeDecl(vertSrc,
|
|
122
|
-
Object.assign(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
+
}
|
|
128
178
|
}
|
|
129
179
|
}
|
|
130
180
|
|
|
131
|
-
layer.
|
|
181
|
+
layer._dataColumns = allDataColumns
|
|
132
182
|
|
|
133
183
|
if (mainInjections.length > 0) {
|
|
134
184
|
vertSrc = injectIntoMainStart(vertSrc, mainInjections.join('\n '))
|
|
135
185
|
}
|
|
136
186
|
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
+
}
|
|
141
194
|
}
|
|
142
195
|
|
|
196
|
+
// Pick IDs
|
|
143
197
|
const isInstanced = layer.instanceCount !== null
|
|
144
198
|
const pickCount = isInstanced ? layer.instanceCount :
|
|
145
|
-
(layer.vertexCount ??
|
|
146
|
-
|
|
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
|
+
}
|
|
147
208
|
const pickIds = new Float32Array(pickCount)
|
|
148
209
|
for (let i = 0; i < pickCount; i++) pickIds[i] = i
|
|
149
210
|
|
|
150
|
-
//
|
|
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
|
|
151
217
|
const attributes = {
|
|
152
|
-
// Original buffer attrs with possible divisors
|
|
153
218
|
...Object.fromEntries(
|
|
154
|
-
Object.entries(
|
|
219
|
+
Object.entries(bufferAttrs).map(([key, buffer]) => {
|
|
155
220
|
const divisor = layer.attributeDivisors[key]
|
|
156
|
-
|
|
157
|
-
return [shaderName(key), attrObj]
|
|
221
|
+
return [key, divisor !== undefined ? { buffer, divisor } : { buffer }]
|
|
158
222
|
})
|
|
159
223
|
),
|
|
160
|
-
|
|
161
|
-
...Object.fromEntries(
|
|
162
|
-
Object.entries(computedBufferAttrs).map(([shaderKey, buffer]) => [shaderKey, { buffer }])
|
|
163
|
-
),
|
|
164
|
-
a_pickId: isInstanced ? { buffer: regl.buffer(pickIds), divisor: 1 } : regl.buffer(pickIds)
|
|
224
|
+
a_pickId: isInstanced ? { buffer: pickIds, divisor: 1 } : { buffer: pickIds }
|
|
165
225
|
}
|
|
166
226
|
|
|
167
|
-
//
|
|
227
|
+
// Build uniforms
|
|
168
228
|
const uniforms = {
|
|
169
|
-
...
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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'),
|
|
174
239
|
u_pickLayerIndex: regl.prop('u_pickLayerIndex'),
|
|
175
|
-
...
|
|
176
|
-
|
|
177
|
-
),
|
|
178
|
-
...allTextureUniforms,
|
|
179
|
-
...allScalarUniforms
|
|
240
|
+
...layer.uniforms,
|
|
241
|
+
...Object.fromEntries(Object.entries(allTextures).map(([k, fn]) => [k, fn]))
|
|
180
242
|
}
|
|
181
243
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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}`)
|
|
185
249
|
}
|
|
186
250
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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}`)
|
|
190
254
|
}
|
|
191
255
|
|
|
192
|
-
//
|
|
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
|
+
|
|
193
266
|
const spatialGlsl = buildSpatialGlsl()
|
|
194
|
-
const colorGlsl = layer.colorAxes.length > 0 ? buildColorGlsl() : ''
|
|
195
|
-
const filterGlsl = layer.filterAxes.length > 0 ? buildFilterGlsl() : ''
|
|
196
|
-
const pickVertDecls = `
|
|
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')
|
|
197
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;`
|
|
198
349
|
const drawConfig = {
|
|
199
|
-
vert: injectPickIdAssignment(injectInto(vertSrc, [spatialGlsl, filterGlsl,
|
|
200
|
-
frag: injectInto(
|
|
350
|
+
vert: injectPickIdAssignment(injectInto(vertSrc, [spatialGlsl, filterGlsl, filterHelpers, columnHelpers, pickVertDecls])),
|
|
351
|
+
frag: injectIntoMainStart(injectInto(fragSrc, [buildApplyColorGlsl(), buildClipFragGlsl(), colorGlsl, colorHelpers, color2dHelpers, filterGlsl, filterHelpers, ndFragHelpers]), clipFragDiscard),
|
|
201
352
|
attributes,
|
|
202
353
|
uniforms,
|
|
203
354
|
viewport: regl.prop("viewport"),
|
|
204
355
|
primitive: layer.primitive,
|
|
205
356
|
lineWidth: layer.lineWidth,
|
|
206
357
|
count: regl.prop("count"),
|
|
207
|
-
...(layer.
|
|
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 } : {})
|
|
208
361
|
}
|
|
209
362
|
|
|
210
363
|
if (layer.instanceCount !== null) {
|
|
211
364
|
drawConfig.instances = regl.prop("instances")
|
|
212
365
|
}
|
|
213
366
|
|
|
214
|
-
return
|
|
367
|
+
return drawConfig
|
|
215
368
|
}
|
|
216
369
|
|
|
217
370
|
schema(data) {
|
|
@@ -219,43 +372,46 @@ export class LayerType {
|
|
|
219
372
|
throw new Error(`LayerType '${this.name}' does not implement schema()`)
|
|
220
373
|
}
|
|
221
374
|
|
|
222
|
-
// Resolves axis config by merging static declarations with dynamic getAxisConfig output.
|
|
223
|
-
// Dynamic values (non-undefined) override static values.
|
|
224
375
|
resolveAxisConfig(parameters, data) {
|
|
225
376
|
const resolved = {
|
|
226
377
|
xAxis: this.xAxis,
|
|
227
378
|
xAxisQuantityKind: this.xAxisQuantityKind,
|
|
228
379
|
yAxis: this.yAxis,
|
|
229
380
|
yAxisQuantityKind: this.yAxisQuantityKind,
|
|
230
|
-
|
|
231
|
-
|
|
381
|
+
zAxis: this.zAxis,
|
|
382
|
+
zAxisQuantityKind: this.zAxisQuantityKind,
|
|
383
|
+
colorAxisQuantityKinds: { ...this.colorAxisQuantityKinds },
|
|
384
|
+
colorAxis2dQuantityKinds: { ...this.colorAxis2dQuantityKinds },
|
|
385
|
+
filterAxisQuantityKinds: { ...this.filterAxisQuantityKinds },
|
|
232
386
|
}
|
|
233
387
|
|
|
234
388
|
if (this._getAxisConfig) {
|
|
235
389
|
const dynamic = this._getAxisConfig.call(this, parameters, data)
|
|
236
|
-
if (dynamic.xAxis !== undefined)
|
|
237
|
-
if (dynamic.xAxisQuantityKind !== undefined)
|
|
238
|
-
if (dynamic.yAxis !== undefined)
|
|
239
|
-
if (dynamic.yAxisQuantityKind !== undefined)
|
|
240
|
-
if (dynamic.
|
|
241
|
-
if (dynamic.
|
|
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
|
|
242
399
|
}
|
|
243
400
|
|
|
244
401
|
return resolved
|
|
245
402
|
}
|
|
246
403
|
|
|
247
|
-
createLayer(parameters, data) {
|
|
404
|
+
async createLayer(regl, parameters, data, plot) {
|
|
248
405
|
if (!this._createLayer) {
|
|
249
406
|
throw new Error(`LayerType '${this.name}' does not implement createLayer()`)
|
|
250
407
|
}
|
|
251
|
-
const gpuConfigs = this._createLayer.call(this, parameters, data)
|
|
408
|
+
const gpuConfigs = await this._createLayer.call(this, regl, parameters, data, plot)
|
|
252
409
|
const axisConfig = this.resolveAxisConfig(parameters, data)
|
|
253
410
|
|
|
254
411
|
return gpuConfigs.map(gpuConfig => new Layer({
|
|
255
412
|
type: this,
|
|
256
413
|
attributes: gpuConfig.attributes ?? {},
|
|
257
414
|
uniforms: gpuConfig.uniforms ?? {},
|
|
258
|
-
nameMap: gpuConfig.nameMap ?? {},
|
|
259
415
|
domains: gpuConfig.domains ?? {},
|
|
260
416
|
lineWidth: gpuConfig.lineWidth ?? 1,
|
|
261
417
|
primitive: gpuConfig.primitive ?? "points",
|
|
@@ -265,9 +421,12 @@ export class LayerType {
|
|
|
265
421
|
blend: gpuConfig.blend ?? null,
|
|
266
422
|
xAxis: axisConfig.xAxis,
|
|
267
423
|
yAxis: axisConfig.yAxis,
|
|
424
|
+
zAxis: axisConfig.zAxis,
|
|
268
425
|
xAxisQuantityKind: axisConfig.xAxisQuantityKind,
|
|
269
426
|
yAxisQuantityKind: axisConfig.yAxisQuantityKind,
|
|
427
|
+
zAxisQuantityKind: axisConfig.zAxisQuantityKind,
|
|
270
428
|
colorAxes: axisConfig.colorAxisQuantityKinds,
|
|
429
|
+
colorAxes2d: axisConfig.colorAxis2dQuantityKinds,
|
|
271
430
|
filterAxes: axisConfig.filterAxisQuantityKinds,
|
|
272
431
|
}))
|
|
273
432
|
}
|