@mwater/visualization 5.4.4 → 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.
- package/.storybook/head.html +0 -1
- package/lib/MWaterContextComponent.js +1 -1
- package/lib/MWaterLoaderComponent.d.ts +2 -2
- package/lib/dashboards/DashboardComponent.js +2 -1
- package/lib/dashboards/LayoutOptionsComponent.js +18 -11
- package/lib/dashboards/ServerDashboardDataSource.d.ts +10 -1
- package/lib/dashboards/ServerDashboardDataSource.js +29 -0
- package/lib/dashboards/layoutOptions.d.ts +5 -1
- package/lib/datagrids/DatagridComponent.js +1 -1
- package/lib/datagrids/ExprCellComponent.d.ts +1 -0
- package/lib/datagrids/ExprCellComponent.js +22 -20
- package/lib/maps/BufferLayer.d.ts +18 -0
- package/lib/maps/BufferLayer.js +24 -14
- package/lib/maps/ChoroplethLayer.d.ts +18 -0
- package/lib/maps/ChoroplethLayer.js +34 -25
- package/lib/maps/ChoroplethLayerDesign.d.ts +3 -2
- package/lib/maps/ChoroplethLayerDesigner.d.ts +11 -1
- package/lib/maps/DirectMapDataSource.js +17 -0
- package/lib/maps/EditHoverOver.d.ts +1 -1
- package/lib/maps/EditHoverOver.js +62 -33
- package/lib/maps/HoverContent.d.ts +10 -5
- package/lib/maps/HoverContent.js +6 -35
- package/lib/maps/Layer.d.ts +37 -0
- package/lib/maps/Layer.js +30 -4
- package/lib/maps/MWaterServerLayer.d.ts +2 -2
- package/lib/maps/MWaterServerLayer.js +6 -6
- package/lib/maps/MapLayerDataSource.d.ts +9 -0
- package/lib/maps/MapUtils.d.ts +19 -1
- package/lib/maps/MapUtils.js +71 -1
- package/lib/maps/MarkersLayer.d.ts +18 -0
- package/lib/maps/MarkersLayer.js +24 -24
- package/lib/maps/MarkersLayerDesignerComponent.d.ts +14 -1
- package/lib/maps/RasterMapViewComponent.js +1 -1
- package/lib/maps/ServerMapDataSource.d.ts +9 -0
- package/lib/maps/ServerMapDataSource.js +29 -0
- package/lib/maps/VectorMapViewComponent.js +6 -6
- package/lib/maps/maps.d.ts +4 -2
- package/lib/mwater_table_selection/FormsListComponent.d.ts +33 -0
- package/lib/mwater_table_selection/FormsListComponent.js +141 -0
- package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +47 -0
- package/lib/mwater_table_selection/IndicatorsListComponent.js +182 -0
- package/lib/mwater_table_selection/IssuesListComponent.d.ts +29 -0
- package/lib/mwater_table_selection/IssuesListComponent.js +123 -0
- package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.d.ts +20 -0
- package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.js +157 -0
- package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.d.ts +17 -0
- package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.js +79 -0
- package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +37 -0
- package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +275 -0
- package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.d.ts +17 -0
- package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.js +94 -0
- package/lib/mwater_table_selection/MWaterMetricsTableListComponent.d.ts +17 -0
- package/lib/mwater_table_selection/MWaterMetricsTableListComponent.js +80 -0
- package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +32 -0
- package/lib/mwater_table_selection/MWaterTableSelectComponent.js +158 -0
- package/lib/quickfilter/Quickfilter.d.ts +2 -0
- package/lib/quickfilter/QuickfiltersDesignComponent.js +18 -10
- package/lib/widgets/charts/Chart.d.ts +11 -0
- package/lib/widgets/charts/Chart.js +15 -0
- package/lib/widgets/charts/ChartWidgetComponent.d.ts +1 -0
- package/lib/widgets/charts/ChartWidgetComponent.js +27 -1
- package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +1 -1
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +1 -1
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +5 -12
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +43 -57
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +113 -110
- package/lib/widgets/charts/layered/LayeredChartUtils.d.ts +2 -1
- package/lib/widgets/charts/layered/LayeredChartUtils.js +0 -2
- package/lib/widgets/charts/pivot/PivotChart.d.ts +2 -0
- package/lib/widgets/charts/pivot/PivotChart.js +156 -0
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +5 -20
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +31 -61
- package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +4 -0
- package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +4 -2
- package/lib/widgets/charts/pivot/PivotChartLayoutComponent.d.ts +5 -44
- package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +38 -63
- package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +7 -68
- package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +58 -106
- package/lib/widgets/charts/table/TableChart.d.ts +2 -0
- package/lib/widgets/charts/table/TableChart.js +172 -1
- package/lib/widgets/charts/table/TableChartDesignerComponent.d.ts +7 -17
- package/lib/widgets/charts/table/TableChartDesignerComponent.js +79 -95
- package/lib/widgets/charts/table/TableChartViewComponent.d.ts +1 -7
- package/lib/widgets/charts/table/TableChartViewComponent.js +19 -27
- package/package.json +3 -8
- package/src/MWaterContextComponent.tsx +1 -1
- package/src/MWaterLoaderComponent.ts +1 -1
- package/src/dashboards/DashboardComponent.tsx +2 -1
- package/src/dashboards/LayoutOptionsComponent.tsx +22 -10
- package/src/dashboards/ServerDashboardDataSource.ts +36 -1
- package/src/dashboards/layoutOptions.tsx +5 -1
- package/src/datagrids/DatagridComponent.tsx +1 -1
- package/src/datagrids/ExprCellComponent.tsx +23 -20
- package/src/maps/BufferLayer.ts +35 -20
- package/src/maps/ChoroplethLayer.ts +51 -33
- package/src/maps/ChoroplethLayerDesign.ts +3 -2
- package/src/maps/ChoroplethLayerDesigner.tsx +2 -2
- package/src/maps/DirectMapDataSource.ts +21 -1
- package/src/maps/EditHoverOver.tsx +91 -51
- package/src/maps/HoverContent.tsx +16 -47
- package/src/maps/Layer.ts +42 -4
- package/src/maps/MWaterServerLayer.ts +6 -6
- package/src/maps/MapLayerDataSource.ts +8 -0
- package/src/maps/MapUtils.ts +70 -3
- package/src/maps/MarkersLayer.ts +34 -24
- package/src/maps/RasterMapViewComponent.ts +1 -1
- package/src/maps/ServerMapDataSource.ts +35 -0
- package/src/maps/VectorMapViewComponent.tsx +6 -6
- package/src/maps/maps.ts +4 -2
- package/src/mwater_table_selection/FormsListComponent.tsx +188 -0
- package/src/mwater_table_selection/IndicatorsListComponent.tsx +283 -0
- package/src/mwater_table_selection/IssuesListComponent.tsx +167 -0
- package/src/mwater_table_selection/MWaterAccountingSystemListComponent.tsx +225 -0
- package/src/{MWaterAssetSystemsListComponent.tsx → mwater_table_selection/MWaterAssetSystemsListComponent.tsx} +2 -2
- package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +377 -0
- package/src/{MWaterCustomTablesetListComponent.tsx → mwater_table_selection/MWaterCustomTablesetListComponent.tsx} +1 -1
- package/src/{MWaterMetricsTableListComponent.tsx → mwater_table_selection/MWaterMetricsTableListComponent.tsx} +1 -1
- package/src/{MWaterTableSelectComponent.tsx → mwater_table_selection/MWaterTableSelectComponent.tsx} +83 -86
- package/src/quickfilter/Quickfilter.ts +3 -0
- package/src/quickfilter/QuickfiltersDesignComponent.tsx +19 -14
- package/src/widgets/charts/Chart.ts +17 -0
- package/src/widgets/charts/ChartWidgetComponent.tsx +36 -1
- package/src/widgets/charts/layered/LayeredChartDesign.ts +1 -1
- package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +23 -24
- package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +260 -211
- package/src/widgets/charts/layered/LayeredChartUtils.ts +7 -7
- package/src/widgets/charts/pivot/PivotChart.ts +191 -0
- package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +124 -129
- package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +4 -2
- package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +120 -149
- package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +178 -198
- package/src/widgets/charts/table/TableChart.ts +177 -1
- package/src/widgets/charts/table/TableChartDesignerComponent.tsx +422 -0
- package/src/widgets/charts/table/{TableChartViewComponent.ts → TableChartViewComponent.tsx} +65 -60
- package/src/MWaterCompleteTableSelectComponent.tsx +0 -975
- package/src/widgets/charts/table/TableChartDesignerComponent.ts +0 -441
|
@@ -39,51 +39,54 @@ export default class ExprCellComponent extends React.Component<ExprCellComponent
|
|
|
39
39
|
return <a href={url} key={id} target="_blank" style={{ paddingLeft: 5, paddingRight: 5 }}>{T`Image`}</a>
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
let node
|
|
44
|
-
const exprUtils = new ExprUtils(this.props.schema)
|
|
42
|
+
renderCellContent() {
|
|
45
43
|
let { value } = this.props
|
|
46
44
|
|
|
45
|
+
const exprUtils = new ExprUtils(this.props.schema)
|
|
46
|
+
|
|
47
47
|
if (value == null || !this.props.expr) {
|
|
48
|
-
|
|
48
|
+
return null
|
|
49
49
|
} else {
|
|
50
50
|
// Parse if should be JSON
|
|
51
51
|
if (["image", "imagelist", "geometry", "text[]"].includes(this.props.exprType) && _.isString(value)) {
|
|
52
|
-
|
|
52
|
+
try {
|
|
53
|
+
value = JSON.parse(value)
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.error("Error parsing JSON", e)
|
|
56
|
+
return "???"
|
|
57
|
+
}
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
// Format if possible
|
|
56
61
|
if (canFormatType(this.props.exprType)) {
|
|
57
|
-
|
|
62
|
+
return formatValue(this.props.exprType, value, this.props.format)
|
|
58
63
|
} else {
|
|
59
64
|
// Convert to node based on type
|
|
60
65
|
switch (this.props.exprType) {
|
|
61
66
|
case "text":
|
|
62
|
-
|
|
63
|
-
break
|
|
67
|
+
return <Linkify properties={{ target: "_blank" }}>{value}</Linkify>
|
|
64
68
|
case "boolean":
|
|
65
69
|
case "enum":
|
|
66
70
|
case "enumset":
|
|
67
71
|
case "text[]":
|
|
68
|
-
|
|
69
|
-
break
|
|
72
|
+
return exprUtils.stringifyExprLiteral(this.props.expr, value, this.props.locale)
|
|
70
73
|
case "date":
|
|
71
|
-
|
|
72
|
-
break
|
|
74
|
+
return moment(value, "YYYY-MM-DD").format("ll")
|
|
73
75
|
case "datetime":
|
|
74
|
-
|
|
75
|
-
break
|
|
76
|
+
return moment(value, moment.ISO_8601).format("lll")
|
|
76
77
|
case "image":
|
|
77
|
-
|
|
78
|
-
break
|
|
78
|
+
return this.renderImage(value.id)
|
|
79
79
|
case "imagelist":
|
|
80
|
-
|
|
81
|
-
break
|
|
80
|
+
return _.map(value, (v: any) => this.renderImage(v.id))
|
|
82
81
|
default:
|
|
83
|
-
|
|
82
|
+
return "" + value
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
render() {
|
|
89
|
+
const content = this.renderCellContent()
|
|
87
90
|
|
|
88
91
|
return (
|
|
89
92
|
<div
|
|
@@ -101,7 +104,7 @@ export default class ExprCellComponent extends React.Component<ExprCellComponent
|
|
|
101
104
|
onClick={this.props.onClick}
|
|
102
105
|
onDoubleClick={this.props.onDoubleClick}
|
|
103
106
|
>
|
|
104
|
-
{
|
|
107
|
+
{content}
|
|
105
108
|
</div>
|
|
106
109
|
)
|
|
107
110
|
}
|
package/src/maps/BufferLayer.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { getDefaultLayoutOptions } from "../dashboards/layoutOptions"
|
|
|
18
18
|
import Widget from "../widgets/Widget"
|
|
19
19
|
import BlocksLayoutManager from "../layouts/blocks/BlocksLayoutManager"
|
|
20
20
|
import { getTranslatableStringsFromLayoutManager } from "../dashboards/DashboardUtils"
|
|
21
|
+
import { getSimpleHoverOverData } from "./MapUtils"
|
|
21
22
|
|
|
22
23
|
/** Layer which draws a buffer around geometries (i.e. a radius circle around points) */
|
|
23
24
|
export default class BufferLayer extends Layer<BufferLayerDesign> {
|
|
@@ -696,29 +697,16 @@ marker-fill: ` +
|
|
|
696
697
|
ev: { data: any; event: any },
|
|
697
698
|
hoverOptions: OnGridHoverOptions<BufferLayerDesign>
|
|
698
699
|
): OnGridHoverResults {
|
|
699
|
-
if (ev.data && ev.data.id) {
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
// Popup
|
|
704
|
-
if (hoverOptions.design.hoverOver) {
|
|
705
|
-
// Create filter using popupFilterJoins
|
|
706
|
-
const popupFilterJoins =
|
|
707
|
-
hoverOptions.design.popupFilterJoins || PopupFilterJoinsUtils.createDefaultPopupFilterJoins(table)
|
|
708
|
-
const popupFilters = PopupFilterJoinsUtils.createPopupFilters(
|
|
709
|
-
popupFilterJoins,
|
|
710
|
-
hoverOptions.schema,
|
|
711
|
-
table,
|
|
712
|
-
ev.data.id
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
results.hoverOver = React.createElement(HoverContent, {
|
|
700
|
+
if (ev.data && ev.data.id && hoverOptions.design.hoverOver && hoverOptions.design.hoverOver.items.length > 0) {
|
|
701
|
+
const results: OnGridHoverResults = {
|
|
702
|
+
hoverOver: React.createElement(HoverContent, {
|
|
716
703
|
key: ev.data.id,
|
|
717
704
|
schema: hoverOptions.schema,
|
|
718
|
-
|
|
719
|
-
|
|
705
|
+
data: ev.data,
|
|
706
|
+
mapLayerDataSource: hoverOptions.layerDataSource,
|
|
707
|
+
design: hoverOptions.design,
|
|
720
708
|
items: hoverOptions.design.hoverOver.items,
|
|
721
|
-
filters:
|
|
709
|
+
filters: hoverOptions.filters,
|
|
722
710
|
locale: hoverOptions.locale,
|
|
723
711
|
translate: hoverOptions.translate
|
|
724
712
|
})
|
|
@@ -950,4 +938,31 @@ marker-fill: ` +
|
|
|
950
938
|
// Remove duplicates
|
|
951
939
|
return _.uniq(strings)
|
|
952
940
|
}
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
/** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
|
|
944
|
+
* It will be called on the server side if using a server map data source, or on the client side if using a direct
|
|
945
|
+
* map data source.
|
|
946
|
+
*/
|
|
947
|
+
getHoverOverData(options: {
|
|
948
|
+
/** Design of the layer */
|
|
949
|
+
design: BufferLayerDesign,
|
|
950
|
+
/** Data of the current item being hovered over. e.g. { id: 123 } */
|
|
951
|
+
data: any,
|
|
952
|
+
/** Filters to apply to the hover over data, not including filtering down to the current item */
|
|
953
|
+
filters: JsonQLFilter[],
|
|
954
|
+
/** Schema to use */
|
|
955
|
+
schema: Schema,
|
|
956
|
+
/** Data source to use */
|
|
957
|
+
dataSource: DataSource,
|
|
958
|
+
}): Promise<{ [key: string]: any }> {
|
|
959
|
+
return getSimpleHoverOverData({
|
|
960
|
+
id: options.data.id,
|
|
961
|
+
table: options.design.table,
|
|
962
|
+
filters: options.filters,
|
|
963
|
+
schema: options.schema,
|
|
964
|
+
dataSource: options.dataSource,
|
|
965
|
+
hoverOverItems: options.design.hoverOver.items,
|
|
966
|
+
})
|
|
967
|
+
}
|
|
953
968
|
}
|
|
@@ -29,6 +29,7 @@ import { getDefaultLayoutOptions } from "../dashboards/layoutOptions"
|
|
|
29
29
|
import Widget from "../widgets/Widget"
|
|
30
30
|
import BlocksLayoutManager from "../layouts/blocks/BlocksLayoutManager"
|
|
31
31
|
import { getTranslatableStringsFromLayoutManager } from "../dashboards/DashboardUtils"
|
|
32
|
+
import { getSimpleHoverOverData } from "./MapUtils"
|
|
32
33
|
|
|
33
34
|
export default class ChoroplethLayer extends Layer<ChoroplethLayerDesign> {
|
|
34
35
|
/** Gets the type of layer definition */
|
|
@@ -1377,13 +1378,9 @@ export default class ChoroplethLayer extends Layer<ChoroplethLayerDesign> {
|
|
|
1377
1378
|
ev: { data: any; event: any },
|
|
1378
1379
|
hoverOptions: OnGridHoverOptions<ChoroplethLayerDesign>
|
|
1379
1380
|
): OnGridHoverResults {
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
if (hoverOptions.design.regionMode == "plain" || hoverOptions.design.regionMode == "direct") {
|
|
1384
|
-
if (!ev.data || !ev.data.id) {
|
|
1385
|
-
return null
|
|
1386
|
-
}
|
|
1381
|
+
// Only applicable to indirect mode
|
|
1382
|
+
if (hoverOptions.design.regionMode !== "indirect") {
|
|
1383
|
+
return null
|
|
1387
1384
|
}
|
|
1388
1385
|
|
|
1389
1386
|
// Ignore if indirect with no table
|
|
@@ -1391,35 +1388,16 @@ export default class ChoroplethLayer extends Layer<ChoroplethLayerDesign> {
|
|
|
1391
1388
|
return null
|
|
1392
1389
|
}
|
|
1393
1390
|
|
|
1394
|
-
if (ev.data && ev.data.id) {
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
// Popup
|
|
1399
|
-
if (hoverOptions.design.hoverOver) {
|
|
1400
|
-
// Create default popup filter joins
|
|
1401
|
-
const defaultPopupFilterJoins: { [tableId: string]: Expr } = {}
|
|
1402
|
-
if (hoverOptions.design.adminRegionExpr) {
|
|
1403
|
-
defaultPopupFilterJoins[hoverOptions.design.table] = hoverOptions.design.adminRegionExpr
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
// Create filter using popupFilterJoins
|
|
1407
|
-
const popupFilterJoins = hoverOptions.design.popupFilterJoins || defaultPopupFilterJoins
|
|
1408
|
-
const popupFilters = PopupFilterJoinsUtils.createPopupFilters(
|
|
1409
|
-
popupFilterJoins,
|
|
1410
|
-
hoverOptions.schema,
|
|
1411
|
-
table,
|
|
1412
|
-
ev.data.id,
|
|
1413
|
-
true
|
|
1414
|
-
)
|
|
1415
|
-
|
|
1416
|
-
results.hoverOver = React.createElement(HoverContent, {
|
|
1391
|
+
if (ev.data && ev.data.id && hoverOptions.design.hoverOver && hoverOptions.design.hoverOver.items.length > 0) {
|
|
1392
|
+
const results: OnGridHoverResults = {
|
|
1393
|
+
hoverOver: React.createElement(HoverContent, {
|
|
1417
1394
|
key: ev.data.id,
|
|
1418
1395
|
schema: hoverOptions.schema,
|
|
1419
|
-
|
|
1420
|
-
|
|
1396
|
+
mapLayerDataSource: hoverOptions.layerDataSource,
|
|
1397
|
+
design: hoverOptions.design,
|
|
1421
1398
|
items: hoverOptions.design.hoverOver.items,
|
|
1422
|
-
|
|
1399
|
+
data: ev.data,
|
|
1400
|
+
filters: hoverOptions.filters,
|
|
1423
1401
|
locale: hoverOptions.locale,
|
|
1424
1402
|
translate: hoverOptions.translate
|
|
1425
1403
|
})
|
|
@@ -1731,4 +1709,44 @@ export default class ChoroplethLayer extends Layer<ChoroplethLayerDesign> {
|
|
|
1731
1709
|
// Remove duplicates
|
|
1732
1710
|
return _.uniq(strings)
|
|
1733
1711
|
}
|
|
1712
|
+
|
|
1713
|
+
/** Gets hover over data for hover over items. This should be implemented by layers that have hover over items.
|
|
1714
|
+
* It will be called on the server side if using a server map data source, or on the client side if using a direct
|
|
1715
|
+
* map data source.
|
|
1716
|
+
*/
|
|
1717
|
+
getHoverOverData(options: {
|
|
1718
|
+
/** Design of the layer */
|
|
1719
|
+
design: ChoroplethLayerDesign,
|
|
1720
|
+
/** Data of the current item being hovered over. e.g. { id: 123 } */
|
|
1721
|
+
data: any,
|
|
1722
|
+
/** Filters to apply to the hover over data, not including filtering down to the current item */
|
|
1723
|
+
filters: JsonQLFilter[],
|
|
1724
|
+
/** Schema to use */
|
|
1725
|
+
schema: Schema,
|
|
1726
|
+
/** Data source to use */
|
|
1727
|
+
dataSource: DataSource,
|
|
1728
|
+
}): Promise<{ [key: string]: any }> {
|
|
1729
|
+
// Use popup filter joins utilities to create filters
|
|
1730
|
+
const popupFilterJoins: { [tableId: string]: Expr } = {}
|
|
1731
|
+
if (options.design.adminRegionExpr) {
|
|
1732
|
+
popupFilterJoins[options.design.table!] = options.design.adminRegionExpr
|
|
1733
|
+
}
|
|
1734
|
+
const popupFilters = PopupFilterJoinsUtils.createPopupFilters(
|
|
1735
|
+
popupFilterJoins,
|
|
1736
|
+
options.schema,
|
|
1737
|
+
options.design.table!,
|
|
1738
|
+
options.data.id,
|
|
1739
|
+
true
|
|
1740
|
+
)
|
|
1741
|
+
|
|
1742
|
+
return getSimpleHoverOverData({
|
|
1743
|
+
// Filter using popup filters instead of id since will return multiple rows
|
|
1744
|
+
id: null,
|
|
1745
|
+
table: options.design.table!,
|
|
1746
|
+
filters: popupFilters,
|
|
1747
|
+
schema: options.schema,
|
|
1748
|
+
dataSource: options.dataSource,
|
|
1749
|
+
hoverOverItems: options.design.hoverOver.items,
|
|
1750
|
+
})
|
|
1751
|
+
}
|
|
1734
1752
|
}
|
|
@@ -62,11 +62,12 @@ export default interface ChoroplethLayerDesign {
|
|
|
62
62
|
/** contains items: which is BlocksLayoutManager items. Will be displayed when the region is clicked. Only when region mode is "indirect" */
|
|
63
63
|
popup: { items: LayoutBlock }
|
|
64
64
|
|
|
65
|
-
hoverOver: { items: HoverOverItem[] }
|
|
66
|
-
|
|
67
65
|
/** customizable filtering for popup. See PopupFilterJoins.md. Only when region mode is "indirect" */
|
|
68
66
|
popupFilterJoins: PopupFilterJoins
|
|
69
67
|
|
|
68
|
+
/** Hover over items to display when hovering over a region. Only when region mode is "indirect" */
|
|
69
|
+
hoverOver: { items: HoverOverItem[] }
|
|
70
|
+
|
|
70
71
|
/** minimum zoom level */
|
|
71
72
|
minZoom?: number
|
|
72
73
|
|
|
@@ -497,7 +497,7 @@ export default class ChoroplethLayerDesigner extends React.Component<{
|
|
|
497
497
|
|
|
498
498
|
const regionsTable = this.props.design.regionsTable || "admin_regions"
|
|
499
499
|
|
|
500
|
-
const defaultPopupFilterJoins = {}
|
|
500
|
+
const defaultPopupFilterJoins: { [tableId: string]: Expr } = {}
|
|
501
501
|
if (this.props.design.adminRegionExpr) {
|
|
502
502
|
defaultPopupFilterJoins[this.props.design.table] = this.props.design.adminRegionExpr
|
|
503
503
|
}
|
|
@@ -521,7 +521,7 @@ export default class ChoroplethLayerDesigner extends React.Component<{
|
|
|
521
521
|
|
|
522
522
|
const regionsTable = this.props.design.regionsTable || "admin_regions"
|
|
523
523
|
|
|
524
|
-
const defaultPopupFilterJoins = {}
|
|
524
|
+
const defaultPopupFilterJoins: { [tableId: string]: Expr } = {}
|
|
525
525
|
if (this.props.design.adminRegionExpr) {
|
|
526
526
|
defaultPopupFilterJoins[this.props.design.table] = this.props.design.adminRegionExpr
|
|
527
527
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _ from "lodash"
|
|
2
|
-
import { DataSource, Expr, injectTableAlias, Schema } from "@mwater/expressions"
|
|
2
|
+
import { DataSource, Expr, ExprCompiler, injectTableAlias, Schema } from "@mwater/expressions"
|
|
3
3
|
import { JsonQLFilter } from "../JsonQLFilter"
|
|
4
4
|
import BlocksLayoutManager from "../layouts/blocks/BlocksLayoutManager"
|
|
5
5
|
import WidgetFactory from "../widgets/WidgetFactory"
|
|
@@ -16,6 +16,7 @@ import TileUrlLayer from "./TileUrlLayer"
|
|
|
16
16
|
import * as QuickfilterUtils from "../quickfilter/QuickfilterUtils"
|
|
17
17
|
import { useState, useEffect } from 'react'
|
|
18
18
|
import { useStableCallback } from "@mwater/react-library/lib/useStableCallback"
|
|
19
|
+
import { JsonQLSelectQuery } from "@mwater/jsonql"
|
|
19
20
|
|
|
20
21
|
export interface DirectMapDataSourceOptions {
|
|
21
22
|
/** schema to use */
|
|
@@ -392,4 +393,23 @@ class DirectLayerDataSource implements MapLayerDataSource {
|
|
|
392
393
|
|
|
393
394
|
return url
|
|
394
395
|
}
|
|
396
|
+
|
|
397
|
+
/** Gets hover over data for hover over items
|
|
398
|
+
* @param design The design of the layer
|
|
399
|
+
* @param data The data of the current item being hovered over. e.g. { id: 123 }
|
|
400
|
+
* @param filters The filters to apply to the hover over data, not including filtering down to the current item
|
|
401
|
+
* @returns A promise that resolves to the hover over data, indexed by the id of the hover over item
|
|
402
|
+
*/
|
|
403
|
+
getHoverOverData(design: any, data: any, filters: JsonQLFilter[]): Promise<{ [key: string]: any }> {
|
|
404
|
+
// Create layer
|
|
405
|
+
const layer = LayerFactory.createLayer(this.options.layerView.type)
|
|
406
|
+
|
|
407
|
+
return layer.getHoverOverData({
|
|
408
|
+
design,
|
|
409
|
+
data,
|
|
410
|
+
filters,
|
|
411
|
+
schema: this.options.schema,
|
|
412
|
+
dataSource: this.options.dataSource,
|
|
413
|
+
})
|
|
414
|
+
}
|
|
395
415
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { omit } from "lodash"
|
|
2
|
-
import { DataSource, Expr, Schema } from "@mwater/expressions"
|
|
2
|
+
import { DataSource, Expr, ExprUtils, Schema } from "@mwater/expressions"
|
|
3
3
|
import { ExprComponent } from "@mwater/expressions-ui"
|
|
4
4
|
import React, { useState } from "react"
|
|
5
|
-
import
|
|
5
|
+
import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent"
|
|
6
6
|
import * as ui from "@mwater/react-library/lib/bootstrap"
|
|
7
7
|
import uuid from "uuid"
|
|
8
8
|
import { HoverOverItem } from "./maps"
|
|
9
|
+
import { canFormatType, getDefaultFormat } from "../valueFormatter"
|
|
10
|
+
import { getFormatOptions } from "../valueFormatter"
|
|
9
11
|
|
|
10
12
|
export interface EditHoverOverProps {
|
|
11
13
|
/** Schema to use */
|
|
@@ -22,63 +24,82 @@ export interface EditHoverOverProps {
|
|
|
22
24
|
defaultPopupFilterJoins: any
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
function EditHoverOver(props: EditHoverOverProps) {
|
|
28
|
+
const { schema, dataSource, design, onDesignChange, table } = props
|
|
26
29
|
const [editing, setEditing] = useState(false)
|
|
30
|
+
const [draftItems, setDraftItems] = useState<HoverOverItem[] | undefined>(undefined)
|
|
27
31
|
|
|
28
32
|
const handleRemovePopup = () => {
|
|
29
|
-
const
|
|
30
|
-
|
|
33
|
+
const newDesign = omit(design, "hoverOver")
|
|
34
|
+
onDesignChange(newDesign)
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const handleItemChange = (item: HoverOverItem) => {
|
|
38
|
+
setDraftItems(draftItems?.map((i) => (item.id === i.id ? item : i)))
|
|
39
|
+
}
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
const handleItemDelete = (item: HoverOverItem) => {
|
|
42
|
+
setDraftItems(draftItems?.filter((i) => item.id !== i.id))
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
const handleAddItem = () => {
|
|
46
|
+
setDraftItems([...(draftItems ?? []), { id: uuid().replace(/-/g, ""), label: "" }])
|
|
47
|
+
}
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
const handleSave = () => {
|
|
50
|
+
const hoverOver = { ...(design.hoverOver ?? {}), items: draftItems ?? [] }
|
|
51
|
+
const newDesign = { ...design, hoverOver }
|
|
52
|
+
onDesignChange(newDesign)
|
|
53
|
+
setEditing(false)
|
|
54
|
+
setDraftItems(undefined)
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
const handleCancel = () => {
|
|
58
|
+
setEditing(false)
|
|
59
|
+
setDraftItems(undefined)
|
|
60
|
+
}
|
|
50
61
|
|
|
51
|
-
|
|
62
|
+
const handleOpen = () => {
|
|
63
|
+
setDraftItems(design.hoverOver?.items ?? [])
|
|
64
|
+
setEditing(true)
|
|
52
65
|
}
|
|
53
66
|
|
|
54
67
|
return (
|
|
55
68
|
<>
|
|
56
|
-
<button className="btn btn-link" onClick={
|
|
69
|
+
<button className="btn btn-link" onClick={handleOpen}>
|
|
57
70
|
<span className="fa fa-pencil" /> {T`Customize Hoverover`}
|
|
58
71
|
</button>
|
|
59
|
-
{
|
|
72
|
+
{design.hoverOver && (
|
|
60
73
|
<button className="btn btn-link" onClick={handleRemovePopup}>
|
|
61
74
|
<span className="fa fa-times" /> {T`Remove Hover over`}
|
|
62
75
|
</button>
|
|
63
76
|
)}
|
|
64
77
|
|
|
65
78
|
{editing && (
|
|
66
|
-
<
|
|
67
|
-
{
|
|
79
|
+
<ActionCancelModalComponent
|
|
80
|
+
onAction={handleSave}
|
|
81
|
+
onCancel={handleCancel}
|
|
82
|
+
actionLabel={T`Save`}
|
|
83
|
+
title={T`Customize Hoverover`}
|
|
84
|
+
size="x-large"
|
|
85
|
+
>
|
|
86
|
+
{(draftItems ?? []).length > 0 && (
|
|
68
87
|
<table className="table">
|
|
69
88
|
<thead>
|
|
70
89
|
<tr>
|
|
71
90
|
<th>{T`Label`}</th>
|
|
72
91
|
<th>{T`Value`}</th>
|
|
73
|
-
<th
|
|
92
|
+
<th style={{ width: "1%", whiteSpace: "nowrap" }}>{T`Format`}</th>
|
|
93
|
+
<th style={{ width: "1%", whiteSpace: "nowrap" }}></th>
|
|
74
94
|
</tr>
|
|
75
95
|
</thead>
|
|
76
96
|
<tbody>
|
|
77
|
-
{
|
|
97
|
+
{draftItems?.map((item: HoverOverItem) => (
|
|
78
98
|
<HoverOverItemEditor
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
key={item.id}
|
|
100
|
+
schema={schema}
|
|
101
|
+
dataSource={dataSource}
|
|
102
|
+
table={table}
|
|
82
103
|
onItemChange={handleItemChange}
|
|
83
104
|
onItemDelete={handleItemDelete}
|
|
84
105
|
item={item}
|
|
@@ -88,20 +109,14 @@ const EditHoverOver: React.FC<EditHoverOverProps> = props => {
|
|
|
88
109
|
</table>
|
|
89
110
|
)}
|
|
90
111
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}>
|
|
100
|
-
<span className="fa fa-plus" />
|
|
101
|
-
{T`Add item`}
|
|
102
|
-
</button>
|
|
103
|
-
)}
|
|
104
|
-
</ModalWindowComponent>
|
|
112
|
+
<button
|
|
113
|
+
className="btn btn-link"
|
|
114
|
+
onClick={handleAddItem}
|
|
115
|
+
>
|
|
116
|
+
<span className="fas fa-plus me-1" />
|
|
117
|
+
{T`Add Item`}
|
|
118
|
+
</button>
|
|
119
|
+
</ActionCancelModalComponent>
|
|
105
120
|
)}
|
|
106
121
|
</>
|
|
107
122
|
)
|
|
@@ -115,20 +130,42 @@ interface HoverOverItemEditorProps {
|
|
|
115
130
|
onItemDelete: (item: HoverOverItem) => void
|
|
116
131
|
table: string
|
|
117
132
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
dataSource,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
|
|
134
|
+
function HoverOverItemEditor(props: HoverOverItemEditorProps) {
|
|
135
|
+
const { schema, dataSource, table, item, onItemChange, onItemDelete } = props
|
|
136
|
+
|
|
137
|
+
function renderFormat() {
|
|
138
|
+
const exprUtils = new ExprUtils(schema)
|
|
139
|
+
const exprType = exprUtils.getExprType(item.value ?? null)
|
|
140
|
+
if (!exprType) {
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!canFormatType(exprType)) {
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const formats = getFormatOptions(exprType)
|
|
149
|
+
if (!formats) {
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<ui.Select
|
|
155
|
+
options={formats.map(f => ({ value: f.value, label: f.label }))}
|
|
156
|
+
value={item.format ?? getDefaultFormat(exprType)}
|
|
157
|
+
onChange={value => onItemChange({ ...item, format: value ?? undefined })}
|
|
158
|
+
style={{ width: "auto", display: "inline-block" }}
|
|
159
|
+
/>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
126
163
|
return (
|
|
127
164
|
<tr>
|
|
128
|
-
<td>
|
|
165
|
+
<td className="align-middle">
|
|
129
166
|
<ui.TextInput value={item.label} onChange={value => onItemChange({ ...item, label: value })} />
|
|
130
167
|
</td>
|
|
131
|
-
<td>
|
|
168
|
+
<td className="align-middle">
|
|
132
169
|
<ExprComponent
|
|
133
170
|
schema={schema}
|
|
134
171
|
dataSource={dataSource}
|
|
@@ -139,7 +176,10 @@ const HoverOverItemEditor: React.FC<HoverOverItemEditorProps> = ({
|
|
|
139
176
|
aggrStatuses={["individual", "literal", "aggregate"]}
|
|
140
177
|
/>
|
|
141
178
|
</td>
|
|
142
|
-
<td>
|
|
179
|
+
<td className="align-middle" style={{ width: "1%", whiteSpace: "nowrap" }}>
|
|
180
|
+
{renderFormat()}
|
|
181
|
+
</td>
|
|
182
|
+
<td className="align-middle" style={{ width: "1%", whiteSpace: "nowrap" }}>
|
|
143
183
|
<button className="btn btn-link" onClick={() => onItemDelete(item)}>
|
|
144
184
|
<span className="fa fa-close" />
|
|
145
185
|
</button>
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import React, { useEffect, useState } from "react"
|
|
2
|
-
import {
|
|
3
|
-
import { JsonQLSelectQuery } from "@mwater/jsonql"
|
|
2
|
+
import { ExprUtils, Schema } from "@mwater/expressions"
|
|
4
3
|
import { JsonQLFilter } from ".."
|
|
5
|
-
import { compact } from "lodash"
|
|
6
4
|
import { HoverOverItem } from "./maps"
|
|
7
5
|
import { canFormatType } from "../valueFormatter"
|
|
8
6
|
import { formatValue } from "../valueFormatter"
|
|
7
|
+
import { MapLayerDataSource } from "./MapLayerDataSource"
|
|
9
8
|
|
|
10
9
|
export interface HoverContentProps {
|
|
11
10
|
/** Schema to use */
|
|
12
11
|
schema: Schema
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
|
|
12
|
+
/** Map data source */
|
|
13
|
+
mapLayerDataSource: MapLayerDataSource
|
|
14
|
+
/** Design of the layer */
|
|
15
|
+
design: any
|
|
16
|
+
/** Data of the current item being hovered over. e.g. { id: 123 } */
|
|
17
|
+
data: any
|
|
18
|
+
/** Additional filters to apply to the hover over data */
|
|
19
|
+
filters: JsonQLFilter[]
|
|
17
20
|
/** Hover over items */
|
|
18
21
|
items: HoverOverItem[]
|
|
19
22
|
/** Locale to use */
|
|
@@ -33,48 +36,14 @@ const HoverContent = (props: HoverContentProps) => {
|
|
|
33
36
|
const items = props.items
|
|
34
37
|
|
|
35
38
|
if (items.length > 0) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
selects: [],
|
|
40
|
-
from: exprCompiler.compileTable(props.table, "main"),
|
|
41
|
-
limit: 1
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
items.forEach((item: HoverOverItem) => {
|
|
45
|
-
if (item.value) {
|
|
46
|
-
query.selects.push({
|
|
47
|
-
type: "select",
|
|
48
|
-
expr: exprCompiler.compileExpr({ expr: item.value, tableAlias: "main" }),
|
|
49
|
-
alias: item.id
|
|
50
|
-
})
|
|
39
|
+
props.mapLayerDataSource.getHoverOverData(props.design, props.data, props.filters).then((data) => {
|
|
40
|
+
if (mounted) {
|
|
41
|
+
setValues(data)
|
|
51
42
|
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
let whereClauses = props.filters.map(f => injectTableAlias(f.jsonql, "main"))
|
|
56
|
-
|
|
57
|
-
whereClauses = compact(whereClauses)
|
|
58
|
-
|
|
59
|
-
// Wrap if multiple
|
|
60
|
-
if (whereClauses.length > 1) {
|
|
61
|
-
query.where = { type: "op", op: "and", exprs: whereClauses }
|
|
62
|
-
} else {
|
|
63
|
-
query.where = whereClauses[0]
|
|
43
|
+
}).catch((error) => {
|
|
44
|
+
if (mounted) {
|
|
45
|
+
setError(error.message)
|
|
64
46
|
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
props.dataSource.performQuery(query, (error: any, data: any) => {
|
|
68
|
-
if (!mounted) {
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (error) {
|
|
73
|
-
setError(props.translate("Error loading hover data"))
|
|
74
|
-
return
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
setValues(data?.[0] ?? {})
|
|
78
47
|
})
|
|
79
48
|
}
|
|
80
49
|
|