@sqlrooms/deck 0.29.0-rc.10 → 0.29.0-rc.12

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 (173) hide show
  1. package/README.md +88 -16
  2. package/dist/BlockMapSettings.d.ts.map +1 -1
  3. package/dist/BlockMapSettings.js +4 -16
  4. package/dist/BlockMapSettings.js.map +1 -1
  5. package/dist/DashboardMapSettings.d.ts.map +1 -1
  6. package/dist/DashboardMapSettings.js +7 -10
  7. package/dist/DashboardMapSettings.js.map +1 -1
  8. package/dist/DeckJsonMap.d.ts.map +1 -1
  9. package/dist/DeckJsonMap.js +20 -18
  10. package/dist/DeckJsonMap.js.map +1 -1
  11. package/dist/DeckJsonMapSpec.d.ts +916 -53
  12. package/dist/DeckJsonMapSpec.d.ts.map +1 -1
  13. package/dist/DeckJsonMapSpec.js +9 -0
  14. package/dist/DeckJsonMapSpec.js.map +1 -1
  15. package/dist/DeckMapDefaultStylesProvider.d.ts +3 -4
  16. package/dist/DeckMapDefaultStylesProvider.d.ts.map +1 -1
  17. package/dist/DeckMapDefaultStylesProvider.js +13 -7
  18. package/dist/DeckMapDefaultStylesProvider.js.map +1 -1
  19. package/dist/DeckMapSurface.d.ts +1 -1
  20. package/dist/DeckMapSurface.js +1 -1
  21. package/dist/DeckMapSurface.js.map +1 -1
  22. package/dist/MapSettings.d.ts +14 -0
  23. package/dist/MapSettings.d.ts.map +1 -1
  24. package/dist/MapSettings.js +555 -186
  25. package/dist/MapSettings.js.map +1 -1
  26. package/dist/MapSettingsControls.d.ts +8 -1
  27. package/dist/MapSettingsControls.d.ts.map +1 -1
  28. package/dist/MapSettingsControls.js +24 -2
  29. package/dist/MapSettingsControls.js.map +1 -1
  30. package/dist/ai.d.ts +19 -5
  31. package/dist/ai.d.ts.map +1 -1
  32. package/dist/ai.js +63 -112
  33. package/dist/ai.js.map +1 -1
  34. package/dist/aiNormalize.d.ts +31 -0
  35. package/dist/aiNormalize.d.ts.map +1 -0
  36. package/dist/aiNormalize.js +630 -0
  37. package/dist/aiNormalize.js.map +1 -0
  38. package/dist/block.d.ts +1 -1
  39. package/dist/block.d.ts.map +1 -1
  40. package/dist/block.js +1 -1
  41. package/dist/block.js.map +1 -1
  42. package/dist/createOrUpdateDeckMapResource.d.ts +6 -2
  43. package/dist/createOrUpdateDeckMapResource.d.ts.map +1 -1
  44. package/dist/createOrUpdateDeckMapResource.js +57 -4
  45. package/dist/createOrUpdateDeckMapResource.js.map +1 -1
  46. package/dist/dashboard.d.ts.map +1 -1
  47. package/dist/dashboard.js +72 -8
  48. package/dist/dashboard.js.map +1 -1
  49. package/dist/dashboardConfig.d.ts +10 -1
  50. package/dist/dashboardConfig.d.ts.map +1 -1
  51. package/dist/dashboardConfig.js +55 -22
  52. package/dist/dashboardConfig.js.map +1 -1
  53. package/dist/datasets/PreparedDatasetStore.d.ts +3 -4
  54. package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -1
  55. package/dist/datasets/PreparedDatasetStore.js +35 -10
  56. package/dist/datasets/PreparedDatasetStore.js.map +1 -1
  57. package/dist/datasets/helpers.d.ts +39 -2
  58. package/dist/datasets/helpers.d.ts.map +1 -1
  59. package/dist/datasets/helpers.js +86 -3
  60. package/dist/datasets/helpers.js.map +1 -1
  61. package/dist/datasets/usePreparedDatasetStates.d.ts.map +1 -1
  62. package/dist/datasets/usePreparedDatasetStates.js +12 -8
  63. package/dist/datasets/usePreparedDatasetStates.js.map +1 -1
  64. package/dist/datasets/wrapGeometryAsWkb.d.ts +20 -0
  65. package/dist/datasets/wrapGeometryAsWkb.d.ts.map +1 -0
  66. package/dist/datasets/wrapGeometryAsWkb.js +65 -0
  67. package/dist/datasets/wrapGeometryAsWkb.js.map +1 -0
  68. package/dist/index.d.ts +3 -2
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +2 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/json/colorScaleFunction.d.ts +12 -4
  73. package/dist/json/colorScaleFunction.d.ts.map +1 -1
  74. package/dist/json/colorScaleFunction.js.map +1 -1
  75. package/dist/json/compileColorScale.d.ts +3 -2
  76. package/dist/json/compileColorScale.d.ts.map +1 -1
  77. package/dist/json/compileColorScale.js +16 -1
  78. package/dist/json/compileColorScale.js.map +1 -1
  79. package/dist/json/compileGeoArrowAccessor.d.ts +5 -0
  80. package/dist/json/compileGeoArrowAccessor.d.ts.map +1 -1
  81. package/dist/json/compileGeoArrowAccessor.js +17 -3
  82. package/dist/json/compileGeoArrowAccessor.js.map +1 -1
  83. package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -1
  84. package/dist/json/createDeckJsonConfiguration.js +278 -151
  85. package/dist/json/createDeckJsonConfiguration.js.map +1 -1
  86. package/dist/json/defaultClasses.d.ts.map +1 -1
  87. package/dist/json/defaultClasses.js +3 -3
  88. package/dist/json/defaultClasses.js.map +1 -1
  89. package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
  90. package/dist/json/extractColorScaleLegends.js +43 -14
  91. package/dist/json/extractColorScaleLegends.js.map +1 -1
  92. package/dist/json/heatmapDefaults.d.ts +17 -7
  93. package/dist/json/heatmapDefaults.d.ts.map +1 -1
  94. package/dist/json/heatmapDefaults.js +54 -12
  95. package/dist/json/heatmapDefaults.js.map +1 -1
  96. package/dist/json/layers/DeckH3HexagonLayer.d.ts.map +1 -1
  97. package/dist/json/layers/DeckH3HexagonLayer.js +9 -14
  98. package/dist/json/layers/DeckH3HexagonLayer.js.map +1 -1
  99. package/dist/json/layers/DeckHeatmapLayer.d.ts +32 -0
  100. package/dist/json/layers/DeckHeatmapLayer.d.ts.map +1 -0
  101. package/dist/json/layers/DeckHeatmapLayer.js +69 -0
  102. package/dist/json/layers/DeckHeatmapLayer.js.map +1 -0
  103. package/dist/json/layers/h3IndexFormat.d.ts +6 -0
  104. package/dist/json/layers/h3IndexFormat.d.ts.map +1 -0
  105. package/dist/json/layers/h3IndexFormat.js +17 -0
  106. package/dist/json/layers/h3IndexFormat.js.map +1 -0
  107. package/dist/json/layers/index.d.ts +2 -0
  108. package/dist/json/layers/index.d.ts.map +1 -1
  109. package/dist/json/layers/index.js +2 -0
  110. package/dist/json/layers/index.js.map +1 -1
  111. package/dist/json/rewriteGeoArrowAccessors.d.ts.map +1 -1
  112. package/dist/json/rewriteGeoArrowAccessors.js +22 -5
  113. package/dist/json/rewriteGeoArrowAccessors.js.map +1 -1
  114. package/dist/json/scaleFunction.d.ts +27 -0
  115. package/dist/json/scaleFunction.d.ts.map +1 -0
  116. package/dist/json/scaleFunction.js +151 -0
  117. package/dist/json/scaleFunction.js.map +1 -0
  118. package/dist/mapAiConfig.d.ts +8 -0
  119. package/dist/mapAiConfig.d.ts.map +1 -1
  120. package/dist/mapAiConfig.js +9 -1
  121. package/dist/mapAiConfig.js.map +1 -1
  122. package/dist/mapAiSharedInstructions.d.ts +3 -0
  123. package/dist/mapAiSharedInstructions.d.ts.map +1 -0
  124. package/dist/mapAiSharedInstructions.js +16 -0
  125. package/dist/mapAiSharedInstructions.js.map +1 -0
  126. package/dist/mapConfig.d.ts +7 -1
  127. package/dist/mapConfig.d.ts.map +1 -1
  128. package/dist/mapConfig.js.map +1 -1
  129. package/dist/mapConfigUtils.d.ts +22 -0
  130. package/dist/mapConfigUtils.d.ts.map +1 -1
  131. package/dist/mapConfigUtils.js +147 -3
  132. package/dist/mapConfigUtils.js.map +1 -1
  133. package/dist/mapFit.d.ts +16 -0
  134. package/dist/mapFit.d.ts.map +1 -1
  135. package/dist/mapFit.js +208 -30
  136. package/dist/mapFit.js.map +1 -1
  137. package/dist/mapLayerConfigUtils.d.ts +64 -1
  138. package/dist/mapLayerConfigUtils.d.ts.map +1 -1
  139. package/dist/mapLayerConfigUtils.js +277 -16
  140. package/dist/mapLayerConfigUtils.js.map +1 -1
  141. package/dist/mapResourceAuthoring.d.ts +3 -1
  142. package/dist/mapResourceAuthoring.d.ts.map +1 -1
  143. package/dist/mapResourceAuthoring.js +413 -20
  144. package/dist/mapResourceAuthoring.js.map +1 -1
  145. package/dist/mosaic.d.ts +1 -1
  146. package/dist/mosaic.d.ts.map +1 -1
  147. package/dist/mosaic.js.map +1 -1
  148. package/dist/prepare/geoarrow.js.map +1 -1
  149. package/dist/prepare/prepareDeckDataset.d.ts.map +1 -1
  150. package/dist/prepare/prepareDeckDataset.js +1 -0
  151. package/dist/prepare/prepareDeckDataset.js.map +1 -1
  152. package/dist/prepare/types.d.ts +3 -0
  153. package/dist/prepare/types.d.ts.map +1 -1
  154. package/dist/prepare/types.js.map +1 -1
  155. package/dist/prepare/wkbDecoder.d.ts +10 -0
  156. package/dist/prepare/wkbDecoder.d.ts.map +1 -1
  157. package/dist/prepare/wkbDecoder.js +141 -20
  158. package/dist/prepare/wkbDecoder.js.map +1 -1
  159. package/dist/prepare/wkbParser.d.ts +9 -0
  160. package/dist/prepare/wkbParser.d.ts.map +1 -1
  161. package/dist/prepare/wkbParser.js +22 -0
  162. package/dist/prepare/wkbParser.js.map +1 -1
  163. package/dist/selectStarAsWkbCollision.d.ts +3 -0
  164. package/dist/selectStarAsWkbCollision.d.ts.map +1 -0
  165. package/dist/selectStarAsWkbCollision.js +78 -0
  166. package/dist/selectStarAsWkbCollision.js.map +1 -0
  167. package/dist/types.d.ts +1 -1
  168. package/dist/types.d.ts.map +1 -1
  169. package/dist/types.js.map +1 -1
  170. package/dist/useDeckMapFitToBounds.d.ts.map +1 -1
  171. package/dist/useDeckMapFitToBounds.js +1 -1
  172. package/dist/useDeckMapFitToBounds.js.map +1 -1
  173. package/package.json +15 -15
@@ -1,17 +1,28 @@
1
1
  import { JSONConfiguration } from '@deck.gl/json';
2
- import { wkbGeometryDecoder } from '../prepare/wkbDecoder';
2
+ import { isPointPositionLayer, promoteToPointPositions, wkbGeometryDecoder, describeGeoArrowPromotionFailure, } from '../prepare/wkbDecoder';
3
3
  import { tryAggregateWaypointsToLineStrings } from './aggregateWaypoints';
4
4
  import { createColorScaleMarker, getAllColorScales, COLOR_SCALE_PROP_NAMES, } from './colorScaleFunction';
5
5
  import { compileColorScale } from './compileColorScale';
6
6
  import { DEFAULT_DECK_JSON_CLASSES, DEFAULT_DECK_JSON_CONSTANTS, DEFAULT_DECK_JSON_ENUMERATIONS, } from './defaultClasses';
7
- import { DEFAULT_HEATMAP_COLOR_RANGE } from './heatmapDefaults';
7
+ import { DEFAULT_HEATMAP_COLOR_RANGE, DEFAULT_HEATMAP_WEIGHTS_TEXTURE_SIZE, } from './heatmapDefaults';
8
8
  import { getLayerCompatibility } from './layerCompatibility';
9
9
  import { isManagedLayer, resolveConfiguredColumn, resolveDatasetId, resolveGeometryColumn, stripLayerExtensionProps, } from './layerConfig';
10
10
  import { rewriteGeoArrowAccessors } from './rewriteGeoArrowAccessors';
11
+ import { isBindableGeoArrowFieldIdentifier } from './compileGeoArrowAccessor';
12
+ import { compileLinearScaleAccessor, compileLinearScaleExpression, createScaleMarker, isScaleMarker, } from './scaleFunction';
11
13
  function getLayerName(Class) {
12
14
  const maybeClass = Class;
13
15
  return maybeClass.layerName ?? maybeClass.name ?? 'UnknownLayer';
14
16
  }
17
+ /**
18
+ * Deck.gl matches layers by id. Each JSON convert would otherwise create a new
19
+ * GPU layer. Dataset id alone collides when two layers share a dataset.
20
+ */
21
+ function assignStableLayerId(props, datasetId, layerName, index) {
22
+ if (typeof props.id === 'string' && props.id !== '')
23
+ return;
24
+ props.id = `${datasetId}:${layerName}:${index}`;
25
+ }
15
26
  function applyColorScale(options) {
16
27
  const { props, table } = options;
17
28
  const allScales = getAllColorScales(props);
@@ -44,16 +55,110 @@ function applyColorScale(options) {
44
55
  }
45
56
  return result;
46
57
  }
58
+ function getElevationTrigger(rawElev) {
59
+ if (rawElev === undefined)
60
+ return 'none';
61
+ if (typeof rawElev === 'string' || typeof rawElev === 'number') {
62
+ return String(rawElev);
63
+ }
64
+ try {
65
+ return JSON.stringify(rawElev);
66
+ }
67
+ catch {
68
+ return String(rawElev);
69
+ }
70
+ }
71
+ function mergeGetElevationTrigger(props, rawElev) {
72
+ const existing = props.updateTriggers &&
73
+ typeof props.updateTriggers === 'object' &&
74
+ !Array.isArray(props.updateTriggers)
75
+ ? props.updateTriggers
76
+ : {};
77
+ return {
78
+ ...props,
79
+ updateTriggers: {
80
+ ...existing,
81
+ getElevation: getElevationTrigger(rawElev),
82
+ },
83
+ };
84
+ }
85
+ /** Compile `getElevation` scale / `@@=` column accessors against the Arrow table. */
86
+ function compileGetElevation(options) {
87
+ const { table, layerName, datasetId, requireFunctionAccessor } = options;
88
+ const nextProps = { ...options.props };
89
+ const rawElev = nextProps.getElevation;
90
+ if (isScaleMarker(rawElev)) {
91
+ const expression = requireFunctionAccessor
92
+ ? undefined
93
+ : compileLinearScaleExpression(table, rawElev);
94
+ if (expression) {
95
+ nextProps.getElevation = expression;
96
+ }
97
+ else {
98
+ const accessor = compileLinearScaleAccessor(table, rawElev);
99
+ if (accessor) {
100
+ nextProps.getElevation = accessor;
101
+ }
102
+ else {
103
+ const field = typeof rawElev.field === 'string' ? rawElev.field : '';
104
+ throw new Error(`Layer "${layerName}" getElevation scale field "${field || '(missing)'}" was not found in dataset "${datasetId}".`);
105
+ }
106
+ }
107
+ }
108
+ else if (typeof rawElev === 'string' && rawElev.startsWith('@@=')) {
109
+ const elevField = rawElev.slice(3).trim();
110
+ const elevVector = table.getChild(elevField);
111
+ if (elevVector) {
112
+ let min = Infinity;
113
+ for (let i = 0; i < elevVector.length; i++) {
114
+ if (typeof elevVector.isValid === 'function' &&
115
+ !elevVector.isValid(i)) {
116
+ continue;
117
+ }
118
+ const raw = elevVector.get(i);
119
+ if (raw == null)
120
+ continue;
121
+ const v = Number(raw);
122
+ if (Number.isFinite(v) && v < min)
123
+ min = v;
124
+ }
125
+ if (Number.isFinite(min)) {
126
+ if (!requireFunctionAccessor &&
127
+ isBindableGeoArrowFieldIdentifier(elevField)) {
128
+ if (min !== 0) {
129
+ nextProps.getElevation = `@@=Math.max(0, ${elevField} - ${min})`;
130
+ }
131
+ }
132
+ else {
133
+ const accessor = compileLinearScaleAccessor(table, {
134
+ field: elevField,
135
+ domain: [min, min],
136
+ });
137
+ if (accessor)
138
+ nextProps.getElevation = accessor;
139
+ }
140
+ }
141
+ }
142
+ }
143
+ return nextProps;
144
+ }
47
145
  function resolveGeoArrowBindings(options) {
48
146
  const { layerName, compatibility, layerProps, prepared, props } = options;
49
147
  let table = prepared.table;
50
148
  const boundProps = {};
51
149
  for (const binding of compatibility.bindings) {
52
- if (props[binding.prop] !== undefined) {
150
+ const existing = props[binding.prop];
151
+ // Prefer Arrow Vector over `@@=column` (avoids empty H3 / missing-column silence).
152
+ const existingIsSimpleAccessor = typeof existing === 'string' &&
153
+ /^@@=[A-Za-z_$][\w$]*$/.test(existing.trim());
154
+ if (existing !== undefined && !existingIsSimpleAccessor) {
53
155
  continue;
54
156
  }
55
157
  if (binding.kind === 'geometry') {
56
- const columnName = resolveConfiguredColumn(layerProps, binding.configKey);
158
+ const columnName = resolveConfiguredColumn(layerProps, binding.configKey) ??
159
+ (existingIsSimpleAccessor
160
+ ? existing.trim().slice(3)
161
+ : undefined);
57
162
  if (binding.required && !columnName) {
58
163
  throw new Error(`Layer "${layerName}" requires _sqlroomsBinding.${binding.configKey}.`);
59
164
  }
@@ -91,10 +196,33 @@ function resolveGeoArrowBindings(options) {
91
196
  `but only point coordinates were found. Available columns: ${available}.`);
92
197
  }
93
198
  if (!resolvedGeometry.nativeGeoArrow) {
94
- if (!compatibility.allowGeoArrowPromotion ||
95
- !wkbGeometryDecoder.supportsGeoArrowPromotion(layerName, resolvedGeometry.encoding, prepared.table, resolvedGeometry.columnName)) {
199
+ if (!compatibility.allowGeoArrowPromotion) {
96
200
  throw new Error(`Layer "${layerName}" cannot render geometry encoding "${resolvedGeometry.encoding}" for dataset "${prepared.datasetId}".`);
97
201
  }
202
+ // Point layers: promote Points only — no silent polygon centroid.
203
+ if (isPointPositionLayer(layerName)) {
204
+ const promoted = promoteToPointPositions(prepared.table, resolvedGeometry.columnName, resolvedGeometry.encoding);
205
+ if (!promoted) {
206
+ throw new Error(`Layer "${layerName}" needs Point positions for dataset "${prepared.datasetId}" ` +
207
+ `(geometry encoding "${resolvedGeometry.encoding}"). ` +
208
+ `Use a point geometry column, or transformSql with ` +
209
+ `ST_AsWKB(ST_Centroid(geom)) / ST_PointOnSurface(geom). ` +
210
+ `For building footprints prefer GeoArrowPolygonLayer or GeoJsonLayer.`);
211
+ }
212
+ boundProps[binding.prop] = promoted.geometryColumn;
213
+ if (table === prepared.table) {
214
+ table = promoted.table;
215
+ }
216
+ continue;
217
+ }
218
+ if (!wkbGeometryDecoder.supportsGeoArrowPromotion(layerName, resolvedGeometry.encoding, prepared.table, resolvedGeometry.columnName)) {
219
+ const pathHint = layerName === 'GeoArrowPathLayer' ||
220
+ layerName === 'GeoArrowTripsLayer'
221
+ ? ` GeoArrowPathLayer needs LineString WKB (or a single-part MultiLineString). Multi-part MultiLineString cannot be stitched into one path — explode/merge with ST_Dump / ST_LineMerge first, then ST_AsWKB.`
222
+ : '';
223
+ const mixedHint = describeGeoArrowPromotionFailure(layerName, resolvedGeometry.encoding, prepared.table, resolvedGeometry.columnName);
224
+ throw new Error(`Layer "${layerName}" cannot render geometry encoding "${resolvedGeometry.encoding}" for dataset "${prepared.datasetId}".${pathHint}${mixedHint}`);
225
+ }
98
226
  }
99
227
  const layerData = prepared.getGeoArrowLayerData(columnName);
100
228
  if (layerData.source === 'promoted') {
@@ -112,7 +240,10 @@ function resolveGeoArrowBindings(options) {
112
240
  }
113
241
  continue;
114
242
  }
115
- const columnName = resolveConfiguredColumn(layerProps, binding.configKey);
243
+ const columnName = resolveConfiguredColumn(layerProps, binding.configKey) ??
244
+ (existingIsSimpleAccessor
245
+ ? existing.trim().slice(3)
246
+ : undefined);
116
247
  if (!columnName) {
117
248
  if (binding.required) {
118
249
  throw new Error(`Layer "${layerName}" requires _sqlroomsBinding.${binding.configKey}.`);
@@ -129,179 +260,175 @@ function resolveGeoArrowBindings(options) {
129
260
  }
130
261
  export function createDeckJsonConfiguration(options) {
131
262
  const { datasetStates, datasetIds } = options;
263
+ let nextManagedLayerIndex = 0;
132
264
  return new JSONConfiguration({
133
265
  classes: DEFAULT_DECK_JSON_CLASSES,
134
266
  enumerations: DEFAULT_DECK_JSON_ENUMERATIONS,
135
267
  constants: DEFAULT_DECK_JSON_CONSTANTS,
136
268
  functions: {
137
269
  colorScale: (props) => createColorScaleMarker(props),
138
- scale: (props) => {
139
- const field = typeof props.field === 'string' ? props.field : undefined;
140
- if (!field)
141
- return undefined;
142
- return `@@=${field}`;
143
- },
270
+ scale: (props) => createScaleMarker(props),
144
271
  },
145
272
  // We preserve raw `@@=` strings here because `@deck.gl/json` would otherwise
146
273
  // eagerly compile them into row-based accessors before `preProcessClassProps`
147
274
  // can rewrite them for GeoArrow's batch-oriented callback contract.
148
275
  convertFunction: ((expression) => `@@=${expression}`),
149
276
  preProcessClassProps: (Class, props) => {
150
- const layerName = getLayerName(Class);
151
- const compatibility = getLayerCompatibility(layerName);
152
- if (!compatibility) {
153
- return props;
154
- }
155
- const layerProps = props;
156
- const extensionProps = layerProps;
157
- const datasetId = resolveDatasetId(extensionProps, datasetIds);
158
- const managed = isManagedLayer(extensionProps, datasetIds) ||
159
- (datasetIds.length > 1 && layerProps.data === undefined);
160
- if (!managed) {
161
- return props;
162
- }
163
- if (!datasetId) {
164
- throw new Error(`Layer "${layerName}" must declare _sqlroomsBinding.dataset when multiple datasets are available.`);
165
- }
166
- const datasetState = datasetStates[datasetId];
167
- if (!datasetState) {
168
- throw new Error(`Layer "${layerName}" references unknown dataset "${datasetId}".`);
277
+ try {
278
+ return preprocessManagedLayer();
169
279
  }
170
- if (datasetState.status !== 'ready') {
171
- return { ...stripLayerExtensionProps(layerProps), data: [] };
280
+ catch (error) {
281
+ // JSONConverter skips postProcessConvertedJson when convert throws.
282
+ nextManagedLayerIndex = 0;
283
+ throw error;
172
284
  }
173
- const prepared = datasetState.prepared;
174
- const geometryColumn = resolveGeometryColumn(extensionProps);
175
- const strippedProps = stripLayerExtensionProps(layerProps);
176
- if (compatibility.representation === 'geojson') {
285
+ function preprocessManagedLayer() {
286
+ const layerName = getLayerName(Class);
287
+ const compatibility = getLayerCompatibility(layerName);
288
+ if (!compatibility) {
289
+ return props;
290
+ }
291
+ const layerProps = props;
292
+ const extensionProps = layerProps;
293
+ const datasetId = resolveDatasetId(extensionProps, datasetIds);
294
+ const managed = isManagedLayer(extensionProps, datasetIds) ||
295
+ (datasetIds.length > 1 && layerProps.data === undefined);
296
+ if (!managed) {
297
+ return props;
298
+ }
299
+ if (!datasetId) {
300
+ throw new Error(`Layer "${layerName}" must declare _sqlroomsBinding.dataset when multiple datasets are available.`);
301
+ }
302
+ const datasetState = datasetStates[datasetId];
303
+ if (!datasetState) {
304
+ throw new Error(`Layer "${layerName}" references unknown dataset "${datasetId}".`);
305
+ }
306
+ if (datasetState.status !== 'ready') {
307
+ const pendingProps = stripLayerExtensionProps(layerProps);
308
+ assignStableLayerId(pendingProps, datasetId, layerName, nextManagedLayerIndex++);
309
+ return { ...pendingProps, data: [] };
310
+ }
311
+ const prepared = datasetState.prepared;
312
+ const geometryColumn = resolveGeometryColumn(extensionProps);
313
+ const strippedProps = stripLayerExtensionProps(layerProps);
314
+ assignStableLayerId(strippedProps, datasetId, layerName, nextManagedLayerIndex++);
315
+ if (compatibility.representation === 'geojson') {
316
+ const baseProps = applyColorScale({
317
+ props: strippedProps,
318
+ table: prepared.table,
319
+ });
320
+ const withElevation = compileGetElevation({
321
+ props: baseProps,
322
+ table: prepared.table,
323
+ layerName,
324
+ datasetId: prepared.datasetId,
325
+ requireFunctionAccessor: true,
326
+ });
327
+ return {
328
+ ...mergeGetElevationTrigger(withElevation, baseProps.getElevation),
329
+ data: prepared.getGeoJsonBinaryData(geometryColumn),
330
+ };
331
+ }
332
+ const { table, boundProps } = resolveGeoArrowBindings({
333
+ layerName,
334
+ compatibility: compatibility,
335
+ layerProps: extensionProps,
336
+ prepared,
337
+ props: strippedProps,
338
+ });
177
339
  const baseProps = applyColorScale({
178
340
  props: strippedProps,
179
- table: prepared.table,
341
+ table,
180
342
  });
181
- return {
182
- ...baseProps,
183
- data: prepared.getGeoJsonBinaryData(geometryColumn),
184
- };
185
- }
186
- const { table, boundProps } = resolveGeoArrowBindings({
187
- layerName,
188
- compatibility: compatibility,
189
- layerProps: extensionProps,
190
- prepared,
191
- props: strippedProps,
192
- });
193
- const baseProps = applyColorScale({
194
- props: strippedProps,
195
- table,
196
- });
197
- const nextProps = {
198
- ...baseProps,
199
- data: table,
200
- ...boundProps,
201
- };
202
- // Normalize getElevation: subtract column minimum so the lowest
203
- // feature sits at ground level and differences are clearly visible.
204
- const rawElev = nextProps.getElevation;
205
- if (typeof rawElev === 'string' && rawElev.startsWith('@@=')) {
206
- const elevField = rawElev.slice(3).trim();
207
- const elevVector = table.getChild(elevField);
208
- if (elevVector) {
209
- let min = Infinity;
210
- for (let i = 0; i < elevVector.length; i++) {
211
- const v = Number(elevVector.get(i));
212
- if (Number.isFinite(v) && v < min)
213
- min = v;
214
- }
215
- if (Number.isFinite(min) && min !== 0) {
216
- nextProps.getElevation = `@@=Math.max(0, ${elevField} - ${min})`;
343
+ const nextProps = compileGetElevation({
344
+ props: {
345
+ ...baseProps,
346
+ data: table,
347
+ ...boundProps,
348
+ },
349
+ table,
350
+ layerName,
351
+ datasetId: prepared.datasetId,
352
+ });
353
+ const rewritten = rewriteGeoArrowAccessors({
354
+ props: nextProps,
355
+ table,
356
+ layerName,
357
+ });
358
+ // Set updateTriggers for @@= accessor props and getElevation
359
+ // so deck.gl re-evaluates them when references change or are cleared.
360
+ {
361
+ const accessorTriggers = {};
362
+ for (const [propName, propValue] of Object.entries(nextProps)) {
363
+ if (typeof propValue === 'string' &&
364
+ propValue.startsWith('@@=') &&
365
+ propName.startsWith('get')) {
366
+ accessorTriggers[propName] = propValue;
367
+ }
217
368
  }
218
- }
219
- }
220
- const rewritten = rewriteGeoArrowAccessors({
221
- props: nextProps,
222
- table,
223
- layerName,
224
- });
225
- // Set updateTriggers for @@= accessor props and getElevation
226
- // so deck.gl re-evaluates them when references change or are cleared.
227
- {
228
- const accessorTriggers = {};
229
- for (const [propName, propValue] of Object.entries(nextProps)) {
230
- if (typeof propValue === 'string' &&
231
- propValue.startsWith('@@=') &&
232
- propName.startsWith('get')) {
233
- accessorTriggers[propName] = propValue;
369
+ // Always emit getElevation trigger so clearing the column invalidates
370
+ // stale heights from a previous column-based accessor.
371
+ if (!('getElevation' in accessorTriggers)) {
372
+ const elev = nextProps.getElevation;
373
+ accessorTriggers.getElevation =
374
+ elev !== undefined ? String(elev) : 'none';
234
375
  }
376
+ const existingTriggers = rewritten.updateTriggers &&
377
+ typeof rewritten.updateTriggers === 'object' &&
378
+ !Array.isArray(rewritten.updateTriggers)
379
+ ? rewritten.updateTriggers
380
+ : {};
381
+ rewritten.updateTriggers = {
382
+ ...existingTriggers,
383
+ ...accessorTriggers,
384
+ };
235
385
  }
236
- // Always emit getElevation trigger so clearing the column invalidates
237
- // stale heights from a previous column-based accessor.
238
- if (!('getElevation' in accessorTriggers)) {
239
- const elev = nextProps.getElevation;
240
- accessorTriggers.getElevation =
241
- elev !== undefined ? String(elev) : 'none';
242
- }
243
- const existingTriggers = rewritten.updateTriggers &&
244
- typeof rewritten.updateTriggers === 'object' &&
245
- !Array.isArray(rewritten.updateTriggers)
246
- ? rewritten.updateTriggers
247
- : {};
248
- rewritten.updateTriggers = {
249
- ...existingTriggers,
250
- ...accessorTriggers,
251
- };
252
- }
253
- // For TripsLayer: compute max timestamp for animation and set defaults
254
- if (layerName === 'GeoArrowTripsLayer' || layerName === 'TripsLayer') {
255
- const tsVector = boundProps.getTimestamps;
256
- if (tsVector) {
257
- let maxTs = 0;
258
- for (let i = 0; i < tsVector.length; i++) {
259
- const listItem = tsVector.get(i);
260
- if (listItem &&
261
- typeof listItem === 'object' &&
262
- 'length' in listItem) {
263
- const list = listItem;
264
- for (let j = 0; j < list.length; j++) {
265
- const v = Number(list.get(j)) || 0;
266
- if (v > maxTs)
267
- maxTs = v;
386
+ // For TripsLayer: compute max timestamp for animation and set defaults
387
+ if (layerName === 'GeoArrowTripsLayer' || layerName === 'TripsLayer') {
388
+ const tsVector = boundProps.getTimestamps;
389
+ if (tsVector) {
390
+ let maxTs = 0;
391
+ for (let i = 0; i < tsVector.length; i++) {
392
+ const listItem = tsVector.get(i);
393
+ if (listItem &&
394
+ typeof listItem === 'object' &&
395
+ 'length' in listItem) {
396
+ const list = listItem;
397
+ for (let j = 0; j < list.length; j++) {
398
+ const v = Number(list.get(j)) || 0;
399
+ if (v > maxTs)
400
+ maxTs = v;
401
+ }
268
402
  }
269
403
  }
270
- }
271
- if (maxTs > 0) {
272
- rewritten._tripsMaxTimestamp = maxTs;
273
- if (!rewritten.trailLength) {
274
- rewritten.trailLength = maxTs;
275
- }
276
- if (rewritten.currentTime === undefined ||
277
- rewritten.currentTime === 0) {
278
- rewritten.currentTime = maxTs;
404
+ if (maxTs > 0) {
405
+ rewritten._tripsMaxTimestamp = maxTs;
406
+ if (!rewritten.trailLength) {
407
+ rewritten.trailLength = maxTs;
408
+ }
409
+ if (rewritten.currentTime === undefined ||
410
+ rewritten.currentTime === 0) {
411
+ rewritten.currentTime = maxTs;
412
+ }
279
413
  }
280
414
  }
281
415
  }
282
- }
283
- // For HeatmapLayer: apply default colorRange (YlOrRd) when not explicitly set.
284
- // Also set updateTriggers to force re-aggregation when colorRange changes.
285
- if (layerName === 'GeoArrowHeatmapLayer') {
286
- if (!rewritten.colorRange) {
287
- rewritten.colorRange = DEFAULT_HEATMAP_COLOR_RANGE;
416
+ // HeatmapLayer remaps colorRange in _updateColorTexture. Putting it in
417
+ // getWeight updateTriggers would mark aggregation dirty and rebuild the
418
+ // GPU weight texture when only the colormap changed.
419
+ if (layerName === 'GeoArrowHeatmapLayer') {
420
+ if (!rewritten.colorRange) {
421
+ rewritten.colorRange = DEFAULT_HEATMAP_COLOR_RANGE;
422
+ }
423
+ if (rewritten.weightsTextureSize === undefined) {
424
+ rewritten.weightsTextureSize = DEFAULT_HEATMAP_WEIGHTS_TEXTURE_SIZE;
425
+ }
288
426
  }
289
- const existingTriggers = rewritten.updateTriggers &&
290
- typeof rewritten.updateTriggers === 'object' &&
291
- !Array.isArray(rewritten.updateTriggers)
292
- ? rewritten.updateTriggers
293
- : {};
294
- const previousGetWeight = existingTriggers.getWeight;
295
- rewritten.updateTriggers = {
296
- ...existingTriggers,
297
- getWeight: previousGetWeight === undefined
298
- ? JSON.stringify(rewritten.colorRange)
299
- : [previousGetWeight, JSON.stringify(rewritten.colorRange)],
300
- };
427
+ return rewritten;
301
428
  }
302
- return rewritten;
303
429
  },
304
430
  postProcessConvertedJson: (json) => {
431
+ nextManagedLayerIndex = 0;
305
432
  if (json &&
306
433
  typeof json === 'object' &&
307
434
  'layers' in json &&