@mwater/visualization 5.4.5 → 5.5.0

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 (132) hide show
  1. package/.storybook/head.html +0 -1
  2. package/lib/MWaterContextComponent.js +1 -1
  3. package/lib/MWaterLoaderComponent.d.ts +2 -2
  4. package/lib/dashboards/DashboardComponent.js +2 -1
  5. package/lib/dashboards/LayoutOptionsComponent.js +18 -11
  6. package/lib/dashboards/ServerDashboardDataSource.d.ts +10 -1
  7. package/lib/dashboards/ServerDashboardDataSource.js +29 -0
  8. package/lib/dashboards/layoutOptions.d.ts +5 -1
  9. package/lib/datagrids/DatagridComponent.js +1 -1
  10. package/lib/datagrids/ExprCellComponent.d.ts +1 -0
  11. package/lib/datagrids/ExprCellComponent.js +22 -20
  12. package/lib/maps/BufferLayer.d.ts +18 -0
  13. package/lib/maps/BufferLayer.js +24 -14
  14. package/lib/maps/ChoroplethLayer.d.ts +18 -0
  15. package/lib/maps/ChoroplethLayer.js +34 -25
  16. package/lib/maps/ChoroplethLayerDesign.d.ts +3 -2
  17. package/lib/maps/ChoroplethLayerDesigner.d.ts +11 -1
  18. package/lib/maps/DirectMapDataSource.js +17 -0
  19. package/lib/maps/EditHoverOver.d.ts +1 -1
  20. package/lib/maps/EditHoverOver.js +62 -33
  21. package/lib/maps/HoverContent.d.ts +10 -5
  22. package/lib/maps/HoverContent.js +6 -35
  23. package/lib/maps/Layer.d.ts +37 -0
  24. package/lib/maps/Layer.js +30 -4
  25. package/lib/maps/MWaterServerLayer.d.ts +2 -2
  26. package/lib/maps/MWaterServerLayer.js +6 -6
  27. package/lib/maps/MapLayerDataSource.d.ts +9 -0
  28. package/lib/maps/MapUtils.d.ts +19 -1
  29. package/lib/maps/MapUtils.js +71 -1
  30. package/lib/maps/MarkersLayer.d.ts +18 -0
  31. package/lib/maps/MarkersLayer.js +24 -24
  32. package/lib/maps/MarkersLayerDesignerComponent.d.ts +14 -1
  33. package/lib/maps/RasterMapViewComponent.js +1 -1
  34. package/lib/maps/ServerMapDataSource.d.ts +9 -0
  35. package/lib/maps/ServerMapDataSource.js +29 -0
  36. package/lib/maps/VectorMapViewComponent.js +6 -6
  37. package/lib/maps/maps.d.ts +4 -2
  38. package/lib/mwater_table_selection/FormsListComponent.d.ts +33 -0
  39. package/lib/mwater_table_selection/FormsListComponent.js +141 -0
  40. package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +47 -0
  41. package/lib/mwater_table_selection/IndicatorsListComponent.js +182 -0
  42. package/lib/mwater_table_selection/IssuesListComponent.d.ts +29 -0
  43. package/lib/mwater_table_selection/IssuesListComponent.js +123 -0
  44. package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.d.ts +20 -0
  45. package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.js +157 -0
  46. package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.d.ts +17 -0
  47. package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.js +79 -0
  48. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +37 -0
  49. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +275 -0
  50. package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.d.ts +17 -0
  51. package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.js +94 -0
  52. package/lib/mwater_table_selection/MWaterMetricsTableListComponent.d.ts +17 -0
  53. package/lib/mwater_table_selection/MWaterMetricsTableListComponent.js +80 -0
  54. package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +32 -0
  55. package/lib/mwater_table_selection/MWaterTableSelectComponent.js +158 -0
  56. package/lib/widgets/charts/Chart.d.ts +11 -0
  57. package/lib/widgets/charts/Chart.js +15 -0
  58. package/lib/widgets/charts/ChartWidgetComponent.d.ts +1 -0
  59. package/lib/widgets/charts/ChartWidgetComponent.js +27 -1
  60. package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +1 -1
  61. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +1 -1
  62. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +5 -12
  63. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +43 -57
  64. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +113 -110
  65. package/lib/widgets/charts/layered/LayeredChartUtils.d.ts +2 -1
  66. package/lib/widgets/charts/layered/LayeredChartUtils.js +0 -2
  67. package/lib/widgets/charts/pivot/PivotChart.d.ts +2 -0
  68. package/lib/widgets/charts/pivot/PivotChart.js +156 -0
  69. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +5 -20
  70. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +31 -61
  71. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +4 -0
  72. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +4 -2
  73. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.d.ts +5 -44
  74. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +38 -63
  75. package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +7 -68
  76. package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +58 -106
  77. package/lib/widgets/charts/table/TableChart.d.ts +2 -0
  78. package/lib/widgets/charts/table/TableChart.js +172 -1
  79. package/lib/widgets/charts/table/TableChartDesignerComponent.d.ts +7 -17
  80. package/lib/widgets/charts/table/TableChartDesignerComponent.js +79 -95
  81. package/lib/widgets/charts/table/TableChartViewComponent.d.ts +1 -7
  82. package/lib/widgets/charts/table/TableChartViewComponent.js +19 -27
  83. package/package.json +3 -8
  84. package/src/MWaterContextComponent.tsx +1 -1
  85. package/src/MWaterLoaderComponent.ts +1 -1
  86. package/src/dashboards/DashboardComponent.tsx +2 -1
  87. package/src/dashboards/LayoutOptionsComponent.tsx +22 -10
  88. package/src/dashboards/ServerDashboardDataSource.ts +36 -1
  89. package/src/dashboards/layoutOptions.tsx +5 -1
  90. package/src/datagrids/DatagridComponent.tsx +1 -1
  91. package/src/datagrids/ExprCellComponent.tsx +23 -20
  92. package/src/maps/BufferLayer.ts +35 -20
  93. package/src/maps/ChoroplethLayer.ts +51 -33
  94. package/src/maps/ChoroplethLayerDesign.ts +3 -2
  95. package/src/maps/ChoroplethLayerDesigner.tsx +2 -2
  96. package/src/maps/DirectMapDataSource.ts +21 -1
  97. package/src/maps/EditHoverOver.tsx +91 -51
  98. package/src/maps/HoverContent.tsx +16 -47
  99. package/src/maps/Layer.ts +42 -4
  100. package/src/maps/MWaterServerLayer.ts +6 -6
  101. package/src/maps/MapLayerDataSource.ts +8 -0
  102. package/src/maps/MapUtils.ts +70 -3
  103. package/src/maps/MarkersLayer.ts +34 -24
  104. package/src/maps/RasterMapViewComponent.ts +1 -1
  105. package/src/maps/ServerMapDataSource.ts +35 -0
  106. package/src/maps/VectorMapViewComponent.tsx +6 -6
  107. package/src/maps/maps.ts +4 -2
  108. package/src/mwater_table_selection/FormsListComponent.tsx +188 -0
  109. package/src/mwater_table_selection/IndicatorsListComponent.tsx +283 -0
  110. package/src/mwater_table_selection/IssuesListComponent.tsx +167 -0
  111. package/src/mwater_table_selection/MWaterAccountingSystemListComponent.tsx +225 -0
  112. package/src/{MWaterAssetSystemsListComponent.tsx → mwater_table_selection/MWaterAssetSystemsListComponent.tsx} +2 -2
  113. package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +377 -0
  114. package/src/{MWaterCustomTablesetListComponent.tsx → mwater_table_selection/MWaterCustomTablesetListComponent.tsx} +1 -1
  115. package/src/{MWaterMetricsTableListComponent.tsx → mwater_table_selection/MWaterMetricsTableListComponent.tsx} +1 -1
  116. package/src/{MWaterTableSelectComponent.tsx → mwater_table_selection/MWaterTableSelectComponent.tsx} +83 -86
  117. package/src/widgets/charts/Chart.ts +17 -0
  118. package/src/widgets/charts/ChartWidgetComponent.tsx +36 -1
  119. package/src/widgets/charts/layered/LayeredChartDesign.ts +1 -1
  120. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +23 -24
  121. package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +260 -211
  122. package/src/widgets/charts/layered/LayeredChartUtils.ts +7 -7
  123. package/src/widgets/charts/pivot/PivotChart.ts +191 -0
  124. package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +124 -129
  125. package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +4 -2
  126. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +120 -149
  127. package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +178 -198
  128. package/src/widgets/charts/table/TableChart.ts +177 -1
  129. package/src/widgets/charts/table/TableChartDesignerComponent.tsx +422 -0
  130. package/src/widgets/charts/table/{TableChartViewComponent.ts → TableChartViewComponent.tsx} +65 -60
  131. package/src/MWaterCompleteTableSelectComponent.tsx +0 -975
  132. package/src/widgets/charts/table/TableChartDesignerComponent.ts +0 -441
@@ -27,64 +27,93 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const lodash_1 = require("lodash");
30
+ const expressions_1 = require("@mwater/expressions");
30
31
  const expressions_ui_1 = require("@mwater/expressions-ui");
31
32
  const react_1 = __importStar(require("react"));
32
- const ModalWindowComponent_1 = __importDefault(require("@mwater/react-library/lib/ModalWindowComponent"));
33
+ const ActionCancelModalComponent_1 = __importDefault(require("@mwater/react-library/lib/ActionCancelModalComponent"));
33
34
  const ui = __importStar(require("@mwater/react-library/lib/bootstrap"));
34
35
  const uuid_1 = __importDefault(require("uuid"));
35
- const EditHoverOver = props => {
36
+ const valueFormatter_1 = require("../valueFormatter");
37
+ const valueFormatter_2 = require("../valueFormatter");
38
+ function EditHoverOver(props) {
39
+ const { schema, dataSource, design, onDesignChange, table } = props;
36
40
  const [editing, setEditing] = (0, react_1.useState)(false);
41
+ const [draftItems, setDraftItems] = (0, react_1.useState)(undefined);
37
42
  const handleRemovePopup = () => {
38
- const design = (0, lodash_1.omit)(props.design, "hoverOver");
39
- props.onDesignChange(design);
40
- };
41
- const handleDesignChange = (items) => {
42
- const hoverOver = { ...(props.design.hoverOver ?? {}), items };
43
- const design = { ...props.design, hoverOver };
44
- return props.onDesignChange(design);
43
+ const newDesign = (0, lodash_1.omit)(design, "hoverOver");
44
+ onDesignChange(newDesign);
45
45
  };
46
46
  const handleItemChange = (item) => {
47
- const items = (props.design.hoverOver?.items ?? []).map((i) => (item.id === i.id ? item : i));
48
- const design = { ...props.design, hoverOver: { ...props.design.hoverOver, items } };
49
- return props.onDesignChange(design);
47
+ setDraftItems(draftItems?.map((i) => (item.id === i.id ? item : i)));
50
48
  };
51
49
  const handleItemDelete = (item) => {
52
- const items = (props.design.hoverOver?.items ?? []).filter((i) => item.id !== i.id);
53
- const design = { ...props.design, hoverOver: { ...props.design.hoverOver, items } };
54
- return props.onDesignChange(design);
50
+ setDraftItems(draftItems?.filter((i) => item.id !== i.id));
51
+ };
52
+ const handleAddItem = () => {
53
+ setDraftItems([...(draftItems ?? []), { id: (0, uuid_1.default)().replace(/-/g, ""), label: "" }]);
54
+ };
55
+ const handleSave = () => {
56
+ const hoverOver = { ...(design.hoverOver ?? {}), items: draftItems ?? [] };
57
+ const newDesign = { ...design, hoverOver };
58
+ onDesignChange(newDesign);
59
+ setEditing(false);
60
+ setDraftItems(undefined);
61
+ };
62
+ const handleCancel = () => {
63
+ setEditing(false);
64
+ setDraftItems(undefined);
65
+ };
66
+ const handleOpen = () => {
67
+ setDraftItems(design.hoverOver?.items ?? []);
68
+ setEditing(true);
55
69
  };
56
70
  return (react_1.default.createElement(react_1.default.Fragment, null,
57
- react_1.default.createElement("button", { className: "btn btn-link", onClick: () => setEditing(true) },
71
+ react_1.default.createElement("button", { className: "btn btn-link", onClick: handleOpen },
58
72
  react_1.default.createElement("span", { className: "fa fa-pencil" }),
59
73
  " ",
60
74
  T `Customize Hoverover`),
61
- props.design.hoverOver && (react_1.default.createElement("button", { className: "btn btn-link", onClick: handleRemovePopup },
75
+ design.hoverOver && (react_1.default.createElement("button", { className: "btn btn-link", onClick: handleRemovePopup },
62
76
  react_1.default.createElement("span", { className: "fa fa-times" }),
63
77
  " ",
64
78
  T `Remove Hover over`)),
65
- editing && (react_1.default.createElement(ModalWindowComponent_1.default, { isOpen: true, onRequestClose: () => setEditing(false) },
66
- (props.design.hoverOver?.items ?? []).length > 0 && (react_1.default.createElement("table", { className: "table" },
79
+ editing && (react_1.default.createElement(ActionCancelModalComponent_1.default, { onAction: handleSave, onCancel: handleCancel, actionLabel: T `Save`, title: T `Customize Hoverover`, size: "x-large" },
80
+ (draftItems ?? []).length > 0 && (react_1.default.createElement("table", { className: "table" },
67
81
  react_1.default.createElement("thead", null,
68
82
  react_1.default.createElement("tr", null,
69
83
  react_1.default.createElement("th", null, T `Label`),
70
84
  react_1.default.createElement("th", null, T `Value`),
71
- react_1.default.createElement("th", null))),
72
- react_1.default.createElement("tbody", null, props.design.hoverOver?.items.map((item) => (react_1.default.createElement(HoverOverItemEditor, { schema: props.schema, dataSource: props.dataSource, table: props.design.table, onItemChange: handleItemChange, onItemDelete: handleItemDelete, item: item })))))),
73
- (props.design.hoverOver?.items ?? []).length < 3 && (react_1.default.createElement("button", { className: "btn btn-link", onClick: () => handleDesignChange([
74
- ...(props.design.hoverOver?.items ?? []),
75
- { id: (0, uuid_1.default)().replace(/-/g, ""), label: "" }
76
- ]) },
77
- react_1.default.createElement("span", { className: "fa fa-plus" }),
78
- T `Add item`))))));
79
- };
80
- const HoverOverItemEditor = ({ schema, dataSource, table, item, onItemChange, onItemDelete }) => {
85
+ react_1.default.createElement("th", { style: { width: "1%", whiteSpace: "nowrap" } }, T `Format`),
86
+ react_1.default.createElement("th", { style: { width: "1%", whiteSpace: "nowrap" } }))),
87
+ react_1.default.createElement("tbody", null, draftItems?.map((item) => (react_1.default.createElement(HoverOverItemEditor, { key: item.id, schema: schema, dataSource: dataSource, table: table, onItemChange: handleItemChange, onItemDelete: handleItemDelete, item: item })))))),
88
+ react_1.default.createElement("button", { className: "btn btn-link", onClick: handleAddItem },
89
+ react_1.default.createElement("span", { className: "fas fa-plus me-1" }),
90
+ T `Add Item`)))));
91
+ }
92
+ function HoverOverItemEditor(props) {
93
+ const { schema, dataSource, table, item, onItemChange, onItemDelete } = props;
94
+ function renderFormat() {
95
+ const exprUtils = new expressions_1.ExprUtils(schema);
96
+ const exprType = exprUtils.getExprType(item.value ?? null);
97
+ if (!exprType) {
98
+ return null;
99
+ }
100
+ if (!(0, valueFormatter_1.canFormatType)(exprType)) {
101
+ return null;
102
+ }
103
+ const formats = (0, valueFormatter_2.getFormatOptions)(exprType);
104
+ if (!formats) {
105
+ return null;
106
+ }
107
+ return (react_1.default.createElement(ui.Select, { options: formats.map(f => ({ value: f.value, label: f.label })), value: item.format ?? (0, valueFormatter_1.getDefaultFormat)(exprType), onChange: value => onItemChange({ ...item, format: value ?? undefined }), style: { width: "auto", display: "inline-block" } }));
108
+ }
81
109
  return (react_1.default.createElement("tr", null,
82
- react_1.default.createElement("td", null,
110
+ react_1.default.createElement("td", { className: "align-middle" },
83
111
  react_1.default.createElement(ui.TextInput, { value: item.label, onChange: value => onItemChange({ ...item, label: value }) })),
84
- react_1.default.createElement("td", null,
112
+ react_1.default.createElement("td", { className: "align-middle" },
85
113
  react_1.default.createElement(expressions_ui_1.ExprComponent, { schema: schema, dataSource: dataSource, table: table, types: ["text", "number", "enum", "boolean", "date", "datetime", "id"], onChange: expr => onItemChange({ ...item, value: expr }), value: item.value ?? null, aggrStatuses: ["individual", "literal", "aggregate"] })),
86
- react_1.default.createElement("td", null,
114
+ react_1.default.createElement("td", { className: "align-middle", style: { width: "1%", whiteSpace: "nowrap" } }, renderFormat()),
115
+ react_1.default.createElement("td", { className: "align-middle", style: { width: "1%", whiteSpace: "nowrap" } },
87
116
  react_1.default.createElement("button", { className: "btn btn-link", onClick: () => onItemDelete(item) },
88
117
  react_1.default.createElement("span", { className: "fa fa-close" })))));
89
- };
118
+ }
90
119
  exports.default = EditHoverOver;
@@ -1,14 +1,19 @@
1
1
  import React from "react";
2
- import { DataSource, Schema } from "@mwater/expressions";
2
+ import { Schema } from "@mwater/expressions";
3
3
  import { JsonQLFilter } from "..";
4
4
  import { HoverOverItem } from "./maps";
5
+ import { MapLayerDataSource } from "./MapLayerDataSource";
5
6
  export interface HoverContentProps {
6
7
  /** Schema to use */
7
8
  schema: Schema;
8
- dataSource: DataSource;
9
- filters?: JsonQLFilter[];
10
- /** Table that hover over is for */
11
- table: string;
9
+ /** Map data source */
10
+ mapLayerDataSource: MapLayerDataSource;
11
+ /** Design of the layer */
12
+ design: any;
13
+ /** Data of the current item being hovered over. e.g. { id: 123 } */
14
+ data: any;
15
+ /** Additional filters to apply to the hover over data */
16
+ filters: JsonQLFilter[];
12
17
  /** Hover over items */
13
18
  items: HoverOverItem[];
14
19
  /** Locale to use */
@@ -25,7 +25,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  const react_1 = __importStar(require("react"));
27
27
  const expressions_1 = require("@mwater/expressions");
28
- const lodash_1 = require("lodash");
29
28
  const valueFormatter_1 = require("../valueFormatter");
30
29
  const valueFormatter_2 = require("../valueFormatter");
31
30
  /** Component that displays hover over content */
@@ -37,42 +36,14 @@ const HoverContent = (props) => {
37
36
  let mounted = true;
38
37
  const items = props.items;
39
38
  if (items.length > 0) {
40
- const exprCompiler = new expressions_1.ExprCompiler(props.schema);
41
- const query = {
42
- type: "query",
43
- selects: [],
44
- from: exprCompiler.compileTable(props.table, "main"),
45
- limit: 1
46
- };
47
- items.forEach((item) => {
48
- if (item.value) {
49
- query.selects.push({
50
- type: "select",
51
- expr: exprCompiler.compileExpr({ expr: item.value, tableAlias: "main" }),
52
- alias: item.id
53
- });
39
+ props.mapLayerDataSource.getHoverOverData(props.design, props.data, props.filters).then((data) => {
40
+ if (mounted) {
41
+ setValues(data);
54
42
  }
55
- });
56
- if (props.filters) {
57
- let whereClauses = props.filters.map(f => (0, expressions_1.injectTableAlias)(f.jsonql, "main"));
58
- whereClauses = (0, lodash_1.compact)(whereClauses);
59
- // Wrap if multiple
60
- if (whereClauses.length > 1) {
61
- query.where = { type: "op", op: "and", exprs: whereClauses };
62
- }
63
- else {
64
- query.where = whereClauses[0];
65
- }
66
- }
67
- props.dataSource.performQuery(query, (error, data) => {
68
- if (!mounted) {
69
- return;
70
- }
71
- if (error) {
72
- setError(props.translate("Error loading hover data"));
73
- return;
43
+ }).catch((error) => {
44
+ if (mounted) {
45
+ setError(error.message);
74
46
  }
75
- setValues(data?.[0] ?? {});
76
47
  });
77
48
  }
78
49
  return () => {
@@ -130,6 +130,25 @@ export default class Layer<LayerDesign> {
130
130
  data: any;
131
131
  event: any;
132
132
  }, options: OnGridClickOptions<LayerDesign>): OnGridClickResults;
133
+ /**
134
+ * Called when the interactivity grid is hovered over.
135
+ * arguments:
136
+ * ev: { data: interactivty data e.g. `{ id: 123 }` }
137
+ * options:
138
+ * design: design of layer
139
+ * schema: schema to use
140
+ * dataSource: data source to use
141
+ * layerDataSource: layer data source
142
+ * scopeData: current scope data if layer is scoping
143
+ * filters: compiled filters to apply to the popup
144
+ *
145
+ * Returns:
146
+ * null
147
+ * or
148
+ * {
149
+ * hoverOver: React element to put into a hover over
150
+ * }
151
+ */
133
152
  onGridHoverOver(ev: {
134
153
  data: any;
135
154
  event: any;
@@ -172,6 +191,24 @@ export default class Layer<LayerDesign> {
172
191
  } | null) => void): void;
173
192
  /** Get strings to be translated */
174
193
  getTranslatableStrings(design: LayerDesign, schema: Schema): string[];
194
+ /** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
195
+ * It will be called on the server side if using a server map data source, or on the client side if using a direct
196
+ * map data source.
197
+ */
198
+ getHoverOverData(options: {
199
+ /** Design of the layer */
200
+ design: LayerDesign;
201
+ /** Data of the current item being hovered over. e.g. { id: 123 } */
202
+ data: any;
203
+ /** Filters to apply to the hover over data, not including filtering down to the current item */
204
+ filters: JsonQLFilter[];
205
+ /** Schema to use */
206
+ schema: Schema;
207
+ /** Data source to use */
208
+ dataSource: DataSource;
209
+ }): Promise<{
210
+ [key: string]: any;
211
+ }>;
175
212
  }
176
213
  export interface LegendOptions<LayerDesign> {
177
214
  design: LayerDesign;
package/lib/maps/Layer.js CHANGED
@@ -56,6 +56,25 @@ class Layer {
56
56
  onGridClick(ev, options) {
57
57
  return null;
58
58
  }
59
+ /**
60
+ * Called when the interactivity grid is hovered over.
61
+ * arguments:
62
+ * ev: { data: interactivty data e.g. `{ id: 123 }` }
63
+ * options:
64
+ * design: design of layer
65
+ * schema: schema to use
66
+ * dataSource: data source to use
67
+ * layerDataSource: layer data source
68
+ * scopeData: current scope data if layer is scoping
69
+ * filters: compiled filters to apply to the popup
70
+ *
71
+ * Returns:
72
+ * null
73
+ * or
74
+ * {
75
+ * hoverOver: React element to put into a hover over
76
+ * }
77
+ */
59
78
  onGridHoverOver(ev, options) {
60
79
  return null;
61
80
  }
@@ -168,10 +187,10 @@ class Layer {
168
187
  const [w, s, e, n] = (0, bbox_1.default)(results[0].bounds);
169
188
  // Pad bounds to prevent too small box (100m)
170
189
  bounds = {
171
- w: w - 0.001,
172
- s: s - 0.001,
173
- e: e + 0.001,
174
- n: n + 0.001
190
+ w: Math.max(w - 0.001, -180),
191
+ s: Math.max(s - 0.001, -90),
192
+ e: Math.min(e + 0.001, 180),
193
+ n: Math.min(n + 0.001, 90)
175
194
  };
176
195
  }
177
196
  return callback(null, bounds);
@@ -182,5 +201,12 @@ class Layer {
182
201
  getTranslatableStrings(design, schema) {
183
202
  return [];
184
203
  }
204
+ /** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
205
+ * It will be called on the server side if using a server map data source, or on the client side if using a direct
206
+ * map data source.
207
+ */
208
+ getHoverOverData(options) {
209
+ return Promise.resolve({});
210
+ }
185
211
  }
186
212
  exports.default = Layer;
@@ -24,8 +24,8 @@ interface LoadingLegendState {
24
24
  }
25
25
  declare class LoadingLegend extends React.Component<LoadingLegendProps, LoadingLegendState> {
26
26
  constructor(props: any);
27
- componentDidMount(): JQuery.jqXHR<any>;
28
- componentWillReceiveProps(nextProps: any): JQuery.jqXHR<any> | undefined;
27
+ componentDidMount(): void;
28
+ componentDidUpdate(prevProps: any): void;
29
29
  render(): React.DetailedReactHTMLElement<{
30
30
  style: {
31
31
  font: "14px/16px Arial, Helvetica, sans-serif";
@@ -81,14 +81,14 @@ class LoadingLegend extends react_1.default.Component {
81
81
  this.state = { html: T `Loading...` };
82
82
  }
83
83
  componentDidMount() {
84
- return jquery_1.default.get(this.props.url).done((data) => {
85
- return this.setState({ html: data });
84
+ jquery_1.default.get(this.props.url).done((data) => {
85
+ this.setState({ html: data });
86
86
  });
87
87
  }
88
- componentWillReceiveProps(nextProps) {
89
- if (nextProps.url !== this.props.url) {
90
- return jquery_1.default.get(nextProps.url).done((data) => {
91
- return this.setState({ html: data });
88
+ componentDidUpdate(prevProps) {
89
+ if (prevProps.url !== this.props.url) {
90
+ jquery_1.default.get(this.props.url).done((data) => {
91
+ this.setState({ html: data });
92
92
  });
93
93
  }
94
94
  }
@@ -19,4 +19,13 @@ export interface MapLayerDataSource {
19
19
  }>;
20
20
  /** Gets widget data source for a popup widget */
21
21
  getPopupWidgetDataSource(design: any, widgetId: string): WidgetDataSource;
22
+ /** Gets hover over data for hover over items
23
+ * @param design The design of the layer
24
+ * @param data The data of the current item being hovered over. e.g. { id: 123 }
25
+ * @param filters The filters to apply to the layer does not include filters that narrow down to a specific item
26
+ * @returns A promise that resolves to the hover over data, indexed by the id of the hover over item
27
+ */
28
+ getHoverOverData(design: any, data: any, filters: JsonQLFilter[]): Promise<{
29
+ [key: string]: any;
30
+ }>;
22
31
  }
@@ -1,7 +1,8 @@
1
1
  import { JsonQLExpr } from "@mwater/jsonql";
2
- import { Schema } from "@mwater/expressions";
2
+ import { DataSource, Schema } from "@mwater/expressions";
3
3
  import { JsonQLFilter } from "../JsonQLFilter";
4
4
  import { MapDesign } from "./MapDesign";
5
+ import { HoverOverItem } from "./maps";
5
6
  export interface MapScope {
6
7
  name: string;
7
8
  filter: JsonQLFilter;
@@ -23,3 +24,20 @@ export declare function getCompiledFilters(design: MapDesign, schema: Schema, fi
23
24
  * Get a list of translatable strings in the map design
24
25
  */
25
26
  export declare function getTranslatableStrings(design: MapDesign, schema: Schema): string[];
27
+ /**
28
+ * Convenience function to get hover over data for a map given an id and a list of hover over items
29
+ */
30
+ export declare function getSimpleHoverOverData(options: {
31
+ /** Id of the item to get hover over data for. If null, will not filter by id */
32
+ id: any;
33
+ /** Table of the item to get hover over data for */
34
+ table: string;
35
+ /** Extra filters to apply to the hover over data, not including filtering down to the current item */
36
+ filters: JsonQLFilter[];
37
+ /** Schema to use */
38
+ schema: Schema;
39
+ /** Data source to use */
40
+ dataSource: DataSource;
41
+ /** Hover over items */
42
+ hoverOverItems: HoverOverItem[];
43
+ }): Promise<import("@mwater/expressions").Row>;
@@ -1,5 +1,28 @@
1
1
  "use strict";
2
2
  // General utilities for a map
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
3
26
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
27
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
28
  };
@@ -11,7 +34,8 @@ exports.convertToMarkersMap = convertToMarkersMap;
11
34
  exports.getFilterableTables = getFilterableTables;
12
35
  exports.getCompiledFilters = getCompiledFilters;
13
36
  exports.getTranslatableStrings = getTranslatableStrings;
14
- const lodash_1 = __importDefault(require("lodash"));
37
+ exports.getSimpleHoverOverData = getSimpleHoverOverData;
38
+ const lodash_1 = __importStar(require("lodash"));
15
39
  const expressions_1 = require("@mwater/expressions");
16
40
  const LayerFactory_1 = __importDefault(require("./LayerFactory"));
17
41
  // Check if can convert to a cluster map. Only maps containing marker views can be
@@ -135,3 +159,49 @@ function getTranslatableStrings(design, schema) {
135
159
  // Remove duplicates
136
160
  return lodash_1.default.uniq(strings);
137
161
  }
162
+ /**
163
+ * Convenience function to get hover over data for a map given an id and a list of hover over items
164
+ */
165
+ async function getSimpleHoverOverData(options) {
166
+ const { id, table, filters, schema, dataSource, hoverOverItems } = options;
167
+ const exprCompiler = new expressions_1.ExprCompiler(schema);
168
+ const query = {
169
+ type: "query",
170
+ selects: [],
171
+ from: exprCompiler.compileTable(table, "main"),
172
+ limit: 1
173
+ };
174
+ for (const item of hoverOverItems) {
175
+ if (item.value) {
176
+ query.selects.push({
177
+ type: "select",
178
+ expr: exprCompiler.compileExpr({ expr: item.value, tableAlias: "main" }),
179
+ alias: item.id
180
+ });
181
+ }
182
+ }
183
+ if (filters) {
184
+ let whereClauses = filters.filter(f => f.table === table).map(f => (0, expressions_1.injectTableAlias)(f.jsonql, "main"));
185
+ // Add id filter
186
+ if (id != null) {
187
+ whereClauses.push({
188
+ type: "op",
189
+ op: "=",
190
+ exprs: [
191
+ exprCompiler.compileExpr({ expr: { type: "id", table }, tableAlias: "main" }),
192
+ { type: "literal", value: id }
193
+ ]
194
+ });
195
+ }
196
+ whereClauses = (0, lodash_1.compact)(whereClauses);
197
+ // Wrap if multiple
198
+ if (whereClauses.length > 1) {
199
+ query.where = { type: "op", op: "and", exprs: whereClauses };
200
+ }
201
+ else {
202
+ query.where = whereClauses[0];
203
+ }
204
+ }
205
+ const rows = await dataSource.performQuery(query);
206
+ return rows?.[0] ?? {};
207
+ }
@@ -48,6 +48,24 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
48
48
  validateDesign(design: MarkersLayerDesign, schema: Schema): string | null;
49
49
  /** Get strings to be translated */
50
50
  getTranslatableStrings(design: MarkersLayerDesign, schema: Schema): string[];
51
+ /** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
52
+ * It will be called on the server side if using a server map data source, or on the client side if using a direct
53
+ * map data source.
54
+ */
55
+ getHoverOverData(options: {
56
+ /** Design of the layer */
57
+ design: MarkersLayerDesign;
58
+ /** Data of the current item being hovered over. e.g. { id: 123 } */
59
+ data: any;
60
+ /** Filters to apply to the hover over data, not including filtering down to the current item */
61
+ filters: JsonQLFilter[];
62
+ /** Schema to use */
63
+ schema: Schema;
64
+ /** Data source to use */
65
+ dataSource: DataSource;
66
+ }): Promise<{
67
+ [key: string]: any;
68
+ }>;
51
69
  }
52
70
  /**
53
71
  * Takes a base query that has any number of selects and where conditions. It must have a geometry
@@ -40,6 +40,7 @@ const HoverContent_1 = __importDefault(require("./HoverContent"));
40
40
  const layoutOptions_1 = require("../dashboards/layoutOptions");
41
41
  const BlocksLayoutManager_1 = __importDefault(require("../layouts/blocks/BlocksLayoutManager"));
42
42
  const DashboardUtils_1 = require("../dashboards/DashboardUtils");
43
+ const MapUtils_1 = require("./MapUtils");
43
44
  class MarkersLayer extends Layer_1.default {
44
45
  /** Gets the type of layer definition */
45
46
  getLayerDefinitionType() {
@@ -445,35 +446,20 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
445
446
  }
446
447
  // same as onGridClick but handles hover over
447
448
  onGridHoverOver(ev, hoverOptions) {
448
- if (ev.data && ev.data.id) {
449
- const { table } = hoverOptions.design;
450
- const results = {};
451
- // Popup
452
- if (hoverOptions.design.hoverOver) {
453
- const exprCompiler = new expressions_1.ExprCompiler(hoverOptions.schema);
454
- results.hoverOver = react_1.default.createElement(HoverContent_1.default, {
449
+ if (ev.data && ev.data.id && hoverOptions.design.hoverOver && hoverOptions.design.hoverOver.items.length > 0) {
450
+ const results = {
451
+ hoverOver: react_1.default.createElement(HoverContent_1.default, {
455
452
  key: ev.data.id,
456
453
  schema: hoverOptions.schema,
457
- dataSource: hoverOptions.dataSource,
458
- table,
454
+ mapLayerDataSource: hoverOptions.layerDataSource,
459
455
  items: hoverOptions.design.hoverOver.items,
460
- filters: [
461
- {
462
- table,
463
- jsonql: {
464
- type: "op",
465
- op: "=",
466
- exprs: [
467
- exprCompiler.compileExpr({ expr: { type: "id", table }, tableAlias: "{alias}" }),
468
- { type: "literal", value: ev.data.id }
469
- ]
470
- }
471
- }
472
- ],
456
+ design: hoverOptions.design,
457
+ data: ev.data,
458
+ filters: hoverOptions.filters,
473
459
  locale: hoverOptions.locale,
474
460
  translate: hoverOptions.translate
475
- });
476
- }
461
+ })
462
+ };
477
463
  return results;
478
464
  }
479
465
  else {
@@ -729,6 +715,20 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
729
715
  // Remove duplicates
730
716
  return lodash_1.default.uniq(strings);
731
717
  }
718
+ /** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
719
+ * It will be called on the server side if using a server map data source, or on the client side if using a direct
720
+ * map data source.
721
+ */
722
+ getHoverOverData(options) {
723
+ return (0, MapUtils_1.getSimpleHoverOverData)({
724
+ id: options.data.id,
725
+ table: options.design.table,
726
+ filters: options.filters,
727
+ schema: options.schema,
728
+ dataSource: options.dataSource,
729
+ hoverOverItems: options.design.hoverOver.items,
730
+ });
731
+ }
732
732
  }
733
733
  exports.default = MarkersLayer;
734
734
  /**
@@ -51,6 +51,19 @@ export default class MarkersLayerDesignerComponent extends React.Component<Marke
51
51
  className: string;
52
52
  }, HTMLElement> | null;
53
53
  renderPopup(): React.CElement<any, EditPopupComponent> | null;
54
- renderHoverOver(): React.FunctionComponentElement<import("./EditHoverOver").EditHoverOverProps> | null;
54
+ renderHoverOver(): React.FunctionComponentElement<{
55
+ design: MarkersLayerDesign;
56
+ onDesignChange: any;
57
+ schema: Schema;
58
+ dataSource: DataSource;
59
+ table: string;
60
+ idTable: string;
61
+ defaultPopupFilterJoins: {
62
+ [x: number]: {
63
+ table: any;
64
+ type: string;
65
+ };
66
+ };
67
+ }> | null;
55
68
  render(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
56
69
  }
@@ -158,7 +158,7 @@ class RasterMapViewComponent extends react_1.default.Component {
158
158
  filters: this.getCompiledFilters(),
159
159
  dataSource: this.props.dataSource,
160
160
  locale: this.context,
161
- translate: this.props.translate ?? (() => ""),
161
+ translate: this.props.translate ?? ((input) => input),
162
162
  onHide: () => this.setState({ legendHidden: true }),
163
163
  zoom: null
164
164
  });
@@ -54,6 +54,15 @@ declare class ServerLayerDataSource implements MapLayerDataSource {
54
54
  getPopupWidgetDataSource(design: any, widgetId: string): ServerMapLayerPopupWidgetDataSource;
55
55
  createUrl(filters: JsonQLFilter[], extension: string): string;
56
56
  createLegacyUrl(design: any, extension: string, filters: JsonQLFilter[]): string;
57
+ /** Gets hover over data for hover over items
58
+ * @param design The design of the layer
59
+ * @param data The data of the current item being hovered over. e.g. { id: 123 }
60
+ * @param filters The filters to apply to the layer does not include filters that narrow down to a specific item
61
+ * @returns A promise that resolves to the hover over data, indexed by the id of the hover over item
62
+ */
63
+ getHoverOverData(design: any, data: any, filters: JsonQLFilter[]): Promise<{
64
+ [key: string]: any;
65
+ }>;
57
66
  }
58
67
  interface ServerMapLayerPopupWidgetDataSourceOptions {
59
68
  /** API url to use for talking to mWater server */