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.
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 +253 -92
  26. package/src/core/Plot.js +644 -162
  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
@@ -0,0 +1,270 @@
1
+ import { ArrayColumn, TextureColumn } from './ColumnData.js'
2
+
3
+ function domainsEqual(a, b) {
4
+ if (a === b) return true
5
+ if (a == null || b == null) return a === b
6
+ return a[0] === b[0] && a[1] === b[1]
7
+ }
8
+
9
+ // Runtime wrapper for a ComputedData instance. Manages live texture references
10
+ // and tracks which axes were accessed so it can recompute when they change.
11
+ export class ComputedDataNode {
12
+ constructor(computedData, params) {
13
+ this._computedData = computedData
14
+ this._params = params
15
+ this._liveRefs = {} // { colName: { texture } }
16
+ this._meta = null
17
+ this._accessedAxes = new Set()
18
+ this._cachedDomains = {}
19
+ this._regl = null
20
+ this._dataGroup = null
21
+ this._version = 0
22
+ }
23
+
24
+ columns() {
25
+ return this._computedData.columns(this._params)
26
+ }
27
+
28
+ getData(col) {
29
+ const ref = this._liveRefs[col]
30
+ if (!ref) return null
31
+ const node = this
32
+ let lastVersion = this._version
33
+ return new TextureColumn(ref, {
34
+ domain: this._meta?.domains?.[col] ?? null,
35
+ quantityKind: this._meta?.quantityKinds?.[col] ?? null,
36
+ length: ref.texture ? (ref.texture._dataLength ?? ref.texture.width) : null,
37
+ shape: this._meta?.shapes?.[col] ?? null,
38
+ refreshFn: async (plot) => {
39
+ await node.refreshIfNeeded(plot)
40
+ if (node._version !== lastVersion) {
41
+ lastVersion = node._version
42
+ return true
43
+ }
44
+ return false
45
+ }
46
+ })
47
+ }
48
+
49
+ getQuantityKind(col) {
50
+ return this._meta?.quantityKinds?.[col] ?? null
51
+ }
52
+
53
+ getDomain(col) {
54
+ return this._meta?.domains?.[col] ?? null
55
+ }
56
+
57
+ async _initialize(regl, dataGroup, plot) {
58
+ this._regl = regl
59
+ this._dataGroup = dataGroup
60
+
61
+ const getAxisDomain = (axisId) => {
62
+ this._accessedAxes.add(axisId)
63
+ return plot ? plot.getAxisDomain(axisId) : null
64
+ }
65
+
66
+ const result = await this._computedData.compute(regl, this._params, dataGroup, getAxisDomain)
67
+ this._meta = result._meta ?? null
68
+
69
+ for (const [key, val] of Object.entries(result)) {
70
+ if (key === '_meta') continue
71
+ this._liveRefs[key] = { texture: val }
72
+ }
73
+
74
+ for (const axisId of this._accessedAxes) {
75
+ this._cachedDomains[axisId] = plot ? plot.getAxisDomain(axisId) : null
76
+ }
77
+ }
78
+
79
+ async refreshIfNeeded(plot) {
80
+ if (this._accessedAxes.size === 0) return
81
+
82
+ let needsRecompute = false
83
+ for (const axisId of this._accessedAxes) {
84
+ if (!domainsEqual(plot.getAxisDomain(axisId), this._cachedDomains[axisId])) {
85
+ needsRecompute = true
86
+ break
87
+ }
88
+ }
89
+ if (!needsRecompute) return
90
+
91
+ const newAccessedAxes = new Set()
92
+ const newCachedDomains = {}
93
+ const getAxisDomain = (axisId) => {
94
+ newAccessedAxes.add(axisId)
95
+ return plot ? plot.getAxisDomain(axisId) : null
96
+ }
97
+
98
+ const result = await this._computedData.compute(this._regl, this._params, this._dataGroup, getAxisDomain)
99
+ this._meta = result._meta ?? null
100
+
101
+ for (const [key, val] of Object.entries(result)) {
102
+ if (key === '_meta') continue
103
+ if (this._liveRefs[key]) {
104
+ this._liveRefs[key].texture = val
105
+ } else {
106
+ this._liveRefs[key] = { texture: val }
107
+ }
108
+ }
109
+
110
+ this._accessedAxes = newAccessedAxes
111
+ for (const axisId of newAccessedAxes) {
112
+ newCachedDomains[axisId] = plot ? plot.getAxisDomain(axisId) : null
113
+ }
114
+ this._cachedDomains = newCachedDomains
115
+ this._version++
116
+ }
117
+ }
118
+
119
+ export class DataGroup {
120
+ constructor(raw) {
121
+ this._children = {}
122
+ for (const [key, value] of Object.entries(raw)) {
123
+ this._children[key] = Data.wrap(value)
124
+ }
125
+ }
126
+
127
+ listData() {
128
+ const result = {}
129
+ for (const [key, child] of Object.entries(this._children)) {
130
+ if (child instanceof Data) result[key] = child
131
+ }
132
+ return result
133
+ }
134
+
135
+ subgroups() {
136
+ const result = {}
137
+ for (const [key, child] of Object.entries(this._children)) {
138
+ if (child instanceof DataGroup) result[key] = child
139
+ }
140
+ return result
141
+ }
142
+
143
+ columns() {
144
+ const cols = []
145
+ for (const [key, child] of Object.entries(this._children)) {
146
+ for (const col of child.columns()) {
147
+ cols.push(`${key}.${col}`)
148
+ }
149
+ }
150
+ return cols
151
+ }
152
+
153
+ _resolve(col) {
154
+ const dotIdx = col.indexOf('.')
155
+ if (dotIdx === -1) return null
156
+ const prefix = col.slice(0, dotIdx)
157
+ const rest = col.slice(dotIdx + 1)
158
+ const child = this._children[prefix]
159
+ if (!child) return null
160
+ return { child, rest }
161
+ }
162
+
163
+ getData(col) {
164
+ const r = this._resolve(col)
165
+ return r ? r.child.getData(r.rest) : undefined
166
+ }
167
+
168
+ getQuantityKind(col) {
169
+ const r = this._resolve(col)
170
+ return r ? r.child.getQuantityKind(r.rest) : undefined
171
+ }
172
+
173
+ getDomain(col) {
174
+ const r = this._resolve(col)
175
+ return r ? r.child.getDomain(r.rest) : undefined
176
+ }
177
+ }
178
+
179
+ export function normalizeData(data) {
180
+ if (data == null) return null
181
+ const wrapped = Data.wrap(data)
182
+ return (wrapped instanceof DataGroup) ? wrapped : new DataGroup({ input: wrapped })
183
+ }
184
+
185
+ export class Data {
186
+ constructor(raw) {
187
+ raw = raw ?? {}
188
+ if (raw.data != null && typeof raw.data === 'object' && !(raw.data instanceof Float32Array)) {
189
+ this._columnar = true
190
+ this._data = raw.data
191
+ this._quantityKinds = raw.quantity_kinds ?? {}
192
+ this._rawDomains = raw.domains ?? {}
193
+ } else {
194
+ this._columnar = false
195
+ this._raw = raw
196
+ }
197
+ }
198
+
199
+ static wrap(data) {
200
+ if (data != null && typeof data.columns === 'function' && typeof data.getData === 'function') {
201
+ return data
202
+ }
203
+
204
+ if (data != null && typeof data === 'object') {
205
+ const isColumnar = data.data != null && typeof data.data === 'object' && !(data.data instanceof Float32Array)
206
+
207
+ if (!isColumnar) {
208
+ const vals = Object.values(data)
209
+ if (vals.length > 0) {
210
+ const isRawFormat = vals.every(v =>
211
+ v instanceof Float32Array ||
212
+ (v && typeof v === 'object' && v.data instanceof Float32Array)
213
+ )
214
+ if (!isRawFormat) {
215
+ return new DataGroup(data)
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ return new Data(data)
222
+ }
223
+
224
+ _entry(col) {
225
+ if (this._columnar) {
226
+ const rawDomain = this._rawDomains[col]
227
+ let domain
228
+ if (Array.isArray(rawDomain)) {
229
+ domain = [rawDomain[0], rawDomain[1]]
230
+ } else if (rawDomain && typeof rawDomain === 'object') {
231
+ domain = [rawDomain.min, rawDomain.max]
232
+ }
233
+ return { data: this._data[col], quantityKind: this._quantityKinds[col], domain }
234
+ }
235
+
236
+ const v = this._raw[col]
237
+ if (v instanceof Float32Array) {
238
+ return { data: v, quantityKind: undefined, domain: undefined }
239
+ }
240
+ if (v && typeof v === 'object') {
241
+ let domain
242
+ if (Array.isArray(v.domain)) {
243
+ domain = [v.domain[0], v.domain[1]]
244
+ } else if (v.domain && typeof v.domain === 'object') {
245
+ domain = [v.domain.min, v.domain.max]
246
+ }
247
+ return { data: v.data, quantityKind: v.quantity_kind, domain }
248
+ }
249
+ return { data: undefined, quantityKind: undefined, domain: undefined }
250
+ }
251
+
252
+ columns() {
253
+ return this._columnar ? Object.keys(this._data) : Object.keys(this._raw)
254
+ }
255
+
256
+ // Returns ArrayColumn (with domain + quantityKind) or null if column not found.
257
+ getData(col) {
258
+ const entry = this._entry(col)
259
+ if (!entry.data) return null
260
+ return new ArrayColumn(entry.data, { domain: entry.domain ?? null, quantityKind: entry.quantityKind ?? null })
261
+ }
262
+
263
+ getQuantityKind(col) {
264
+ return this._entry(col).quantityKind
265
+ }
266
+
267
+ getDomain(col) {
268
+ return this._entry(col).domain
269
+ }
270
+ }
@@ -128,11 +128,67 @@ export class Float {
128
128
  document.addEventListener('mousemove', onMouseMove)
129
129
  document.addEventListener('mouseup', onMouseUp)
130
130
 
131
+ // Touch support
132
+ const onDragBarTouchStart = (e) => {
133
+ if (e.touches.length !== 1) return
134
+ e.preventDefault()
135
+ const t = e.touches[0]
136
+ mode = 'drag'
137
+ startX = t.clientX
138
+ startY = t.clientY
139
+ startLeft = parseInt(this._el.style.left, 10)
140
+ startTop = parseInt(this._el.style.top, 10)
141
+ this._dragBar.style.cursor = 'grabbing'
142
+ }
143
+
144
+ const onResizeTouchStart = (e) => {
145
+ if (e.touches.length !== 1) return
146
+ e.preventDefault()
147
+ e.stopPropagation()
148
+ const t = e.touches[0]
149
+ mode = 'resize'
150
+ startX = t.clientX
151
+ startY = t.clientY
152
+ startW = this._el.offsetWidth
153
+ startH = this._el.offsetHeight
154
+ }
155
+
156
+ const onTouchMove = (e) => {
157
+ if (!mode || e.touches.length !== 1) return
158
+ e.preventDefault()
159
+ const t = e.touches[0]
160
+ const dx = t.clientX - startX
161
+ const dy = t.clientY - startY
162
+ if (mode === 'drag') {
163
+ this._el.style.left = (startLeft + dx) + 'px'
164
+ this._el.style.top = (startTop + dy) + 'px'
165
+ } else {
166
+ this._el.style.width = Math.max(MIN_WIDTH, startW + dx) + 'px'
167
+ this._el.style.height = Math.max(MIN_HEIGHT, startH + dy) + 'px'
168
+ }
169
+ }
170
+
171
+ const onTouchEnd = () => {
172
+ if (mode === 'drag') this._dragBar.style.cursor = 'grab'
173
+ mode = null
174
+ }
175
+
176
+ this._dragBar.addEventListener('touchstart', onDragBarTouchStart, { passive: false })
177
+ this._resizeHandle.addEventListener('touchstart', onResizeTouchStart, { passive: false })
178
+ document.addEventListener('touchmove', onTouchMove, { passive: false })
179
+ document.addEventListener('touchend', onTouchEnd)
180
+ document.addEventListener('touchcancel', onTouchEnd)
181
+
131
182
  this._cleanupInteraction = () => {
132
183
  this._dragBar.removeEventListener('mousedown', onDragBarMouseDown)
133
184
  this._resizeHandle.removeEventListener('mousedown', onResizeMouseDown)
134
185
  document.removeEventListener('mousemove', onMouseMove)
135
186
  document.removeEventListener('mouseup', onMouseUp)
187
+ this._dragBar.removeEventListener('touchstart', onDragBarTouchStart)
188
+ this._resizeHandle.removeEventListener('touchstart', onResizeTouchStart)
189
+ document.removeEventListener('touchmove', onTouchMove)
190
+ document.removeEventListener('touchend', onTouchEnd)
191
+ document.removeEventListener('touchcancel', onTouchEnd)
136
192
  }
137
193
  }
138
194
 
package/src/index.js CHANGED
@@ -1,10 +1,14 @@
1
1
  export { LayerType } from "./core/LayerType.js"
2
2
  export { Layer } from "./core/Layer.js"
3
- export { Data } from "./core/Data.js"
4
- export { AxisRegistry, AXES } from "./axes/AxisRegistry.js"
3
+ export { Data, DataGroup } from "./data/Data.js"
4
+ export { AxisRegistry, AXES, AXES_2D, AXIS_GEOMETRY, axisEndpoints, axisPosAtN } from "./axes/AxisRegistry.js"
5
+ export { Camera } from "./axes/Camera.js"
6
+ export { TickLabelAtlas } from "./axes/TickLabelAtlas.js"
5
7
  export { ColorAxisRegistry } from "./axes/ColorAxisRegistry.js"
6
8
  export { FilterAxisRegistry, buildFilterGlsl } from "./axes/FilterAxisRegistry.js"
7
9
  export { Plot } from "./core/Plot.js"
10
+ export { PlotGroup } from "./core/PlotGroup.js"
11
+ export { ComputePipeline, ComputeOutput } from "./core/ComputePipeline.js"
8
12
  export { pointsLayerType } from "./layers/PointsLayer.js"
9
13
  export { linesLayerType } from "./layers/LinesLayer.js"
10
14
  export { registerLayerType, getLayerType, getRegisteredLayerTypes } from "./core/LayerTypeRegistry.js"
@@ -20,9 +24,11 @@ export { Float } from "./floats/Float.js"
20
24
  export { Filterbar } from "./floats/Filterbar.js"
21
25
  export { filterbarLayerType } from "./layers/FilterbarLayer.js"
22
26
  export { tileLayerType, TileLayerType } from "./layers/TileLayer.js"
23
- export { histogramLayerType } from "./layers/HistogramLayer.js"
27
+ export { barsLayerType } from "./layers/BarsLayer.js"
24
28
  export { registerEpsgDef, parseCrsCode, crsToQkX, crsToQkY, qkToEpsgCode, reproject } from "./geo/EpsgUtils.js"
25
- export { Computation, TextureComputation, GlslComputation, EXPRESSION_REF, computationSchema, registerTextureComputation, registerGlslComputation, isTexture } from "./compute/ComputationRegistry.js"
29
+ export { Computation, TextureComputation, GlslComputation, ComputedData } from "./data/Computation.js"
30
+ export { EXPRESSION_REF, computationSchema, buildTransformSchema, registerTextureComputation, registerGlslComputation, registerComputedData, getComputedData } from "./compute/ComputationRegistry.js"
31
+ export { ComputedDataNode } from "./data/Data.js"
26
32
 
27
33
  // Register all matplotlib colorscales (side-effect import)
28
34
  import "./colorscales/MatplotlibColorscales.js"
@@ -35,3 +41,9 @@ import "./compute/fft.js"
35
41
  import "./compute/conv.js"
36
42
  import "./compute/hist.js"
37
43
  import "./compute/axisFilter.js"
44
+ import "./compute/elementwise.js"
45
+ import "./compute/util.js"
46
+ import "./compute/scatter2dInterpolate.js"
47
+
48
+ // Register BarsLayer (side-effect import)
49
+ import "./layers/BarsLayer.js"
@@ -0,0 +1,168 @@
1
+ import { LayerType } from "../core/LayerType.js"
2
+ import { Data } from "../data/Data.js"
3
+ import { registerLayerType } from "../core/LayerTypeRegistry.js"
4
+ import { AXES } from "../axes/AxisRegistry.js"
5
+
6
+ // Generic instanced bar layer. Renders `instanceCount` bars using live texture refs
7
+ // for bin center positions and bar lengths (counts).
8
+ //
9
+ // Each bar is a quad drawn as a triangle strip (4 vertices).
10
+ // Per-instance: x_center (bin centre, from texture) and a_pickId (bin index, divisor 1).
11
+ // Per-vertex: a_corner ∈ {0,1,2,3} — selects which corner of the rectangle.
12
+ // corner 0: bottom-left corner 1: bottom-right
13
+ // corner 2: top-left corner 3: top-right
14
+ //
15
+ // orientation "vertical" — bins on x-axis, bars extend upward (default)
16
+ // orientation "horizontal" — bins on y-axis, bars extend rightward
17
+
18
+ const BARS_VERT = `#version 300 es
19
+ precision mediump float;
20
+
21
+ in float a_corner;
22
+ in float x_center;
23
+ in float count;
24
+
25
+ uniform vec2 xDomain;
26
+ uniform vec2 yDomain;
27
+ uniform float xScaleType;
28
+ uniform float yScaleType;
29
+ uniform float u_binHalfWidth;
30
+ uniform float u_horizontal;
31
+
32
+ void main() {
33
+ float side = mod(a_corner, 2.0); // 0 = left, 1 = right
34
+ float vert = floor(a_corner / 2.0); // 0 = bottom, 1 = top
35
+
36
+ float bx = mix(x_center + (side * 2.0 - 1.0) * u_binHalfWidth, side * count, u_horizontal);
37
+ float by = mix(vert * count, x_center + (vert * 2.0 - 1.0) * u_binHalfWidth, u_horizontal);
38
+
39
+ gl_Position = plot_pos(vec2(bx, by));
40
+ }
41
+ `
42
+
43
+ const BARS_FRAG = `#version 300 es
44
+ precision mediump float;
45
+ uniform vec4 u_color;
46
+ void main() {
47
+ fragColor = gladly_apply_color(u_color);
48
+ }
49
+ `
50
+
51
+ class BarsLayerType extends LayerType {
52
+ constructor() {
53
+ super({ name: "bars", vert: BARS_VERT, frag: BARS_FRAG })
54
+ }
55
+
56
+ _getAxisConfig(parameters, data) {
57
+ const d = Data.wrap(data)
58
+ const { xData, yData, xAxis = "xaxis_bottom", yAxis = "yaxis_left", orientation = "vertical" } = parameters
59
+ if (orientation === "horizontal") {
60
+ return {
61
+ xAxis,
62
+ xAxisQuantityKind: d.getQuantityKind(yData) ?? yData,
63
+ yAxis,
64
+ yAxisQuantityKind: d.getQuantityKind(xData) ?? xData,
65
+ }
66
+ }
67
+ return {
68
+ xAxis,
69
+ xAxisQuantityKind: d.getQuantityKind(xData) ?? xData,
70
+ yAxis,
71
+ yAxisQuantityKind: d.getQuantityKind(yData) ?? yData,
72
+ }
73
+ }
74
+
75
+ schema(data) {
76
+ const cols = Data.wrap(data).columns()
77
+ return {
78
+ type: "object",
79
+ properties: {
80
+ xData: {
81
+ type: "string",
82
+ enum: cols,
83
+ description: "Column name for bin center x positions"
84
+ },
85
+ yData: {
86
+ type: "string",
87
+ enum: cols,
88
+ description: "Column name for bar heights (counts)"
89
+ },
90
+ color: {
91
+ type: "array",
92
+ items: { type: "number" },
93
+ minItems: 4,
94
+ maxItems: 4,
95
+ default: [0.2, 0.5, 0.8, 1.0],
96
+ description: "Bar colour as [R, G, B, A] in [0, 1]"
97
+ },
98
+ orientation: {
99
+ type: "string",
100
+ enum: ["vertical", "horizontal"],
101
+ default: "vertical",
102
+ description: "vertical: bins on x-axis, bars extend up; horizontal: bins on y-axis, bars extend right"
103
+ },
104
+ xAxis: {
105
+ type: "string",
106
+ enum: AXES.filter(a => a.includes("x")),
107
+ default: "xaxis_bottom"
108
+ },
109
+ yAxis: {
110
+ type: "string",
111
+ enum: AXES.filter(a => a.includes("y")),
112
+ default: "yaxis_left"
113
+ }
114
+ },
115
+ required: ["xData", "yData"]
116
+ }
117
+ }
118
+
119
+ _createLayer(regl, parameters, data, plot) {
120
+ const d = Data.wrap(data)
121
+ const {
122
+ xData,
123
+ yData,
124
+ color = [0.2, 0.5, 0.8, 1.0],
125
+ orientation = "vertical",
126
+ } = parameters
127
+
128
+ const xRef = d.getData(xData)
129
+ const yRef = d.getData(yData)
130
+ if (!xRef) throw new Error(`BarsLayer: column '${xData}' not found`)
131
+ if (!yRef) throw new Error(`BarsLayer: column '${yData}' not found`)
132
+
133
+ const bins = xRef.length ?? 1
134
+
135
+ const xDomain = d.getDomain(xData) ?? [0, 1]
136
+ const yDomain = d.getDomain(yData) ?? [0, 1]
137
+ const binHalfWidth = (xDomain[1] - xDomain[0]) / (2 * bins)
138
+
139
+ const xQK = d.getQuantityKind(xData) ?? xData
140
+ const yQK = d.getQuantityKind(yData) ?? yData
141
+
142
+ // Per-vertex corner indices 0–3 (triangle-strip quad)
143
+ const a_corner = new Float32Array([0, 1, 2, 3])
144
+
145
+ return [{
146
+ attributes: {
147
+ a_corner, // per-vertex, no divisor
148
+ x_center: xRef, // live ref → resolved via _isLive path in resolveToGlslExpr
149
+ count: yRef, // live ref → resolved via _isLive path
150
+ },
151
+ uniforms: {
152
+ u_binHalfWidth: binHalfWidth,
153
+ u_color: color,
154
+ u_horizontal: orientation === "horizontal" ? 1.0 : 0.0,
155
+ },
156
+ vertexCount: 4,
157
+ instanceCount: bins,
158
+ primitive: "triangle strip",
159
+ domains: {
160
+ [xQK]: xDomain,
161
+ [yQK]: yDomain,
162
+ },
163
+ }]
164
+ }
165
+ }
166
+
167
+ export const barsLayerType = new BarsLayerType()
168
+ registerLayerType("bars", barsLayerType)
@@ -7,6 +7,7 @@ const quadCy = new Float32Array([-1, -1, 1, 1])
7
7
 
8
8
  export const colorbarLayerType = new LayerType({
9
9
  name: "colorbar",
10
+ suppressWarnings: true,
10
11
 
11
12
  getAxisConfig: function(parameters) {
12
13
  const { colorAxis, orientation = "horizontal" } = parameters
@@ -15,33 +16,33 @@ export const colorbarLayerType = new LayerType({
15
16
  xAxisQuantityKind: orientation === "horizontal" ? colorAxis : undefined,
16
17
  yAxis: orientation === "vertical" ? "yaxis_left" : null,
17
18
  yAxisQuantityKind: orientation === "vertical" ? colorAxis : undefined,
18
- colorAxisQuantityKinds: [colorAxis],
19
+ colorAxisQuantityKinds: { '': colorAxis },
19
20
  }
20
21
  },
21
22
 
22
- vert: `
23
+ vert: `#version 300 es
23
24
  precision mediump float;
24
- attribute float cx;
25
- attribute float cy;
25
+ in float cx;
26
+ in float cy;
26
27
  uniform int horizontal;
27
- varying float tval;
28
+ out float tval;
28
29
  void main() {
29
30
  gl_Position = vec4(cx, cy, 0.0, 1.0);
30
31
  tval = horizontal == 1 ? (cx + 1.0) / 2.0 : (cy + 1.0) / 2.0;
31
32
  }
32
33
  `,
33
34
 
34
- frag: `
35
+ frag: `#version 300 es
35
36
  precision mediump float;
36
37
  uniform int colorscale;
37
38
  uniform vec2 color_range;
38
39
  uniform float color_scale_type;
39
- varying float tval;
40
+ in float tval;
40
41
  void main() {
41
42
  float r0 = color_scale_type > 0.5 ? log(color_range.x) : color_range.x;
42
43
  float r1 = color_scale_type > 0.5 ? log(color_range.y) : color_range.y;
43
44
  float v = r0 + tval * (r1 - r0);
44
- gl_FragColor = gladly_apply_color(map_color(colorscale, vec2(r0, r1), v));
45
+ fragColor = gladly_apply_color(map_color(colorscale, vec2(r0, r1), v));
45
46
  }
46
47
  `,
47
48
 
@@ -55,18 +56,13 @@ export const colorbarLayerType = new LayerType({
55
56
  required: ["colorAxis"]
56
57
  }),
57
58
 
58
- createLayer: function(parameters) {
59
+ createLayer: function(regl, parameters) {
59
60
  const { colorAxis, orientation = "horizontal" } = parameters
60
61
  return [{
61
62
  attributes: { cx: quadCx, cy: quadCy },
62
63
  uniforms: { horizontal: orientation === "horizontal" ? 1 : 0 },
63
64
  primitive: "triangle strip",
64
65
  vertexCount: 4,
65
- nameMap: {
66
- [`colorscale_${colorAxis}`]: 'colorscale',
67
- [`color_range_${colorAxis}`]: 'color_range',
68
- [`color_scale_type_${colorAxis}`]: 'color_scale_type',
69
- },
70
66
  }]
71
67
  }
72
68
  })
@@ -7,6 +7,7 @@ const quadCy = new Float32Array([-1, -1, 1, 1])
7
7
 
8
8
  export const colorbar2dLayerType = new LayerType({
9
9
  name: "colorbar2d",
10
+ suppressWarnings: true,
10
11
 
11
12
  getAxisConfig: function(parameters) {
12
13
  const { xAxis, yAxis } = parameters
@@ -15,16 +16,17 @@ export const colorbar2dLayerType = new LayerType({
15
16
  xAxisQuantityKind: xAxis,
16
17
  yAxis: "yaxis_left",
17
18
  yAxisQuantityKind: yAxis,
18
- colorAxisQuantityKinds: [xAxis, yAxis],
19
+ colorAxisQuantityKinds: { '_a': xAxis, '_b': yAxis },
20
+ colorAxis2dQuantityKinds: { '': ['_a', '_b'] },
19
21
  }
20
22
  },
21
23
 
22
- vert: `
24
+ vert: `#version 300 es
23
25
  precision mediump float;
24
- attribute float cx;
25
- attribute float cy;
26
- varying float tval_x;
27
- varying float tval_y;
26
+ in float cx;
27
+ in float cy;
28
+ out float tval_x;
29
+ out float tval_y;
28
30
  void main() {
29
31
  gl_Position = vec4(cx, cy, 0.0, 1.0);
30
32
  tval_x = (cx + 1.0) / 2.0;
@@ -37,16 +39,14 @@ export const colorbar2dLayerType = new LayerType({
37
39
  // values to map_color_s_2d which re-applies the scale type internally. The exp() call
38
40
  // is the inverse of the log() that map_color_s_2d will apply, so log-scale roundtrips
39
41
  // correctly and linear-scale is a no-op (exp(log(v)) == v, but for linear vt == v anyway).
40
- frag: `
42
+ frag: `#version 300 es
41
43
  precision mediump float;
42
- uniform int colorscale_a;
43
44
  uniform vec2 color_range_a;
44
45
  uniform float color_scale_type_a;
45
- uniform int colorscale_b;
46
46
  uniform vec2 color_range_b;
47
47
  uniform float color_scale_type_b;
48
- varying float tval_x;
49
- varying float tval_y;
48
+ in float tval_x;
49
+ in float tval_y;
50
50
  void main() {
51
51
  float r0_a = color_scale_type_a > 0.5 ? log(color_range_a.x) : color_range_a.x;
52
52
  float r1_a = color_scale_type_a > 0.5 ? log(color_range_a.y) : color_range_a.y;
@@ -58,10 +58,7 @@ export const colorbar2dLayerType = new LayerType({
58
58
  float vt_b = r0_b + tval_y * (r1_b - r0_b);
59
59
  float v_b = color_scale_type_b > 0.5 ? exp(vt_b) : vt_b;
60
60
 
61
- gl_FragColor = map_color_s_2d(
62
- colorscale_a, color_range_a, v_a, color_scale_type_a,
63
- colorscale_b, color_range_b, v_b, color_scale_type_b
64
- );
61
+ fragColor = map_color_2d_(vec2(v_a, v_b));
65
62
  }
66
63
  `,
67
64
 
@@ -75,21 +72,13 @@ export const colorbar2dLayerType = new LayerType({
75
72
  required: ["xAxis", "yAxis"]
76
73
  }),
77
74
 
78
- createLayer: function(parameters) {
75
+ createLayer: function(regl, parameters) {
79
76
  const { xAxis, yAxis } = parameters
80
77
  return [{
81
78
  attributes: { cx: quadCx, cy: quadCy },
82
79
  uniforms: {},
83
80
  primitive: "triangle strip",
84
81
  vertexCount: 4,
85
- nameMap: {
86
- [`colorscale_${xAxis}`]: 'colorscale_a',
87
- [`color_range_${xAxis}`]: 'color_range_a',
88
- [`color_scale_type_${xAxis}`]: 'color_scale_type_a',
89
- [`colorscale_${yAxis}`]: 'colorscale_b',
90
- [`color_range_${yAxis}`]: 'color_range_b',
91
- [`color_scale_type_${yAxis}`]: 'color_scale_type_b',
92
- },
93
82
  }]
94
83
  }
95
84
  })