@mwater/visualization 5.4.1 → 5.4.2

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 (269) hide show
  1. package/lib/ColorComponent.js +2 -1
  2. package/lib/IdSelection.d.ts +16 -0
  3. package/lib/IdSelection.js +59 -0
  4. package/lib/MWaterAddRelatedIndicatorComponent.js +2 -2
  5. package/lib/MWaterCompleteTableSelectComponent.d.ts +3 -8
  6. package/lib/MWaterCompleteTableSelectComponent.js +36 -42
  7. package/lib/MWaterLoaderComponent.d.ts +11 -10
  8. package/lib/MWaterLoaderComponent.js +1 -1
  9. package/lib/MWaterResponsesFilterComponent.js +1 -1
  10. package/lib/MWaterTableSelectComponent.d.ts +0 -1
  11. package/lib/MWaterTableSelectComponent.js +4 -6
  12. package/lib/autotranslate.d.ts +20 -0
  13. package/lib/autotranslate.js +122 -0
  14. package/lib/axes/AxisBuilder.js +3 -3
  15. package/lib/axes/AxisColorEditorComponent.js +4 -0
  16. package/lib/axes/AxisComponent.d.ts +8 -12
  17. package/lib/axes/AxisComponent.js +32 -80
  18. package/lib/axes/CategoryMapComponent.js +4 -4
  19. package/lib/axes/RangesComponent.js +2 -2
  20. package/lib/dashboards/DashboardComponent.d.ts +6 -0
  21. package/lib/dashboards/DashboardComponent.js +44 -12
  22. package/lib/dashboards/DashboardDesign.d.ts +11 -2
  23. package/lib/dashboards/DashboardUtils.d.ts +5 -0
  24. package/lib/dashboards/DashboardUtils.js +30 -0
  25. package/lib/dashboards/DashboardViewComponent.d.ts +2 -0
  26. package/lib/dashboards/DashboardViewComponent.js +16 -3
  27. package/lib/dashboards/ServerDashboardDataSource.js +2 -1
  28. package/lib/dashboards/SettingsModalComponent.d.ts +1 -1
  29. package/lib/dashboards/SettingsModalComponent.js +256 -19
  30. package/lib/dashboards/WidgetComponent.d.ts +6 -3
  31. package/lib/dashboards/WidgetComponent.js +3 -1
  32. package/lib/datagrids/CellEditor.d.ts +19 -0
  33. package/lib/datagrids/CellEditor.js +223 -0
  34. package/lib/datagrids/DatagridComponent.d.ts +18 -87
  35. package/lib/datagrids/DatagridComponent.js +304 -222
  36. package/lib/datagrids/DatagridViewComponent.d.ts +15 -53
  37. package/lib/datagrids/DatagridViewComponent.js +256 -257
  38. package/lib/datagrids/DirectDatagridDataSource.js +2 -3
  39. package/lib/datagrids/ExprCellComponent.d.ts +8 -15
  40. package/lib/datagrids/ExprCellComponent.js +11 -15
  41. package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -6
  42. package/lib/datagrids/FindReplaceModalComponent.js +38 -75
  43. package/lib/index.css +1 -1
  44. package/lib/index.d.ts +0 -1
  45. package/lib/index.js +0 -1
  46. package/lib/layouts/blocks/HorizontalBlockComponent.js +2 -2
  47. package/lib/mWaterLoader.d.ts +1 -1
  48. package/lib/maps/BufferLayer.d.ts +7 -5
  49. package/lib/maps/BufferLayer.js +69 -48
  50. package/lib/maps/BufferLayerDesign.d.ts +21 -14
  51. package/lib/maps/BufferLayerDesignerComponent.d.ts +16 -31
  52. package/lib/maps/BufferLayerDesignerComponent.js +68 -102
  53. package/lib/maps/ChoroplethLayer.d.ts +5 -4
  54. package/lib/maps/ChoroplethLayer.js +32 -9
  55. package/lib/maps/ChoroplethLayerDesign.d.ts +6 -2
  56. package/lib/maps/ChoroplethLayerDesigner.js +4 -2
  57. package/lib/maps/ClusterLayer.d.ts +3 -4
  58. package/lib/maps/ClusterLayer.js +2 -1
  59. package/lib/maps/DetailLevelSelectComponent.js +1 -1
  60. package/lib/maps/DirectMapDataSource.js +2 -1
  61. package/lib/maps/EditPopupComponent.js +5 -3
  62. package/lib/maps/GridLayer.d.ts +3 -4
  63. package/lib/maps/GridLayer.js +2 -1
  64. package/lib/maps/GridLayerDesigner.js +5 -3
  65. package/lib/maps/HoverContent.d.ts +11 -3
  66. package/lib/maps/HoverContent.js +25 -9
  67. package/lib/maps/Layer.d.ts +24 -3
  68. package/lib/maps/Layer.js +5 -1
  69. package/lib/maps/LayerFactory.js +0 -8
  70. package/lib/maps/LayerLegendComponent.js +0 -1
  71. package/lib/maps/LayerSwitcherComponent.d.ts +1 -0
  72. package/lib/maps/LayerSwitcherComponent.js +1 -1
  73. package/lib/maps/LeafletMapComponent.js +3 -1
  74. package/lib/maps/LegendComponent.d.ts +1 -0
  75. package/lib/maps/LegendComponent.js +9 -1
  76. package/lib/maps/MWaterServerLayer.d.ts +2 -2
  77. package/lib/maps/MWaterServerLayer.js +2 -2
  78. package/lib/maps/MapComponent.js +3 -3
  79. package/lib/maps/MapDesign.d.ts +2 -0
  80. package/lib/maps/MapDesignerComponent.d.ts +4 -3
  81. package/lib/maps/MapDesignerComponent.js +68 -74
  82. package/lib/maps/MapLayerViewDesignerComponent.js +2 -2
  83. package/lib/maps/MapUtils.d.ts +4 -0
  84. package/lib/maps/MapUtils.js +19 -0
  85. package/lib/maps/MapViewComponent.d.ts +8 -3
  86. package/lib/maps/MarkersLayer.d.ts +5 -4
  87. package/lib/maps/MarkersLayer.js +33 -7
  88. package/lib/maps/MarkersLayerDesign.d.ts +19 -16
  89. package/lib/maps/PopupFilterJoinsUtils.d.ts +6 -3
  90. package/lib/maps/PopupFilterJoinsUtils.js +0 -6
  91. package/lib/maps/RasterMapViewComponent.d.ts +3 -31
  92. package/lib/maps/RasterMapViewComponent.js +7 -2
  93. package/lib/maps/ServerMapDataSource.js +2 -1
  94. package/lib/maps/SwitchableTileUrlLayer.d.ts +3 -3
  95. package/lib/maps/SwitchableTileUrlLayer.js +2 -1
  96. package/lib/maps/TileUrlLayer.d.ts +4 -5
  97. package/lib/maps/TileUrlLayer.js +2 -1
  98. package/lib/maps/VectorMapViewComponent.d.ts +5 -37
  99. package/lib/maps/VectorMapViewComponent.js +19 -8
  100. package/lib/maps/maps.d.ts +3 -0
  101. package/lib/quickfilter/QuickfiltersComponent.d.ts +2 -0
  102. package/lib/quickfilter/QuickfiltersComponent.js +9 -7
  103. package/lib/quickfilter/QuickfiltersDesignComponent.d.ts +1 -1
  104. package/lib/quickfilter/QuickfiltersDesignComponent.js +19 -35
  105. package/lib/richtext/ExprItemsHtmlConverter.d.ts +5 -2
  106. package/lib/richtext/ExprItemsHtmlConverter.js +4 -4
  107. package/lib/richtext/ExprItemsTranslator.d.ts +5 -0
  108. package/lib/richtext/ExprItemsTranslator.js +149 -0
  109. package/lib/richtext/ItemsHtmlConverter.d.ts +1 -1
  110. package/lib/richtext/ItemsHtmlConverter.js +31 -15
  111. package/lib/wellknown.js +12 -9
  112. package/lib/widgets/IFrameWidget.d.ts +4 -4
  113. package/lib/widgets/ImageWidget.d.ts +7 -4
  114. package/lib/widgets/ImageWidget.js +9 -1
  115. package/lib/widgets/ImageWidgetComponent.d.ts +1 -0
  116. package/lib/widgets/ImageWidgetComponent.js +1 -1
  117. package/lib/widgets/MapWidget.d.ts +5 -48
  118. package/lib/widgets/MapWidget.js +26 -63
  119. package/lib/widgets/MarkdownWidget.d.ts +3 -0
  120. package/lib/widgets/MarkdownWidget.js +3 -0
  121. package/lib/widgets/TOCWidget.d.ts +15 -27
  122. package/lib/widgets/TOCWidget.js +107 -183
  123. package/lib/widgets/Widget.d.ts +18 -7
  124. package/lib/widgets/Widget.js +4 -0
  125. package/lib/widgets/WidgetScopesViewComponent.js +1 -1
  126. package/lib/widgets/charts/Chart.d.ts +10 -1
  127. package/lib/widgets/charts/Chart.js +22 -11
  128. package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
  129. package/lib/widgets/charts/ChartViewComponent.js +6 -3
  130. package/lib/widgets/charts/ChartWidget.d.ts +2 -0
  131. package/lib/widgets/charts/ChartWidget.js +9 -1
  132. package/lib/widgets/charts/ChartWidgetComponent.d.ts +4 -0
  133. package/lib/widgets/charts/ChartWidgetComponent.js +2 -2
  134. package/lib/widgets/charts/calendar/CalendarChart.d.ts +1 -0
  135. package/lib/widgets/charts/calendar/CalendarChart.js +26 -0
  136. package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +3 -1
  137. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.d.ts +1 -0
  138. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.js +8 -0
  139. package/lib/widgets/charts/layered/LayeredChart.d.ts +2 -0
  140. package/lib/widgets/charts/layered/LayeredChart.js +63 -3
  141. package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +1 -1
  142. package/lib/widgets/charts/layered/LayeredChartCompiler.js +1 -1
  143. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +2 -2
  144. package/lib/widgets/charts/layered/LayeredChartViewComponent.js +8 -3
  145. package/lib/widgets/charts/pivot/PivotChart.d.ts +1 -0
  146. package/lib/widgets/charts/pivot/PivotChart.js +63 -0
  147. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +1 -1
  148. package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +7 -4
  149. package/lib/widgets/charts/table/OrderingsComponent.js +1 -1
  150. package/lib/widgets/charts/table/TableChart.d.ts +1 -0
  151. package/lib/widgets/charts/table/TableChart.js +15 -0
  152. package/lib/widgets/text/TextComponent.d.ts +11 -4
  153. package/lib/widgets/text/TextComponent.js +11 -8
  154. package/lib/widgets/text/TextWidget.d.ts +6 -3
  155. package/lib/widgets/text/TextWidget.js +7 -1
  156. package/lib/widgets/text/TextWidgetComponent.d.ts +4 -0
  157. package/lib/widgets/text/TextWidgetComponent.js +7 -1
  158. package/lib/widgets/text/TextWidgetDesign.d.ts +2 -4
  159. package/lib/widgets/text/TextWidgetDesign.js +1 -1
  160. package/package.json +7 -8
  161. package/src/ColorComponent.tsx +1 -2
  162. package/src/IdSelection.ts +62 -0
  163. package/src/MWaterAddRelatedIndicatorComponent.ts +3 -2
  164. package/src/MWaterCompleteTableSelectComponent.tsx +36 -46
  165. package/src/MWaterLoaderComponent.ts +28 -26
  166. package/src/MWaterResponsesFilterComponent.ts +5 -2
  167. package/src/MWaterTableSelectComponent.tsx +5 -9
  168. package/src/autotranslate.ts +141 -0
  169. package/src/axes/AxisBuilder.ts +3 -3
  170. package/src/axes/AxisColorEditorComponent.tsx +5 -0
  171. package/src/axes/{AxisComponent.ts → AxisComponent.tsx} +106 -106
  172. package/src/axes/CategoryMapComponent.ts +4 -4
  173. package/src/axes/RangesComponent.ts +3 -2
  174. package/src/dashboards/DashboardComponent.tsx +79 -14
  175. package/src/dashboards/DashboardDesign.ts +9 -2
  176. package/src/dashboards/DashboardUtils.ts +39 -0
  177. package/src/dashboards/DashboardViewComponent.tsx +22 -3
  178. package/src/dashboards/ServerDashboardDataSource.ts +2 -1
  179. package/src/dashboards/SettingsModalComponent.tsx +450 -35
  180. package/src/dashboards/WidgetComponent.tsx +12 -6
  181. package/src/datagrids/CellEditor.tsx +354 -0
  182. package/src/datagrids/DatagridComponent.tsx +646 -0
  183. package/src/datagrids/DatagridViewComponent.tsx +539 -0
  184. package/src/datagrids/DirectDatagridDataSource.ts +2 -3
  185. package/src/datagrids/{ExprCellComponent.ts → ExprCellComponent.tsx} +28 -23
  186. package/src/datagrids/{FindReplaceModalComponent.ts → FindReplaceModalComponent.tsx} +109 -122
  187. package/src/index.css +1 -1
  188. package/src/index.ts +0 -1
  189. package/src/layouts/blocks/HorizontalBlockComponent.ts +2 -2
  190. package/src/mWaterLoader.ts +1 -1
  191. package/src/maps/BufferLayer.ts +83 -60
  192. package/src/maps/BufferLayerDesign.ts +20 -14
  193. package/src/maps/BufferLayerDesignerComponent.tsx +309 -0
  194. package/src/maps/ChoroplethLayer.ts +40 -19
  195. package/src/maps/ChoroplethLayerDesign.ts +4 -2
  196. package/src/maps/ChoroplethLayerDesigner.tsx +4 -2
  197. package/src/maps/ClusterLayer.ts +4 -10
  198. package/src/maps/DetailLevelSelectComponent.ts +1 -1
  199. package/src/maps/DirectMapDataSource.ts +2 -1
  200. package/src/maps/EditPopupComponent.ts +7 -3
  201. package/src/maps/GridLayer.ts +4 -10
  202. package/src/maps/GridLayerDesigner.tsx +5 -3
  203. package/src/maps/HoverContent.tsx +40 -16
  204. package/src/maps/Layer.ts +28 -10
  205. package/src/maps/LayerFactory.ts +0 -8
  206. package/src/maps/LayerLegendComponent.ts +2 -4
  207. package/src/maps/LayerSwitcherComponent.tsx +6 -2
  208. package/src/maps/LeafletMapComponent.tsx +3 -1
  209. package/src/maps/LegendComponent.tsx +10 -1
  210. package/src/maps/MWaterServerLayer.ts +3 -3
  211. package/src/maps/MapComponent.ts +3 -3
  212. package/src/maps/MapDesign.ts +3 -0
  213. package/src/maps/MapDesignerComponent.tsx +165 -162
  214. package/src/maps/MapLayerViewDesignerComponent.ts +2 -2
  215. package/src/maps/MapUtils.ts +24 -0
  216. package/src/maps/MapViewComponent.tsx +11 -3
  217. package/src/maps/MarkersLayer.ts +44 -18
  218. package/src/maps/MarkersLayerDesign.ts +19 -16
  219. package/src/maps/PopupFilterJoinsUtils.ts +6 -2
  220. package/src/maps/RasterMapViewComponent.ts +9 -45
  221. package/src/maps/ServerMapDataSource.ts +2 -2
  222. package/src/maps/SwitchableTileUrlLayer.tsx +4 -10
  223. package/src/maps/TileUrlLayer.tsx +4 -10
  224. package/src/maps/VectorMapViewComponent.tsx +28 -55
  225. package/src/maps/maps.ts +3 -0
  226. package/src/quickfilter/QuickfiltersComponent.ts +13 -7
  227. package/src/quickfilter/QuickfiltersDesignComponent.tsx +56 -74
  228. package/src/richtext/ExprItemsHtmlConverter.ts +9 -5
  229. package/src/richtext/ExprItemsTranslator.ts +176 -0
  230. package/src/richtext/ItemsHtmlConverter.ts +33 -18
  231. package/src/wellknown.ts +33 -30
  232. package/src/widgets/ImageWidget.ts +10 -1
  233. package/src/widgets/ImageWidgetComponent.ts +3 -2
  234. package/src/widgets/{MapWidget.ts → MapWidget.tsx} +90 -101
  235. package/src/widgets/MarkdownWidget.ts +3 -0
  236. package/src/widgets/TOCWidget.tsx +281 -0
  237. package/src/widgets/Widget.ts +25 -5
  238. package/src/widgets/WidgetScopesViewComponent.ts +2 -1
  239. package/src/widgets/charts/Chart.ts +31 -12
  240. package/src/widgets/charts/ChartViewComponent.ts +13 -3
  241. package/src/widgets/charts/ChartWidget.ts +11 -1
  242. package/src/widgets/charts/ChartWidgetComponent.tsx +9 -1
  243. package/src/widgets/charts/calendar/CalendarChart.ts +29 -0
  244. package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +3 -1
  245. package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +9 -0
  246. package/src/widgets/charts/layered/LayeredChart.ts +71 -3
  247. package/src/widgets/charts/layered/LayeredChartCompiler.ts +2 -2
  248. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +4 -2
  249. package/src/widgets/charts/layered/LayeredChartViewComponent.ts +10 -4
  250. package/src/widgets/charts/pivot/PivotChart.ts +73 -0
  251. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +1 -1
  252. package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +6 -4
  253. package/src/widgets/charts/table/OrderingsComponent.tsx +2 -1
  254. package/src/widgets/charts/table/TableChart.ts +17 -0
  255. package/src/widgets/text/TextComponent.tsx +22 -12
  256. package/src/widgets/text/TextWidget.ts +9 -2
  257. package/src/widgets/text/TextWidgetComponent.tsx +16 -1
  258. package/src/widgets/text/TextWidgetDesign.ts +4 -7
  259. package/test/IdSelectionTests.ts +54 -0
  260. package/test/LayeredChartCompilerTests.ts +0 -2
  261. package/test/richtext/ExprItemsTranslatorTests.ts +144 -0
  262. package/test/wellknownTests.ts +144 -0
  263. package/src/datagrids/DatagridComponent.ts +0 -478
  264. package/src/datagrids/DatagridViewComponent.ts +0 -464
  265. package/src/datagrids/EditExprCellComponent.tsx +0 -305
  266. package/src/datagrids/README.md +0 -3
  267. package/src/maps/BufferLayerDesignerComponent.ts +0 -311
  268. package/src/widgets/TOCWidget.ts +0 -326
  269. package/test/LegoLayoutEngineTests.ts +0 -69
@@ -38,6 +38,12 @@ export interface ChartViewComponentProps {
38
38
 
39
39
  /** A key that changes when the widget should be refreshed */
40
40
  refreshKey?: any
41
+
42
+ /** Locale to use for display */
43
+ locale: string
44
+
45
+ /** Translate function to use for display */
46
+ translate: (input: string) => string
41
47
  }
42
48
 
43
49
  interface ChartViewComponentState {
@@ -197,15 +203,18 @@ export default class ChartViewComponent extends React.Component<ChartViewCompone
197
203
  if (this.state.dataError) {
198
204
  return this.renderError()
199
205
  }
206
+
207
+ // Translate design if needed
208
+ const translatedDesign = this.props.onDesignChange || !this.props.translate || !this.state.validDesign ? this.state.validDesign : this.props.chart.translateDesign(this.state.validDesign, this.props.translate)
200
209
 
201
210
  return R(
202
211
  "div",
203
212
  { style },
204
- this.state.validDesign
213
+ translatedDesign
205
214
  ? this.props.chart.createViewElement({
206
215
  schema: this.props.schema,
207
216
  dataSource: this.props.dataSource,
208
- design: this.state.validDesign,
217
+ design: translatedDesign,
209
218
  onDesignChange: this.props.onDesignChange,
210
219
  data: this.state.data,
211
220
  scope: this.props.scope,
@@ -213,7 +222,8 @@ export default class ChartViewComponent extends React.Component<ChartViewCompone
213
222
  width: this.props.width,
214
223
  height: this.props.height,
215
224
  onRowClick: this.props.onRowClick,
216
- filters: this.props.filters
225
+ filters: this.props.filters,
226
+ locale: this.props.locale,
217
227
  })
218
228
  : undefined,
219
229
  this.state.dataLoading ? this.renderSpinner() : undefined
@@ -41,7 +41,9 @@ export default class ChartWidget extends Widget {
41
41
  width: options.width,
42
42
  height: options.height,
43
43
  onRowClick: options.onRowClick,
44
- refreshKey: options.refreshKey
44
+ refreshKey: options.refreshKey,
45
+ locale: options.locale,
46
+ translate: options.translate
45
47
  })
46
48
  }
47
49
 
@@ -70,4 +72,12 @@ export default class ChartWidget extends Widget {
70
72
  isAutoHeight() {
71
73
  return this.chart.isAutoHeight()
72
74
  }
75
+
76
+ /** Get a list of translatable strings in the design */
77
+ getTranslatableStrings(design: any, schema: Schema) {
78
+ // Clean design first
79
+ const cleanDesign = this.chart.cleanDesign(design, schema)
80
+
81
+ return this.chart.getTranslatableStrings(cleanDesign, schema)
82
+ }
73
83
  }
@@ -48,6 +48,12 @@ export interface ChartWidgetComponentProps {
48
48
 
49
49
  /** A key that changes when the widget should be refreshed */
50
50
  refreshKey?: any
51
+
52
+ /** Locale to use for display */
53
+ locale: string
54
+
55
+ /** Translate function to use for display */
56
+ translate: (input: string) => string
51
57
  }
52
58
 
53
59
  // Complete chart widget
@@ -134,6 +140,8 @@ export class ChartWidgetComponent extends React.PureComponent<ChartWidgetCompone
134
140
  onScopeChange={this.props.onScopeChange}
135
141
  onRowClick={this.props.onRowClick}
136
142
  refreshKey={this.props.refreshKey}
143
+ locale={this.props.locale}
144
+ translate={this.props.translate}
137
145
  />
138
146
  }
139
147
 
@@ -251,7 +259,7 @@ export class ChartWidgetComponent extends React.PureComponent<ChartWidgetCompone
251
259
  this.props.filters
252
260
  )
253
261
  if (!designError) {
254
- dropdownItems.push({ label: T`Export Data`, icon: "save-file", onClick: this.handleSaveCsvFile })
262
+ dropdownItems.push({ label: T`Export Data`, onClick: this.handleSaveCsvFile })
255
263
  }
256
264
  if (this.props.onDesignChange != null) {
257
265
  dropdownItems.unshift({
@@ -224,4 +224,33 @@ export default class CalendarChart extends Chart {
224
224
  getPlaceholderIcon() {
225
225
  return "fa-calendar"
226
226
  }
227
+
228
+ translateDesign(design: CalendarChartDesign, translate: (input: string) => string) {
229
+ return produce(design, draft => {
230
+ // Translate title text
231
+ if (draft.titleText) {
232
+ draft.titleText = translate(draft.titleText)
233
+ }
234
+
235
+ // Translate axis category labels
236
+ if (draft.dateAxis?.categoryLabels) {
237
+ for (const key in draft.dateAxis.categoryLabels) {
238
+ draft.dateAxis.categoryLabels[key] = translate(draft.dateAxis.categoryLabels[key])
239
+ }
240
+ }
241
+ if (draft.valueAxis?.categoryLabels) {
242
+ for (const key in draft.valueAxis.categoryLabels) {
243
+ draft.valueAxis.categoryLabels[key] = translate(draft.valueAxis.categoryLabels[key])
244
+ }
245
+ }
246
+
247
+ // Translate null labels
248
+ if (draft.dateAxis?.nullLabel) {
249
+ draft.dateAxis.nullLabel = translate(draft.dateAxis.nullLabel)
250
+ }
251
+ if (draft.valueAxis?.nullLabel) {
252
+ draft.valueAxis.nullLabel = translate(draft.valueAxis.nullLabel)
253
+ }
254
+ })
255
+ }
227
256
  }
@@ -113,7 +113,9 @@ export default class CalendarChartViewComponent extends React.Component<Calendar
113
113
  const scopeData: WidgetScope = {
114
114
  name:
115
115
  this.axisBuilder.summarizeAxis(this.props.design.dateAxis!, this.context) +
116
- T` is ` +
116
+ " " +
117
+ T`is` +
118
+ " " +
117
119
  this.axisBuilder.formatValue(this.props.design.dateAxis!, data, this.context),
118
120
  filter: {
119
121
  jsonql: this.axisBuilder.createValueFilter(this.props.design.dateAxis!, data),
@@ -227,4 +227,13 @@ export default class ImageMosaicChart extends Chart {
227
227
  getPlaceholderIcon() {
228
228
  return "fa-th"
229
229
  }
230
+
231
+ translateDesign(design: ImageMosaicChartDesign, translate: (input: string) => string) {
232
+ return produce(design, draft => {
233
+ // Translate title text
234
+ if (draft.titleText) {
235
+ draft.titleText = translate(draft.titleText)
236
+ }
237
+ })
238
+ }
230
239
  }
@@ -1,3 +1,4 @@
1
+
1
2
  import _ from "lodash"
2
3
  import React from "react"
3
4
  import async from "async"
@@ -16,8 +17,8 @@ import { JsonQLFilter } from "../../.."
16
17
  import { JsonQLQuery } from "@mwater/jsonql"
17
18
  import LayeredChartViewComponent from "./LayeredChartViewComponent"
18
19
  import LayeredChartDesignerComponent from "./LayeredChartDesignerComponent"
20
+ import { translateHtmlItems } from "../../../richtext/ExprItemsTranslator"
19
21
 
20
- // See LayeredChart Design.md for the design
21
22
  export default class LayeredChart extends Chart {
22
23
  cleanDesign(design: LayeredChartDesign, schema: Schema): LayeredChartDesign {
23
24
  const exprCleaner = new ExprCleaner(schema)
@@ -130,7 +131,7 @@ export default class LayeredChart extends Chart {
130
131
  return T`Missing Y Axis`
131
132
  }
132
133
 
133
- if (!layer.axes.x && compiler.isXAxisRequired(design, layerId)) {
134
+ if (!layer.axes.x && compiler.isXAxisRequired(design)) {
134
135
  return T`Missing X Axis`
135
136
  }
136
137
  if (!layer.axes.color && compiler.isColorAxisRequired(design, layerId)) {
@@ -246,7 +247,9 @@ export default class LayeredChart extends Chart {
246
247
  height: options.height,
247
248
 
248
249
  scope: options.scope,
249
- onScopeChange: options.onScopeChange
250
+ onScopeChange: options.onScopeChange,
251
+
252
+ locale: options.locale,
250
253
  }
251
254
 
252
255
  return React.createElement(LayeredChartViewComponent, props)
@@ -356,4 +359,69 @@ export default class LayeredChart extends Chart {
356
359
  getPlaceholderIcon() {
357
360
  return "fa-bar-chart"
358
361
  }
362
+
363
+ /** Translates the design */
364
+ translateDesign(design: LayeredChartDesign, translate: (input: string) => string) {
365
+ return produce(design, draft => {
366
+ // Translate axis labels
367
+ if (draft.xAxisLabelText) {
368
+ draft.xAxisLabelText = translate(draft.xAxisLabelText)
369
+ }
370
+ if (draft.yAxisLabelText) {
371
+ draft.yAxisLabelText = translate(draft.yAxisLabelText)
372
+ }
373
+
374
+ // Translate layer names
375
+ for (const layer of draft.layers) {
376
+ if (layer.name) {
377
+ layer.name = translate(layer.name)
378
+ }
379
+
380
+ // Translate axis category labels
381
+ if (layer.axes.x?.categoryLabels) {
382
+ for (const key in layer.axes.x.categoryLabels) {
383
+ layer.axes.x.categoryLabels[key] = translate(layer.axes.x.categoryLabels[key])
384
+ }
385
+ }
386
+ if (layer.axes.y?.categoryLabels) {
387
+ for (const key in layer.axes.y.categoryLabels) {
388
+ layer.axes.y.categoryLabels[key] = translate(layer.axes.y.categoryLabels[key])
389
+ }
390
+ }
391
+ if (layer.axes.color?.categoryLabels) {
392
+ for (const key in layer.axes.color.categoryLabels) {
393
+ layer.axes.color.categoryLabels[key] = translate(layer.axes.color.categoryLabels[key])
394
+ }
395
+ }
396
+
397
+ // Translate null labels
398
+ if (layer.axes.x?.nullLabel) {
399
+ layer.axes.x.nullLabel = translate(layer.axes.x.nullLabel)
400
+ }
401
+ if (layer.axes.y?.nullLabel) {
402
+ layer.axes.y.nullLabel = translate(layer.axes.y.nullLabel)
403
+ }
404
+ if (layer.axes.color?.nullLabel) {
405
+ layer.axes.color.nullLabel = translate(layer.axes.color.nullLabel)
406
+ }
407
+ }
408
+
409
+ // Translate y thresholds
410
+ if (draft.yThresholds) {
411
+ for (const threshold of draft.yThresholds) {
412
+ if (threshold.label) {
413
+ threshold.label = translate(threshold.label)
414
+ }
415
+ }
416
+ }
417
+
418
+ // Translate header and footer using ExprItemsTranslator
419
+ if (draft.header) {
420
+ draft.header.items = translateHtmlItems(draft.header.items || [], translate)
421
+ }
422
+ if (draft.footer) {
423
+ draft.footer.items = translateHtmlItems(draft.footer.items || [], translate)
424
+ }
425
+ })
426
+ }
359
427
  }
@@ -473,7 +473,7 @@ export default class LayeredChartCompiler {
473
473
  }
474
474
 
475
475
  // Compiles data for a polar chart (pie/donut) with no x axis
476
- compileDataPolar(design: LayeredChartDesign, data: C3ChartData, locale: any): C3Data {
476
+ compileDataPolar(design: LayeredChartDesign, data: C3ChartData, locale?: string): C3Data {
477
477
  let order: "asc" | "desc" | null
478
478
  const columns: any = []
479
479
  const types: { [key: string]: ChartTypes } = {}
@@ -670,7 +670,7 @@ export default class LayeredChartCompiler {
670
670
  const trendlineSeries = seriesY + ":trendline"
671
671
  columns.push([trendlineSeries].concat(calculateLinearRegression(yValues, xValues)))
672
672
  types[trendlineSeries] = line ? line() : "line"
673
- names[trendlineSeries] = names[seriesY] + T` Trendline`
673
+ names[trendlineSeries] = names[seriesY] + " " + T`Trendline`
674
674
  xs[trendlineSeries] = seriesX
675
675
  colors[trendlineSeries] = layer.color || defaultColors[layerIndex]
676
676
  legendHide.push(trendlineSeries) // Hide in legend
@@ -270,7 +270,8 @@ export default class LayeredChartDesignerComponent extends React.Component<Layer
270
270
  "button",
271
271
  { className: "btn btn-link", type: "button", onClick: this.handleAddLayer },
272
272
  R("span", { className: "fas fa-plus" }),
273
- T` Add Another Series`
273
+ " ",
274
+ T`Add Another Series`
274
275
  )
275
276
  : undefined
276
277
  )
@@ -481,7 +482,8 @@ class ThresholdsComponent extends React.Component<{
481
482
  "button",
482
483
  { type: "button", className: "btn btn-sm btn-link", onClick: this.handleAdd },
483
484
  R("i", { className: "fa fa-plus" }),
484
- T` Add Y Threshold`
485
+ " ",
486
+ T`Add Y Threshold`
485
487
  )
486
488
  )
487
489
  }
@@ -105,7 +105,8 @@ export default class LayeredChartViewComponent extends React.Component<
105
105
  schema: this.props.schema,
106
106
  dataSource: this.props.dataSource,
107
107
  exprValues: this.props.data.header || {},
108
- width: this.props.width
108
+ width: this.props.width,
109
+ locale: this.context
109
110
  })
110
111
  )
111
112
  }
@@ -125,7 +126,8 @@ export default class LayeredChartViewComponent extends React.Component<
125
126
  schema: this.props.schema,
126
127
  dataSource: this.props.dataSource,
127
128
  exprValues: this.props.data.footer || {},
128
- width: this.props.width
129
+ width: this.props.width,
130
+ locale: this.context
129
131
  })
130
132
  )
131
133
  }
@@ -171,7 +173,7 @@ interface C3ChartComponentProps {
171
173
  class C3ChartComponent extends React.Component<C3ChartComponentProps> {
172
174
  throttledCreateChart: ((props: C3ChartComponentProps) => any) & _.Cancelable
173
175
  chart: any
174
- chartDiv: any
176
+ chartDiv: HTMLDivElement | null
175
177
 
176
178
  constructor(props: C3ChartComponentProps) {
177
179
  super(props)
@@ -190,6 +192,10 @@ class C3ChartComponent extends React.Component<C3ChartComponentProps> {
190
192
  this.chart.destroy()
191
193
  }
192
194
 
195
+ if (!this.chartDiv) {
196
+ return
197
+ }
198
+
193
199
  const compiler = new LayeredChartCompiler({ schema: props.schema })
194
200
  const chartOptions: any = compiler.createChartOptions({
195
201
  design: this.props.design,
@@ -531,7 +537,7 @@ class C3ChartComponent extends React.Component<C3ChartComponentProps> {
531
537
 
532
538
  return R("div", {
533
539
  ref: c => {
534
- return (this.chartDiv = c)
540
+ this.chartDiv = c
535
541
  }
536
542
  })
537
543
  }
@@ -14,6 +14,7 @@ import PivotChartLayoutBuilder from "./PivotChartLayoutBuilder"
14
14
  import { WidgetDataSource } from "../../WidgetDataSource"
15
15
  import { PivotChartDesign, PivotChartSegment } from "./PivotChartDesign"
16
16
  import { JsonQLFilter } from "../../../JsonQLFilter"
17
+ import { translateHtmlItems } from "../../../richtext/ExprItemsTranslator"
17
18
 
18
19
  // Store true as a weakly cached value if a design is already clean
19
20
  const cleanDesignCache = new WeakCache()
@@ -422,4 +423,76 @@ export default class PivotChart extends Chart {
422
423
  getPlaceholderIcon() {
423
424
  return "fa-magic"
424
425
  }
426
+
427
+ translateDesign(design: PivotChartDesign, translate: (input: string) => string) {
428
+ return produce(design, draft => {
429
+ // Helper function to translate a segment and its children
430
+ const translateSegment = (segment: PivotChartSegment) => {
431
+ // Translate segment label
432
+ if (segment.label) {
433
+ segment.label = translate(segment.label)
434
+ }
435
+
436
+ // Translate value axis labels
437
+ if (segment.valueAxis?.categoryLabels) {
438
+ for (const key in segment.valueAxis.categoryLabels) {
439
+ segment.valueAxis.categoryLabels[key] = translate(segment.valueAxis.categoryLabels[key])
440
+ }
441
+ }
442
+
443
+ // Translate null label
444
+ if (segment.valueAxis?.nullLabel) {
445
+ segment.valueAxis.nullLabel = translate(segment.valueAxis.nullLabel)
446
+ }
447
+
448
+ // Recursively translate children
449
+ if (segment.children) {
450
+ segment.children.forEach(translateSegment)
451
+ }
452
+ }
453
+
454
+ // Translate all row segments
455
+ draft.rows.forEach(translateSegment)
456
+
457
+ // Translate all column segments
458
+ draft.columns.forEach(translateSegment)
459
+
460
+ // Translate all intersections
461
+ for (const intersection of Object.values(draft.intersections)) {
462
+ // Translate value axis labels
463
+ if (intersection.valueAxis?.categoryLabels) {
464
+ for (const key in intersection.valueAxis.categoryLabels) {
465
+ intersection.valueAxis.categoryLabels[key] = translate(intersection.valueAxis.categoryLabels[key])
466
+ }
467
+ }
468
+
469
+ // Translate null label
470
+ if (intersection.valueAxis?.nullLabel) {
471
+ intersection.valueAxis.nullLabel = translate(intersection.valueAxis.nullLabel)
472
+ }
473
+
474
+ // Translate segment value axis override labels
475
+ if (intersection.segmentValueAxisOverrides) {
476
+ for (const axis of Object.values(intersection.segmentValueAxisOverrides)) {
477
+ if (axis?.categoryLabels) {
478
+ for (const key in axis.categoryLabels) {
479
+ axis.categoryLabels[key] = translate(axis.categoryLabels[key])
480
+ }
481
+ }
482
+ if (axis?.nullLabel) {
483
+ axis.nullLabel = translate(axis.nullLabel)
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ // Translate header and footer using ExprItemsTranslator
490
+ if (draft.header?.items) {
491
+ draft.header.items = translateHtmlItems(draft.header.items, translate)
492
+ }
493
+ if (draft.footer?.items) {
494
+ draft.footer.items = translateHtmlItems(draft.footer.items, translate)
495
+ }
496
+ })
497
+ }
425
498
  }
@@ -393,7 +393,7 @@ class LayoutCellComponent extends React.Component<LayoutCellComponentProps> {
393
393
  R("a", { className: "link-plain", onClick: this.props.onEditSection }, T`Edit`),
394
394
  cell.summarize
395
395
  ? [
396
- R("span", { className: "text-muted" }, T` / `),
396
+ R("span", { className: "text-muted" }, ` / `),
397
397
  R("a", { className: "link-plain", onClick: this.props.onSummarizeSegment }, T`Summarize`)
398
398
  ]
399
399
  : undefined
@@ -95,13 +95,15 @@ export default class SegmentDesignerComponent extends React.Component<
95
95
  <ui.Radio key="single" value={this.state.mode} radioValue={"single"} onChange={this.handleMode}>
96
96
  {T`Single ${this.props.segmentType}`}
97
97
  <span className="text-muted">
98
- {T` - used for summary ${this.props.segmentType}s and empty ${this.props.segmentType}s`}
98
+ {` - `}
99
+ {T`used for summary ${this.props.segmentType}s and empty ${this.props.segmentType}s`}
99
100
  </span>
100
101
  </ui.Radio>,
101
102
 
102
103
  <ui.Radio key="multiple" value={this.state.mode} radioValue={"multiple"} onChange={this.handleMode}>
103
104
  {T`Multiple ${this.props.segmentType}s`}
104
- <span className="text-muted">{T` - disaggregate data by a field`}</span>
105
+ {" - "}
106
+ <span className="text-muted">{T`disaggregate data by a field`}</span>
105
107
  </ui.Radio>
106
108
  )
107
109
  }
@@ -170,7 +172,7 @@ export default class SegmentDesignerComponent extends React.Component<
170
172
  ui.FormGroup,
171
173
  {
172
174
  labelMuted: true,
173
- label: [R(ui.Icon, { id: "glyphicon-filter" }), T` Filters`],
175
+ label: [R(ui.Icon, { id: "glyphicon-filter" }), " ", T`Filters`],
174
176
  hint: T`Filters all data associated with this ${this.props.segmentType}`
175
177
  },
176
178
  R(FilterExprComponent, {
@@ -265,7 +267,7 @@ export default class SegmentDesignerComponent extends React.Component<
265
267
  ui.FormGroup,
266
268
  {
267
269
  labelMuted: true,
268
- label: [R(ui.Icon, { id: "fa-sort-amount-asc" }), T` Sort`],
270
+ label: [R(ui.Icon, { id: "fa-sort-amount-asc" }), " ", T`Sort`],
269
271
  hint: T`Sorts the display of this ${this.props.segmentType}`
270
272
  },
271
273
  R(ExprComponent, {
@@ -56,7 +56,8 @@ export default class OrderingsComponent extends React.Component<OrderingsCompone
56
56
  "button",
57
57
  { type: "button", className: "btn btn-sm btn-secondary", onClick: this.handleAdd, key: "add" },
58
58
  R("span", { className: "fas fa-plus" }),
59
- T` Add Ordering`
59
+ " ",
60
+ T`Add Ordering`
60
61
  )
61
62
  )
62
63
  }
@@ -431,4 +431,21 @@ export default class TableChart extends Chart {
431
431
  getPlaceholderIcon() {
432
432
  return "fa-table"
433
433
  }
434
+
435
+ translateDesign(design: TableChartDesign, translate: (input: string) => string) {
436
+ return produce(design, draft => {
437
+ // Translate title text
438
+ if (draft.titleText) {
439
+ draft.titleText = translate(draft.titleText)
440
+ }
441
+
442
+ // Translate column headers and axis labels
443
+ for (const column of draft.columns) {
444
+ // Translate header text
445
+ if (column.headerText) {
446
+ column.headerText = translate(column.headerText)
447
+ }
448
+ }
449
+ })
450
+ }
434
451
  }
@@ -3,18 +3,22 @@ import _ from "lodash"
3
3
  import RichTextComponent from "../../richtext/RichTextComponent"
4
4
  import ExprInsertModalComponent from "./ExprInsertModalComponent"
5
5
  import ExprUpdateModalComponent from "./ExprUpdateModalComponent"
6
- import ExprItemsHtmlConverter from "../../richtext/ExprItemsHtmlConverter"
6
+ import ExprItemsHtmlConverter, { HtmlItemExpr, HtmlItemOrExpr } from "../../richtext/ExprItemsHtmlConverter"
7
7
  import { TextWidgetDesign } from "./TextWidgetDesign"
8
8
  import { DataSource, Schema } from "@mwater/expressions"
9
9
  import { LocaleContext } from "@mwater/expressions-ui"
10
10
 
11
11
  export interface TextComponentProps {
12
12
  design: TextWidgetDesign
13
+
14
+ /** Called when design changes. If not set, will be in display mode, otherwise in edit mode */
13
15
  onDesignChange?: (design: TextWidgetDesign) => void
14
16
  schema: Schema
15
17
  dataSource: DataSource
18
+
16
19
  /** Expression values */
17
20
  exprValues: { [key: string]: any }
21
+
18
22
  width?: number
19
23
  height?: number
20
24
 
@@ -23,10 +27,15 @@ export interface TextComponentProps {
23
27
 
24
28
  /** Optional lookup of string name to value. Used for {{branding}} and other replacement strings in text widget */
25
29
  namedStrings?: { [key: string]: string }
30
+
31
+ /** Locale to use for display */
32
+ locale: string
26
33
  }
27
34
 
28
- // Text component which is provided with the data it needs, rather than loading it.
29
- // Used by TextWidgetComponent and also by other components that embed text fields
35
+ /**
36
+ * Text component which is provided with the data it needs, rather than loading it.
37
+ * Used by TextWidgetComponent and also by other components that embed text fields
38
+ */
30
39
  export default class TextComponent extends React.Component<TextComponentProps> {
31
40
  static contextType = LocaleContext
32
41
  exprInsertModal: ExprInsertModalComponent | null = null
@@ -38,7 +47,7 @@ export default class TextComponent extends React.Component<TextComponentProps> {
38
47
  this.props.schema,
39
48
  this.props.onDesignChange != null,
40
49
  this.props.exprValues,
41
- // Display summaries if in design more and singleRowTable is set
50
+ // Display summaries if in design mode and singleRowTable is set
42
51
  this.props.onDesignChange != null && this.props.singleRowTable != null,
43
52
  // Only replace named strings if not editing
44
53
  this.props.onDesignChange == null ? this.props.namedStrings : undefined,
@@ -46,12 +55,12 @@ export default class TextComponent extends React.Component<TextComponentProps> {
46
55
  )
47
56
  }
48
57
 
49
- handleItemsChange = (items: any) => {
58
+ handleItemsChange = (items: HtmlItemOrExpr[]) => {
50
59
  const design = { ...this.props.design, items }
51
60
  return this.props.onDesignChange!(design)
52
61
  }
53
62
 
54
- handleInsertExpr = (item: any) => {
63
+ handleInsertExpr = (item: HtmlItemExpr) => {
55
64
  const html = '<div data-embed="' + _.escape(JSON.stringify(item)) + '"></div>'
56
65
 
57
66
  return this.editor!.pasteHTML(html)
@@ -70,26 +79,27 @@ export default class TextComponent extends React.Component<TextComponentProps> {
70
79
  })
71
80
 
72
81
  const items = replaceItemInItems(this.props.design.items || [], item)
73
- return this.props.onDesignChange!({ ...this.props.design, items })
82
+ this.props.onDesignChange!({ ...this.props.design, items })
74
83
  }
75
84
 
76
- handleItemClick = (item: any) => {
77
- return this.exprUpdateModal!.open(item, (item: any) => {
85
+ handleItemClick = (item: HtmlItemExpr) => {
86
+ this.exprUpdateModal!.open(item, (item) => {
78
87
  // Replace in items
79
- return this.replaceItem(item)
88
+ this.replaceItem(item)
80
89
  })
81
90
  }
82
91
 
83
92
  handleAddExpr = (ev: React.MouseEvent<HTMLDivElement>) => {
84
93
  ev.preventDefault()
85
- return this.exprInsertModal!.open()
94
+ this.exprInsertModal!.open()
86
95
  }
87
96
 
88
97
  renderExtraPaletteButtons() {
89
98
  return (
90
99
  <div key="expr" className="mwater-visualization-text-palette-item" onMouseDown={this.handleAddExpr}>
91
100
  <i className="fa fa-plus" />
92
- {T` Expression`}
101
+ {" "}
102
+ {T`Expression`}
93
103
  </div>
94
104
  )
95
105
  }
@@ -12,6 +12,7 @@ import { JsonQLSelectQuery } from "@mwater/jsonql"
12
12
  import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
13
13
  import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
14
14
  import { TextWidgetDesign } from "./TextWidgetDesign"
15
+ import { getHtmlItemsStrings } from "../../richtext/ExprItemsTranslator"
15
16
 
16
17
  export default class TextWidget extends Widget {
17
18
  // Creates a React element that is a view of the widget
@@ -44,7 +45,9 @@ export default class TextWidget extends Widget {
44
45
  singleRowTable: options.singleRowTable,
45
46
  namedStrings: options.namedStrings,
46
47
  ref: options.widgetRef,
47
- refreshKey: options.refreshKey
48
+ refreshKey: options.refreshKey,
49
+ locale: options.locale,
50
+ translate: options.translate
48
51
  })
49
52
  }
50
53
 
@@ -191,7 +194,7 @@ export default class TextWidget extends Widget {
191
194
  }
192
195
 
193
196
  // Get expression items recursively
194
- getExprItems(items: HtmlItem[]): HtmlItemExpr[] {
197
+ getExprItems(items?: HtmlItem[]): HtmlItemExpr[] {
195
198
  let exprItems: any[] = []
196
199
  for (let item of items || []) {
197
200
  if ((item as any).type === "expr") {
@@ -267,4 +270,8 @@ export default class TextWidget extends Widget {
267
270
 
268
271
  return entries
269
272
  }
273
+
274
+ getTranslatableStrings(design: TextWidgetDesign, schema: Schema): string[] {
275
+ return getHtmlItemsStrings(design.items || [])
276
+ }
270
277
  }