@mwater/visualization 5.5.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 (275) hide show
  1. package/lib/ColorComponent.js +2 -2
  2. package/lib/MWaterContextComponent.d.ts +1 -1
  3. package/lib/MWaterGlobalFiltersComponent.d.ts +2 -2
  4. package/lib/MWaterGlobalFiltersComponent.js +11 -20
  5. package/lib/MWaterLoaderComponent.d.ts +4 -13
  6. package/lib/MWaterLoaderComponent.js +2 -11
  7. package/lib/TranslationsTabComponent.d.ts +34 -0
  8. package/lib/TranslationsTabComponent.js +256 -0
  9. package/lib/UndoStack.d.ts +2 -1
  10. package/lib/UndoStack.js +12 -6
  11. package/lib/dashboards/DashboardComponent.js +6 -5
  12. package/lib/dashboards/DashboardDesign.d.ts +1 -1
  13. package/lib/dashboards/ServerDashboardDataSource.d.ts +0 -1
  14. package/lib/dashboards/ServerDashboardDataSource.js +0 -25
  15. package/lib/dashboards/SettingsModalComponent.js +9 -233
  16. package/lib/datagrids/DatagridComponent.js +27 -2
  17. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -3
  18. package/lib/datagrids/DatagridDesignerComponent.js +108 -120
  19. package/lib/datagrids/DatagridViewComponent.js +33 -6
  20. package/lib/datagrids/OrderBysDesignerComponent.d.ts +7 -7
  21. package/lib/datagrids/OrderBysDesignerComponent.js +19 -28
  22. package/lib/index.css +45 -2
  23. package/lib/index.d.ts +5 -5
  24. package/lib/index.js +2 -3
  25. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +8 -1
  26. package/lib/layouts/blocks/BlocksDisplayComponent.js +46 -4
  27. package/lib/maps/BufferLayer.d.ts +0 -13
  28. package/lib/maps/BufferLayer.js +24 -237
  29. package/lib/maps/BufferLayerDesign.d.ts +1 -1
  30. package/lib/maps/BufferLayerDesignerComponent.d.ts +1 -1
  31. package/lib/maps/BufferLayerDesignerComponent.js +2 -7
  32. package/lib/maps/ChoroplethLayer.d.ts +1 -16
  33. package/lib/maps/ChoroplethLayer.js +25 -358
  34. package/lib/maps/ChoroplethLayerDesign.d.ts +5 -2
  35. package/lib/maps/ChoroplethLayerDesigner.d.ts +10 -32
  36. package/lib/maps/ChoroplethLayerDesigner.js +58 -89
  37. package/lib/maps/ClusterLayer.d.ts +0 -9
  38. package/lib/maps/ClusterLayer.js +0 -250
  39. package/lib/maps/DirectMapDataSource.js +1 -48
  40. package/lib/maps/EditHoverOver.d.ts +4 -3
  41. package/lib/maps/EditHoverOver.js +3 -3
  42. package/lib/maps/GridLayer.d.ts +0 -15
  43. package/lib/maps/GridLayer.js +0 -212
  44. package/lib/maps/HoverContent.js +1 -1
  45. package/lib/maps/Layer.d.ts +1 -26
  46. package/lib/maps/Layer.js +0 -13
  47. package/lib/maps/LeafletMapComponent.js +10 -19
  48. package/lib/maps/MapComponent.d.ts +19 -35
  49. package/lib/maps/MapComponent.js +135 -77
  50. package/lib/maps/MapControlComponent.d.ts +4 -5
  51. package/lib/maps/MapControlComponent.js +5 -12
  52. package/lib/maps/MapDesign.d.ts +8 -0
  53. package/lib/maps/MapDesignerComponent.d.ts +2 -0
  54. package/lib/maps/MapDesignerComponent.js +7 -2
  55. package/lib/maps/MapLayerDataSource.d.ts +0 -4
  56. package/lib/maps/MapLayerViewDesignerComponent.d.ts +3 -1
  57. package/lib/maps/MapLayerViewDesignerComponent.js +5 -1
  58. package/lib/maps/MapLayersDesignerComponent.d.ts +2 -0
  59. package/lib/maps/MapLayersDesignerComponent.js +2 -1
  60. package/lib/maps/MapTranslationsTab.d.ts +15 -0
  61. package/lib/maps/MapTranslationsTab.js +47 -0
  62. package/lib/maps/MapUtils.d.ts +11 -0
  63. package/lib/maps/MapUtils.js +57 -1
  64. package/lib/maps/MapViewComponent.d.ts +1 -1
  65. package/lib/maps/MapViewComponent.js +1 -8
  66. package/lib/maps/MarkersLayer.d.ts +1 -14
  67. package/lib/maps/MarkersLayer.js +89 -254
  68. package/lib/maps/MarkersLayerDesign.d.ts +5 -1
  69. package/lib/maps/MarkersLayerDesignerComponent.d.ts +32 -57
  70. package/lib/maps/MarkersLayerDesignerComponent.js +158 -134
  71. package/lib/maps/ServerMapDataSource.d.ts +0 -1
  72. package/lib/maps/ServerMapDataSource.js +0 -25
  73. package/lib/maps/SwitchableTileUrlLayer.d.ts +0 -2
  74. package/lib/maps/SwitchableTileUrlLayer.js +0 -9
  75. package/lib/maps/TileUrlLayer.d.ts +0 -1
  76. package/lib/maps/TileUrlLayer.js +0 -5
  77. package/lib/maps/VectorMapViewComponent.js +13 -10
  78. package/lib/maps/symbols/font-awesome/asterisk.png +0 -0
  79. package/lib/maps/symbols/font-awesome/ban.png +0 -0
  80. package/lib/maps/symbols/font-awesome/beer.png +0 -0
  81. package/lib/maps/symbols/font-awesome/bell.png +0 -0
  82. package/lib/maps/symbols/font-awesome/bolt.png +0 -0
  83. package/lib/maps/symbols/font-awesome/building.png +0 -0
  84. package/lib/maps/symbols/font-awesome/bullseye.png +0 -0
  85. package/lib/maps/symbols/font-awesome/bus.png +0 -0
  86. package/lib/maps/symbols/font-awesome/caret-up.png +0 -0
  87. package/lib/maps/symbols/font-awesome/certificate.png +0 -0
  88. package/lib/maps/symbols/font-awesome/check-circle.png +0 -0
  89. package/lib/maps/symbols/font-awesome/check.png +0 -0
  90. package/lib/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  91. package/lib/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  92. package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
  93. package/lib/maps/symbols/font-awesome/cloud.png +0 -0
  94. package/lib/maps/symbols/font-awesome/comment.png +0 -0
  95. package/lib/maps/symbols/font-awesome/crosshairs.png +0 -0
  96. package/lib/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  97. package/lib/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  98. package/lib/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  99. package/lib/maps/symbols/font-awesome/female.png +0 -0
  100. package/lib/maps/symbols/font-awesome/file.png +0 -0
  101. package/lib/maps/symbols/font-awesome/flag.png +0 -0
  102. package/lib/maps/symbols/font-awesome/flask.png +0 -0
  103. package/lib/maps/symbols/font-awesome/h-square.png +0 -0
  104. package/lib/maps/symbols/font-awesome/home.png +0 -0
  105. package/lib/maps/symbols/font-awesome/info-circle.png +0 -0
  106. package/lib/maps/symbols/font-awesome/male.png +0 -0
  107. package/lib/maps/symbols/font-awesome/medkit.png +0 -0
  108. package/lib/maps/symbols/font-awesome/mobile.png +0 -0
  109. package/lib/maps/symbols/font-awesome/plus-circle.png +0 -0
  110. package/lib/maps/symbols/font-awesome/plus-square.png +0 -0
  111. package/lib/maps/symbols/font-awesome/plus.png +0 -0
  112. package/lib/maps/symbols/font-awesome/square.png +0 -0
  113. package/lib/maps/symbols/font-awesome/star.png +0 -0
  114. package/lib/maps/symbols/font-awesome/thumbs-down.png +0 -0
  115. package/lib/maps/symbols/font-awesome/thumbs-up.png +0 -0
  116. package/lib/maps/symbols/font-awesome/ticket.png +0 -0
  117. package/lib/maps/symbols/font-awesome/times-circle.png +0 -0
  118. package/lib/maps/symbols/font-awesome/times.png +0 -0
  119. package/lib/maps/symbols/font-awesome/tint.png +0 -0
  120. package/lib/maps/symbols/font-awesome/tree.png +0 -0
  121. package/lib/maps/symbols/font-awesome/university.png +0 -0
  122. package/lib/maps/symbols/font-awesome/usd.png +0 -0
  123. package/lib/maps/symbols/font-awesome/user.png +0 -0
  124. package/lib/maps/symbols/font-awesome/users.png +0 -0
  125. package/lib/maps/symbols/font-awesome/wheelchair.png +0 -0
  126. package/lib/maps/symbols/sdf-ize.sh +93 -0
  127. package/lib/maps/vectorMaps.d.ts +6 -6
  128. package/lib/maps/vectorMaps.js +33 -45
  129. package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +4 -2
  130. package/lib/mwater_table_selection/IndicatorsListComponent.js +103 -34
  131. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.d.ts +18 -0
  132. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.js +80 -0
  133. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +26 -0
  134. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +237 -51
  135. package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +2 -2
  136. package/lib/mwater_table_selection/MWaterTableSelectComponent.js +9 -4
  137. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.d.ts +19 -0
  138. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.js +111 -0
  139. package/lib/quickfilter/QuickfiltersComponent.d.ts +3 -102
  140. package/lib/quickfilter/QuickfiltersComponent.js +53 -110
  141. package/lib/quickfilter/TextLiteralComponent.d.ts +23 -47
  142. package/lib/quickfilter/TextLiteralComponent.js +85 -82
  143. package/lib/widgets/MapWidget.js +6 -3
  144. package/lib/widgets/text/ExprItemEditorComponent.d.ts +3 -8
  145. package/lib/widgets/text/ExprItemEditorComponent.js +36 -33
  146. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +1 -0
  147. package/package.json +3 -4
  148. package/src/ColorComponent.tsx +2 -2
  149. package/src/MWaterContextComponent.tsx +1 -1
  150. package/src/{MWaterGlobalFiltersComponent.ts → MWaterGlobalFiltersComponent.tsx} +32 -33
  151. package/src/{MWaterLoaderComponent.ts → MWaterLoaderComponent.tsx} +17 -18
  152. package/src/TranslationsTabComponent.tsx +429 -0
  153. package/src/UndoStack.ts +14 -6
  154. package/src/dashboards/DashboardComponent.tsx +6 -5
  155. package/src/dashboards/DashboardDesign.ts +1 -1
  156. package/src/dashboards/ServerDashboardDataSource.ts +0 -31
  157. package/src/dashboards/SettingsModalComponent.tsx +27 -383
  158. package/src/datagrids/DatagridComponent.tsx +36 -2
  159. package/src/datagrids/DatagridDesignerComponent.tsx +241 -229
  160. package/src/datagrids/DatagridViewComponent.tsx +44 -7
  161. package/src/datagrids/OrderBysDesignerComponent.tsx +61 -70
  162. package/src/index.css +45 -2
  163. package/src/index.ts +5 -11
  164. package/src/layouts/blocks/BlocksDisplayComponent.tsx +60 -5
  165. package/src/maps/BufferLayer.ts +30 -263
  166. package/src/maps/BufferLayerDesign.ts +1 -1
  167. package/src/maps/BufferLayerDesignerComponent.tsx +2 -7
  168. package/src/maps/ChoroplethLayer.ts +30 -394
  169. package/src/maps/ChoroplethLayerDesign.ts +5 -2
  170. package/src/maps/ChoroplethLayerDesigner.tsx +169 -165
  171. package/src/maps/ClusterLayer.ts +0 -274
  172. package/src/maps/DirectMapDataSource.ts +2 -61
  173. package/src/maps/EditHoverOver.tsx +9 -5
  174. package/src/maps/GridLayer.ts +0 -224
  175. package/src/maps/HoverContent.tsx +1 -1
  176. package/src/maps/Layer.ts +1 -35
  177. package/src/maps/LeafletMapComponent.tsx +10 -19
  178. package/src/maps/MapComponent.tsx +448 -0
  179. package/src/maps/MapControlComponent.tsx +41 -0
  180. package/src/maps/MapDesign.ts +6 -0
  181. package/src/maps/MapDesignerComponent.tsx +18 -1
  182. package/src/maps/MapLayerDataSource.ts +0 -5
  183. package/src/maps/MapLayerViewDesignerComponent.ts +9 -2
  184. package/src/maps/MapLayersDesignerComponent.ts +4 -1
  185. package/src/maps/MapTranslationsTab.tsx +53 -0
  186. package/src/maps/MapUtils.ts +61 -1
  187. package/src/maps/MapViewComponent.tsx +2 -8
  188. package/src/maps/MarkersLayer.ts +101 -275
  189. package/src/maps/MarkersLayerDesign.ts +7 -1
  190. package/src/maps/MarkersLayerDesignerComponent.tsx +436 -0
  191. package/src/maps/ServerMapDataSource.ts +0 -31
  192. package/src/maps/SwitchableTileUrlLayer.tsx +0 -11
  193. package/src/maps/TileUrlLayer.tsx +0 -6
  194. package/src/maps/VectorMapViewComponent.tsx +15 -15
  195. package/src/maps/symbols/font-awesome/asterisk.png +0 -0
  196. package/src/maps/symbols/font-awesome/ban.png +0 -0
  197. package/src/maps/symbols/font-awesome/beer.png +0 -0
  198. package/src/maps/symbols/font-awesome/bell.png +0 -0
  199. package/src/maps/symbols/font-awesome/bolt.png +0 -0
  200. package/src/maps/symbols/font-awesome/building.png +0 -0
  201. package/src/maps/symbols/font-awesome/bullseye.png +0 -0
  202. package/src/maps/symbols/font-awesome/bus.png +0 -0
  203. package/src/maps/symbols/font-awesome/caret-up.png +0 -0
  204. package/src/maps/symbols/font-awesome/certificate.png +0 -0
  205. package/src/maps/symbols/font-awesome/check-circle.png +0 -0
  206. package/src/maps/symbols/font-awesome/check.png +0 -0
  207. package/src/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  208. package/src/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  209. package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
  210. package/src/maps/symbols/font-awesome/cloud.png +0 -0
  211. package/src/maps/symbols/font-awesome/comment.png +0 -0
  212. package/src/maps/symbols/font-awesome/crosshairs.png +0 -0
  213. package/src/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  214. package/src/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  215. package/src/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  216. package/src/maps/symbols/font-awesome/female.png +0 -0
  217. package/src/maps/symbols/font-awesome/file.png +0 -0
  218. package/src/maps/symbols/font-awesome/flag.png +0 -0
  219. package/src/maps/symbols/font-awesome/flask.png +0 -0
  220. package/src/maps/symbols/font-awesome/h-square.png +0 -0
  221. package/src/maps/symbols/font-awesome/home.png +0 -0
  222. package/src/maps/symbols/font-awesome/info-circle.png +0 -0
  223. package/src/maps/symbols/font-awesome/male.png +0 -0
  224. package/src/maps/symbols/font-awesome/medkit.png +0 -0
  225. package/src/maps/symbols/font-awesome/mobile.png +0 -0
  226. package/src/maps/symbols/font-awesome/plus-circle.png +0 -0
  227. package/src/maps/symbols/font-awesome/plus-square.png +0 -0
  228. package/src/maps/symbols/font-awesome/plus.png +0 -0
  229. package/src/maps/symbols/font-awesome/square.png +0 -0
  230. package/src/maps/symbols/font-awesome/star.png +0 -0
  231. package/src/maps/symbols/font-awesome/thumbs-down.png +0 -0
  232. package/src/maps/symbols/font-awesome/thumbs-up.png +0 -0
  233. package/src/maps/symbols/font-awesome/ticket.png +0 -0
  234. package/src/maps/symbols/font-awesome/times-circle.png +0 -0
  235. package/src/maps/symbols/font-awesome/times.png +0 -0
  236. package/src/maps/symbols/font-awesome/tint.png +0 -0
  237. package/src/maps/symbols/font-awesome/tree.png +0 -0
  238. package/src/maps/symbols/font-awesome/university.png +0 -0
  239. package/src/maps/symbols/font-awesome/usd.png +0 -0
  240. package/src/maps/symbols/font-awesome/user.png +0 -0
  241. package/src/maps/symbols/font-awesome/users.png +0 -0
  242. package/src/maps/symbols/font-awesome/wheelchair.png +0 -0
  243. package/src/maps/symbols/sdf-ize.sh +93 -0
  244. package/src/maps/vectorMaps.tsx +32 -53
  245. package/src/mwater_table_selection/IndicatorsListComponent.tsx +165 -37
  246. package/src/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.tsx +111 -0
  247. package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +373 -37
  248. package/src/mwater_table_selection/MWaterTableSelectComponent.tsx +12 -8
  249. package/src/mwater_table_selection/MWaterWorkflowsSelectComponent.tsx +159 -0
  250. package/src/quickfilter/{QuickfiltersComponent.ts → QuickfiltersComponent.tsx} +165 -158
  251. package/src/quickfilter/TextLiteralComponent.tsx +197 -0
  252. package/src/widgets/MapWidget.tsx +11 -1
  253. package/src/widgets/text/ExprItemEditorComponent.tsx +83 -77
  254. package/src/widgets/text/ExprUpdateModalComponent.tsx +1 -0
  255. package/test/UndoStackTests.ts +52 -1
  256. package/.storybook/config.js +0 -7
  257. package/.storybook/head.html +0 -3
  258. package/.storybook/webpack.config.js +0 -15
  259. package/src/maps/BingLayer.ts +0 -146
  260. package/src/maps/MapComponent.ts +0 -312
  261. package/src/maps/MapControlComponent.ts +0 -46
  262. package/src/maps/MarkersLayerDesignerComponent.ts +0 -374
  263. package/src/maps/RasterMapViewComponent.ts +0 -345
  264. package/src/quickfilter/TextLiteralComponent.ts +0 -165
  265. package/stories/UpdateableComponent.js +0 -29
  266. package/stories/consoles.js +0 -202
  267. package/stories/dashboards.js +0 -217
  268. package/stories/datagridDesign.js +0 -114
  269. package/stories/datagrids.js +0 -69
  270. package/stories/dates.js +0 -80
  271. package/stories/exprcomponent.js +0 -43
  272. package/stories/index.js +0 -18
  273. package/stories/leaflet.js +0 -59
  274. package/stories/maps.js +0 -24
  275. package/stories/pivotChart.js +0 -235
@@ -0,0 +1,93 @@
1
+ #!/bin/bash
2
+
3
+
4
+ # https://stackoverflow.com/questions/63299999/how-can-i-create-sdf-icons-used-in-mapbox-from-png#63314688
5
+
6
+ set -o pipefail
7
+ set -exu
8
+
9
+ cd "$(dirname "$0")"
10
+
11
+ MKTEMP="$(which gmktemp || which mktemp)"
12
+ TMPDIR1="$("$MKTEMP" -d)"
13
+ TMPDIR2="$("$MKTEMP" -d)"
14
+
15
+ trap "rm -rf '$TMPDIR1' '$TMPDIR2' ; pkill -P '$$'" EXIT
16
+
17
+ declare -a IMGFILES
18
+
19
+ IMGFILES=(
20
+ asterisk.png
21
+ ban.png
22
+ beer.png
23
+ bell.png
24
+ bolt.png
25
+ building.png
26
+ bullseye.png
27
+ bus.png
28
+ caret-up.png
29
+ certificate.png
30
+ check-circle.png
31
+ check.png
32
+ chevron-circle-down.png
33
+ chevron-circle-up.png
34
+ cloud-rain.png
35
+ cloud.png
36
+ comment.png
37
+ crosshairs.png
38
+ dot-circle-o.png
39
+ exclamation-circle.png
40
+ exclamation-triangle.png
41
+ female.png
42
+ file.png
43
+ flag.png
44
+ flask.png
45
+ h-square.png
46
+ home.png
47
+ info-circle.png
48
+ male.png
49
+ medkit.png
50
+ mobile.png
51
+ plus-circle.png
52
+ plus-square.png
53
+ plus.png
54
+ square.png
55
+ star.png
56
+ thumbs-down.png
57
+ thumbs-up.png
58
+ ticket.png
59
+ times-circle.png
60
+ times.png
61
+ tint.png
62
+ tree.png
63
+ university.png
64
+ usd.png
65
+ user.png
66
+ users.png
67
+ wheelchair.png
68
+ )
69
+
70
+ SVGINDIR="$(realpath -e "../../../../../apps/mwater-server/lib/routes/maps/marker-symbols/font-awesome")"
71
+ PNGOUTDIR="$(realpath "./font-awesome")"
72
+
73
+ rm -rvf "$PNGOUTDIR"
74
+ mkdir -pv "$PNGOUTDIR"
75
+
76
+ which image-sdf || npm install -g image-sdf
77
+
78
+ for IMGFILE in "${IMGFILES[@]}"
79
+ do
80
+ BASENAME="$(basename "$IMGFILE" .png)"
81
+ nice magick "$SVGINDIR/$BASENAME.svg" -channel RGB -negate -size 2000x2000 "$TMPDIR1/$BASENAME.png"
82
+ image-sdf "$TMPDIR1/$BASENAME.png" --spread 32 --downscale 2 --color black --output "$TMPDIR2/$BASENAME.png" &
83
+ done
84
+ wait
85
+
86
+ for IMGFILE in "$TMPDIR2"/*.png
87
+ do
88
+ magick "$IMGFILE" -resize 20x20 "$PNGOUTDIR/$(basename "$IMGFILE")" &
89
+ done
90
+ wait
91
+
92
+ cd "$PNGOUTDIR"
93
+ identify ./*.png
@@ -7,6 +7,9 @@ import "maplibre-gl/dist/maplibre-gl.css"
7
7
  import "./VectorMapViewComponent.css"
8
8
  import React from "react"
9
9
 
10
+ // Re-export maplibregl for consumers
11
+ export { default as maplibregl } from "maplibre-gl"
12
+
10
13
  /** Set to true to enable printing by preserving the drawing buffer */
11
14
  let printingModeEnabled = false
12
15
 
@@ -29,11 +32,6 @@ export function getMapTilerApiKey(): string {
29
32
  return mapTilerApiKey
30
33
  }
31
34
 
32
- /** Check if vector maps are enabled by setting API key */
33
- export function areVectorMapsEnabled() {
34
- return mapTilerApiKey !== ""
35
- }
36
-
37
35
  export type BaseLayer = "bing_road" | "bing_aerial" | "cartodb_positron" | "cartodb_dark_matter" | "blank"
38
36
 
39
37
  /** Loads a vector map, refreshing the WebGL context as needed */
@@ -43,8 +41,9 @@ export function useVectorMap(options: {
43
41
  scrollZoom?: boolean
44
42
  dragPan?: boolean
45
43
  touchZoomRotate?: boolean
44
+ padding?: number
46
45
  }) {
47
- const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate } = options
46
+ const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate, padding } = options
48
47
 
49
48
  // Maplibre map
50
49
  const [map, setMap] = useState<maplibregl.Map>()
@@ -89,9 +88,8 @@ export function useVectorMap(options: {
89
88
  }
90
89
 
91
90
  try {
92
- const m = new maplibregl.Map({
91
+ const mapConstructorOptions: maplibregl.MapOptions = {
93
92
  container: divRef,
94
- bounds: bounds,
95
93
  scrollZoom: scrollZoom === false ? false : true,
96
94
  dragPan: dragPan === false ? false : true,
97
95
  touchZoomRotate: touchZoomRotate === false ? false : true,
@@ -102,13 +100,24 @@ export function useVectorMap(options: {
102
100
  layers: [],
103
101
  sources: {}
104
102
  },
105
- // Prevent scrolling outside of world bounds
106
103
  maxBounds: [
107
104
  [-179.9, -85], // Southwest coordinates
108
105
  [179.9, 85] // Northeast coordinates
109
106
  ],
110
- preserveDrawingBuffer: printingModeEnabled
111
- })
107
+ // In maplibre-gl v5+, WebGL context options must be in canvasContextAttributes
108
+ canvasContextAttributes: {
109
+ preserveDrawingBuffer: printingModeEnabled
110
+ }
111
+ }
112
+
113
+ if (bounds) {
114
+ mapConstructorOptions.bounds = bounds
115
+ if (padding !== undefined) {
116
+ mapConstructorOptions.fitBoundsOptions = { padding }
117
+ }
118
+ }
119
+
120
+ const m = new maplibregl.Map(mapConstructorOptions)
112
121
 
113
122
  setHasWebGLContext(true)
114
123
 
@@ -135,10 +144,12 @@ export function useVectorMap(options: {
135
144
  // Check if known
136
145
  const mapSymbol = getMapSymbols().find((s) => s.value == ev.id)
137
146
  if (mapSymbol) {
138
- m.loadImage(mapSymbol.url, (err: any, image: any) => {
139
- if (image && !m.hasImage(mapSymbol.value)) {
140
- m.addImage(mapSymbol.value, image, { sdf: true })
147
+ m.loadImage(mapSymbol.url).then((response) => {
148
+ if (response && response.data && !m.hasImage(mapSymbol.value)) {
149
+ m.addImage(mapSymbol.value, response.data, { sdf: true })
141
150
  }
151
+ }).catch((err) => {
152
+ console.error("Error loading map symbol:", err)
142
153
  })
143
154
  }
144
155
  })
@@ -240,9 +251,8 @@ export function useBaseStyle(baseLayer: BaseLayer) {
240
251
  } else if (baseLayer == "bing_road") {
241
252
  loadStyle(`https://api.maptiler.com/maps/streets-v2/style.json?key=${mapTilerApiKey}`)
242
253
  } else if (baseLayer == "bing_aerial") {
243
- // Switched to Bing for superior aerial imagery
244
- loadBingBasemap("AerialWithLabels", 1).then(setBaseStyle)
245
- // loadStyle(`https://api.maptiler.com/maps/hybrid/style.json?key=${mapTilerApiKey}`)
254
+ // Stadia Maps
255
+ loadStyle("https://tiles.stadiamaps.com/styles/alidade_satellite.json?api_key=835a418e-91f9-4eb8-9856-0883c3656c9d")
246
256
  } else if (baseLayer == "blank") {
247
257
  setBaseStyle({
248
258
  version: 8,
@@ -310,7 +320,10 @@ export function AttributionControl(props: {
310
320
  if (props.baseLayer == "bing_aerial") {
311
321
  return (
312
322
  <div className="newmap-attribution-control">
313
- Copyright © 2022 Microsoft and its suppliers.
323
+ &copy; <a href="https://stadiamaps.com/" target="_blank">Stadia Maps</a>
324
+ &copy; <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
325
+ &copy; <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>
326
+ &copy; CNES, Distribution Airbus DS, &copy; Airbus DS, &copy; PlanetObserver (Contains Copernicus Data)
314
327
  {props.extraText ? " " + props.extraText : null}
315
328
  </div>
316
329
  )
@@ -338,10 +351,7 @@ export function VectorMapLogo(props: {
338
351
  }
339
352
 
340
353
  if (props.baseLayer == "bing_aerial") {
341
- return <img
342
- src="https://dev.virtualearth.net/Branding/logo_powered_by.png"
343
- style={{ position: "absolute", bottom: 38, left: 11, height: 22, zIndex: 1000, pointerEvents: "none" }}
344
- />
354
+ return null
345
355
  }
346
356
 
347
357
  return <img
@@ -350,36 +360,6 @@ export function VectorMapLogo(props: {
350
360
  />
351
361
  }
352
362
 
353
- async function loadBingBasemap(basemapType: "AerialWithLabels", opacity: number): Promise<maplibregl.StyleSpecification> {
354
- // Load metadata
355
- const bingApiKey = "Ao26dWY2IC8PjorsJKFaoR85EPXCnCohrJdisCWXIULAXFo0JAXquGauppTMQbyU"
356
-
357
- const metadata = await fetch(`https://dev.virtualearth.net/REST/v1/Imagery/Metadata/${basemapType}?key=${bingApiKey}`).then((response) => response.json())
358
- const resource = metadata.resourceSets[0].resources[0]
359
-
360
- return {
361
- sources: {
362
- "bing_raster": {
363
- type: "raster",
364
- tiles: resource.imageUrlSubdomains.map((subdomain: string) =>
365
- resource.imageUrl.replace("{subdomain}", subdomain).replace("{culture}", "").replace("http:", "https:")),
366
- tileSize: resource.imageHeight,
367
- }
368
- },
369
- layers: [
370
- {
371
- id: "bing_raster",
372
- type: "raster",
373
- source: "bing_raster",
374
- paint: {
375
- "raster-opacity": opacity
376
- }
377
- }
378
- ],
379
- version: 8
380
- }
381
- }
382
-
383
363
  /** Persists map bounds to local storage */
384
364
  export function usePersistedMapBounds(map: Map | undefined, localStorageKey: string) {
385
365
  const [bounds, setBounds] = useState<{ n: number, e: number, s: number, w: number } | null>(null)
@@ -421,4 +401,3 @@ export function usePersistedMapBounds(map: Map | undefined, localStorageKey: str
421
401
  }
422
402
  }, [map])
423
403
  }
424
-
@@ -6,7 +6,7 @@ import * as uiComponents from "../UIComponents"
6
6
  import { ExprUtils, Schema } from "@mwater/expressions"
7
7
  import ModalPopupComponent from "@mwater/react-library/lib/ModalPopupComponent"
8
8
 
9
- interface IndicatorsListComponentProps {
9
+ export interface IndicatorsListComponentProps {
10
10
  /** Url to hit api */
11
11
  apiUrl: string
12
12
  /** Optional client */
@@ -31,7 +31,7 @@ interface IndicatorsListComponentState {
31
31
  export class IndicatorsListComponent extends React.Component<IndicatorsListComponentProps, IndicatorsListComponentState> {
32
32
  addIndicatorConfirmPopup: AddIndicatorConfirmPopupComponent | null
33
33
 
34
- constructor(props: any) {
34
+ constructor(props: IndicatorsListComponentProps) {
35
35
  super(props)
36
36
  this.state = {
37
37
  indicators: null,
@@ -42,7 +42,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
42
42
  componentDidMount() {
43
43
  // Get names and basic of forms
44
44
  const query: any = {}
45
- query.fields = JSON.stringify({ "design.name": 1, "design.desc": 1, "design.recommended": 1, deprecated: 1 })
45
+ query.fields = JSON.stringify({ "design.name": 1, "design.desc": 1, "design.recommended": 1, deprecated: 1, "design.category": 1, "design.subcategory": 1, "design.code": 1, "design.organization": 1 })
46
46
  query.client = this.props.client
47
47
 
48
48
  // Get list of all indicator names
@@ -62,11 +62,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
62
62
  )
63
63
 
64
64
  return this.setState({
65
- indicators: _.map(indicators, (indicator) => ({
66
- id: indicator._id,
67
- name: ExprUtils.localizeString(indicator.design.name, T.locale),
68
- desc: ExprUtils.localizeString(indicator.design.desc, T.locale)
69
- }))
65
+ indicators: indicators
70
66
  })
71
67
  }).fail((xhr: any) => {
72
68
  return this.setState({ error: xhr.responseText })
@@ -102,25 +98,110 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
102
98
  this.addIndicatorConfirmPopup!.show(tableId)
103
99
  }
104
100
 
105
- render() {
106
- let indicators
107
- if (this.state.error) {
108
- return <div className="alert alert-danger">{this.state.error}</div>
101
+ handleOpenIndicator = (id: string) => {
102
+ this.handleSelect("indicator_values:" + id)
103
+ }
104
+
105
+ // Render a simplified version of IndicatorListComponent from mwater-portal
106
+ renderIndicatorList(indicators: any[], searchText: string) {
107
+ // Filter indicators based on search text
108
+ let filteredIndicators = indicators
109
+ if (searchText) {
110
+ const searchTerms = searchText.toLowerCase().split(" ")
111
+ filteredIndicators = indicators.filter(indicator => {
112
+ const searchFields = [
113
+ ExprUtils.localizeString(indicator.design.name, T.locale),
114
+ indicator.design.code,
115
+ indicator.design.organization,
116
+ indicator.design.category,
117
+ indicator.design.subcategory
118
+ ]
119
+
120
+ return searchTerms.every(term =>
121
+ searchFields.some(field =>
122
+ field && field.toLowerCase().includes(term)
123
+ )
124
+ )
125
+ })
109
126
  }
110
127
 
111
- // Filter indicators
112
- if (this.state.search) {
113
- const escapeRegExp = (s: any) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&")
128
+ // Split into recommended and all indicators
129
+ const recommendedIndicators = filteredIndicators.filter(indicator => indicator.design.recommended)
130
+ const otherIndicators = filteredIndicators.filter(indicator => !indicator.design.recommended)
114
131
 
115
- const searchStringRegExp = new RegExp(escapeRegExp(this.state.search), "i")
132
+ // Group by category
133
+ const groupByCategory = (indicators: any[]) => {
134
+ const categories: Record<string, any[]> = {}
116
135
 
117
- indicators = _.filter(this.state.indicators || [], (indicator) => indicator.name.match(searchStringRegExp))
118
- } else {
119
- ;({ indicators } = this.state)
136
+ indicators.forEach(indicator => {
137
+ const category = indicator.design.category || T`Uncategorized`
138
+ if (!categories[category]) {
139
+ categories[category] = []
140
+ }
141
+ categories[category].push(indicator)
142
+ })
143
+
144
+ return categories
120
145
  }
121
146
 
122
- // Remove if already included
123
- indicators = _.filter(indicators || [], (f) => !(this.props.extraTables || []).includes(`indicator_values:${f.id}`))
147
+ const recommendedByCategory = groupByCategory(recommendedIndicators)
148
+ const otherByCategory = groupByCategory(otherIndicators)
149
+
150
+ return (
151
+ <div>
152
+ {recommendedIndicators.length > 0 && (
153
+ <div>
154
+ <h4>{T`Recommended Indicators`}</h4>
155
+ {_.map(recommendedByCategory, (categoryIndicators, category) => (
156
+ <div key={category}>
157
+ <h5>{category}</h5>
158
+ <table className="table table-hover">
159
+ <tbody>
160
+ {_.map(categoryIndicators, indicator => (
161
+ <tr key={indicator._id} onClick={() => this.handleOpenIndicator(indicator._id)}>
162
+ <td>
163
+ <IndicatorListItemComponent
164
+ indicator={indicator}
165
+ onClick={() => this.handleOpenIndicator(indicator._id)}
166
+ />
167
+ </td>
168
+ </tr>
169
+ ))}
170
+ </tbody>
171
+ </table>
172
+ </div>
173
+ ))}
174
+ </div>
175
+ )}
176
+
177
+ <h4>{T`All Indicators`}</h4>
178
+ {_.map(otherByCategory, (categoryIndicators, category) => (
179
+ <div key={category}>
180
+ <h5>{category}</h5>
181
+ <table className="table table-hover">
182
+ <tbody>
183
+ {_.map(categoryIndicators, indicator => (
184
+ <tr key={indicator._id} onClick={() => this.handleOpenIndicator(indicator._id)}>
185
+ <td>
186
+ <IndicatorListItemComponent
187
+ indicator={indicator}
188
+ onClick={() => this.handleOpenIndicator(indicator._id)}
189
+ />
190
+ </td>
191
+ </tr>
192
+ ))}
193
+ </tbody>
194
+ </table>
195
+ </div>
196
+ ))}
197
+ </div>
198
+ )
199
+ }
200
+
201
+ render() {
202
+ if (this.state.error) {
203
+ return <div className="alert alert-danger">{this.state.error}</div>
204
+ }
124
205
 
125
206
  let tables = _.filter(
126
207
  this.props.schema.getTables(),
@@ -142,14 +223,12 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
142
223
  <label>{T`Included Indicators:`}</label>
143
224
  {tables.length > 0 ? (
144
225
  <uiComponents.OptionListComponent
145
- items={_.map(tables, (table) => {
146
- return {
147
- name: ExprUtils.localizeString(table.name, T.locale),
148
- desc: ExprUtils.localizeString(table.desc, T.locale),
149
- onClick: this.handleSelect.bind(null, table.id),
150
- onRemove: this.handleTableRemove.bind(null, table)
151
- }
152
- })}
226
+ items={_.map(tables, (table) => ({
227
+ name: ExprUtils.localizeString(table.name, T.locale),
228
+ desc: ExprUtils.localizeString(table.desc, T.locale),
229
+ onClick: () => this.handleSelect(table.id),
230
+ onRemove: () => this.handleTableRemove(table)
231
+ }))}
153
232
  />
154
233
  ) : (
155
234
  <div>{T`None`}</div>
@@ -161,7 +240,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
161
240
  {!this.state.indicators || this.state.indicators.length === 0 ? (
162
241
  <div className="alert alert-info">
163
242
  <i className="fa fa-spinner fa-spin" />
164
- &nbsp;{T`Loading...`}
243
+ {"\u00A0" + T`Loading...`}
165
244
  </div>
166
245
  ) : (
167
246
  <>
@@ -176,13 +255,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
176
255
  onChange={(ev: any) => this.setState({ search: ev.target.value })}
177
256
  />
178
257
 
179
- <uiComponents.OptionListComponent
180
- items={_.map(indicators, (indicator) => ({
181
- name: indicator.name,
182
- desc: indicator.desc,
183
- onClick: this.handleSelect.bind(null, "indicator_values:" + indicator.id)
184
- }))}
185
- />
258
+ {this.renderIndicatorList(this.state.indicators, this.state.search)}
186
259
  </>
187
260
  )}
188
261
  </div>
@@ -190,6 +263,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
190
263
  }
191
264
  }
192
265
 
266
+
193
267
  interface AddIndicatorConfirmPopupComponentProps {
194
268
  schema: Schema
195
269
  /** Called with table selected */
@@ -281,3 +355,57 @@ are certain that you want to use the raw indicator table`}
281
355
  )
282
356
  }
283
357
  }
358
+
359
+ // Single indicator item in a list
360
+ // Local port of the class found in mwater-portal
361
+ class IndicatorListItemComponent extends React.Component<{
362
+ indicator: any
363
+ onClick: any
364
+ }> {
365
+
366
+ renderIcon() {
367
+ switch (this.props.indicator.type) {
368
+ case "expression":
369
+ // R 'i', className: "text-muted fa fa-fw fa-calculator"
370
+ return null
371
+ case "response":
372
+ // R 'i', className: "text-muted fa fa-fw fa-list-alt"
373
+ return null
374
+ case "set":
375
+ return (
376
+ <span className="fa-stack" style={{ paddingRight: 6 }}>
377
+ <i className="fa fa-th-list fa-stack-1x text-muted" />
378
+ <i className="fa fa-circle fa-stack-1x" style={{ color: "white", paddingLeft: 15 }} />
379
+ <i className="fa fa-check-circle fa-stack-1x text-primary" style={{ paddingLeft: 15 }} />
380
+ </span>
381
+ )
382
+ }
383
+ return null
384
+ }
385
+
386
+ render() {
387
+ return (
388
+ <div onClick={this.props.onClick} style={{ cursor: "pointer" }}>
389
+ <div key="name" style={{ fontWeight: "bold" }}>
390
+ {this.renderIcon()}
391
+ {ExprUtils.localizeString(this.props.indicator.design.name, T.locale)}
392
+ {this.props.indicator.design.code ? ` (${this.props.indicator.design.code})` : undefined}
393
+ {this.props.indicator.design.organization ? (
394
+ <span className="text-muted"> {T`by ${this.props.indicator.design.organization}`}</span>
395
+ ) : undefined}
396
+ </div>
397
+
398
+ <div key="desc" className="text-muted">
399
+ {ExprUtils.localizeString(this.props.indicator.design.desc, T.locale)}
400
+ {this.props.indicator.design.category
401
+ ? [
402
+ ` (${this.props.indicator.design.category}`,
403
+ this.props.indicator.design.subcategory ? `/${this.props.indicator.design.subcategory}` : undefined,
404
+ `)`
405
+ ]
406
+ : undefined}
407
+ </div>
408
+ </div>
409
+ )
410
+ }
411
+ }
@@ -0,0 +1,111 @@
1
+ import _ from "lodash"
2
+ import { Schema, ExprUtils } from "@mwater/expressions"
3
+ import { useState, useEffect } from "react"
4
+ import React from "react"
5
+ import { OptionListComponent } from "../UIComponents"
6
+ import { TextInput } from "@mwater/react-library/lib/bootstrap"
7
+
8
+ interface MWaterCalculatedDataSourcesListComponentProps {
9
+ apiUrl: string
10
+ schema: Schema
11
+ client?: string
12
+ user?: string
13
+ onChange: (tableId: string | null) => void
14
+ extraTables: string[]
15
+ onExtraTableAdd: (tableId: string) => void
16
+ onExtraTableRemove: (tableId: string) => void
17
+ locale?: string
18
+ }
19
+
20
+ /**
21
+ * A list of calculated data sources that can be selected.
22
+ */
23
+ export const MWaterCalculatedDataSourcesListComponent = (props: MWaterCalculatedDataSourcesListComponentProps) => {
24
+ const [calculatedSources, setCalculatedSources] = useState<CalculatedSource[]>()
25
+ const [search, setSearch] = useState<string | null>("")
26
+ const [extraTableNeeded, setExtraTableNeeded] = useState<string>()
27
+
28
+ useEffect(() => {
29
+ fetch(`${props.apiUrl}calculated_data_sources?client=${props.client || ""}`)
30
+ .then((response) => response.json())
31
+ .then((body: CalculatedSource[]) => {
32
+ // Filter out calculated data sources that have never been calculated
33
+ const calculatedSources = body.filter((s) => s.last_calculated)
34
+
35
+ setCalculatedSources(
36
+ _.sortByAll(calculatedSources, [
37
+ (s) => (props.extraTables.some((t) => t == `calculated:${s._sid}`) ? 0 : 1),
38
+ (s) => ExprUtils.localizeString(s.name, props.locale)
39
+ ])
40
+ )
41
+ })
42
+ }, [])
43
+
44
+ useEffect(() => {
45
+ if (extraTableNeeded && props.schema.getTable(extraTableNeeded)) {
46
+ props.onChange(extraTableNeeded)
47
+ }
48
+ })
49
+
50
+ const selectTable = (source: CalculatedSource) => {
51
+ const qualifiedTableId = `calculated:${source._sid}`
52
+
53
+ if (props.schema.getTable(qualifiedTableId)) {
54
+ props.onChange(qualifiedTableId)
55
+ return
56
+ }
57
+
58
+ setExtraTableNeeded(qualifiedTableId)
59
+ props.onExtraTableAdd(qualifiedTableId)
60
+ }
61
+
62
+ const handleRemove = (source: CalculatedSource) => {
63
+ const match = props.extraTables.find((t) => t == `calculated:${source._sid}`)
64
+ if (match) {
65
+ if (confirm(T`Remove this table? Some widgets may not work correctly.`)) {
66
+ props.onChange(null)
67
+ props.onExtraTableRemove(match)
68
+ }
69
+ }
70
+ }
71
+
72
+ if (!calculatedSources || extraTableNeeded) {
73
+ return (
74
+ <div>
75
+ <i className="fa fa-spin fa-spinner" /> {T`Loading...`}
76
+ </div>
77
+ )
78
+ }
79
+
80
+ const renderCalculatedSources = () => {
81
+ const items = calculatedSources
82
+ .map((s) => {
83
+ const alreadyIncluded = props.extraTables.some((t) => t == `calculated:${s._sid}`)
84
+ return {
85
+ name: ExprUtils.localizeString(s.name, props.locale) || "",
86
+ desc: s.description ? ExprUtils.localizeString(s.description, props.locale) || "" : undefined,
87
+ onClick: () => selectTable(s),
88
+ onRemove: alreadyIncluded ? handleRemove.bind(null, s) : undefined
89
+ }
90
+ })
91
+ .filter((item) => !search || item.name.toLowerCase().includes(search.toLowerCase()))
92
+
93
+ return <OptionListComponent items={items} />
94
+ }
95
+
96
+ return (
97
+ <div>
98
+ <TextInput value={search} onChange={setSearch} placeholder={T`Search...`} searchIcon />
99
+ <br/>
100
+ {renderCalculatedSources()}
101
+ </div>
102
+ )
103
+ }
104
+
105
+ interface CalculatedSource {
106
+ _id: string
107
+ _sid: number
108
+ name: { _base: string; [code: string]: string }
109
+ description?: { _base: string; [code: string]: string }
110
+ last_calculated?: string
111
+ }