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.
Files changed (44) hide show
  1. package/README.md +9 -2
  2. package/package.json +10 -11
  3. package/src/axes/Axis.js +320 -172
  4. package/src/axes/AxisLink.js +6 -2
  5. package/src/axes/AxisRegistry.js +116 -39
  6. package/src/axes/Camera.js +47 -0
  7. package/src/axes/ColorAxisRegistry.js +10 -2
  8. package/src/axes/FilterAxisRegistry.js +1 -1
  9. package/src/axes/TickLabelAtlas.js +99 -0
  10. package/src/axes/ZoomController.js +446 -124
  11. package/src/colorscales/ColorscaleRegistry.js +30 -10
  12. package/src/compute/ComputationRegistry.js +126 -184
  13. package/src/compute/axisFilter.js +21 -9
  14. package/src/compute/conv.js +64 -8
  15. package/src/compute/elementwise.js +72 -0
  16. package/src/compute/fft.js +106 -20
  17. package/src/compute/filter.js +105 -103
  18. package/src/compute/hist.js +247 -142
  19. package/src/compute/kde.js +64 -46
  20. package/src/compute/scatter2dInterpolate.js +277 -0
  21. package/src/compute/util.js +196 -0
  22. package/src/core/ComputePipeline.js +153 -0
  23. package/src/core/GlBase.js +141 -0
  24. package/src/core/Layer.js +22 -8
  25. package/src/core/LayerType.js +251 -92
  26. package/src/core/Plot.js +630 -152
  27. package/src/core/PlotGroup.js +204 -0
  28. package/src/core/ShaderQueue.js +73 -0
  29. package/src/data/ColumnData.js +269 -0
  30. package/src/data/Computation.js +95 -0
  31. package/src/data/Data.js +270 -0
  32. package/src/floats/Float.js +56 -0
  33. package/src/index.js +16 -4
  34. package/src/layers/BarsLayer.js +168 -0
  35. package/src/layers/ColorbarLayer.js +10 -14
  36. package/src/layers/ColorbarLayer2d.js +13 -24
  37. package/src/layers/FilterbarLayer.js +4 -3
  38. package/src/layers/LinesLayer.js +108 -122
  39. package/src/layers/PointsLayer.js +73 -69
  40. package/src/layers/ScatterShared.js +62 -106
  41. package/src/layers/TileLayer.js +20 -16
  42. package/src/math/mat4.js +100 -0
  43. package/src/core/Data.js +0 -67
  44. package/src/layers/HistogramLayer.js +0 -212
@@ -3,6 +3,7 @@ import { registerLayerType } from "../core/LayerTypeRegistry.js"
3
3
 
4
4
  export const filterbarLayerType = new LayerType({
5
5
  name: "filterbar",
6
+ suppressWarnings: true,
6
7
 
7
8
  getAxisConfig: function(parameters) {
8
9
  const { filterAxis, orientation = "horizontal" } = parameters
@@ -16,15 +17,15 @@ export const filterbarLayerType = new LayerType({
16
17
 
17
18
  // Nothing is rendered — vertexCount is always 0.
18
19
  // These minimal shaders satisfy the WebGL compiler but never execute.
19
- vert: `
20
+ vert: `#version 300 es
20
21
  precision mediump float;
21
22
  uniform vec2 xDomain;
22
23
  uniform vec2 yDomain;
23
24
  void main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }
24
25
  `,
25
- frag: `
26
+ frag: `#version 300 es
26
27
  precision mediump float;
27
- void main() { gl_FragColor = gladly_apply_color(vec4(0.0, 0.0, 0.0, 0.0)); }
28
+ void main() { fragColor = gladly_apply_color(vec4(0.0, 0.0, 0.0, 0.0)); }
28
29
  `,
29
30
 
30
31
  schema: () => ({
@@ -1,117 +1,94 @@
1
1
  // Lines mode uses instanced rendering:
2
- // - Template: 2 vertices with a_endPoint in {0.0, 1.0} (divisor=0 → interpolates)
3
- // - Per-segment: a_x0/x1, a_y0/y1, a_v0/v1, a_seg0/seg1 (divisor=1 constant per instance)
4
- //
5
- // Because a_v0 and a_v1 are instanced, they are the same at both template vertices for a given
6
- // segment, so varyings set from them are constant across the line (no GPU interpolation).
7
- // Only v_t (from a_endPoint) interpolates, giving the position along the segment.
2
+ // - Template: 2 vertices with a_endPoint in {0.0, 1.0} (divisor=0 → per-vertex)
3
+ // - Per-segment data (x0/x1, y0/y1, v0/v1, seg0/seg1, f0/f1) sampled from GPU textures
4
+ // using a_pickId (= gl_InstanceID) + 0.0 or + 1.0 as the index.
8
5
  //
9
6
  // Segment boundary handling: when a_seg0 != a_seg1, collapse both template vertices to
10
7
  // (a_x0, a_y0) producing a zero-length degenerate line that the rasterizer discards.
11
8
 
12
9
  import { ScatterLayerTypeBase } from "./ScatterShared.js"
13
- import { Data } from "../core/Data.js"
10
+ import { Data } from "../data/Data.js"
14
11
  import { registerLayerType } from "../core/LayerTypeRegistry.js"
12
+ import { EXPRESSION_REF_OPT, resolveQuantityKind, resolveExprToColumn } from "../compute/ComputationRegistry.js"
15
13
 
16
- function makeLinesVert(hasFilter) {
17
- return `
14
+ function makeLinesVert(hasFilter, hasSegIds, hasV, hasV2, hasZ) {
15
+ return `#version 300 es
18
16
  precision mediump float;
19
- attribute float a_endPoint;
20
- attribute float a_x0, a_y0;
21
- attribute float a_x1, a_y1;
22
- attribute float a_v0, a_v1;
23
- attribute float a_v20, a_v21;
24
- attribute float a_seg0, a_seg1;
25
- ${hasFilter ? 'attribute float a_f0, a_f1;\n uniform vec4 filter_range;' : ''}
17
+ in float a_endPoint;
18
+ in float a_x0;
19
+ in float a_y0;
20
+ ${hasZ ? 'in float a_z0;\n in float a_z1;' : ''}
21
+ in float a_x1;
22
+ in float a_y1;
23
+ ${hasV ? 'in float a_v0;\n in float a_v1;' : ''}
24
+ ${hasV2 ? 'in float a_v20;\n in float a_v21;' : ''}
25
+ ${hasSegIds ? 'in float a_seg0;\n in float a_seg1;' : ''}
26
+ ${hasFilter ? 'in float a_f0;\n in float a_f1;' : ''}
26
27
  uniform vec2 xDomain;
27
28
  uniform vec2 yDomain;
28
29
  uniform float xScaleType;
29
30
  uniform float yScaleType;
30
- varying float v_color_start;
31
- varying float v_color_end;
32
- varying float v_color2_start;
33
- varying float v_color2_end;
34
- varying float v_t;
31
+ out float v_color_start;
32
+ out float v_color_end;
33
+ out float v_color2_start;
34
+ out float v_color2_end;
35
+ out float v_t;
35
36
  void main() {
36
- float same_seg = abs(a_seg0 - a_seg1) < 0.5 ? 1.0 : 0.0;
37
- ${hasFilter ? 'if (!filter_in_range(filter_range, a_f0) || !filter_in_range(filter_range, a_f1)) same_seg = 0.0;' : ''}
37
+ float same_seg = ${hasSegIds ? 'abs(a_seg0 - a_seg1) < 0.5 ? 1.0 : 0.0' : '1.0'};
38
+ ${hasFilter ? 'if (!filter_(a_f0) || !filter_(a_f1)) same_seg = 0.0;' : ''}
38
39
  float t = same_seg * a_endPoint;
39
40
  float x = mix(a_x0, a_x1, t);
40
41
  float y = mix(a_y0, a_y1, t);
41
- float nx = normalize_axis(x, xDomain, xScaleType);
42
- float ny = normalize_axis(y, yDomain, yScaleType);
43
- gl_Position = vec4(nx * 2.0 - 1.0, ny * 2.0 - 1.0, 0, 1);
44
- v_color_start = a_v0;
45
- v_color_end = a_v1;
46
- v_color2_start = a_v20;
47
- v_color2_end = a_v21;
42
+ ${hasZ ? 'float z = mix(a_z0, a_z1, t);\n gl_Position = plot_pos_3d(vec3(x, y, z));'
43
+ : 'gl_Position = plot_pos(vec2(x, y));'}
44
+ v_color_start = ${hasV ? 'a_v0' : '0.0'};
45
+ v_color_end = ${hasV ? 'a_v1' : '0.0'};
46
+ v_color2_start = ${hasV2 ? 'a_v20' : '0.0'};
47
+ v_color2_end = ${hasV2 ? 'a_v21' : '0.0'};
48
48
  v_t = a_endPoint;
49
49
  }
50
50
  `
51
51
  }
52
52
 
53
- const LINES_FRAG = `
53
+ function makeLinesFrag(hasFirst, hasSecond) {
54
+ return `#version 300 es
54
55
  precision mediump float;
55
-
56
- uniform int colorscale;
57
- uniform vec2 color_range;
58
- uniform float color_scale_type;
59
-
60
- uniform int colorscale2;
61
- uniform vec2 color_range2;
62
- uniform float color_scale_type2;
63
-
64
- uniform float alphaBlend;
65
56
  uniform float u_lineColorMode;
66
- uniform float u_useSecondColor;
67
-
68
- varying float v_color_start;
69
- varying float v_color_end;
70
- varying float v_color2_start;
71
- varying float v_color2_end;
72
- varying float v_t;
73
-
57
+ in float v_color_start;
58
+ in float v_color_end;
59
+ in float v_color2_start;
60
+ in float v_color2_end;
61
+ in float v_t;
74
62
  void main() {
63
+ ${!hasFirst ? `
64
+ fragColor = vec4(0.0, 0.0, 0.0, 1.0);` : hasSecond ? `
75
65
  float value = u_lineColorMode > 0.5
76
66
  ? (v_t < 0.5 ? v_color_start : v_color_end)
77
67
  : mix(v_color_start, v_color_end, v_t);
78
-
79
- if (u_useSecondColor > 0.5) {
80
- float value2 = u_lineColorMode > 0.5
81
- ? (v_t < 0.5 ? v_color2_start : v_color2_end)
82
- : mix(v_color2_start, v_color2_end, v_t);
83
-
84
- gl_FragColor = map_color_s_2d(
85
- colorscale, color_range, value, color_scale_type,
86
- colorscale2, color_range2, value2, color_scale_type2
87
- );
88
-
89
- if (alphaBlend > 0.5) {
90
- gl_FragColor.a *= gl_FragColor.a;
91
- }
92
- } else {
93
- gl_FragColor = map_color_s(colorscale, color_range, value, color_scale_type, alphaBlend);
94
- }
68
+ float value2 = u_lineColorMode > 0.5
69
+ ? (v_t < 0.5 ? v_color2_start : v_color2_end)
70
+ : mix(v_color2_start, v_color2_end, v_t);
71
+ fragColor = map_color_2d_(vec2(value, value2));` : `
72
+ float value = u_lineColorMode > 0.5
73
+ ? (v_t < 0.5 ? v_color_start : v_color_end)
74
+ : mix(v_color_start, v_color_end, v_t);
75
+ fragColor = map_color_(value);`}
95
76
  }
96
77
  `
78
+ }
97
79
 
98
80
  class LinesLayerType extends ScatterLayerTypeBase {
99
81
  constructor() {
100
- super({ name: "lines", vert: makeLinesVert(false), frag: LINES_FRAG })
82
+ super({ name: "lines", vert: makeLinesVert(false, false, false, false), frag: makeLinesFrag(false, false) })
101
83
  }
102
84
 
103
85
  schema(data) {
104
- const dataProperties = Data.wrap(data).columns()
86
+ const d = Data.wrap(data)
105
87
  return {
106
- $schema: "https://json-schema.org/draft/2020-12/schema",
107
88
  type: "object",
108
89
  properties: {
109
- ...this._commonSchemaProperties(dataProperties),
110
- lineSegmentIdData: {
111
- type: "string",
112
- enum: dataProperties,
113
- description: "Column for segment IDs; only consecutive points sharing the same ID are connected"
114
- },
90
+ ...this._commonSchemaProperties(d),
91
+ lineSegmentIdData: EXPRESSION_REF_OPT,
115
92
  lineColorMode: {
116
93
  type: "string",
117
94
  enum: ["gradient", "midpoint"],
@@ -125,73 +102,82 @@ class LinesLayerType extends ScatterLayerTypeBase {
125
102
  description: "Line width in pixels (note: browsers may clamp values above 1)"
126
103
  }
127
104
  },
128
- required: ["xData", "yData", "vData"]
105
+ required: ["xData", "yData", "zData", "zAxis"]
129
106
  }
130
107
  }
131
108
 
132
- _createLayer(parameters, data) {
109
+ async _createLayer(regl, parameters, data, plot) {
133
110
  const d = Data.wrap(data)
134
- const { lineSegmentIdData, lineColorMode = "gradient", lineWidth = 1.0 } = parameters
135
- const { xData, yData, vData, vData2, fData, alphaBlend, xQK, yQK, vQK, vQK2, fQK, srcX, srcY, srcV, srcV2, srcF } =
136
- this._resolveColorData(parameters, d)
137
-
138
- const useSecond = vData2 ? 1.0 : 0.0
139
- const domains = this._buildDomains(d, xData, yData, vData, vData2, xQK, yQK, vQK, vQK2)
140
- const blendConfig = this._buildBlendConfig(alphaBlend)
141
-
142
- const N = srcX.length
143
- const segIds = lineSegmentIdData ? d.getData(lineSegmentIdData) : null
144
- const zeroSegs = new Float32Array(N - 1)
145
- const seg0 = segIds ? segIds.subarray(0, N - 1) : zeroSegs
146
- const seg1 = segIds ? segIds.subarray(1, N) : zeroSegs
111
+ const { lineSegmentIdData: lineSegmentIdDataRaw, lineColorMode = "gradient", lineWidth = 1.0 } = parameters
112
+ const lineSegmentIdData = (lineSegmentIdDataRaw == null || lineSegmentIdDataRaw === "none") ? null : lineSegmentIdDataRaw
113
+ const { xData, yData, zData: zDataOrig, vData: vDataOrig, vData2: vData2Orig, fData: fDataOrig } = parameters
114
+ const zData = (zDataOrig == null || zDataOrig === "none") ? null : zDataOrig
115
+ const vData = (vDataOrig == null || vDataOrig === "none") ? null : vDataOrig
116
+ const vData2 = (vData2Orig == null || vData2Orig === "none") ? null : vData2Orig
117
+ const fData = (fDataOrig == null || fDataOrig === "none") ? null : fDataOrig
118
+
119
+ const xQK = resolveQuantityKind(xData, d) ?? xData
120
+ const yQK = resolveQuantityKind(yData, d) ?? yData
121
+ const zQK = zData ? (resolveQuantityKind(zData, d) ?? zData) : null
122
+ const vQK = vData ? (resolveQuantityKind(vData, d) ?? vData) : null
123
+ const vQK2 = vData2 ? (resolveQuantityKind(vData2, d) ?? vData2) : null
124
+
125
+ const colX = await resolveExprToColumn(xData, d, regl, plot)
126
+ const colY = await resolveExprToColumn(yData, d, regl, plot)
127
+ const colZ = zData ? await resolveExprToColumn(zData, d, regl, plot) : null
128
+ const colV = vData ? await resolveExprToColumn(vData, d, regl, plot) : null
129
+ const colV2 = vData2 ? await resolveExprToColumn(vData2, d, regl, plot) : null
130
+ const colF = fData ? await resolveExprToColumn(fData, d, regl, plot) : null
131
+ const colSeg = lineSegmentIdData ? await resolveExprToColumn(lineSegmentIdData, d, regl, plot) : null
132
+
133
+ if (!colX) throw new Error(`Data column '${xData}' not found`)
134
+ if (!colY) throw new Error(`Data column '${yData}' not found`)
135
+
136
+ const N = colX.length
137
+ const domains = this._buildDomains(d, xData, yData, zData, vData, vData2, xQK, yQK, zQK, vQK, vQK2)
138
+
139
+ // For vData: if a string column, offset-sample start/end; if a computed expression,
140
+ // pass through as-is (both endpoints get the same value, matching old behaviour).
141
+ const vAttr0 = vData ? (colV ? colV.withOffset('0.0') : vData) : null
142
+ const vAttr1 = vData ? (colV ? colV.withOffset('1.0') : vData) : null
143
+ const vAttr20 = vData2 ? (colV2 ? colV2.withOffset('0.0') : vData2) : null
144
+ const vAttr21 = vData2 ? (colV2 ? colV2.withOffset('1.0') : vData2) : null
147
145
 
148
146
  return [{
149
147
  attributes: {
150
148
  a_endPoint: new Float32Array([0.0, 1.0]),
151
- a_x0: srcX.subarray(0, N - 1),
152
- a_x1: srcX.subarray(1, N),
153
- a_y0: srcY.subarray(0, N - 1),
154
- a_y1: srcY.subarray(1, N),
155
- a_v0: vData ? srcV.subarray(0, N - 1) : new Float32Array(N - 1),
156
- a_v1: vData ? srcV.subarray(1, N) : new Float32Array(N - 1),
157
- a_v20: vData2 ? srcV2.subarray(0, N - 1) : new Float32Array(N - 1),
158
- a_v21: vData2 ? srcV2.subarray(1, N) : new Float32Array(N - 1),
159
- a_seg0: seg0,
160
- a_seg1: seg1,
161
- ...(fData ? {
162
- a_f0: srcF.subarray(0, N - 1),
163
- a_f1: srcF.subarray(1, N),
164
- } : {}),
165
- },
166
- attributeDivisors: {
167
- a_x0: 1, a_x1: 1,
168
- a_y0: 1, a_y1: 1,
169
- a_v0: 1, a_v1: 1,
170
- a_v20: 1, a_v21: 1,
171
- a_seg0: 1, a_seg1: 1,
172
- ...(fData ? { a_f0: 1, a_f1: 1 } : {}),
149
+ a_x0: colX.withOffset('0.0'),
150
+ a_x1: colX.withOffset('1.0'),
151
+ a_y0: colY.withOffset('0.0'),
152
+ a_y1: colY.withOffset('1.0'),
153
+ ...(colZ ? { a_z0: colZ.withOffset('0.0'), a_z1: colZ.withOffset('1.0') } : {}),
154
+ ...(vAttr0 !== null ? { a_v0: vAttr0, a_v1: vAttr1 } : {}),
155
+ ...(vAttr20 !== null ? { a_v20: vAttr20, a_v21: vAttr21 } : {}),
156
+ ...(colSeg ? { a_seg0: colSeg.withOffset('0.0'), a_seg1: colSeg.withOffset('1.0') } : {}),
157
+ ...(fData ? { a_f0: colF.withOffset('0.0'), a_f1: colF.withOffset('1.0') } : {}),
173
158
  },
174
159
  uniforms: {
175
- alphaBlend: alphaBlend ? 1.0 : 0.0,
176
160
  u_lineColorMode: lineColorMode === "midpoint" ? 1.0 : 0.0,
177
- u_useSecondColor: useSecond,
178
- ...(vData ? {} : { colorscale: 0, color_range: [0, 1], color_scale_type: 0.0 }),
179
- ...(vData2 ? {} : { colorscale2: 0, color_range2: [0, 1], color_scale_type2: 0.0 })
180
161
  },
181
- nameMap: this._buildNameMap(vData, vQK, vData2, vQK2, fData, fQK),
182
162
  domains,
183
163
  primitive: "lines",
184
164
  lineWidth,
185
165
  vertexCount: 2,
186
166
  instanceCount: N - 1,
187
- blend: blendConfig,
188
167
  }]
189
168
  }
190
169
 
191
- createDrawCommand(regl, layer) {
192
- const hasFilter = layer.filterAxes.length > 0
193
- this.vert = makeLinesVert(hasFilter)
194
- return super.createDrawCommand(regl, layer)
170
+ async createDrawCommand(regl, layer, plot) {
171
+ const hasFilter = Object.keys(layer.filterAxes).length > 0
172
+ const hasFirst = '' in layer.colorAxes
173
+ const hasSecond = '2' in layer.colorAxes
174
+ const hasSegIds = 'a_seg0' in layer.attributes
175
+ const hasV = 'a_v0' in layer.attributes
176
+ const hasV2 = 'a_v20' in layer.attributes
177
+ const hasZ = 'a_z0' in layer.attributes
178
+ this.vert = makeLinesVert(hasFilter, hasSegIds, hasV, hasV2, hasZ)
179
+ this.frag = makeLinesFrag(hasFirst, hasSecond)
180
+ return await super.createDrawCommand(regl, layer, plot)
195
181
  }
196
182
  }
197
183
 
@@ -1,112 +1,116 @@
1
1
  import { ScatterLayerTypeBase } from "./ScatterShared.js"
2
- import { Data } from "../core/Data.js"
2
+ import { Data } from "../data/Data.js"
3
3
  import { registerLayerType } from "../core/LayerTypeRegistry.js"
4
+ import { resolveQuantityKind } from "../compute/ComputationRegistry.js"
4
5
 
5
- function makePointsVert(hasFilter) {
6
- return `
6
+ function makePointsVert(hasFilter, hasZ) {
7
+ return `#version 300 es
7
8
  precision mediump float;
8
- attribute float x;
9
- attribute float y;
10
- attribute float color_data;
11
- attribute float color_data2;
12
- ${hasFilter ? 'attribute float filter_data;\n uniform vec4 filter_range;' : ''}
9
+ in float x;
10
+ in float y;
11
+ ${hasZ ? 'in float z;' : ''}
12
+ in float color_data;
13
+ in float color_data2;
14
+ ${hasFilter ? 'in float filter_data;' : ''}
13
15
  uniform vec2 xDomain;
14
16
  uniform vec2 yDomain;
15
17
  uniform float xScaleType;
16
18
  uniform float yScaleType;
17
- varying float value;
18
- varying float value2;
19
+ uniform float u_pointSize;
20
+ out float value;
21
+ out float value2;
19
22
  void main() {
20
- ${hasFilter ? 'if (!filter_in_range(filter_range, filter_data)) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; }' : ''}
21
- float nx = normalize_axis(x, xDomain, xScaleType);
22
- float ny = normalize_axis(y, yDomain, yScaleType);
23
- gl_Position = vec4(nx*2.0-1.0, ny*2.0-1.0, 0, 1);
24
- gl_PointSize = 4.0;
23
+ ${hasFilter ? 'if (!filter_(filter_data)) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; }' : ''}
24
+ ${hasZ ? 'gl_Position = plot_pos_3d(vec3(x, y, z));' : 'gl_Position = plot_pos(vec2(x, y));'}
25
+ gl_PointSize = u_pointSize;
25
26
  value = color_data;
26
27
  value2 = color_data2;
27
28
  }
28
29
  `
29
30
  }
30
31
 
31
- const POINTS_FRAG = `
32
+ function makePointsFrag(hasFirst, hasSecond) {
33
+ return `#version 300 es
32
34
  precision mediump float;
33
- uniform int colorscale;
34
- uniform vec2 color_range;
35
- uniform float color_scale_type;
36
-
37
- uniform int colorscale2;
38
- uniform vec2 color_range2;
39
- uniform float color_scale_type2;
40
-
41
- uniform float alphaBlend;
42
- uniform float u_useSecondColor;
43
-
44
- varying float value;
45
- varying float value2;
46
-
35
+ in float value;
36
+ in float value2;
47
37
  void main() {
48
- if (u_useSecondColor > 0.5) {
49
- gl_FragColor = map_color_s_2d(
50
- colorscale, color_range, value, color_scale_type,
51
- colorscale2, color_range2, value2, color_scale_type2
52
- );
53
- if (alphaBlend > 0.5) {
54
- gl_FragColor.a *= gl_FragColor.a;
55
- }
56
- } else {
57
- gl_FragColor = map_color_s(colorscale, color_range, value, color_scale_type, alphaBlend);
58
- }
38
+ ${hasFirst
39
+ ? (hasSecond
40
+ ? 'fragColor = map_color_2d_(vec2(value, value2));'
41
+ : 'fragColor = map_color_2d_x_(value);')
42
+ : (hasSecond
43
+ ? 'fragColor = map_color_2d_y_2(value2);'
44
+ : 'fragColor = vec4(0.0, 0.0, 0.0, 1.0);')}
59
45
  }
60
46
  `
47
+ }
61
48
 
62
49
  class PointsLayerType extends ScatterLayerTypeBase {
63
50
  constructor() {
64
- super({ name: "points", vert: makePointsVert(false), frag: POINTS_FRAG })
51
+ super({ name: "points", vert: makePointsVert(false), frag: makePointsFrag(false) })
65
52
  }
66
53
 
67
54
  schema(data) {
68
- const dataProperties = Data.wrap(data).columns()
55
+ const d = Data.wrap(data)
69
56
  return {
70
- $schema: "https://json-schema.org/draft/2020-12/schema",
71
57
  type: "object",
72
- properties: this._commonSchemaProperties(dataProperties),
73
- required: ["xData", "yData", "vData"]
58
+ properties: {
59
+ ...this._commonSchemaProperties(d),
60
+ pointSize: { type: "integer", default: 4, minimum: 1 },
61
+ },
62
+ required: ["xData", "yData", "zData", "zAxis", "pointSize"]
74
63
  }
75
64
  }
76
65
 
77
- _createLayer(parameters, data) {
66
+ _createLayer(regl, parameters, data, plot) {
78
67
  const d = Data.wrap(data)
79
- const { xData, yData, vData, vData2, fData, alphaBlend, xQK, yQK, vQK, vQK2, fQK, srcX, srcY, srcV, srcV2, srcF } =
80
- this._resolveColorData(parameters, d)
68
+ const { vData: vDataRaw, vData2: vData2Raw, fData: fDataRaw, zData: zDataRaw } = parameters
69
+ const vDataIn = (vDataRaw == null || vDataRaw === "none") ? null : vDataRaw
70
+ const vData2In = (vData2Raw == null || vData2Raw === "none") ? null : vData2Raw
71
+ const fData = (fDataRaw == null || fDataRaw === "none") ? null : fDataRaw
72
+ const zData = (zDataRaw == null || zDataRaw === "none") ? null : zDataRaw
73
+ const vData = vDataIn
74
+ const vData2 = vData2In
75
+
76
+ const xQK = resolveQuantityKind(parameters.xData, d) ?? undefined
77
+ const yQK = resolveQuantityKind(parameters.yData, d) ?? undefined
78
+ const zQK = zData ? (resolveQuantityKind(zData, d) ?? undefined) : undefined
79
+ const vQK = vData ? resolveQuantityKind(vData, d) : null
80
+ const vQK2 = vData2 ? resolveQuantityKind(vData2, d) : null
81
81
 
82
- const useSecond = vData2 ? 1.0 : 0.0
83
- const domains = this._buildDomains(d, xData, yData, vData, vData2, xQK, yQK, vQK, vQK2)
84
- const blendConfig = this._buildBlendConfig(alphaBlend)
82
+ const domains = this._buildDomains(d, parameters.xData, parameters.yData, zData, vData, vData2, xQK, yQK, zQK, vQK, vQK2)
83
+
84
+ // Vertex count: read from data when xData is a plain column name so that
85
+ // Plot.render() can determine how many vertices to draw even when other
86
+ // attributes are computed expressions resolved at draw time.
87
+ const vertexCount = typeof parameters.xData === 'string'
88
+ ? (d.getData(parameters.xData)?.length ?? null)
89
+ : null
85
90
 
86
91
  return [{
87
92
  attributes: {
88
- x: srcX,
89
- y: srcY,
90
- color_data: vData ? srcV : new Float32Array(srcX.length),
91
- color_data2: vData2 ? srcV2 : new Float32Array(srcX.length),
92
- ...(fData ? { filter_data: srcF } : {}),
93
- },
94
- uniforms: {
95
- alphaBlend: alphaBlend ? 1.0 : 0.0,
96
- u_useSecondColor: useSecond,
97
- ...(vData ? {} : { colorscale: 0, color_range: [0, 1], color_scale_type: 0.0 }),
98
- ...(vData2 ? {} : { colorscale2: 0, color_range2: [0, 1], color_scale_type2: 0.0 })
93
+ x: parameters.xData,
94
+ y: parameters.yData,
95
+ ...(zData !== null ? { z: zData } : {}),
96
+ color_data: vData !== null ? vData : new Float32Array(vertexCount ?? 0).fill(NaN),
97
+ color_data2: vData2 !== null ? vData2 : new Float32Array(vertexCount ?? 0).fill(NaN),
98
+ ...(fData != null ? { filter_data: fData } : {}),
99
99
  },
100
+ uniforms: { u_pointSize: () => parameters.pointSize ?? 4 },
100
101
  domains,
101
- nameMap: this._buildNameMap(vData, vQK, vData2, vQK2, fData, fQK),
102
- blend: blendConfig,
102
+ vertexCount,
103
103
  }]
104
104
  }
105
105
 
106
- createDrawCommand(regl, layer) {
107
- const hasFilter = layer.filterAxes.length > 0
108
- this.vert = makePointsVert(hasFilter)
109
- return super.createDrawCommand(regl, layer)
106
+ async createDrawCommand(regl, layer, plot) {
107
+ const hasFilter = Object.keys(layer.filterAxes).length > 0
108
+ const hasFirst = '' in layer.colorAxes
109
+ const hasSecond = '2' in layer.colorAxes
110
+ const hasZ = 'z' in layer.attributes
111
+ this.vert = makePointsVert(hasFilter, hasZ)
112
+ this.frag = makePointsFrag(hasFirst, hasSecond)
113
+ return await super.createDrawCommand(regl, layer, plot)
110
114
  }
111
115
  }
112
116