@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.
Files changed (92) hide show
  1. package/lib/ColorComponent.js +2 -2
  2. package/lib/TranslationsTabComponent.d.ts +34 -0
  3. package/lib/TranslationsTabComponent.js +256 -0
  4. package/lib/dashboards/DashboardComponent.js +1 -1
  5. package/lib/dashboards/ServerDashboardDataSource.d.ts +0 -1
  6. package/lib/dashboards/ServerDashboardDataSource.js +0 -15
  7. package/lib/dashboards/SettingsModalComponent.js +9 -233
  8. package/lib/datagrids/DatagridComponent.js +5 -0
  9. package/lib/datagrids/DatagridViewComponent.js +30 -4
  10. package/lib/maps/BufferLayer.d.ts +0 -13
  11. package/lib/maps/BufferLayer.js +12 -237
  12. package/lib/maps/BufferLayerDesignerComponent.d.ts +1 -1
  13. package/lib/maps/BufferLayerDesignerComponent.js +0 -5
  14. package/lib/maps/ChoroplethLayer.d.ts +1 -16
  15. package/lib/maps/ChoroplethLayer.js +13 -358
  16. package/lib/maps/ClusterLayer.d.ts +0 -9
  17. package/lib/maps/ClusterLayer.js +0 -250
  18. package/lib/maps/DirectMapDataSource.js +1 -38
  19. package/lib/maps/GridLayer.d.ts +0 -15
  20. package/lib/maps/GridLayer.js +0 -212
  21. package/lib/maps/Layer.d.ts +1 -26
  22. package/lib/maps/Layer.js +0 -13
  23. package/lib/maps/MapComponent.d.ts +19 -35
  24. package/lib/maps/MapComponent.js +135 -76
  25. package/lib/maps/MapControlComponent.d.ts +4 -5
  26. package/lib/maps/MapControlComponent.js +5 -12
  27. package/lib/maps/MapDesign.d.ts +8 -0
  28. package/lib/maps/MapDesignerComponent.d.ts +2 -0
  29. package/lib/maps/MapDesignerComponent.js +7 -2
  30. package/lib/maps/MapLayerDataSource.d.ts +0 -4
  31. package/lib/maps/MapLayerViewDesignerComponent.d.ts +3 -1
  32. package/lib/maps/MapLayerViewDesignerComponent.js +5 -1
  33. package/lib/maps/MapLayersDesignerComponent.d.ts +2 -0
  34. package/lib/maps/MapLayersDesignerComponent.js +2 -1
  35. package/lib/maps/MapTranslationsTab.d.ts +15 -0
  36. package/lib/maps/MapTranslationsTab.js +47 -0
  37. package/lib/maps/MapUtils.d.ts +11 -0
  38. package/lib/maps/MapUtils.js +47 -0
  39. package/lib/maps/MapViewComponent.d.ts +1 -1
  40. package/lib/maps/MapViewComponent.js +1 -8
  41. package/lib/maps/MarkersLayer.d.ts +1 -14
  42. package/lib/maps/MarkersLayer.js +71 -252
  43. package/lib/maps/MarkersLayerDesign.d.ts +4 -0
  44. package/lib/maps/MarkersLayerDesignerComponent.d.ts +20 -16
  45. package/lib/maps/MarkersLayerDesignerComponent.js +77 -23
  46. package/lib/maps/ServerMapDataSource.d.ts +0 -1
  47. package/lib/maps/ServerMapDataSource.js +0 -15
  48. package/lib/maps/SwitchableTileUrlLayer.d.ts +0 -2
  49. package/lib/maps/SwitchableTileUrlLayer.js +0 -9
  50. package/lib/maps/TileUrlLayer.d.ts +0 -1
  51. package/lib/maps/TileUrlLayer.js +0 -5
  52. package/lib/maps/VectorMapViewComponent.js +12 -1
  53. package/lib/maps/vectorMaps.d.ts +5 -6
  54. package/lib/maps/vectorMaps.js +13 -9
  55. package/lib/widgets/MapWidget.js +2 -1
  56. package/package.json +2 -2
  57. package/src/ColorComponent.tsx +2 -2
  58. package/src/TranslationsTabComponent.tsx +429 -0
  59. package/src/dashboards/DashboardComponent.tsx +1 -1
  60. package/src/dashboards/ServerDashboardDataSource.ts +0 -19
  61. package/src/dashboards/SettingsModalComponent.tsx +27 -383
  62. package/src/datagrids/DatagridComponent.tsx +6 -0
  63. package/src/datagrids/DatagridViewComponent.tsx +41 -5
  64. package/src/maps/BufferLayer.ts +16 -262
  65. package/src/maps/BufferLayerDesignerComponent.tsx +0 -6
  66. package/src/maps/ChoroplethLayer.ts +16 -393
  67. package/src/maps/ClusterLayer.ts +0 -274
  68. package/src/maps/DirectMapDataSource.ts +2 -49
  69. package/src/maps/GridLayer.ts +0 -224
  70. package/src/maps/Layer.ts +1 -35
  71. package/src/maps/MapComponent.tsx +448 -0
  72. package/src/maps/MapControlComponent.tsx +41 -0
  73. package/src/maps/MapDesign.ts +6 -0
  74. package/src/maps/MapDesignerComponent.tsx +18 -1
  75. package/src/maps/MapLayerDataSource.ts +0 -5
  76. package/src/maps/MapLayerViewDesignerComponent.ts +9 -2
  77. package/src/maps/MapLayersDesignerComponent.ts +4 -1
  78. package/src/maps/MapTranslationsTab.tsx +53 -0
  79. package/src/maps/MapUtils.ts +48 -0
  80. package/src/maps/MapViewComponent.tsx +2 -8
  81. package/src/maps/MarkersLayer.ts +79 -270
  82. package/src/maps/MarkersLayerDesign.ts +6 -0
  83. package/src/maps/MarkersLayerDesignerComponent.tsx +114 -38
  84. package/src/maps/ServerMapDataSource.ts +0 -19
  85. package/src/maps/SwitchableTileUrlLayer.tsx +0 -11
  86. package/src/maps/TileUrlLayer.tsx +0 -6
  87. package/src/maps/VectorMapViewComponent.tsx +13 -2
  88. package/src/maps/vectorMaps.tsx +12 -9
  89. package/src/widgets/MapWidget.tsx +2 -0
  90. package/src/maps/MapComponent.ts +0 -311
  91. package/src/maps/MapControlComponent.ts +0 -46
  92. package/src/maps/RasterMapViewComponent.ts +0 -345
@@ -18,7 +18,7 @@ import { getDefaultLayoutOptions } from "../dashboards/layoutOptions"
18
18
  import Widget from "../widgets/Widget"
19
19
  import BlocksLayoutManager from "../layouts/blocks/BlocksLayoutManager"
20
20
  import { getTranslatableStringsFromLayoutManager } from "../dashboards/DashboardUtils"
21
- import { getSimpleHoverOverData } from "./MapUtils"
21
+ import { getSimpleHoverOverData, getTranslatableStringsFromAxis, translateAxis } from "./MapUtils"
22
22
 
23
23
  /** Layer which draws a buffer around geometries (i.e. a radius circle around points) */
24
24
  export default class BufferLayer extends Layer<BufferLayerDesign> {
@@ -313,259 +313,6 @@ export default class BufferLayer extends Layer<BufferLayerDesign> {
313
313
  return query
314
314
  }
315
315
 
316
- // Gets the layer definition as JsonQL + CSS in format:
317
- // {
318
- // layers: array of { id: layer id, jsonql: jsonql that includes "the_webmercator_geom" as a column }
319
- // css: carto css
320
- // interactivity: (optional) { layer: id of layer, fields: array of field names }
321
- // }
322
- // arguments:
323
- // design: design of layer
324
- // schema: schema to use
325
- // 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
326
- getJsonQLCss(design: BufferLayerDesign, schema: Schema, filters: JsonQLFilter[]) {
327
- // Create design
328
- const layerDef = {
329
- layers: [{ id: "layer0", jsonql: this.createMapnikJsonQL(design, schema, filters) }],
330
- css: this.createCss(design, schema),
331
- interactivity: {
332
- layer: "layer0",
333
- fields: ["id"]
334
- }
335
- }
336
-
337
- return layerDef
338
- }
339
-
340
- createMapnikJsonQL(design: BufferLayerDesign, schema: Schema, filters: JsonQLFilter[]) {
341
- let colorExpr: JsonQLExpr
342
- const axisBuilder = new AxisBuilder({ schema })
343
- const exprCompiler = new ExprCompiler(schema)
344
-
345
- // Get radius expression
346
- const radiusCompiledExpr: JsonQLExpr = exprCompiler.compileExpr({
347
- expr: design.radiusExpr ?? { type: "literal", valueType: "number", value: design.radius },
348
- tableAlias: "main"
349
- })
350
-
351
- // Convert radius in meters to a maximum number of degrees latitude
352
- const radiusDegCompiledExpr: JsonQLExpr = { type: "op", op: "/", exprs: [radiusCompiledExpr, 100000] }
353
-
354
- /*
355
- Query:
356
- select
357
- <primary key> as id,
358
- [<color axis> as color,
359
- st_transform(<geometry axis>, 3857) as the_geom_webmercator,
360
- radius * 2 / (!pixel_width! * cos(st_ymin(st_transform(geometryExpr, 4326)) * 0.017453293) as width
361
- from <table> as main
362
- where
363
- <geometry axis> is not null
364
- * Bounding box filter for speed
365
- and <geometry axis> &&
366
- ST_Transform(ST_Expand(
367
- * Prevent 3857 overflow (i.e. > 85 degrees lat)
368
- ST_Intersection(
369
- ST_Transform(!bbox!, 4326),
370
- ST_Expand(ST_MakeEnvelope(-180, -85, 180, 85, 4326), -<radius in degrees>))
371
- , <radius in degrees>})
372
- , 3857)
373
- and <other filters>
374
- */
375
-
376
- // Compile geometry axis
377
- let geometryExpr = axisBuilder.compileAxis({ axis: design.axes.geometry!, tableAlias: "main" })
378
-
379
- // radius * 2 / (!pixel_width! * cos(st_ymin(st_transform(geometryExpr, 4326)) * 0.017453293) + 1 # add one to make always visible
380
- const widthExpr: JsonQLExpr = {
381
- type: "op",
382
- op: "+",
383
- exprs: [
384
- {
385
- type: "op",
386
- op: "/",
387
- exprs: [
388
- { type: "op", op: "*", exprs: [radiusCompiledExpr, 2] },
389
- {
390
- type: "op",
391
- op: "*",
392
- exprs: [
393
- { type: "op", op: "nullif", exprs: [{ type: "token", token: "!pixel_height!" }, 0] },
394
- {
395
- type: "op",
396
- op: "cos",
397
- exprs: [
398
- {
399
- type: "op",
400
- op: "*",
401
- exprs: [
402
- {
403
- type: "op",
404
- op: "ST_YMIN",
405
- exprs: [{ type: "op", op: "ST_Transform", exprs: [geometryExpr, 4326] }]
406
- },
407
- 0.017453293
408
- ]
409
- }
410
- ]
411
- }
412
- ]
413
- }
414
- ]
415
- },
416
- 2
417
- ]
418
- }
419
-
420
- const selects: JsonQLSelect[] = [
421
- {
422
- type: "select",
423
- expr: { type: "field", tableAlias: "main", column: schema.getTable(design.table)!.primaryKey },
424
- alias: "id"
425
- }, // main primary key as id
426
- { type: "select", expr: geometryExpr, alias: "the_geom_webmercator" },
427
- { type: "select", expr: widthExpr, alias: "width" } // Width of circles
428
- ]
429
-
430
- // Add color select if color axis
431
- if (design.axes.color) {
432
- colorExpr = axisBuilder.compileAxis({ axis: design.axes.color, tableAlias: "main" })
433
- selects.push({ type: "select", expr: colorExpr, alias: "color" })
434
- }
435
-
436
- // Select _id, location and clustered row number
437
- const query: JsonQLQuery = {
438
- type: "query",
439
- selects,
440
- from: exprCompiler.compileTable(design.table, "main")
441
- }
442
-
443
- const boundingBox: JsonQLExpr = {
444
- type: "op",
445
- op: "ST_Transform",
446
- exprs: [
447
- {
448
- type: "op",
449
- op: "ST_Expand",
450
- exprs: [
451
- {
452
- type: "op",
453
- op: "ST_Intersection",
454
- exprs: [
455
- { type: "op", op: "ST_Transform", exprs: [{ type: "token", token: "!bbox!" }, 4326] },
456
- {
457
- type: "op",
458
- op: "ST_Expand",
459
- exprs: [
460
- { type: "op", op: "ST_MakeEnvelope", exprs: [-180, -85, 180, 85, 4326] },
461
- { type: "op", op: "*", exprs: [radiusDegCompiledExpr, -1] }
462
- ]
463
- }
464
- ]
465
- },
466
- radiusDegCompiledExpr
467
- ]
468
- },
469
- 3857
470
- ]
471
- }
472
-
473
- // Create filters. First ensure geometry and limit to bounding box
474
- let whereClauses: JsonQLExpr[] = [
475
- { type: "op", op: "is not null", exprs: [geometryExpr] },
476
- {
477
- type: "op",
478
- op: "&&",
479
- exprs: [geometryExpr, boundingBox]
480
- }
481
- ]
482
-
483
- // Then add filters baked into layer
484
- if (design.filter) {
485
- whereClauses.push(exprCompiler.compileExpr({ expr: design.filter, tableAlias: "main" }))
486
- }
487
-
488
- // Then add extra filters passed in, if relevant
489
- // Get relevant filters
490
- const relevantFilters = _.where(filters, { table: design.table })
491
- for (let filter of relevantFilters) {
492
- whereClauses.push(injectTableAlias(filter.jsonql, "main"))
493
- }
494
-
495
- whereClauses = _.compact(whereClauses)
496
-
497
- // Wrap if multiple
498
- if (whereClauses.length > 1) {
499
- query.where = { type: "op", op: "and", exprs: whereClauses }
500
- } else {
501
- query.where = whereClauses[0]
502
- }
503
-
504
- // Sort order
505
- if (design.axes.color && design.axes.color.colorMap) {
506
- // TODO should use categories, not colormap order
507
- const order = design.axes.color.drawOrder || _.pluck(design.axes.color.colorMap, "value")
508
- const categories = axisBuilder.getCategories(design.axes.color, order)
509
-
510
- const cases = _.map(categories, (category, i) => {
511
- return {
512
- when:
513
- category.value != null
514
- ? ({ type: "op", op: "=", exprs: [colorExpr, category.value] } as JsonQLExpr)
515
- : ({ type: "op", op: "is null", exprs: [colorExpr] } as JsonQLExpr),
516
- then: order.indexOf(category.value) || -1
517
- }
518
- })
519
-
520
- if (cases.length > 0) {
521
- query.orderBy = [
522
- {
523
- expr: {
524
- type: "case",
525
- cases
526
- },
527
- direction: "desc" // Reverse color map order
528
- }
529
- ]
530
- }
531
- }
532
-
533
- return query
534
- }
535
-
536
- createCss(design: BufferLayerDesign, schema: Schema) {
537
- let css =
538
- `\
539
- #layer0 {
540
- marker-fill-opacity: ` +
541
- design.fillOpacity +
542
- `;
543
- marker-type: ellipse;
544
- marker-width: [width];
545
- marker-line-width: 0;
546
- marker-allow-overlap: true;
547
- marker-ignore-placement: true;
548
- marker-fill: ` +
549
- (design.color || "transparent") +
550
- `;
551
- }\
552
- `
553
-
554
- // If color axes, add color conditions
555
- if (design.axes.color != null && design.axes.color.colorMap != null) {
556
- for (let item of design.axes.color.colorMap) {
557
- // If invisible
558
- if ((design.axes.color.excludedValues || []).includes(item.value)) {
559
- css += `#layer0 [color=${JSON.stringify(item.value)}] { marker-fill-opacity: 0; }\n`
560
- } else {
561
- css += `#layer0 [color=${JSON.stringify(item.value)}] { marker-fill: ${item.color}; }\n`
562
- }
563
- }
564
- }
565
-
566
- return css
567
- }
568
-
569
316
  // Called when the interactivity grid is clicked.
570
317
  // arguments:
571
318
  // ev: { data: interactivty data e.g. `{ id: 123 }` }
@@ -760,7 +507,7 @@ marker-fill: ` +
760
507
  // Get the legend to be optionally displayed on the map. Returns
761
508
  // a React element
762
509
  getLegend(options: LegendOptions<BufferLayerDesign>): ReactNode {
763
- const { design, schema, name, dataSource, locale, filters } = options
510
+ const { design, schema, name, dataSource, locale, filters, translate } = options
764
511
  const _filters = filters.slice()
765
512
  if (design.filter != null) {
766
513
  const exprCompiler = new ExprCompiler(schema)
@@ -771,16 +518,20 @@ marker-fill: ` +
771
518
  }
772
519
 
773
520
  const axisBuilder = new AxisBuilder({ schema })
521
+
522
+ // Clean and translate axis
523
+ const axis = translateAxis(axisBuilder.cleanAxis({
524
+ axis: design.axes.color,
525
+ table: design.table,
526
+ types: ["enum", "text", "boolean", "date"],
527
+ aggrNeed: "none"
528
+ }), translate)
529
+
774
530
  return React.createElement(LayerLegendComponent, {
775
531
  schema,
776
- name,
532
+ name: translate(name),
777
533
  filters: _.compact(_filters),
778
- axis: axisBuilder.cleanAxis({
779
- axis: design.axes.color,
780
- table: design.table,
781
- types: ["enum", "text", "boolean", "date"],
782
- aggrNeed: "none"
783
- })!,
534
+ axis: axis!,
784
535
  radiusLayer: true,
785
536
  defaultColor: design.color,
786
537
  locale
@@ -932,6 +683,9 @@ marker-fill: ` +
932
683
  getTranslatableStrings(design: BufferLayerDesign, schema: Schema): string[] {
933
684
  const strings: string[] = []
934
685
 
686
+ // Add strings from axis category labels and null labels
687
+ strings.push(...getTranslatableStringsFromAxis(design.axes.color))
688
+
935
689
  // Add strings from hoverOver items
936
690
  if (design.hoverOver && design.hoverOver.items) {
937
691
  for (const item of design.hoverOver.items) {
@@ -14,7 +14,6 @@ import * as PopupFilterJoinsUtils from "./PopupFilterJoinsUtils"
14
14
  import { Checkbox } from "@mwater/react-library/lib/bootstrap"
15
15
  import { BufferLayerDesign } from "./BufferLayerDesign"
16
16
  import { JsonQLFilter } from "../JsonQLFilter"
17
- import { areVectorMapsEnabled } from "./vectorMaps"
18
17
  import { EditHoverOver } from "./EditHoverOver"
19
18
 
20
19
  export interface BufferLayerDesignerComponentProps {
@@ -138,11 +137,6 @@ export default class BufferLayerDesignerComponent extends React.Component<Buffer
138
137
  }
139
138
 
140
139
  renderUnionShapes() {
141
- // Only implemented for vector maps
142
- if (!areVectorMapsEnabled()) {
143
- return null
144
- }
145
-
146
140
  return (
147
141
  <div className="mb-3">
148
142
  <Checkbox