gladly-plot 0.0.5 → 0.0.7
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 +253 -92
- package/src/core/Plot.js +644 -162
- 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,237 @@ 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
|
+
const pk = qk.replace(/\./g, '_')
|
|
246
|
+
uniforms[`colorscale${suffix}`] = regl.prop(`colorscale_${pk}`)
|
|
247
|
+
uniforms[`color_range${suffix}`] = regl.prop(`color_range_${pk}`)
|
|
248
|
+
uniforms[`color_scale_type${suffix}`] = regl.prop(`color_scale_type_${pk}`)
|
|
249
|
+
uniforms[`alpha_blend${suffix}`] = regl.prop(`alpha_blend_${pk}`)
|
|
185
250
|
}
|
|
186
251
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
252
|
+
for (const [suffix, qk] of Object.entries(layer.filterAxes)) {
|
|
253
|
+
const pk = qk.replace(/\./g, '_')
|
|
254
|
+
uniforms[`filter_range${suffix}`] = regl.prop(`filter_range_${pk}`)
|
|
255
|
+
uniforms[`filter_scale_type${suffix}`] = regl.prop(`filter_scale_type_${pk}`)
|
|
190
256
|
}
|
|
191
257
|
|
|
192
|
-
//
|
|
258
|
+
// Strip spatial uniforms from vert (re-declared in buildSpatialGlsl)
|
|
259
|
+
vertSrc = removeUniformDecl(vertSrc, 'xDomain')
|
|
260
|
+
vertSrc = removeUniformDecl(vertSrc, 'yDomain')
|
|
261
|
+
vertSrc = removeUniformDecl(vertSrc, 'zDomain')
|
|
262
|
+
vertSrc = removeUniformDecl(vertSrc, 'xScaleType')
|
|
263
|
+
vertSrc = removeUniformDecl(vertSrc, 'yScaleType')
|
|
264
|
+
vertSrc = removeUniformDecl(vertSrc, 'zScaleType')
|
|
265
|
+
vertSrc = removeUniformDecl(vertSrc, 'u_is3D')
|
|
266
|
+
vertSrc = removeUniformDecl(vertSrc, 'u_mvp')
|
|
267
|
+
|
|
193
268
|
const spatialGlsl = buildSpatialGlsl()
|
|
194
|
-
const colorGlsl = layer.colorAxes.length > 0 ? buildColorGlsl() : ''
|
|
195
|
-
const filterGlsl = layer.filterAxes.length > 0 ? buildFilterGlsl() : ''
|
|
196
|
-
const pickVertDecls = `
|
|
269
|
+
const colorGlsl = (Object.keys(layer.colorAxes).length > 0 || Object.keys(layer.colorAxes2d).length > 0) ? buildColorGlsl() : ''
|
|
270
|
+
const filterGlsl = Object.keys(layer.filterAxes).length > 0 ? buildFilterGlsl() : ''
|
|
271
|
+
const pickVertDecls = `in float a_pickId;\nout float v_pickId;`
|
|
272
|
+
|
|
273
|
+
const hasNdColumns = ndColumnHelperLines.length > 0
|
|
274
|
+
const ndColumnHelpersStr = ndColumnHelperLines.join('\n')
|
|
275
|
+
|
|
276
|
+
// Column helpers for vert: precision + all samplers + sampleColumn + sampleColumnND + wrappers
|
|
277
|
+
const columnHelpers = allDataColumns.length > 0
|
|
278
|
+
? [
|
|
279
|
+
'precision highp sampler2D;',
|
|
280
|
+
samplerDecls,
|
|
281
|
+
SAMPLE_COLUMN_GLSL,
|
|
282
|
+
hasNdColumns ? SAMPLE_COLUMN_ND_GLSL : '',
|
|
283
|
+
ndColumnHelpersStr,
|
|
284
|
+
].filter(Boolean).join('\n')
|
|
285
|
+
: ''
|
|
286
|
+
|
|
287
|
+
// Column helpers for frag: only nD column samplers + sampleColumnND + wrappers
|
|
288
|
+
// (1D columns stay in vert; their a_pickId is a vertex attribute)
|
|
289
|
+
const ndFragHelpers = hasNdColumns
|
|
290
|
+
? [
|
|
291
|
+
'precision highp sampler2D;',
|
|
292
|
+
...Object.keys(ndTextures).map(n => `uniform sampler2D ${n};`),
|
|
293
|
+
SAMPLE_COLUMN_ND_GLSL,
|
|
294
|
+
ndColumnHelpersStr,
|
|
295
|
+
].join('\n')
|
|
296
|
+
: ''
|
|
297
|
+
|
|
298
|
+
const fnSuffix = (s) => s.replace(/^_+/, '')
|
|
299
|
+
|
|
300
|
+
const colorHelperLines = []
|
|
301
|
+
let fragSrc = this.frag
|
|
302
|
+
for (const [suffix] of Object.entries(layer.colorAxes)) {
|
|
303
|
+
colorHelperLines.push(
|
|
304
|
+
`uniform int colorscale${suffix};`,
|
|
305
|
+
`uniform vec2 color_range${suffix};`,
|
|
306
|
+
`uniform float color_scale_type${suffix};`,
|
|
307
|
+
`uniform float alpha_blend${suffix};`,
|
|
308
|
+
`vec4 map_color_${fnSuffix(suffix)}(float value) {`,
|
|
309
|
+
` return map_color_s(colorscale${suffix}, color_range${suffix}, value, color_scale_type${suffix}, alpha_blend${suffix});`,
|
|
310
|
+
`}`,
|
|
311
|
+
`vec4 map_color_2d_x_${fnSuffix(suffix)}(float value) {`,
|
|
312
|
+
` return map_color_s_2d(colorscale${suffix}, color_range${suffix}, value, color_scale_type${suffix}, alpha_blend${suffix},`,
|
|
313
|
+
` colorscale${suffix}, color_range${suffix}, 0.0/0.0, color_scale_type${suffix}, 0.0);`,
|
|
314
|
+
`}`,
|
|
315
|
+
`vec4 map_color_2d_y_${fnSuffix(suffix)}(float value) {`,
|
|
316
|
+
` return map_color_s_2d(colorscale${suffix}, color_range${suffix}, 0.0/0.0, color_scale_type${suffix}, 0.0,`,
|
|
317
|
+
` colorscale${suffix}, color_range${suffix}, value, color_scale_type${suffix}, alpha_blend${suffix});`,
|
|
318
|
+
`}`
|
|
319
|
+
)
|
|
320
|
+
fragSrc = removeUniformDecl(fragSrc, `colorscale${suffix}`)
|
|
321
|
+
fragSrc = removeUniformDecl(fragSrc, `color_range${suffix}`)
|
|
322
|
+
fragSrc = removeUniformDecl(fragSrc, `color_scale_type${suffix}`)
|
|
323
|
+
fragSrc = removeUniformDecl(fragSrc, `alpha_blend${suffix}`)
|
|
324
|
+
}
|
|
325
|
+
const colorHelpers = colorHelperLines.join('\n')
|
|
326
|
+
|
|
327
|
+
const color2dHelperLines = []
|
|
328
|
+
for (const [suffix2d, [s1, s2]] of Object.entries(layer.colorAxes2d)) {
|
|
329
|
+
color2dHelperLines.push(
|
|
330
|
+
`vec4 map_color_2d_${fnSuffix(suffix2d)}(vec2 values) {`,
|
|
331
|
+
` return map_color_s_2d(colorscale${s1}, color_range${s1}, values.x, color_scale_type${s1}, alpha_blend${s1},`,
|
|
332
|
+
` colorscale${s2}, color_range${s2}, values.y, color_scale_type${s2}, alpha_blend${s2});`,
|
|
333
|
+
`}`
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
const color2dHelpers = color2dHelperLines.join('\n')
|
|
337
|
+
|
|
338
|
+
const filterHelperLines = []
|
|
339
|
+
for (const [suffix] of Object.entries(layer.filterAxes)) {
|
|
340
|
+
filterHelperLines.push(
|
|
341
|
+
`uniform vec4 filter_range${suffix};`,
|
|
342
|
+
`bool filter_${fnSuffix(suffix)}(float value) {`,
|
|
343
|
+
` return filter_in_range(filter_range${suffix}, value);`,
|
|
344
|
+
`}`
|
|
345
|
+
)
|
|
346
|
+
vertSrc = removeUniformDecl(vertSrc, `filter_range${suffix}`)
|
|
347
|
+
}
|
|
348
|
+
const filterHelpers = filterHelperLines.join('\n')
|
|
197
349
|
|
|
350
|
+
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
351
|
const drawConfig = {
|
|
199
|
-
vert: injectPickIdAssignment(injectInto(vertSrc, [spatialGlsl, filterGlsl,
|
|
200
|
-
frag: injectInto(
|
|
352
|
+
vert: injectPickIdAssignment(injectInto(vertSrc, [spatialGlsl, filterGlsl, filterHelpers, columnHelpers, pickVertDecls])),
|
|
353
|
+
frag: injectIntoMainStart(injectInto(fragSrc, [buildApplyColorGlsl(), buildClipFragGlsl(), colorGlsl, colorHelpers, color2dHelpers, filterGlsl, filterHelpers, ndFragHelpers]), clipFragDiscard),
|
|
201
354
|
attributes,
|
|
202
355
|
uniforms,
|
|
203
356
|
viewport: regl.prop("viewport"),
|
|
204
357
|
primitive: layer.primitive,
|
|
205
358
|
lineWidth: layer.lineWidth,
|
|
206
359
|
count: regl.prop("count"),
|
|
207
|
-
...(layer.
|
|
360
|
+
...(Object.keys(layer.colorAxes).length > 0 || Object.keys(layer.colorAxes2d).length > 0
|
|
361
|
+
? { blend: { enable: true, func: { srcRGB: 'src alpha', dstRGB: 'one minus src alpha', srcAlpha: 0, dstAlpha: 1 } } }
|
|
362
|
+
: layer.blend ? { blend: layer.blend } : {})
|
|
208
363
|
}
|
|
209
364
|
|
|
210
365
|
if (layer.instanceCount !== null) {
|
|
211
366
|
drawConfig.instances = regl.prop("instances")
|
|
212
367
|
}
|
|
213
368
|
|
|
214
|
-
return
|
|
369
|
+
return drawConfig
|
|
215
370
|
}
|
|
216
371
|
|
|
217
372
|
schema(data) {
|
|
@@ -219,43 +374,46 @@ export class LayerType {
|
|
|
219
374
|
throw new Error(`LayerType '${this.name}' does not implement schema()`)
|
|
220
375
|
}
|
|
221
376
|
|
|
222
|
-
// Resolves axis config by merging static declarations with dynamic getAxisConfig output.
|
|
223
|
-
// Dynamic values (non-undefined) override static values.
|
|
224
377
|
resolveAxisConfig(parameters, data) {
|
|
225
378
|
const resolved = {
|
|
226
379
|
xAxis: this.xAxis,
|
|
227
380
|
xAxisQuantityKind: this.xAxisQuantityKind,
|
|
228
381
|
yAxis: this.yAxis,
|
|
229
382
|
yAxisQuantityKind: this.yAxisQuantityKind,
|
|
230
|
-
|
|
231
|
-
|
|
383
|
+
zAxis: this.zAxis,
|
|
384
|
+
zAxisQuantityKind: this.zAxisQuantityKind,
|
|
385
|
+
colorAxisQuantityKinds: { ...this.colorAxisQuantityKinds },
|
|
386
|
+
colorAxis2dQuantityKinds: { ...this.colorAxis2dQuantityKinds },
|
|
387
|
+
filterAxisQuantityKinds: { ...this.filterAxisQuantityKinds },
|
|
232
388
|
}
|
|
233
389
|
|
|
234
390
|
if (this._getAxisConfig) {
|
|
235
391
|
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.
|
|
392
|
+
if (dynamic.xAxis !== undefined) resolved.xAxis = dynamic.xAxis
|
|
393
|
+
if (dynamic.xAxisQuantityKind !== undefined) resolved.xAxisQuantityKind = dynamic.xAxisQuantityKind
|
|
394
|
+
if (dynamic.yAxis !== undefined) resolved.yAxis = dynamic.yAxis
|
|
395
|
+
if (dynamic.yAxisQuantityKind !== undefined) resolved.yAxisQuantityKind = dynamic.yAxisQuantityKind
|
|
396
|
+
if (dynamic.zAxis !== undefined) resolved.zAxis = dynamic.zAxis
|
|
397
|
+
if (dynamic.zAxisQuantityKind !== undefined) resolved.zAxisQuantityKind = dynamic.zAxisQuantityKind
|
|
398
|
+
if (dynamic.colorAxisQuantityKinds !== undefined) resolved.colorAxisQuantityKinds = dynamic.colorAxisQuantityKinds
|
|
399
|
+
if (dynamic.colorAxis2dQuantityKinds !== undefined) resolved.colorAxis2dQuantityKinds = dynamic.colorAxis2dQuantityKinds
|
|
400
|
+
if (dynamic.filterAxisQuantityKinds !== undefined) resolved.filterAxisQuantityKinds = dynamic.filterAxisQuantityKinds
|
|
242
401
|
}
|
|
243
402
|
|
|
244
403
|
return resolved
|
|
245
404
|
}
|
|
246
405
|
|
|
247
|
-
createLayer(parameters, data) {
|
|
406
|
+
async createLayer(regl, parameters, data, plot) {
|
|
248
407
|
if (!this._createLayer) {
|
|
249
408
|
throw new Error(`LayerType '${this.name}' does not implement createLayer()`)
|
|
250
409
|
}
|
|
251
|
-
const gpuConfigs = this._createLayer.call(this, parameters, data)
|
|
410
|
+
const gpuConfigs = await this._createLayer.call(this, regl, parameters, data, plot)
|
|
252
411
|
const axisConfig = this.resolveAxisConfig(parameters, data)
|
|
253
412
|
|
|
254
413
|
return gpuConfigs.map(gpuConfig => new Layer({
|
|
255
414
|
type: this,
|
|
256
415
|
attributes: gpuConfig.attributes ?? {},
|
|
257
416
|
uniforms: gpuConfig.uniforms ?? {},
|
|
258
|
-
nameMap: gpuConfig.nameMap ?? {},
|
|
259
417
|
domains: gpuConfig.domains ?? {},
|
|
260
418
|
lineWidth: gpuConfig.lineWidth ?? 1,
|
|
261
419
|
primitive: gpuConfig.primitive ?? "points",
|
|
@@ -265,9 +423,12 @@ export class LayerType {
|
|
|
265
423
|
blend: gpuConfig.blend ?? null,
|
|
266
424
|
xAxis: axisConfig.xAxis,
|
|
267
425
|
yAxis: axisConfig.yAxis,
|
|
426
|
+
zAxis: axisConfig.zAxis,
|
|
268
427
|
xAxisQuantityKind: axisConfig.xAxisQuantityKind,
|
|
269
428
|
yAxisQuantityKind: axisConfig.yAxisQuantityKind,
|
|
429
|
+
zAxisQuantityKind: axisConfig.zAxisQuantityKind,
|
|
270
430
|
colorAxes: axisConfig.colorAxisQuantityKinds,
|
|
431
|
+
colorAxes2d: axisConfig.colorAxis2dQuantityKinds,
|
|
271
432
|
filterAxes: axisConfig.filterAxisQuantityKinds,
|
|
272
433
|
}))
|
|
273
434
|
}
|