@mwater/visualization 5.6.0 → 5.6.1
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/lib/ColorComponent.js +2 -2
- package/lib/TranslationsTabComponent.d.ts +34 -0
- package/lib/TranslationsTabComponent.js +256 -0
- package/lib/dashboards/DashboardComponent.js +1 -1
- package/lib/dashboards/ServerDashboardDataSource.d.ts +0 -1
- package/lib/dashboards/ServerDashboardDataSource.js +0 -15
- package/lib/dashboards/SettingsModalComponent.js +9 -233
- package/lib/datagrids/DatagridComponent.js +5 -0
- package/lib/datagrids/DatagridViewComponent.js +30 -4
- package/lib/maps/BufferLayer.d.ts +0 -13
- package/lib/maps/BufferLayer.js +12 -237
- package/lib/maps/BufferLayerDesignerComponent.d.ts +1 -1
- package/lib/maps/BufferLayerDesignerComponent.js +0 -5
- package/lib/maps/ChoroplethLayer.d.ts +1 -16
- package/lib/maps/ChoroplethLayer.js +13 -358
- package/lib/maps/ClusterLayer.d.ts +0 -9
- package/lib/maps/ClusterLayer.js +0 -250
- package/lib/maps/DirectMapDataSource.js +1 -38
- package/lib/maps/GridLayer.d.ts +0 -15
- package/lib/maps/GridLayer.js +0 -212
- package/lib/maps/Layer.d.ts +1 -26
- package/lib/maps/Layer.js +0 -13
- package/lib/maps/MapComponent.d.ts +19 -35
- package/lib/maps/MapComponent.js +135 -76
- package/lib/maps/MapControlComponent.d.ts +4 -5
- package/lib/maps/MapControlComponent.js +5 -12
- package/lib/maps/MapDesign.d.ts +8 -0
- package/lib/maps/MapDesignerComponent.d.ts +2 -0
- package/lib/maps/MapDesignerComponent.js +7 -2
- package/lib/maps/MapLayerDataSource.d.ts +0 -4
- package/lib/maps/MapLayerViewDesignerComponent.d.ts +3 -1
- package/lib/maps/MapLayerViewDesignerComponent.js +5 -1
- package/lib/maps/MapLayersDesignerComponent.d.ts +2 -0
- package/lib/maps/MapLayersDesignerComponent.js +2 -1
- package/lib/maps/MapTranslationsTab.d.ts +15 -0
- package/lib/maps/MapTranslationsTab.js +47 -0
- package/lib/maps/MapUtils.d.ts +11 -0
- package/lib/maps/MapUtils.js +47 -0
- package/lib/maps/MapViewComponent.d.ts +1 -1
- package/lib/maps/MapViewComponent.js +1 -8
- package/lib/maps/MarkersLayer.d.ts +1 -14
- package/lib/maps/MarkersLayer.js +71 -252
- package/lib/maps/MarkersLayerDesign.d.ts +4 -0
- package/lib/maps/MarkersLayerDesignerComponent.d.ts +20 -16
- package/lib/maps/MarkersLayerDesignerComponent.js +77 -23
- package/lib/maps/ServerMapDataSource.d.ts +0 -1
- package/lib/maps/ServerMapDataSource.js +0 -15
- package/lib/maps/SwitchableTileUrlLayer.d.ts +0 -2
- package/lib/maps/SwitchableTileUrlLayer.js +0 -9
- package/lib/maps/TileUrlLayer.d.ts +0 -1
- package/lib/maps/TileUrlLayer.js +0 -5
- package/lib/maps/VectorMapViewComponent.js +12 -1
- package/lib/maps/vectorMaps.d.ts +5 -6
- package/lib/maps/vectorMaps.js +13 -9
- package/lib/widgets/MapWidget.js +2 -1
- package/package.json +2 -2
- package/src/ColorComponent.tsx +2 -2
- package/src/TranslationsTabComponent.tsx +429 -0
- package/src/dashboards/DashboardComponent.tsx +1 -1
- package/src/dashboards/ServerDashboardDataSource.ts +0 -19
- package/src/dashboards/SettingsModalComponent.tsx +27 -383
- package/src/datagrids/DatagridComponent.tsx +6 -0
- package/src/datagrids/DatagridViewComponent.tsx +41 -5
- package/src/maps/BufferLayer.ts +16 -262
- package/src/maps/BufferLayerDesignerComponent.tsx +0 -6
- package/src/maps/ChoroplethLayer.ts +16 -393
- package/src/maps/ClusterLayer.ts +0 -274
- package/src/maps/DirectMapDataSource.ts +2 -49
- package/src/maps/GridLayer.ts +0 -224
- package/src/maps/Layer.ts +1 -35
- package/src/maps/MapComponent.tsx +448 -0
- package/src/maps/MapControlComponent.tsx +41 -0
- package/src/maps/MapDesign.ts +6 -0
- package/src/maps/MapDesignerComponent.tsx +18 -1
- package/src/maps/MapLayerDataSource.ts +0 -5
- package/src/maps/MapLayerViewDesignerComponent.ts +9 -2
- package/src/maps/MapLayersDesignerComponent.ts +4 -1
- package/src/maps/MapTranslationsTab.tsx +53 -0
- package/src/maps/MapUtils.ts +48 -0
- package/src/maps/MapViewComponent.tsx +2 -8
- package/src/maps/MarkersLayer.ts +79 -270
- package/src/maps/MarkersLayerDesign.ts +6 -0
- package/src/maps/MarkersLayerDesignerComponent.tsx +114 -38
- package/src/maps/ServerMapDataSource.ts +0 -19
- package/src/maps/SwitchableTileUrlLayer.tsx +0 -11
- package/src/maps/TileUrlLayer.tsx +0 -6
- package/src/maps/VectorMapViewComponent.tsx +13 -2
- package/src/maps/vectorMaps.tsx +12 -9
- package/src/widgets/MapWidget.tsx +2 -0
- package/src/maps/MapComponent.ts +0 -311
- package/src/maps/MapControlComponent.ts +0 -46
- package/src/maps/RasterMapViewComponent.ts +0 -345
|
@@ -19,6 +19,10 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
19
19
|
const [rows, setRows] = (0, react_2.useState)([]);
|
|
20
20
|
const [entirelyLoaded, setEntirelyLoaded] = (0, react_2.useState)(false);
|
|
21
21
|
const loadStateRef = (0, react_2.useRef)(null);
|
|
22
|
+
// Track which design key the current rows were loaded with to avoid rendering stale data
|
|
23
|
+
// with a mismatched column structure (e.g. after column reorder)
|
|
24
|
+
const [loadedDesignKey, setLoadedDesignKey] = (0, react_2.useState)(null);
|
|
25
|
+
const currentDesignKey = getDatagridReloadKey(props.design);
|
|
22
26
|
// Get row header width based on selection and showRowNumbers
|
|
23
27
|
const rowHeaderWidth = props.selectedRows
|
|
24
28
|
? (props.design.showRowNumbers ? 70 : 30) // With selection: 70 for both, 30 for just checkbox
|
|
@@ -75,13 +79,17 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
75
79
|
whiteSpace: "nowrap",
|
|
76
80
|
padding: "0 8px"
|
|
77
81
|
};
|
|
78
|
-
|
|
82
|
+
// If design key doesn't match, rows are stale - show loading state
|
|
83
|
+
if (loadedDesignKey !== currentDesignKey || options.row >= rows.length) {
|
|
84
|
+
return (react_1.default.createElement("div", { style: rowHeaderStyle }, props.design.showRowNumbers ? (react_1.default.createElement("div", { style: { flex: 1, textAlign: "right" } }, options.row + 1)) : null));
|
|
85
|
+
}
|
|
86
|
+
const rowId = rows[options.row].id;
|
|
79
87
|
const isSelected = rowId != null && props.selectedRows ? props.selectedRows.isSelected(rowId) : false;
|
|
80
|
-
const isSubtable =
|
|
88
|
+
const isSubtable = rows[options.row].subtable >= 0;
|
|
81
89
|
return (react_1.default.createElement("div", { style: rowHeaderStyle },
|
|
82
90
|
props.selectedRows && !isSubtable && (react_1.default.createElement("input", { type: "checkbox", style: { marginRight: 4 }, checked: isSelected, onChange: rowId != null && props.onSelectedRowsChange ? () => handleRowSelect(rowId) : undefined, readOnly: !props.onSelectedRowsChange })),
|
|
83
91
|
props.design.showRowNumbers ? (react_1.default.createElement("div", { style: { flex: 1, textAlign: "right" } }, options.row + 1)) : null));
|
|
84
|
-
}, [rows, props.selectedRows, props.onSelectedRowsChange, props.design.showRowNumbers, handleRowSelect]);
|
|
92
|
+
}, [rows, props.selectedRows, props.onSelectedRowsChange, props.design.showRowNumbers, handleRowSelect, loadedDesignKey, currentDesignKey]);
|
|
85
93
|
const loadMoreRows = (0, useStableCallback_1.useStableCallback)((callback) => {
|
|
86
94
|
const loadState = {
|
|
87
95
|
design: props.design,
|
|
@@ -103,6 +111,7 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
103
111
|
loadStateRef.current = null;
|
|
104
112
|
setRows(prev => [...prev, ...newRows]);
|
|
105
113
|
setEntirelyLoaded(newRows.length < (props.pageSize || 100));
|
|
114
|
+
setLoadedDesignKey(getDatagridReloadKey(loadState.design));
|
|
106
115
|
callback?.();
|
|
107
116
|
}
|
|
108
117
|
});
|
|
@@ -110,6 +119,7 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
110
119
|
function reload() {
|
|
111
120
|
setRows([]);
|
|
112
121
|
setEntirelyLoaded(false);
|
|
122
|
+
setLoadedDesignKey(null);
|
|
113
123
|
}
|
|
114
124
|
// Reset rows when design, filters or refreshKey changes
|
|
115
125
|
(0, react_2.useEffect)(() => {
|
|
@@ -203,6 +213,10 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
203
213
|
return false;
|
|
204
214
|
});
|
|
205
215
|
const handleCopy = (0, useStableCallback_1.useStableCallback)((rowIndex, colIndex) => {
|
|
216
|
+
// If design key doesn't match, rows are stale - don't copy
|
|
217
|
+
if (loadedDesignKey !== currentDesignKey || rowIndex >= rows.length) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
206
220
|
const row = rows[rowIndex];
|
|
207
221
|
const col = props.design.columns[colIndex];
|
|
208
222
|
const value = row[`c${colIndex}`];
|
|
@@ -227,6 +241,13 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
227
241
|
navigator.clipboard.writeText(formattedValue || "");
|
|
228
242
|
});
|
|
229
243
|
const renderCell = (0, useStableCallback_1.useStableCallback)((options) => {
|
|
244
|
+
// If rows were loaded with a different design key, show loading state to avoid
|
|
245
|
+
// rendering stale data with mismatched column structure (e.g. after column reorder)
|
|
246
|
+
if (loadedDesignKey !== currentDesignKey) {
|
|
247
|
+
lodash_1.default.defer(() => loadMoreRows());
|
|
248
|
+
return react_1.default.createElement("div", { style: { padding: 8 } },
|
|
249
|
+
react_1.default.createElement("i", { className: "fa fa-spinner fa-spin text-muted" }));
|
|
250
|
+
}
|
|
230
251
|
if (options.row >= rows.length) {
|
|
231
252
|
lodash_1.default.defer(() => loadMoreRows());
|
|
232
253
|
return react_1.default.createElement("div", { style: { padding: 8 } },
|
|
@@ -272,7 +293,8 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
272
293
|
} }, column.label || exprUtils.summarizeExpr(column.expr, props.design.locale)));
|
|
273
294
|
});
|
|
274
295
|
const renderCellEditor = (0, useStableCallback_1.useStableCallback)((options) => {
|
|
275
|
-
|
|
296
|
+
// If design key doesn't match, rows are stale - don't render editor
|
|
297
|
+
if (loadedDesignKey !== currentDesignKey || options.row >= rows.length) {
|
|
276
298
|
return react_1.default.createElement("div", null);
|
|
277
299
|
}
|
|
278
300
|
const column = props.design.columns[options.col];
|
|
@@ -288,6 +310,10 @@ const DatagridViewComponent = (0, react_2.forwardRef)((props, ref) => {
|
|
|
288
310
|
if (options.col === -1) {
|
|
289
311
|
return false;
|
|
290
312
|
}
|
|
313
|
+
// If design key doesn't match, rows are stale - don't allow edit
|
|
314
|
+
if (loadedDesignKey !== currentDesignKey || options.row >= rows.length) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
291
317
|
const rowId = rows[options.row].id;
|
|
292
318
|
if (rowId == null) {
|
|
293
319
|
return false;
|
|
@@ -11,19 +11,6 @@ export default class BufferLayer extends Layer<BufferLayerDesign> {
|
|
|
11
11
|
getLayerDefinitionType(): "VectorTile";
|
|
12
12
|
getVectorTile(design: BufferLayerDesign, sourceId: string, schema: Schema, filters: JsonQLFilter[], opacity: number): VectorTileDef;
|
|
13
13
|
createVectorJsonQL(design: BufferLayerDesign, schema: Schema, filters: JsonQLFilter[]): JsonQLQuery;
|
|
14
|
-
getJsonQLCss(design: BufferLayerDesign, schema: Schema, filters: JsonQLFilter[]): {
|
|
15
|
-
layers: {
|
|
16
|
-
id: string;
|
|
17
|
-
jsonql: import("@mwater/jsonql").JsonQLSelectQuery;
|
|
18
|
-
}[];
|
|
19
|
-
css: string;
|
|
20
|
-
interactivity: {
|
|
21
|
-
layer: string;
|
|
22
|
-
fields: string[];
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
createMapnikJsonQL(design: BufferLayerDesign, schema: Schema, filters: JsonQLFilter[]): import("@mwater/jsonql").JsonQLSelectQuery;
|
|
26
|
-
createCss(design: BufferLayerDesign, schema: Schema): string;
|
|
27
14
|
onGridClick(ev: {
|
|
28
15
|
data: any;
|
|
29
16
|
event: any;
|
package/lib/maps/BufferLayer.js
CHANGED
|
@@ -296,235 +296,6 @@ class BufferLayer extends Layer_1.default {
|
|
|
296
296
|
}
|
|
297
297
|
return query;
|
|
298
298
|
}
|
|
299
|
-
// Gets the layer definition as JsonQL + CSS in format:
|
|
300
|
-
// {
|
|
301
|
-
// layers: array of { id: layer id, jsonql: jsonql that includes "the_webmercator_geom" as a column }
|
|
302
|
-
// css: carto css
|
|
303
|
-
// interactivity: (optional) { layer: id of layer, fields: array of field names }
|
|
304
|
-
// }
|
|
305
|
-
// arguments:
|
|
306
|
-
// design: design of layer
|
|
307
|
-
// schema: schema to use
|
|
308
|
-
// filters: array of filters to apply. Each is { table: table id, jsonql: jsonql condition with {alias} for tableAlias. Use injectAlias to put in table alias
|
|
309
|
-
getJsonQLCss(design, schema, filters) {
|
|
310
|
-
// Create design
|
|
311
|
-
const layerDef = {
|
|
312
|
-
layers: [{ id: "layer0", jsonql: this.createMapnikJsonQL(design, schema, filters) }],
|
|
313
|
-
css: this.createCss(design, schema),
|
|
314
|
-
interactivity: {
|
|
315
|
-
layer: "layer0",
|
|
316
|
-
fields: ["id"]
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
return layerDef;
|
|
320
|
-
}
|
|
321
|
-
createMapnikJsonQL(design, schema, filters) {
|
|
322
|
-
let colorExpr;
|
|
323
|
-
const axisBuilder = new AxisBuilder_1.default({ schema });
|
|
324
|
-
const exprCompiler = new expressions_1.ExprCompiler(schema);
|
|
325
|
-
// Get radius expression
|
|
326
|
-
const radiusCompiledExpr = exprCompiler.compileExpr({
|
|
327
|
-
expr: design.radiusExpr ?? { type: "literal", valueType: "number", value: design.radius },
|
|
328
|
-
tableAlias: "main"
|
|
329
|
-
});
|
|
330
|
-
// Convert radius in meters to a maximum number of degrees latitude
|
|
331
|
-
const radiusDegCompiledExpr = { type: "op", op: "/", exprs: [radiusCompiledExpr, 100000] };
|
|
332
|
-
/*
|
|
333
|
-
Query:
|
|
334
|
-
select
|
|
335
|
-
<primary key> as id,
|
|
336
|
-
[<color axis> as color,
|
|
337
|
-
st_transform(<geometry axis>, 3857) as the_geom_webmercator,
|
|
338
|
-
radius * 2 / (!pixel_width! * cos(st_ymin(st_transform(geometryExpr, 4326)) * 0.017453293) as width
|
|
339
|
-
from <table> as main
|
|
340
|
-
where
|
|
341
|
-
<geometry axis> is not null
|
|
342
|
-
* Bounding box filter for speed
|
|
343
|
-
and <geometry axis> &&
|
|
344
|
-
ST_Transform(ST_Expand(
|
|
345
|
-
* Prevent 3857 overflow (i.e. > 85 degrees lat)
|
|
346
|
-
ST_Intersection(
|
|
347
|
-
ST_Transform(!bbox!, 4326),
|
|
348
|
-
ST_Expand(ST_MakeEnvelope(-180, -85, 180, 85, 4326), -<radius in degrees>))
|
|
349
|
-
, <radius in degrees>})
|
|
350
|
-
, 3857)
|
|
351
|
-
and <other filters>
|
|
352
|
-
*/
|
|
353
|
-
// Compile geometry axis
|
|
354
|
-
let geometryExpr = axisBuilder.compileAxis({ axis: design.axes.geometry, tableAlias: "main" });
|
|
355
|
-
// radius * 2 / (!pixel_width! * cos(st_ymin(st_transform(geometryExpr, 4326)) * 0.017453293) + 1 # add one to make always visible
|
|
356
|
-
const widthExpr = {
|
|
357
|
-
type: "op",
|
|
358
|
-
op: "+",
|
|
359
|
-
exprs: [
|
|
360
|
-
{
|
|
361
|
-
type: "op",
|
|
362
|
-
op: "/",
|
|
363
|
-
exprs: [
|
|
364
|
-
{ type: "op", op: "*", exprs: [radiusCompiledExpr, 2] },
|
|
365
|
-
{
|
|
366
|
-
type: "op",
|
|
367
|
-
op: "*",
|
|
368
|
-
exprs: [
|
|
369
|
-
{ type: "op", op: "nullif", exprs: [{ type: "token", token: "!pixel_height!" }, 0] },
|
|
370
|
-
{
|
|
371
|
-
type: "op",
|
|
372
|
-
op: "cos",
|
|
373
|
-
exprs: [
|
|
374
|
-
{
|
|
375
|
-
type: "op",
|
|
376
|
-
op: "*",
|
|
377
|
-
exprs: [
|
|
378
|
-
{
|
|
379
|
-
type: "op",
|
|
380
|
-
op: "ST_YMIN",
|
|
381
|
-
exprs: [{ type: "op", op: "ST_Transform", exprs: [geometryExpr, 4326] }]
|
|
382
|
-
},
|
|
383
|
-
0.017453293
|
|
384
|
-
]
|
|
385
|
-
}
|
|
386
|
-
]
|
|
387
|
-
}
|
|
388
|
-
]
|
|
389
|
-
}
|
|
390
|
-
]
|
|
391
|
-
},
|
|
392
|
-
2
|
|
393
|
-
]
|
|
394
|
-
};
|
|
395
|
-
const selects = [
|
|
396
|
-
{
|
|
397
|
-
type: "select",
|
|
398
|
-
expr: { type: "field", tableAlias: "main", column: schema.getTable(design.table).primaryKey },
|
|
399
|
-
alias: "id"
|
|
400
|
-
}, // main primary key as id
|
|
401
|
-
{ type: "select", expr: geometryExpr, alias: "the_geom_webmercator" },
|
|
402
|
-
{ type: "select", expr: widthExpr, alias: "width" } // Width of circles
|
|
403
|
-
];
|
|
404
|
-
// Add color select if color axis
|
|
405
|
-
if (design.axes.color) {
|
|
406
|
-
colorExpr = axisBuilder.compileAxis({ axis: design.axes.color, tableAlias: "main" });
|
|
407
|
-
selects.push({ type: "select", expr: colorExpr, alias: "color" });
|
|
408
|
-
}
|
|
409
|
-
// Select _id, location and clustered row number
|
|
410
|
-
const query = {
|
|
411
|
-
type: "query",
|
|
412
|
-
selects,
|
|
413
|
-
from: exprCompiler.compileTable(design.table, "main")
|
|
414
|
-
};
|
|
415
|
-
const boundingBox = {
|
|
416
|
-
type: "op",
|
|
417
|
-
op: "ST_Transform",
|
|
418
|
-
exprs: [
|
|
419
|
-
{
|
|
420
|
-
type: "op",
|
|
421
|
-
op: "ST_Expand",
|
|
422
|
-
exprs: [
|
|
423
|
-
{
|
|
424
|
-
type: "op",
|
|
425
|
-
op: "ST_Intersection",
|
|
426
|
-
exprs: [
|
|
427
|
-
{ type: "op", op: "ST_Transform", exprs: [{ type: "token", token: "!bbox!" }, 4326] },
|
|
428
|
-
{
|
|
429
|
-
type: "op",
|
|
430
|
-
op: "ST_Expand",
|
|
431
|
-
exprs: [
|
|
432
|
-
{ type: "op", op: "ST_MakeEnvelope", exprs: [-180, -85, 180, 85, 4326] },
|
|
433
|
-
{ type: "op", op: "*", exprs: [radiusDegCompiledExpr, -1] }
|
|
434
|
-
]
|
|
435
|
-
}
|
|
436
|
-
]
|
|
437
|
-
},
|
|
438
|
-
radiusDegCompiledExpr
|
|
439
|
-
]
|
|
440
|
-
},
|
|
441
|
-
3857
|
|
442
|
-
]
|
|
443
|
-
};
|
|
444
|
-
// Create filters. First ensure geometry and limit to bounding box
|
|
445
|
-
let whereClauses = [
|
|
446
|
-
{ type: "op", op: "is not null", exprs: [geometryExpr] },
|
|
447
|
-
{
|
|
448
|
-
type: "op",
|
|
449
|
-
op: "&&",
|
|
450
|
-
exprs: [geometryExpr, boundingBox]
|
|
451
|
-
}
|
|
452
|
-
];
|
|
453
|
-
// Then add filters baked into layer
|
|
454
|
-
if (design.filter) {
|
|
455
|
-
whereClauses.push(exprCompiler.compileExpr({ expr: design.filter, tableAlias: "main" }));
|
|
456
|
-
}
|
|
457
|
-
// Then add extra filters passed in, if relevant
|
|
458
|
-
// Get relevant filters
|
|
459
|
-
const relevantFilters = lodash_1.default.where(filters, { table: design.table });
|
|
460
|
-
for (let filter of relevantFilters) {
|
|
461
|
-
whereClauses.push((0, expressions_1.injectTableAlias)(filter.jsonql, "main"));
|
|
462
|
-
}
|
|
463
|
-
whereClauses = lodash_1.default.compact(whereClauses);
|
|
464
|
-
// Wrap if multiple
|
|
465
|
-
if (whereClauses.length > 1) {
|
|
466
|
-
query.where = { type: "op", op: "and", exprs: whereClauses };
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
query.where = whereClauses[0];
|
|
470
|
-
}
|
|
471
|
-
// Sort order
|
|
472
|
-
if (design.axes.color && design.axes.color.colorMap) {
|
|
473
|
-
// TODO should use categories, not colormap order
|
|
474
|
-
const order = design.axes.color.drawOrder || lodash_1.default.pluck(design.axes.color.colorMap, "value");
|
|
475
|
-
const categories = axisBuilder.getCategories(design.axes.color, order);
|
|
476
|
-
const cases = lodash_1.default.map(categories, (category, i) => {
|
|
477
|
-
return {
|
|
478
|
-
when: category.value != null
|
|
479
|
-
? { type: "op", op: "=", exprs: [colorExpr, category.value] }
|
|
480
|
-
: { type: "op", op: "is null", exprs: [colorExpr] },
|
|
481
|
-
then: order.indexOf(category.value) || -1
|
|
482
|
-
};
|
|
483
|
-
});
|
|
484
|
-
if (cases.length > 0) {
|
|
485
|
-
query.orderBy = [
|
|
486
|
-
{
|
|
487
|
-
expr: {
|
|
488
|
-
type: "case",
|
|
489
|
-
cases
|
|
490
|
-
},
|
|
491
|
-
direction: "desc" // Reverse color map order
|
|
492
|
-
}
|
|
493
|
-
];
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return query;
|
|
497
|
-
}
|
|
498
|
-
createCss(design, schema) {
|
|
499
|
-
let css = `\
|
|
500
|
-
#layer0 {
|
|
501
|
-
marker-fill-opacity: ` +
|
|
502
|
-
design.fillOpacity +
|
|
503
|
-
`;
|
|
504
|
-
marker-type: ellipse;
|
|
505
|
-
marker-width: [width];
|
|
506
|
-
marker-line-width: 0;
|
|
507
|
-
marker-allow-overlap: true;
|
|
508
|
-
marker-ignore-placement: true;
|
|
509
|
-
marker-fill: ` +
|
|
510
|
-
(design.color || "transparent") +
|
|
511
|
-
`;
|
|
512
|
-
}\
|
|
513
|
-
`;
|
|
514
|
-
// If color axes, add color conditions
|
|
515
|
-
if (design.axes.color != null && design.axes.color.colorMap != null) {
|
|
516
|
-
for (let item of design.axes.color.colorMap) {
|
|
517
|
-
// If invisible
|
|
518
|
-
if ((design.axes.color.excludedValues || []).includes(item.value)) {
|
|
519
|
-
css += `#layer0 [color=${JSON.stringify(item.value)}] { marker-fill-opacity: 0; }\n`;
|
|
520
|
-
}
|
|
521
|
-
else {
|
|
522
|
-
css += `#layer0 [color=${JSON.stringify(item.value)}] { marker-fill: ${item.color}; }\n`;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return css;
|
|
527
|
-
}
|
|
528
299
|
// Called when the interactivity grid is clicked.
|
|
529
300
|
// arguments:
|
|
530
301
|
// ev: { data: interactivty data e.g. `{ id: 123 }` }
|
|
@@ -686,7 +457,7 @@ marker-fill: ` +
|
|
|
686
457
|
// Get the legend to be optionally displayed on the map. Returns
|
|
687
458
|
// a React element
|
|
688
459
|
getLegend(options) {
|
|
689
|
-
const { design, schema, name, dataSource, locale, filters } = options;
|
|
460
|
+
const { design, schema, name, dataSource, locale, filters, translate } = options;
|
|
690
461
|
const _filters = filters.slice();
|
|
691
462
|
if (design.filter != null) {
|
|
692
463
|
const exprCompiler = new expressions_1.ExprCompiler(schema);
|
|
@@ -696,16 +467,18 @@ marker-fill: ` +
|
|
|
696
467
|
}
|
|
697
468
|
}
|
|
698
469
|
const axisBuilder = new AxisBuilder_1.default({ schema });
|
|
470
|
+
// Clean and translate axis
|
|
471
|
+
const axis = (0, MapUtils_1.translateAxis)(axisBuilder.cleanAxis({
|
|
472
|
+
axis: design.axes.color,
|
|
473
|
+
table: design.table,
|
|
474
|
+
types: ["enum", "text", "boolean", "date"],
|
|
475
|
+
aggrNeed: "none"
|
|
476
|
+
}), translate);
|
|
699
477
|
return react_1.default.createElement(LayerLegendComponent_1.default, {
|
|
700
478
|
schema,
|
|
701
|
-
name,
|
|
479
|
+
name: translate(name),
|
|
702
480
|
filters: lodash_1.default.compact(_filters),
|
|
703
|
-
axis:
|
|
704
|
-
axis: design.axes.color,
|
|
705
|
-
table: design.table,
|
|
706
|
-
types: ["enum", "text", "boolean", "date"],
|
|
707
|
-
aggrNeed: "none"
|
|
708
|
-
}),
|
|
481
|
+
axis: axis,
|
|
709
482
|
radiusLayer: true,
|
|
710
483
|
defaultColor: design.color,
|
|
711
484
|
locale
|
|
@@ -827,6 +600,8 @@ marker-fill: ` +
|
|
|
827
600
|
/** Get strings to be translated */
|
|
828
601
|
getTranslatableStrings(design, schema) {
|
|
829
602
|
const strings = [];
|
|
603
|
+
// Add strings from axis category labels and null labels
|
|
604
|
+
strings.push(...(0, MapUtils_1.getTranslatableStringsFromAxis)(design.axes.color));
|
|
830
605
|
// Add strings from hoverOver items
|
|
831
606
|
if (design.hoverOver && design.hoverOver.items) {
|
|
832
607
|
for (const item of design.hoverOver.items) {
|
|
@@ -24,7 +24,7 @@ export default class BufferLayerDesignerComponent extends React.Component<Buffer
|
|
|
24
24
|
renderTable(): React.JSX.Element;
|
|
25
25
|
renderGeometryAxis(): React.JSX.Element | undefined;
|
|
26
26
|
renderRadius(): React.JSX.Element;
|
|
27
|
-
renderUnionShapes(): React.JSX.Element
|
|
27
|
+
renderUnionShapes(): React.JSX.Element;
|
|
28
28
|
renderColor(): React.JSX.Element | undefined;
|
|
29
29
|
renderFillOpacity(): React.JSX.Element;
|
|
30
30
|
renderFilter(): React.JSX.Element | null;
|
|
@@ -38,7 +38,6 @@ const EditPopupComponent_1 = __importDefault(require("./EditPopupComponent"));
|
|
|
38
38
|
const ZoomLevelsComponent_1 = __importDefault(require("./ZoomLevelsComponent"));
|
|
39
39
|
const PopupFilterJoinsUtils = __importStar(require("./PopupFilterJoinsUtils"));
|
|
40
40
|
const bootstrap_1 = require("@mwater/react-library/lib/bootstrap");
|
|
41
|
-
const vectorMaps_1 = require("./vectorMaps");
|
|
42
41
|
const EditHoverOver_1 = require("./EditHoverOver");
|
|
43
42
|
class BufferLayerDesignerComponent extends react_1.default.Component {
|
|
44
43
|
handleTableChange = (table) => {
|
|
@@ -104,10 +103,6 @@ class BufferLayerDesignerComponent extends react_1.default.Component {
|
|
|
104
103
|
react_1.default.createElement(expressions_ui_1.ExprComponent, { schema: this.props.schema, value: radiusExpr, onChange: this.handleRadiusExprChange, dataSource: this.props.dataSource, table: this.props.design.table, types: ["number"] })));
|
|
105
104
|
}
|
|
106
105
|
renderUnionShapes() {
|
|
107
|
-
// Only implemented for vector maps
|
|
108
|
-
if (!(0, vectorMaps_1.areVectorMapsEnabled)()) {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
106
|
return (react_1.default.createElement("div", { className: "mb-3" },
|
|
112
107
|
react_1.default.createElement(bootstrap_1.Checkbox, { value: this.props.design.unionShapes, onChange: this.handleUnionShapesChange }, T `Combine circles (advanced)`)));
|
|
113
108
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React, { ReactNode } from "react";
|
|
2
2
|
import Layer, { OnGridClickOptions, OnGridHoverOptions, VectorTileDef, LegendOptions } from "./Layer";
|
|
3
3
|
import { Schema, DataSource } from "@mwater/expressions";
|
|
4
|
-
import {
|
|
4
|
+
import { OnGridClickResults, OnGridHoverResults } from "./maps";
|
|
5
5
|
import { JsonQLFilter } from "../index";
|
|
6
6
|
import ChoroplethLayerDesign from "./ChoroplethLayerDesign";
|
|
7
|
-
import { JsonQLQuery } from "@mwater/jsonql";
|
|
8
7
|
export default class ChoroplethLayer extends Layer<ChoroplethLayerDesign> {
|
|
9
8
|
/** Gets the type of layer definition */
|
|
10
9
|
getLayerDefinitionType(): "VectorTile";
|
|
@@ -12,20 +11,6 @@ export default class ChoroplethLayer extends Layer<ChoroplethLayerDesign> {
|
|
|
12
11
|
createPlainVectorTile(design: ChoroplethLayerDesign, sourceId: string, schema: Schema, filters: JsonQLFilter[], opacity: number): VectorTileDef;
|
|
13
12
|
createIndirectVectorTile(design: ChoroplethLayerDesign, sourceId: string, schema: Schema, filters: JsonQLFilter[], opacity: number): VectorTileDef;
|
|
14
13
|
createDirectVectorTile(design: ChoroplethLayerDesign, sourceId: string, schema: Schema, filters: JsonQLFilter[], opacity: number): VectorTileDef;
|
|
15
|
-
/** Gets the layer definition as JsonQL + CSS in format:
|
|
16
|
-
* {
|
|
17
|
-
* layers: array of { id: layer id, jsonql: jsonql that includes "the_webmercator_geom" as a column }
|
|
18
|
-
* css: carto css
|
|
19
|
-
* interactivity: (optional) { layer: id of layer, fields: array of field names }
|
|
20
|
-
* }
|
|
21
|
-
* arguments:
|
|
22
|
-
* design: design of layer
|
|
23
|
-
* schema: schema to use
|
|
24
|
-
* filters: array of filters to apply
|
|
25
|
-
*/
|
|
26
|
-
getJsonQLCss(design: ChoroplethLayerDesign, schema: Schema, filters: JsonQLFilter[]): LayerDefinition;
|
|
27
|
-
createMapnikJsonQL(design: ChoroplethLayerDesign, schema: Schema, filters: JsonQLFilter[]): JsonQLQuery;
|
|
28
|
-
createCss(design: ChoroplethLayerDesign, schema: Schema, filters: JsonQLFilter[]): string;
|
|
29
14
|
/**
|
|
30
15
|
* Called when the interactivity grid is clicked.
|
|
31
16
|
* arguments:
|