@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
@@ -25,6 +25,8 @@ export interface MapLayerViewDesignerComponentProps {
25
25
  connectDropTarget?: any
26
26
  allowEditingLayer: boolean
27
27
  filters?: any
28
+ /** Translate function to use for display */
29
+ translate?: (input: string) => string
28
30
  }
29
31
 
30
32
  interface MapLayerViewDesignerComponentState {
@@ -36,7 +38,7 @@ export default class MapLayerViewDesignerComponent extends React.Component<
36
38
  MapLayerViewDesignerComponentProps,
37
39
  MapLayerViewDesignerComponentState
38
40
  > {
39
- constructor(props: any) {
41
+ constructor(props: MapLayerViewDesignerComponentProps) {
40
42
  super(props)
41
43
 
42
44
  const layer = LayerFactory.createLayer(this.props.layerView.type)
@@ -127,10 +129,15 @@ export default class MapLayerViewDesignerComponent extends React.Component<
127
129
  }
128
130
 
129
131
  renderName() {
132
+ // Translate the name if a translate function is provided
133
+ const displayName = this.props.translate
134
+ ? this.props.translate(this.props.layerView.name)
135
+ : this.props.layerView.name
136
+
130
137
  return R(
131
138
  "span",
132
139
  { className: "hover-display-parent", onClick: this.handleRename, style: { cursor: "pointer" } },
133
- this.props.layerView.name,
140
+ displayName,
134
141
  " ",
135
142
  R("span", { className: "hover-display-child fas fa-pencil-alt text-muted" })
136
143
  )
@@ -21,6 +21,8 @@ export interface MapLayersDesignerComponentProps {
21
21
  /** True to allow editing layers */
22
22
  allowEditingLayers: boolean
23
23
  filters?: any
24
+ /** Translate function to use for display */
25
+ translate?: (input: string) => string
24
26
  }
25
27
 
26
28
  // Designer for layer selection in the map
@@ -102,7 +104,8 @@ export default class MapLayersDesignerComponent extends React.Component<MapLayer
102
104
  connectDragPreview,
103
105
  connectDropTarget,
104
106
  allowEditingLayer: this.props.allowEditingLayers,
105
- filters: _.compact(filters)
107
+ filters: _.compact(filters),
108
+ translate: this.props.translate
106
109
  })
107
110
  )
108
111
  }
@@ -0,0 +1,53 @@
1
+ import React, { useMemo } from "react"
2
+ import { Schema } from "@mwater/expressions"
3
+ import { MapDesign } from "./MapDesign"
4
+ import { TranslationsTabComponent } from "../TranslationsTabComponent"
5
+ import * as MapUtils from "./MapUtils"
6
+ import produce from "immer"
7
+
8
+ export interface MapTranslationsTabProps {
9
+ /** Schema to use */
10
+ schema: Schema
11
+ /** Map design */
12
+ design: MapDesign
13
+ /** Called with new design */
14
+ onDesignChange: (design: MapDesign) => void
15
+ }
16
+
17
+ /**
18
+ * Translations tab for map designer that wraps the reusable TranslationsTabComponent
19
+ */
20
+ export function MapTranslationsTab(props: MapTranslationsTabProps) {
21
+ const { design, onDesignChange, schema } = props
22
+
23
+ const translatableStrings = useMemo(
24
+ () => MapUtils.getTranslatableStrings(design, schema),
25
+ [design, schema]
26
+ )
27
+
28
+ return (
29
+ <TranslationsTabComponent
30
+ locale={design.locale || "en"}
31
+ otherLocales={design.otherLocales || []}
32
+ translations={design.translations || {}}
33
+ translatableStrings={translatableStrings}
34
+ onLocaleChange={(locale) =>
35
+ onDesignChange(produce(design, draft => {
36
+ draft.locale = locale
37
+ }))
38
+ }
39
+ onOtherLocalesChange={(otherLocales) =>
40
+ onDesignChange(produce(design, draft => {
41
+ draft.otherLocales = otherLocales
42
+ }))
43
+ }
44
+ onTranslationsChange={(translations) =>
45
+ onDesignChange(produce(design, draft => {
46
+ draft.translations = translations
47
+ }))
48
+ }
49
+ downloadFilename="Map Translations.xlsx"
50
+ baseLanguageDescription={T`This is the language that the map is written in.`}
51
+ />
52
+ )
53
+ }
@@ -8,6 +8,7 @@ import LayerFactory from "./LayerFactory"
8
8
  import { MapDesign } from "./MapDesign"
9
9
  import { produce } from "immer"
10
10
  import { HoverOverItem } from "./maps"
11
+ import { Axis } from "../axes/Axis"
11
12
 
12
13
  export interface MapScope {
13
14
  name: string
@@ -172,6 +173,53 @@ export function getTranslatableStrings(design: MapDesign, schema: Schema): strin
172
173
  return _.uniq(strings)
173
174
  }
174
175
 
176
+ /**
177
+ * Get translatable strings from an axis's categoryLabels and nullLabel.
178
+ * Always includes "None" since it's the default label for null values in AxisBuilder.
179
+ */
180
+ export function getTranslatableStringsFromAxis(axis: Axis | null | undefined): string[] {
181
+ const strings: string[] = []
182
+ if (axis?.categoryLabels) {
183
+ strings.push(...Object.values(axis.categoryLabels))
184
+ }
185
+ if (axis?.nullLabel) {
186
+ strings.push(axis.nullLabel)
187
+ } else {
188
+ // Always include "None" as it's the default nullLabel in AxisBuilder
189
+ strings.push("None")
190
+ }
191
+ return strings
192
+ }
193
+
194
+ /**
195
+ * Translate an axis's category labels and null label.
196
+ * If no nullLabel is set, translates the default "None" and sets it so AxisBuilder uses it.
197
+ */
198
+ export function translateAxis(
199
+ axis: Axis | null | undefined,
200
+ translate: (input: string) => string
201
+ ): Axis | null | undefined {
202
+ if (!axis) return axis
203
+
204
+ return produce(axis, draft => {
205
+ if (draft.categoryLabels) {
206
+ for (const key in draft.categoryLabels) {
207
+ draft.categoryLabels[key] = translate(draft.categoryLabels[key])
208
+ }
209
+ }
210
+ if (draft.nullLabel) {
211
+ draft.nullLabel = translate(draft.nullLabel)
212
+ } else {
213
+ // Translate the default "None" and set it so AxisBuilder uses it
214
+ // instead of falling back to T`None` which uses the global locale
215
+ const translatedNone = translate("None")
216
+ if (translatedNone !== "None") {
217
+ draft.nullLabel = translatedNone
218
+ }
219
+ }
220
+ })
221
+ }
222
+
175
223
  /**
176
224
  * Convenience function to get hover over data for a map given an id and a list of hover over items
177
225
  */
@@ -191,21 +239,33 @@ export async function getSimpleHoverOverData(options: {
191
239
  }) {
192
240
  const { id, table, filters, schema, dataSource, hoverOverItems } = options
193
241
 
242
+ const exprUtils = new ExprUtils(schema)
194
243
  const exprCompiler = new ExprCompiler(schema)
195
244
  const query: JsonQLSelectQuery = {
196
245
  type: "query",
197
246
  selects: [],
198
247
  from: exprCompiler.compileTable(table, "main"),
248
+ groupBy: [],
199
249
  limit: 1
200
250
  }
201
251
 
202
- for (const item of hoverOverItems) {
252
+ // Check if any items are aggregate
253
+ const isAggregate = hoverOverItems.some(item => exprUtils.getExprAggrStatus(item.value ?? null) === "aggregate")
254
+
255
+ for (let i = 0; i < hoverOverItems.length; i++) {
256
+ const item = hoverOverItems[i]
257
+
203
258
  if (item.value) {
204
259
  query.selects.push({
205
260
  type: "select",
206
261
  expr: exprCompiler.compileExpr({ expr: item.value, tableAlias: "main" }),
207
262
  alias: item.id
208
263
  })
264
+
265
+ // Group by if there are aggregate items and this is not aggregate
266
+ if (isAggregate && exprUtils.getExprAggrStatus(item.value) !== "aggregate") {
267
+ query.groupBy!.push(i + 1)
268
+ }
209
269
  }
210
270
  }
211
271
 
@@ -6,8 +6,6 @@ import { MapDesign } from "./MapDesign"
6
6
  import { MapDataSource } from "./MapDataSource"
7
7
  import { VectorMapViewComponent } from "./VectorMapViewComponent"
8
8
  import { MapScope } from "./MapUtils"
9
- import RasterMapViewComponent from "./RasterMapViewComponent"
10
- import { areVectorMapsEnabled } from "./vectorMaps"
11
9
 
12
10
  export interface MapViewComponentProps {
13
11
  schema: Schema
@@ -50,7 +48,7 @@ export interface MapViewComponentProps {
50
48
  /** Locale to use. Overrides map design locale */
51
49
  locale?: string
52
50
 
53
- /** Translate function to use for display. TODO: implement this */
51
+ /** Translate function to use for display */
54
52
  translate?: (input: string) => string
55
53
 
56
54
  /** Increment to force refresh */
@@ -62,9 +60,5 @@ export interface MapViewComponentProps {
62
60
 
63
61
  /** Component that displays just the map */
64
62
  export function MapViewComponent(props: MapViewComponentProps) {
65
- if (areVectorMapsEnabled()) {
66
- return <VectorMapViewComponent {...props} />
67
- } else {
68
- return <RasterMapViewComponent {...props} />
69
- }
63
+ return <VectorMapViewComponent {...props} />
70
64
  }
@@ -20,7 +20,7 @@ import Widget from "../widgets/Widget"
20
20
  import { WidgetDataSource } from "../widgets/WidgetDataSource"
21
21
  import BlocksLayoutManager from "../layouts/blocks/BlocksLayoutManager"
22
22
  import { getTranslatableStringsFromLayoutManager } from "../dashboards/DashboardUtils"
23
- import { getSimpleHoverOverData } from "./MapUtils"
23
+ import { getSimpleHoverOverData, getTranslatableStringsFromAxis, translateAxis } from "./MapUtils"
24
24
 
25
25
  export default class MarkersLayer extends Layer<MarkersLayerDesign> {
26
26
  /** Gets the type of layer definition */
@@ -115,6 +115,9 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
115
115
  filter: addFilter(["==", ["geometry-type"], "Point"])
116
116
  })
117
117
  } else {
118
+ // For some reason, scales down from 20 to 14. No idea why
119
+ const iconSize = (design.markerSize || 10) / 14
120
+
118
121
  mapLayers.push({
119
122
  id: `${sourceId}:points`,
120
123
  type: "symbol",
@@ -123,11 +126,60 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
123
126
  layout: {
124
127
  "icon-image": design.symbol,
125
128
  "icon-allow-overlap": true,
126
- "icon-size": (design.markerSize || 10) / 14 // For some reason, scales down from 20 to 14. No idea why
129
+ "icon-size": iconSize,
127
130
  },
128
131
  paint: {
129
132
  "icon-color": color,
130
- "icon-opacity": opacity
133
+ "icon-opacity": opacity,
134
+ "icon-halo-color": compileColorToMapbox("#FFFFFFCC", design.axes.color?.excludedValues),
135
+ "icon-halo-width": iconSize * 5,
136
+ },
137
+ filter: addFilter(["==", ["geometry-type"], "Point"])
138
+ })
139
+ }
140
+
141
+ // Add labels layer if label axis is defined (points only)
142
+ if (design.axes.label) {
143
+ // Determine text-anchor and text-offset based on labelPosition
144
+ let textAnchor: "top" | "bottom" | "left" | "right"
145
+ let textOffset: [number, number]
146
+ switch (design.labelPosition) {
147
+ case "top":
148
+ textAnchor = "bottom"
149
+ textOffset = [0, -0.8]
150
+ break
151
+ case "left":
152
+ textAnchor = "right"
153
+ textOffset = [-0.8, 0]
154
+ break
155
+ case "right":
156
+ textAnchor = "left"
157
+ textOffset = [0.8, 0]
158
+ break
159
+ case "bottom":
160
+ default:
161
+ textAnchor = "top"
162
+ textOffset = [0, 0.8]
163
+ break
164
+ }
165
+
166
+ mapLayers.push({
167
+ id: `${sourceId}:labels`,
168
+ type: "symbol",
169
+ source: sourceId,
170
+ "source-layer": "main",
171
+ layout: {
172
+ "text-field": ["to-string", ["get", "label"]],
173
+ "text-size": 10,
174
+ "text-anchor": textAnchor,
175
+ "text-offset": textOffset,
176
+ "text-allow-overlap": false
177
+ },
178
+ paint: {
179
+ "text-color": compileColorToMapbox("#000000", design.axes.color?.excludedValues),
180
+ "text-halo-color": compileColorToMapbox("rgba(255, 255, 255, 0.8)", design.axes.color?.excludedValues),
181
+ "text-halo-width": 1.5,
182
+ "text-opacity": opacity
131
183
  },
132
184
  filter: addFilter(["==", ["geometry-type"], "Point"])
133
185
  })
@@ -175,6 +227,12 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
175
227
  basequery.selects.push({ type: "select", expr: colorExpr, alias: "color" })
176
228
  }
177
229
 
230
+ // Add label select if label axis
231
+ if (design.axes.label) {
232
+ const labelExpr = axisBuilder.compileAxis({ axis: design.axes.label, tableAlias: "basequery" })
233
+ basequery.selects.push({ type: "select", expr: labelExpr, alias: "label" })
234
+ }
235
+
178
236
  // Create filters
179
237
  let whereClauses: JsonQLExpr[] = []
180
238
 
@@ -204,269 +262,6 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
204
262
  return markersQuery
205
263
  }
206
264
 
207
- // Gets the layer definition as JsonQL + CSS in format:
208
- // {
209
- // layers: array of { id: layer id, jsonql: jsonql that includes "the_webmercator_geom" as a column }
210
- // css: carto css
211
- // interactivity: (optional) { layer: id of layer, fields: array of field names }
212
- // }
213
- // arguments:
214
- // design: design of layer
215
- // schema: schema to use
216
- // 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
217
- getJsonQLCss(design: MarkersLayerDesign, schema: Schema, filters: JsonQLFilter[]) {
218
- // Create design
219
- const layerDef = {
220
- layers: [
221
- {
222
- id: "layer0",
223
- jsonql: this.createMapnikJsonQL(design, schema, filters)
224
- }
225
- ],
226
- css: this.createCss(design),
227
- interactivity: {
228
- layer: "layer0",
229
- fields: ["id"]
230
- }
231
- }
232
-
233
- return layerDef
234
- }
235
-
236
- createMapnikJsonQL(design: MarkersLayerDesign, schema: Schema, filters: JsonQLFilter[]): JsonQLQuery {
237
- const axisBuilder = new AxisBuilder({ schema })
238
- const exprCompiler = new ExprCompiler(schema)
239
-
240
- // Compile geometry axis
241
- let geometryExpr = axisBuilder.compileAxis({ axis: design.axes.geometry, tableAlias: "innerquery" })
242
-
243
- // row_number() over (partition by round(ST_XMin(location)/!(pixel_width!*5)), round(ST_YMin(location)/(!pixel_height!*5))) AS r
244
- const cluster: JsonQLSelect = {
245
- type: "select",
246
- expr: {
247
- type: "op",
248
- op: "row_number",
249
- exprs: [],
250
- over: {
251
- partitionBy: [
252
- {
253
- type: "op",
254
- op: "round",
255
- exprs: [
256
- {
257
- type: "op",
258
- op: "/",
259
- exprs: [
260
- { type: "op", op: "ST_XMin", exprs: [geometryExpr] },
261
- { type: "op", op: "*", exprs: [{ type: "token", token: "!pixel_width!" }, 5] }
262
- ]
263
- }
264
- ]
265
- },
266
- {
267
- type: "op",
268
- op: "round",
269
- exprs: [
270
- {
271
- type: "op",
272
- op: "/",
273
- exprs: [
274
- { type: "op", op: "ST_YMin", exprs: [geometryExpr] },
275
- { type: "op", op: "*", exprs: [{ type: "token", token: "!pixel_height!" }, 5] }
276
- ]
277
- }
278
- ]
279
- }
280
- ]
281
- }
282
- },
283
- alias: "r"
284
- }
285
-
286
- // Select _id, location and clustered row number
287
- const innerquery: JsonQLSelectQuery = {
288
- type: "query",
289
- selects: [
290
- {
291
- type: "select",
292
- expr: { type: "field", tableAlias: "innerquery", column: schema.getTable(design.table)!.primaryKey },
293
- alias: "id"
294
- }, // main primary key as id
295
- { type: "select", expr: geometryExpr, alias: "the_geom_webmercator" }, // geometry as the_geom_webmercator
296
- cluster
297
- ],
298
- from: exprCompiler.compileTable(design.table, "innerquery")
299
- }
300
-
301
- // Add color select if color axis
302
- if (design.axes.color) {
303
- const colorExpr = axisBuilder.compileAxis({ axis: design.axes.color, tableAlias: "innerquery" })
304
- innerquery.selects.push({ type: "select", expr: colorExpr, alias: "color" })
305
- }
306
-
307
- // Create filters. First limit to bounding box
308
- let whereClauses: JsonQLExpr[] = [
309
- {
310
- type: "op",
311
- op: "&&",
312
- exprs: [geometryExpr, { type: "token", token: "!bbox!" }]
313
- }
314
- ]
315
-
316
- // Then add filters baked into layer
317
- if (design.filter) {
318
- whereClauses.push(exprCompiler.compileExpr({ expr: design.filter, tableAlias: "innerquery" }))
319
- }
320
-
321
- // Then add extra filters passed in, if relevant
322
- // Get relevant filters
323
- const relevantFilters = _.where(filters, { table: design.table })
324
- for (let filter of relevantFilters) {
325
- whereClauses.push(injectTableAlias(filter.jsonql, "innerquery"))
326
- }
327
-
328
- whereClauses = _.compact(whereClauses)
329
-
330
- // Wrap if multiple
331
- if (whereClauses.length > 1) {
332
- innerquery.where = { type: "op", op: "and", exprs: whereClauses }
333
- } else {
334
- innerquery.where = whereClauses[0]
335
- }
336
-
337
- // Create outer query which takes where r <= 3 to limit # of points in a cluster
338
- const outerquery: JsonQLQuery = {
339
- type: "query",
340
- selects: [
341
- {
342
- type: "select",
343
- expr: { type: "field", tableAlias: "innerquery", column: "id" },
344
- alias: "id"
345
- }, // innerquery._id as id
346
- {
347
- type: "select",
348
- expr: { type: "field", tableAlias: "innerquery", column: "the_geom_webmercator" },
349
- alias: "the_geom_webmercator"
350
- }, // innerquery.the_geom_webmercator as the_geom_webmercator
351
- {
352
- type: "select",
353
- expr: {
354
- type: "op",
355
- op: "ST_GeometryType",
356
- exprs: [{ type: "field", tableAlias: "innerquery", column: "the_geom_webmercator" }]
357
- },
358
- alias: "geometry_type"
359
- } // ST_GeometryType(innerquery.the_geom_webmercator) as geometry_type
360
- ],
361
- from: { type: "subquery", query: innerquery, alias: "innerquery" },
362
- where: { type: "op", op: "<=", exprs: [{ type: "field", tableAlias: "innerquery", column: "r" }, 3] }
363
- }
364
-
365
- // Add color select if color axis
366
- if (design.axes.color) {
367
- outerquery.selects.push({
368
- type: "select",
369
- expr: { type: "field", tableAlias: "innerquery", column: "color" },
370
- alias: "color"
371
- }) // innerquery.color as color
372
- }
373
-
374
- return outerquery
375
- }
376
-
377
- // Creates CartoCSS
378
- createCss(design: MarkersLayerDesign) {
379
- let stroke, symbol
380
- let css = ""
381
-
382
- if (design.symbol) {
383
- symbol = `marker-file: url(${design.symbol});`
384
- stroke = "marker-line-width: 60;"
385
- } else {
386
- symbol = "marker-type: ellipse;"
387
- stroke = "marker-line-width: 1;"
388
- }
389
-
390
- // Should only display markers when it is a point geometry
391
- css +=
392
- `\
393
- #layer0[geometry_type='ST_Point'] {
394
- marker-fill: ` +
395
- (design.color || "#666666") +
396
- `;
397
- marker-width: ` +
398
- (design.markerSize || 10) +
399
- `;
400
- marker-line-color: white;\
401
- ` +
402
- stroke +
403
- `\
404
- marker-line-opacity: 0.6;
405
- marker-placement: point;\
406
- ` +
407
- symbol +
408
- `\
409
- marker-allow-overlap: true;
410
- }
411
- #layer0 {
412
- line-color: ` +
413
- (design.color || "#666666") +
414
- `;
415
- line-width: ` +
416
- (design.lineWidth != null ? design.lineWidth : "3") +
417
- `;
418
- }
419
- #layer0[geometry_type='ST_Polygon'],#layer0[geometry_type='ST_MultiPolygon'] {
420
- polygon-fill: ` +
421
- (design.color || "#666666") +
422
- `;
423
- polygon-opacity: ${design.polygonFillOpacity ?? 0.25};
424
- }
425
- \
426
- `
427
-
428
- // If color axes, add color conditions
429
- if (design.axes.color && design.axes.color.colorMap) {
430
- for (let item of design.axes.color.colorMap) {
431
- // If invisible
432
- if (_.includes(design.axes.color.excludedValues || [], item.value)) {
433
- css +=
434
- `\
435
- #layer0[color=` +
436
- JSON.stringify(item.value) +
437
- `] { line-opacity: 0; marker-line-opacity: 0; marker-fill-opacity: 0; polygon-opacity: 0; }\
438
- `
439
- } else {
440
- css +=
441
- `\
442
- #layer0[color=` +
443
- JSON.stringify(item.value) +
444
- "] { line-color: " +
445
- item.color +
446
- ` }
447
- #layer0[color=` +
448
- JSON.stringify(item.value) +
449
- "][geometry_type='ST_Point'] { marker-fill: " +
450
- item.color +
451
- ` }
452
- #layer0[color=` +
453
- JSON.stringify(item.value) +
454
- "][geometry_type='ST_Polygon'],#layer0[color=" +
455
- JSON.stringify(item.value) +
456
- `][geometry_type='ST_MultiPolygon'] {
457
- polygon-fill: ` +
458
- item.color +
459
- `;\
460
- ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" : ""}\
461
- }\
462
- `
463
- }
464
- }
465
- }
466
-
467
- return css
468
- }
469
-
470
265
  // same as onGridClick but handles hover over
471
266
  onGridHoverOver(
472
267
  ev: { data: any; event: any },
@@ -647,6 +442,15 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
647
442
  }
648
443
 
649
444
  const axisBuilder = new AxisBuilder({ schema })
445
+
446
+ // Clean and translate axis
447
+ const axis = translateAxis(axisBuilder.cleanAxis({
448
+ axis: design.axes.color || null,
449
+ table: design.table,
450
+ types: ["enum", "text", "boolean", "date"],
451
+ aggrNeed: "none"
452
+ }), translate)
453
+
650
454
  return React.createElement(LayerLegendComponent, {
651
455
  schema,
652
456
  defaultColor: design.color,
@@ -654,12 +458,7 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
654
458
  markerSize: design.markerSize,
655
459
  name: translate(name),
656
460
  filters: _.compact(_filters),
657
- axis: axisBuilder.cleanAxis({
658
- axis: design.axes.color || null,
659
- table: design.table,
660
- types: ["enum", "text", "boolean", "date"],
661
- aggrNeed: "none"
662
- }),
461
+ axis,
663
462
  locale
664
463
  })
665
464
  }
@@ -734,8 +533,27 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
734
533
  types: ["enum", "text", "boolean", "date"],
735
534
  aggrNeed: "none"
736
535
  })!
536
+ draft.axes.label = axisBuilder.cleanAxis({
537
+ axis: draft.axes.label ? original(draft.axes.label) || null : null,
538
+ table: design.table,
539
+ types: ["text", "number"],
540
+ aggrNeed: "none"
541
+ }) || undefined
737
542
 
738
543
  draft.filter = exprCleaner.cleanExpr(design.filter || null, { table: draft.table })
544
+
545
+ // Clean hover over expressions
546
+ if (design.table && design.hoverOver && design.hoverOver.items) {
547
+ for (let i = 0; i < design.hoverOver.items.length; i++) {
548
+ const item = design.hoverOver.items[i]
549
+ if (item.value) {
550
+ draft.hoverOver!.items[i].value = exprCleaner.cleanExpr(item.value || null, {
551
+ table: design.table,
552
+ aggrStatuses: ["individual", "literal"]
553
+ })
554
+ }
555
+ }
556
+ }
739
557
  })
740
558
 
741
559
  return design
@@ -765,6 +583,12 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
765
583
  return error
766
584
  }
767
585
 
586
+ // Validate label
587
+ error = axisBuilder.validateAxis({ axis: design.axes.label || null })
588
+ if (error) {
589
+ return error
590
+ }
591
+
768
592
  // Check that doesn't compile to null (persistent bug that haven't been able to track down)
769
593
  if (!axisBuilder.compileAxis({ axis: design.axes.geometry, tableAlias: "innerquery" })) {
770
594
  return "Null geometry axis"
@@ -783,6 +607,9 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
783
607
  getTranslatableStrings(design: MarkersLayerDesign, schema: Schema): string[] {
784
608
  const strings: string[] = []
785
609
 
610
+ // Add strings from axis category labels and null labels
611
+ strings.push(...getTranslatableStringsFromAxis(design.axes.color))
612
+
786
613
  // Add strings from hoverOver items
787
614
  if (design.hoverOver && design.hoverOver.items) {
788
615
  for (const item of design.hoverOver.items) {
@@ -804,7 +631,7 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
804
631
  }
805
632
 
806
633
  /** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
807
- * It will be called on the server side if using a server map data source, or on the client side if using a direct
634
+ * It will be called on the server side if using a server map data source, or on the client side if using a direct
808
635
  * map data source.
809
636
  */
810
637
  getHoverOverData(options: {
@@ -825,7 +652,7 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
825
652
  filters: options.filters,
826
653
  schema: options.schema,
827
654
  dataSource: options.dataSource,
828
- hoverOverItems: options.design.hoverOver.items,
655
+ hoverOverItems: options.design.hoverOver!.items,
829
656
  })
830
657
  }
831
658
  }
@@ -971,4 +798,3 @@ export function createMarkersVectorQuery(baseQuery: JsonQLSelectQuery) {
971
798
 
972
799
  return outerquery
973
800
  }
974
-