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.
- package/README.md +9 -2
- package/package.json +10 -11
- package/src/axes/Axis.js +401 -0
- package/src/{AxisLink.js → axes/AxisLink.js} +6 -2
- package/src/{AxisQuantityKindRegistry.js → axes/AxisQuantityKindRegistry.js} +7 -0
- package/src/axes/AxisRegistry.js +179 -0
- package/src/axes/Camera.js +47 -0
- package/src/axes/ColorAxisRegistry.js +101 -0
- package/src/{FilterAxisRegistry.js → axes/FilterAxisRegistry.js} +63 -0
- package/src/axes/TickLabelAtlas.js +99 -0
- package/src/axes/ZoomController.js +463 -0
- package/src/colorscales/BivariateColorscales.js +205 -0
- package/src/colorscales/ColorscaleRegistry.js +144 -0
- package/src/compute/ComputationRegistry.js +179 -0
- package/src/compute/axisFilter.js +59 -0
- package/src/compute/conv.js +286 -0
- package/src/compute/elementwise.js +72 -0
- package/src/compute/fft.js +378 -0
- package/src/compute/filter.js +229 -0
- package/src/compute/hist.js +285 -0
- package/src/compute/kde.js +120 -0
- 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 +59 -0
- package/src/core/LayerType.js +433 -0
- package/src/core/Plot.js +1213 -0
- 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/{Colorbar.js → floats/Colorbar.js} +19 -5
- package/src/floats/Colorbar2d.js +77 -0
- package/src/{Filterbar.js → floats/Filterbar.js} +18 -4
- package/src/{FilterbarFloat.js → floats/Float.js} +73 -30
- package/src/{EpsgUtils.js → geo/EpsgUtils.js} +1 -1
- package/src/index.js +47 -22
- package/src/layers/BarsLayer.js +168 -0
- package/src/{ColorbarLayer.js → layers/ColorbarLayer.js} +12 -16
- package/src/layers/ColorbarLayer2d.js +86 -0
- package/src/{FilterbarLayer.js → layers/FilterbarLayer.js} +6 -5
- package/src/layers/LinesLayer.js +185 -0
- package/src/layers/PointsLayer.js +118 -0
- package/src/layers/ScatterShared.js +98 -0
- package/src/{TileLayer.js → layers/TileLayer.js} +24 -20
- package/src/math/mat4.js +100 -0
- package/src/Axis.js +0 -48
- package/src/AxisRegistry.js +0 -54
- package/src/ColorAxisRegistry.js +0 -49
- package/src/ColorscaleRegistry.js +0 -52
- package/src/Data.js +0 -67
- package/src/Float.js +0 -159
- package/src/Layer.js +0 -44
- package/src/LayerType.js +0 -209
- package/src/Plot.js +0 -1073
- package/src/ScatterLayer.js +0 -287
- /package/src/{MatplotlibColorscales.js → colorscales/MatplotlibColorscales.js} +0 -0
- /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
|
+
}
|