@hisptz/dhis2-analytics 2.1.36 → 2.2.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/dist/components/Map/DHIS2Map.js +3 -1
- package/dist/components/Map/DHIS2Map.js.map +1 -1
- package/dist/components/Map/components/MapControls/components/TimelineControl/index.js +236 -0
- package/dist/components/Map/components/MapControls/components/TimelineControl/index.js.map +1 -0
- package/dist/components/Map/components/MapControls/index.js +17 -12
- package/dist/components/Map/components/MapControls/index.js.map +1 -1
- package/dist/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.js +62 -55
- package/dist/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.js.map +1 -1
- package/dist/components/Map/components/MapProvider/components/MapLayerProvider/index.js +14 -2
- package/dist/components/Map/components/MapProvider/components/MapLayerProvider/index.js.map +1 -1
- package/dist/components/Map/components/MapProvider/components/MapPeriodFilterProvider/index.js +19 -0
- package/dist/components/Map/components/MapProvider/components/MapPeriodFilterProvider/index.js.map +1 -0
- package/dist/components/Map/components/MapProvider/hooks/index.js +4 -0
- package/dist/components/Map/components/MapProvider/hooks/index.js.map +1 -1
- package/dist/components/Map/components/MapProvider/index.js +22 -5
- package/dist/components/Map/components/MapProvider/index.js.map +1 -1
- package/dist/components/Map/index.js +21 -0
- package/dist/components/Map/state/index.js +9 -0
- package/dist/components/Map/state/index.js.map +1 -1
- package/dist/components/Map/utils/helpers.js +74 -0
- package/dist/components/Map/utils/helpers.js.map +1 -1
- package/dist/esm/components/Map/DHIS2Map.js +3 -1
- package/dist/esm/components/Map/DHIS2Map.js.map +1 -1
- package/dist/esm/components/Map/components/MapControls/components/TimelineControl/index.js +234 -0
- package/dist/esm/components/Map/components/MapControls/components/TimelineControl/index.js.map +1 -0
- package/dist/esm/components/Map/components/MapControls/index.js +17 -12
- package/dist/esm/components/Map/components/MapControls/index.js.map +1 -1
- package/dist/esm/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.js +66 -59
- package/dist/esm/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.js.map +1 -1
- package/dist/esm/components/Map/components/MapProvider/components/MapLayerProvider/index.js +15 -3
- package/dist/esm/components/Map/components/MapProvider/components/MapLayerProvider/index.js.map +1 -1
- package/dist/esm/components/Map/components/MapProvider/components/MapPeriodFilterProvider/index.js +17 -0
- package/dist/esm/components/Map/components/MapProvider/components/MapPeriodFilterProvider/index.js.map +1 -0
- package/dist/esm/components/Map/components/MapProvider/hooks/index.js +5 -2
- package/dist/esm/components/Map/components/MapProvider/hooks/index.js.map +1 -1
- package/dist/esm/components/Map/components/MapProvider/index.js +22 -5
- package/dist/esm/components/Map/components/MapProvider/index.js.map +1 -1
- package/dist/esm/components/Map/index.js +3 -0
- package/dist/esm/components/Map/state/index.js +9 -1
- package/dist/esm/components/Map/state/index.js.map +1 -1
- package/dist/esm/components/Map/utils/helpers.js +72 -1
- package/dist/esm/components/Map/utils/helpers.js.map +1 -1
- package/dist/types/components/Map/DHIS2Map.d.ts.map +1 -1
- package/dist/types/components/Map/components/MapArea/interfaces/index.d.ts +5 -2
- package/dist/types/components/Map/components/MapArea/interfaces/index.d.ts.map +1 -1
- package/dist/types/components/Map/components/MapControls/components/TimelineControl/index.d.ts +26 -0
- package/dist/types/components/Map/components/MapControls/components/TimelineControl/index.d.ts.map +1 -0
- package/dist/types/components/Map/components/MapControls/index.d.ts +3 -4
- package/dist/types/components/Map/components/MapControls/index.d.ts.map +1 -1
- package/dist/types/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.d.ts.map +1 -1
- package/dist/types/components/Map/components/MapProvider/components/MapLayerProvider/index.d.ts.map +1 -1
- package/dist/types/components/Map/components/MapProvider/components/MapPeriodFilterProvider/index.d.ts +8 -0
- package/dist/types/components/Map/components/MapProvider/components/MapPeriodFilterProvider/index.d.ts.map +1 -0
- package/dist/types/components/Map/components/MapProvider/hooks/index.d.ts +1 -0
- package/dist/types/components/Map/components/MapProvider/hooks/index.d.ts.map +1 -1
- package/dist/types/components/Map/components/MapProvider/index.d.ts +2 -2
- package/dist/types/components/Map/components/MapProvider/index.d.ts.map +1 -1
- package/dist/types/components/Map/index.d.ts +3 -0
- package/dist/types/components/Map/index.d.ts.map +1 -1
- package/dist/types/components/Map/interfaces/index.d.ts +2 -0
- package/dist/types/components/Map/interfaces/index.d.ts.map +1 -1
- package/dist/types/components/Map/state/index.d.ts +8 -0
- package/dist/types/components/Map/state/index.d.ts.map +1 -1
- package/dist/types/components/Map/utils/helpers.d.ts +7 -0
- package/dist/types/components/Map/utils/helpers.d.ts.map +1 -1
- package/package.json +10 -6
|
@@ -23,6 +23,7 @@ const MapComponent = ({
|
|
|
23
23
|
legends,
|
|
24
24
|
setRef,
|
|
25
25
|
analyticsOptions,
|
|
26
|
+
renderingStrategy,
|
|
26
27
|
base
|
|
27
28
|
}) => {
|
|
28
29
|
const sanitizedPointLayers = [
|
|
@@ -44,8 +45,9 @@ const MapComponent = ({
|
|
|
44
45
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45
46
|
MapProvider.MapProvider,
|
|
46
47
|
{
|
|
47
|
-
periodSelection,
|
|
48
48
|
orgUnitSelection,
|
|
49
|
+
periodSelection,
|
|
50
|
+
renderingStrategy,
|
|
49
51
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
50
52
|
MapArea__default.default,
|
|
51
53
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Map/DHIS2Map.tsx"],"names":["jsx","MapProvider","MapArea"],"mappings":";;;;;;;;;;;AAUA,MAAM,eAAe,CAAC;AAAA,EACrB,gBAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAA;AAAA,EACA,UAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACD,CAAA,KAAgB;AACf,EAAA,MAAM,oBAAA,GAA2C;AAAA,IAChD;AAAA,MACC,IAAA,EAAM,OAAA;AAAA,MACN,EAAA,EAAI,OAAA;AAAA,MACJ,OAAA,EAAS,YAAY,OAAA,IAAW,KAAA;AAAA,MAChC,GAAG;AAAA;AACJ,GACD;AACA,EAAA,MAAM,uBAAA,GAAiD;AAAA,IACtD;AAAA,MACC,GAAG,aAAA;AAAA,MACH,IAAA,EAAM,SAAA;AAAA,MACN,EAAA,EAAI,UAAA;AAAA,MACJ,OAAA,EAAS,eAAe,OAAA,IAAW;AAAA;AACpC,GACD;AAEA,EAAA,uBACCA,cAAA;AAAA,IAACC,uBAAA;AAAA,IAAA;AAAA,MACA,eAAA;AAAA,MACA,
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Map/DHIS2Map.tsx"],"names":["jsx","MapProvider","MapArea"],"mappings":";;;;;;;;;;;AAUA,MAAM,eAAe,CAAC;AAAA,EACrB,gBAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAA;AAAA,EACA,UAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,gBAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACD,CAAA,KAAgB;AACf,EAAA,MAAM,oBAAA,GAA2C;AAAA,IAChD;AAAA,MACC,IAAA,EAAM,OAAA;AAAA,MACN,EAAA,EAAI,OAAA;AAAA,MACJ,OAAA,EAAS,YAAY,OAAA,IAAW,KAAA;AAAA,MAChC,GAAG;AAAA;AACJ,GACD;AACA,EAAA,MAAM,uBAAA,GAAiD;AAAA,IACtD;AAAA,MACC,GAAG,aAAA;AAAA,MACH,IAAA,EAAM,SAAA;AAAA,MACN,EAAA,EAAI,UAAA;AAAA,MACJ,OAAA,EAAS,eAAe,OAAA,IAAW;AAAA;AACpC,GACD;AAEA,EAAA,uBACCA,cAAA;AAAA,IAACC,uBAAA;AAAA,IAAA;AAAA,MACA,gBAAA;AAAA,MACA,eAAA;AAAA,MACA,iBAAA;AAAA,MAEA,QAAA,kBAAAD,cAAA;AAAA,QAACE,wBAAA;AAAA,QAAA;AAAA,UACA,IAAA,EAAM;AAAA,YACL,GAAG;AAAA,WACJ;AAAA,UACA,MAAA,EAAQ;AAAA,YACP,cAAA;AAAA,YACA,iBAAA;AAAA,YACA,cAAA,EAAgB,uBAAA;AAAA,YAChB,WAAA,EAAa;AAAA,WACd;AAAA,UACA,eAAA;AAAA,UACA,gBAAA;AAAA,UACA,OAAA;AAAA,UACA,QAAA;AAAA,UAEA,GAAA,EAAK,MAAA;AAAA,UACL;AAAA,SAAA;AAAA,QAFK;AAAA;AAGN;AAAA,GACD;AAEF,CAAA;AACO,MAAM,QAAA,GAAyB;AAK/B,MAAM,GAAA,GAAM","file":"DHIS2Map.js","sourcesContent":["import MapArea from \"./components/MapArea/index.js\";\nimport {\n\tCustomBoundaryLayer,\n\tCustomPointLayer,\n} from \"./components/MapLayer/interfaces\";\nimport { MapProvider } from \"./components/MapProvider\";\nimport { MapProps } from \"./interfaces\";\nimport \"leaflet/dist/leaflet.css\";\nimport type { FC } from \"react\";\n\nconst MapComponent = ({\n\torgUnitSelection,\n\tpointLayer,\n\tboundaryLayer,\n\tthematicLayers,\n\tearthEngineLayers,\n\tperiodSelection,\n\tmapOptions,\n\tkey,\n\tcontrols,\n\tshowPeriodTitle,\n\tlegends,\n\tsetRef,\n\tanalyticsOptions,\n\trenderingStrategy,\n\tbase,\n}: MapProps) => {\n\tconst sanitizedPointLayers: CustomPointLayer[] = [\n\t\t{\n\t\t\ttype: \"point\",\n\t\t\tid: \"point\",\n\t\t\tenabled: pointLayer?.enabled ?? false,\n\t\t\t...pointLayer,\n\t\t},\n\t];\n\tconst sanitizedBoundaryLayers: CustomBoundaryLayer[] = [\n\t\t{\n\t\t\t...boundaryLayer,\n\t\t\ttype: \"overlay\",\n\t\t\tid: \"boundary\",\n\t\t\tenabled: boundaryLayer?.enabled ?? false,\n\t\t},\n\t];\n\n\treturn (\n\t\t<MapProvider\n\t\t\torgUnitSelection={orgUnitSelection}\n\t\t\tperiodSelection={periodSelection}\n\t\t\trenderingStrategy={renderingStrategy}\n\t\t>\n\t\t\t<MapArea\n\t\t\t\tbase={{\n\t\t\t\t\t...base,\n\t\t\t\t}}\n\t\t\t\tlayers={{\n\t\t\t\t\tthematicLayers,\n\t\t\t\t\tearthEngineLayers,\n\t\t\t\t\tboundaryLayers: sanitizedBoundaryLayers,\n\t\t\t\t\tpointLayers: sanitizedPointLayers,\n\t\t\t\t}}\n\t\t\t\tshowPeriodTitle={showPeriodTitle}\n\t\t\t\tanalyticsOptions={analyticsOptions}\n\t\t\t\tlegends={legends}\n\t\t\t\tcontrols={controls}\n\t\t\t\tkey={key}\n\t\t\t\tref={setRef}\n\t\t\t\tmapOptions={mapOptions}\n\t\t\t/>\n\t\t</MapProvider>\n\t);\n};\nexport const DHIS2Map: FC<MapProps> = MapComponent;\n\n/**\n * @deprecated since `v2`. Use `DHIS2Map` instead\n * */\nexport const Map = DHIS2Map;\n"]}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var d3Axis = require('d3-axis');
|
|
5
|
+
var d3Scale = require('d3-scale');
|
|
6
|
+
var d3Selection = require('d3-selection');
|
|
7
|
+
var leaflet = require('leaflet');
|
|
8
|
+
var luxon = require('luxon');
|
|
9
|
+
var reactDom = require('react-dom');
|
|
10
|
+
var react = require('react');
|
|
11
|
+
var reactLeaflet = require('react-leaflet');
|
|
12
|
+
var index_js = require('../../../../state/index.js');
|
|
13
|
+
var helpers_js = require('../../../../utils/helpers.js');
|
|
14
|
+
|
|
15
|
+
function resolveDates(tl) {
|
|
16
|
+
if ("step" in tl) {
|
|
17
|
+
const [start, end] = tl.range;
|
|
18
|
+
const dates = [];
|
|
19
|
+
let cur = luxon.DateTime.fromJSDate(start);
|
|
20
|
+
const endDt = luxon.DateTime.fromJSDate(end);
|
|
21
|
+
while (cur <= endDt) {
|
|
22
|
+
dates.push(cur.toJSDate());
|
|
23
|
+
cur = cur.plus(tl.step);
|
|
24
|
+
}
|
|
25
|
+
return dates;
|
|
26
|
+
}
|
|
27
|
+
return [...tl.range];
|
|
28
|
+
}
|
|
29
|
+
const ACCENT = "#2c6693";
|
|
30
|
+
const PADDING_LEFT = 40;
|
|
31
|
+
const PADDING_RIGHT = 20;
|
|
32
|
+
const LABEL_WIDTH = 80;
|
|
33
|
+
const PERIOD_RECT_HEIGHT = 8;
|
|
34
|
+
const PERIOD_RECT_GAP = 1;
|
|
35
|
+
const AXIS_OFFSET = 4;
|
|
36
|
+
function TimelineUI({
|
|
37
|
+
autoplay: initialAutoplay,
|
|
38
|
+
button,
|
|
39
|
+
dates,
|
|
40
|
+
interval,
|
|
41
|
+
onStep
|
|
42
|
+
}) {
|
|
43
|
+
const [index, setIndex] = react.useState(0);
|
|
44
|
+
const [playing, setPlaying] = react.useState(initialAutoplay);
|
|
45
|
+
const [svgWidth, setSvgWidth] = react.useState(null);
|
|
46
|
+
const svgRef = react.useRef(null);
|
|
47
|
+
const axisRef = react.useRef(null);
|
|
48
|
+
const intervalRef = react.useRef(null);
|
|
49
|
+
react.useEffect(() => {
|
|
50
|
+
const el = svgRef.current;
|
|
51
|
+
if (!el) return;
|
|
52
|
+
const measure = () => {
|
|
53
|
+
setSvgWidth(el.getBoundingClientRect().width);
|
|
54
|
+
};
|
|
55
|
+
measure();
|
|
56
|
+
const ro = new ResizeObserver(measure);
|
|
57
|
+
ro.observe(el);
|
|
58
|
+
return () => {
|
|
59
|
+
ro.disconnect();
|
|
60
|
+
};
|
|
61
|
+
}, []);
|
|
62
|
+
const trackWidth = svgWidth !== null ? svgWidth - PADDING_LEFT - PADDING_RIGHT : 0;
|
|
63
|
+
const timeScale = react.useMemo(() => {
|
|
64
|
+
if (!trackWidth || dates.length < 2) return null;
|
|
65
|
+
const periodMs = dates[1].getTime() - dates[0].getTime();
|
|
66
|
+
const domainEnd = new Date(dates[dates.length - 1].getTime() + periodMs);
|
|
67
|
+
return d3Scale.scaleTime().domain([dates[0], domainEnd]).range([0, trackWidth]);
|
|
68
|
+
}, [dates, trackWidth]);
|
|
69
|
+
react.useEffect(() => {
|
|
70
|
+
if (!timeScale || !axisRef.current || !trackWidth) return;
|
|
71
|
+
const maxTicks = Math.round(trackWidth / LABEL_WIDTH);
|
|
72
|
+
const axis = d3Axis.axisBottom(timeScale).ticks(maxTicks);
|
|
73
|
+
d3Selection.select(axisRef.current).call(axis);
|
|
74
|
+
d3Selection.select(axisRef.current).select(".domain").attr("stroke", "#ccc");
|
|
75
|
+
d3Selection.select(axisRef.current).selectAll(".tick line").attr("stroke", "#ccc");
|
|
76
|
+
d3Selection.select(axisRef.current).selectAll(".tick text").attr("fill", "#666").attr("font-size", "10px").attr("font-family", "sans-serif");
|
|
77
|
+
}, [timeScale, trackWidth]);
|
|
78
|
+
const stepTo = react.useCallback(
|
|
79
|
+
(idx) => {
|
|
80
|
+
setIndex(idx);
|
|
81
|
+
onStep(dates[idx]);
|
|
82
|
+
},
|
|
83
|
+
[dates, onStep]
|
|
84
|
+
);
|
|
85
|
+
react.useEffect(() => {
|
|
86
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
87
|
+
if (!playing) return;
|
|
88
|
+
intervalRef.current = setInterval(() => {
|
|
89
|
+
setIndex((prev) => {
|
|
90
|
+
const next = prev + 1 >= dates.length ? 0 : prev + 1;
|
|
91
|
+
onStep(dates[next]);
|
|
92
|
+
return next;
|
|
93
|
+
});
|
|
94
|
+
}, interval);
|
|
95
|
+
return () => {
|
|
96
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
97
|
+
};
|
|
98
|
+
}, [playing, interval, dates, onStep]);
|
|
99
|
+
const periodRects = react.useMemo(() => {
|
|
100
|
+
if (!timeScale || dates.length < 2) return null;
|
|
101
|
+
const unitWidth = timeScale(dates[1]) - timeScale(dates[0]);
|
|
102
|
+
return dates.map((date, i) => {
|
|
103
|
+
const x = timeScale(date);
|
|
104
|
+
const spanWidth = i < dates.length - 1 ? timeScale(dates[i + 1]) - x : unitWidth;
|
|
105
|
+
const w = Math.max(spanWidth - PERIOD_RECT_GAP, 1);
|
|
106
|
+
const capturedIndex = i;
|
|
107
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
108
|
+
"rect",
|
|
109
|
+
{
|
|
110
|
+
fill: capturedIndex === index ? ACCENT : "#b0c4d8",
|
|
111
|
+
height: PERIOD_RECT_HEIGHT,
|
|
112
|
+
onClick: () => {
|
|
113
|
+
setPlaying(false);
|
|
114
|
+
stepTo(capturedIndex);
|
|
115
|
+
},
|
|
116
|
+
rx: 1,
|
|
117
|
+
style: { cursor: "pointer" },
|
|
118
|
+
width: w,
|
|
119
|
+
x,
|
|
120
|
+
y: 0
|
|
121
|
+
},
|
|
122
|
+
date.toISOString()
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
}, [timeScale, dates, index, stepTo]);
|
|
126
|
+
const RECT_ROW_Y = 6;
|
|
127
|
+
const svgHeight = RECT_ROW_Y + PERIOD_RECT_HEIGHT + AXIS_OFFSET + 24;
|
|
128
|
+
const playLabel = playing ? button?.playingText ?? "Pause" : button?.pausedText ?? "Play";
|
|
129
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
130
|
+
"svg",
|
|
131
|
+
{
|
|
132
|
+
"aria-label": "Timeline",
|
|
133
|
+
height: svgHeight,
|
|
134
|
+
ref: svgRef,
|
|
135
|
+
style: {
|
|
136
|
+
background: "white",
|
|
137
|
+
boxShadow: "0 -1px 4px rgba(0,0,0,0.15)",
|
|
138
|
+
display: "block",
|
|
139
|
+
width: "100%"
|
|
140
|
+
},
|
|
141
|
+
children: [
|
|
142
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
143
|
+
"g",
|
|
144
|
+
{
|
|
145
|
+
"aria-label": playLabel,
|
|
146
|
+
onClick: () => {
|
|
147
|
+
setPlaying((p) => !p);
|
|
148
|
+
},
|
|
149
|
+
role: "button",
|
|
150
|
+
style: { cursor: "pointer" },
|
|
151
|
+
transform: `translate(7, ${RECT_ROW_Y - 8})`,
|
|
152
|
+
children: [
|
|
153
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0 0h24v24H0z", fillOpacity: 0 }),
|
|
154
|
+
playing ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z", fill: ACCENT }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v14l11-7z", fill: ACCENT })
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
),
|
|
158
|
+
timeScale !== null && /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${PADDING_LEFT}, ${RECT_ROW_Y})`, children: periodRects }),
|
|
159
|
+
timeScale !== null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
160
|
+
"g",
|
|
161
|
+
{
|
|
162
|
+
ref: axisRef,
|
|
163
|
+
transform: `translate(${PADDING_LEFT}, ${RECT_ROW_Y + PERIOD_RECT_HEIGHT + AXIS_OFFSET})`
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
function TimelineControl({
|
|
171
|
+
autoplay = false,
|
|
172
|
+
button,
|
|
173
|
+
interval = 1e3,
|
|
174
|
+
periodType,
|
|
175
|
+
position = "bottom",
|
|
176
|
+
timeline
|
|
177
|
+
}) {
|
|
178
|
+
const map = reactLeaflet.useMap();
|
|
179
|
+
const {
|
|
180
|
+
periodType: contextPeriodType,
|
|
181
|
+
setActivePeriod,
|
|
182
|
+
setPeriodType
|
|
183
|
+
} = react.useContext(index_js.MapPeriodFilterContext);
|
|
184
|
+
const [container, setContainer] = react.useState(null);
|
|
185
|
+
react.useEffect(() => {
|
|
186
|
+
if (periodType) setPeriodType(periodType);
|
|
187
|
+
}, [periodType, setPeriodType]);
|
|
188
|
+
const resolvedPeriodType = periodType ?? contextPeriodType ?? "Monthly";
|
|
189
|
+
const dates = react.useMemo(() => resolveDates(timeline), [timeline]);
|
|
190
|
+
react.useEffect(() => {
|
|
191
|
+
const mapEl = map.getContainer();
|
|
192
|
+
const div = leaflet.DomUtil.create("div", "", mapEl);
|
|
193
|
+
leaflet.DomEvent.disableClickPropagation(div);
|
|
194
|
+
leaflet.DomEvent.disableScrollPropagation(div);
|
|
195
|
+
const isTop = position.startsWith("top");
|
|
196
|
+
Object.assign(div.style, {
|
|
197
|
+
bottom: isTop ? "auto" : "18px",
|
|
198
|
+
boxSizing: "border-box",
|
|
199
|
+
left: "0",
|
|
200
|
+
padding: isTop ? "8px 8px 0" : "0 8px 8px",
|
|
201
|
+
position: "absolute",
|
|
202
|
+
right: "0",
|
|
203
|
+
top: isTop ? "0" : "auto",
|
|
204
|
+
zIndex: "1000"
|
|
205
|
+
});
|
|
206
|
+
setContainer(div);
|
|
207
|
+
return () => {
|
|
208
|
+
div.remove();
|
|
209
|
+
setContainer(null);
|
|
210
|
+
};
|
|
211
|
+
}, [map, position]);
|
|
212
|
+
const handleStep = react.useCallback(
|
|
213
|
+
(date) => {
|
|
214
|
+
setActivePeriod(helpers_js.dateToDHIS2PeriodId(date, resolvedPeriodType));
|
|
215
|
+
},
|
|
216
|
+
[resolvedPeriodType, setActivePeriod]
|
|
217
|
+
);
|
|
218
|
+
if (!container) return null;
|
|
219
|
+
return reactDom.createPortal(
|
|
220
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
221
|
+
TimelineUI,
|
|
222
|
+
{
|
|
223
|
+
autoplay,
|
|
224
|
+
button,
|
|
225
|
+
dates,
|
|
226
|
+
interval,
|
|
227
|
+
onStep: handleStep
|
|
228
|
+
}
|
|
229
|
+
),
|
|
230
|
+
container
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
exports.TimelineControl = TimelineControl;
|
|
235
|
+
//# sourceMappingURL=index.js.map
|
|
236
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/components/Map/components/MapControls/components/TimelineControl/index.tsx"],"names":["DateTime","useState","useRef","useEffect","useMemo","scaleTime","axisBottom","select","useCallback","jsx","jsxs","useMap","useContext","MapPeriodFilterContext","DomUtil","DomEvent","dateToDHIS2PeriodId","createPortal"],"mappings":"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","file":"index.js","sourcesContent":["import { axisBottom } from \"d3-axis\";\nimport { scaleTime } from \"d3-scale\";\nimport { select } from \"d3-selection\";\nimport { DomEvent, DomUtil } from \"leaflet\";\nimport { DateTime, type DurationObjectUnits } from \"luxon\";\nimport { createPortal } from \"react-dom\";\nimport {\n\ttype ReactElement,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { useMap } from \"react-leaflet\";\nimport { MapPeriodFilterContext } from \"../../../../state/index.js\";\nimport { dateToDHIS2PeriodId, type DHIS2PeriodType } from \"../../../../utils/helpers.js\";\n\nexport type { DHIS2PeriodType };\n\nexport type TimelineRange =\n\t| { range: [Date, Date]; step: DurationObjectUnits }\n\t| { range: [Date, Date, ...Date[]] };\n\nexport type TimelinePosition =\n\t| \"bottom\"\n\t| \"bottomleft\"\n\t| \"bottomright\"\n\t| \"bottomcenter\"\n\t| \"top\"\n\t| \"topleft\"\n\t| \"topright\"\n\t| \"topcenter\";\n\nexport interface TimelineControlOptions {\n\tautoplay?: boolean;\n\tbutton?: {\n\t\tpausedText?: string;\n\t\tplayingText?: string;\n\t};\n\tinterval?: number;\n\tperiodType?: DHIS2PeriodType;\n\tposition?: TimelinePosition;\n\ttimeline: {\n\t\tdateFormat: string;\n\t} & TimelineRange;\n}\n\nfunction resolveDates(tl: TimelineControlOptions[\"timeline\"]): Date[] {\n\tif (\"step\" in tl) {\n\t\tconst [start, end] = tl.range;\n\t\tconst dates: Date[] = [];\n\t\tlet cur = DateTime.fromJSDate(start);\n\t\tconst endDt = DateTime.fromJSDate(end);\n\t\twhile (cur <= endDt) {\n\t\t\tdates.push(cur.toJSDate());\n\t\t\tcur = cur.plus(tl.step);\n\t\t}\n\t\treturn dates;\n\t}\n\treturn [...tl.range];\n}\n\nconst ACCENT = \"#2c6693\";\nconst PADDING_LEFT = 40; // space for play/pause icon\nconst PADDING_RIGHT = 20;\nconst LABEL_WIDTH = 80; // min pixels per axis tick label\nconst PERIOD_RECT_HEIGHT = 8;\nconst PERIOD_RECT_GAP = 1; // gap between adjacent period rects\nconst AXIS_OFFSET = 4; // pixels between rect bottom and axis line\n\n\nfunction TimelineUI({\n\tautoplay: initialAutoplay,\n\tbutton,\n\tdates,\n\tinterval,\n\tonStep,\n}: {\n\tautoplay: boolean;\n\tbutton?: TimelineControlOptions[\"button\"];\n\tdates: Date[];\n\tinterval: number;\n\tonStep: (date: Date) => void;\n}): ReactElement {\n\tconst [index, setIndex] = useState(0);\n\tconst [playing, setPlaying] = useState(initialAutoplay);\n\tconst [svgWidth, setSvgWidth] = useState<number | null>(null);\n\tconst svgRef = useRef<SVGSVGElement>(null);\n\tconst axisRef = useRef<SVGGElement>(null);\n\tconst intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n\tuseEffect(() => {\n\t\tconst el = svgRef.current;\n\t\tif (!el) return;\n\t\tconst measure = (): void => { setSvgWidth(el.getBoundingClientRect().width); };\n\t\tmeasure();\n\t\tconst ro = new ResizeObserver(measure);\n\t\tro.observe(el);\n\t\treturn () => { ro.disconnect(); };\n\t}, []);\n\n\tconst trackWidth = svgWidth !== null ? svgWidth - PADDING_LEFT - PADDING_RIGHT : 0;\n\n\tconst timeScale = useMemo(() => {\n\t\tif (!trackWidth || dates.length < 2) return null;\n\t\tconst periodMs = dates[1].getTime() - dates[0].getTime();\n\t\tconst domainEnd = new Date(dates[dates.length - 1].getTime() + periodMs);\n\t\treturn scaleTime()\n\t\t\t.domain([dates[0], domainEnd])\n\t\t\t.range([0, trackWidth]);\n\t}, [dates, trackWidth]);\n\n\tuseEffect(() => {\n\t\tif (!timeScale || !axisRef.current || !trackWidth) return;\n\t\tconst maxTicks = Math.round(trackWidth / LABEL_WIDTH);\n\t\tconst axis = axisBottom<Date>(timeScale).ticks(maxTicks);\n\t\tselect<SVGGElement, unknown>(axisRef.current).call(axis);\n\t\tselect(axisRef.current).select(\".domain\").attr(\"stroke\", \"#ccc\");\n\t\tselect(axisRef.current).selectAll(\".tick line\").attr(\"stroke\", \"#ccc\");\n\t\tselect(axisRef.current)\n\t\t\t.selectAll<SVGTextElement, unknown>(\".tick text\")\n\t\t\t.attr(\"fill\", \"#666\")\n\t\t\t.attr(\"font-size\", \"10px\")\n\t\t\t.attr(\"font-family\", \"sans-serif\");\n\t}, [timeScale, trackWidth]);\n\n\tconst stepTo = useCallback(\n\t\t(idx: number) => {\n\t\t\tsetIndex(idx);\n\t\t\tonStep(dates[idx]);\n\t\t},\n\t\t[dates, onStep],\n\t);\n\n\t// Autoplay interval\n\tuseEffect(() => {\n\t\tif (intervalRef.current) clearInterval(intervalRef.current);\n\t\tif (!playing) return;\n\t\tintervalRef.current = setInterval(() => {\n\t\t\tsetIndex((prev) => {\n\t\t\t\tconst next = prev + 1 >= dates.length ? 0 : prev + 1;\n\t\t\t\tonStep(dates[next]);\n\t\t\t\treturn next;\n\t\t\t});\n\t\t}, interval);\n\t\treturn () => {\n\t\t\tif (intervalRef.current) clearInterval(intervalRef.current);\n\t\t};\n\t}, [playing, interval, dates, onStep]);\n\n\tconst periodRects = useMemo(() => {\n\t\tif (!timeScale || dates.length < 2) return null;\n\t\tconst unitWidth = timeScale(dates[1]) - timeScale(dates[0]);\n\t\treturn dates.map((date, i) => {\n\t\t\tconst x = timeScale(date);\n\t\t\tconst spanWidth = i < dates.length - 1\n\t\t\t\t? timeScale(dates[i + 1]) - x\n\t\t\t\t: unitWidth;\n\t\t\tconst w = Math.max(spanWidth - PERIOD_RECT_GAP, 1);\n\t\t\tconst capturedIndex = i;\n\t\t\treturn (\n\t\t\t\t<rect\n\t\t\t\t\tkey={date.toISOString()}\n\t\t\t\t\tfill={capturedIndex === index ? ACCENT : \"#b0c4d8\"}\n\t\t\t\t\theight={PERIOD_RECT_HEIGHT}\n\t\t\t\t\tonClick={() => { setPlaying(false); stepTo(capturedIndex); }}\n\t\t\t\t\trx={1}\n\t\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\t\twidth={w}\n\t\t\t\t\tx={x}\n\t\t\t\t\ty={0}\n\t\t\t\t/>\n\t\t\t);\n\t\t});\n\t}, [timeScale, dates, index, stepTo]);\n\n\n\tconst RECT_ROW_Y = 6;\n\tconst svgHeight = RECT_ROW_Y + PERIOD_RECT_HEIGHT + AXIS_OFFSET + 24\n\n\tconst playLabel = playing\n\t\t? (button?.playingText ?? \"Pause\")\n\t\t: (button?.pausedText ?? \"Play\");\n\n\treturn (\n\t\t<svg\n\t\t\taria-label=\"Timeline\"\n\t\t\theight={svgHeight}\n\t\t\tref={svgRef}\n\t\t\tstyle={{\n\t\t\t\tbackground: \"white\",\n\t\t\t\tboxShadow: \"0 -1px 4px rgba(0,0,0,0.15)\",\n\t\t\t\tdisplay: \"block\",\n\t\t\t\twidth: \"100%\",\n\t\t\t}}\n\t\t>\n\t\t\t{/* Play / Pause — Material Design SVG icon */}\n\t\t\t<g\n\t\t\t\taria-label={playLabel}\n\t\t\t\tonClick={() => { setPlaying((p) => !p); }}\n\t\t\t\trole=\"button\"\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\ttransform={`translate(7, ${RECT_ROW_Y - 8})`}\n\t\t\t>\n\t\t\t\t<path d=\"M0 0h24v24H0z\" fillOpacity={0} />\n\t\t\t\t{playing\n\t\t\t\t\t? <path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\" fill={ACCENT} />\n\t\t\t\t\t: <path d=\"M8 5v14l11-7z\" fill={ACCENT} />\n\t\t\t\t}\n\t\t\t</g>\n\n\t\t\t{/* Period rectangles */}\n\t\t\t{timeScale !== null && (\n\t\t\t\t<g transform={`translate(${PADDING_LEFT}, ${RECT_ROW_Y})`}>\n\t\t\t\t\t{periodRects}\n\t\t\t\t</g>\n\t\t\t)}\n\n\t\t\t{/* D3 x-axis */}\n\t\t\t{timeScale !== null && (\n\t\t\t\t<g\n\t\t\t\t\tref={axisRef}\n\t\t\t\t\ttransform={`translate(${PADDING_LEFT}, ${RECT_ROW_Y + PERIOD_RECT_HEIGHT + AXIS_OFFSET})`}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</svg>\n\t);\n}\n\n\nexport function TimelineControl({\n\tautoplay = false,\n\tbutton,\n\tinterval = 1000,\n\tperiodType,\n\tposition = \"bottom\",\n\ttimeline,\n}: TimelineControlOptions): ReactElement | null {\n\tconst map = useMap();\n\tconst {\n\t\tperiodType: contextPeriodType,\n\t\tsetActivePeriod,\n\t\tsetPeriodType,\n\t} = useContext(MapPeriodFilterContext);\n\tconst [container, setContainer] = useState<HTMLElement | null>(null);\n\n\tuseEffect(() => {\n\t\tif (periodType) setPeriodType(periodType);\n\t}, [periodType, setPeriodType]);\n\n\tconst resolvedPeriodType = periodType ?? contextPeriodType ?? \"Monthly\";\n\tconst dates = useMemo(() => resolveDates(timeline), [timeline]);\n\n\tuseEffect(() => {\n\t\tconst mapEl = map.getContainer();\n\t\tconst div = DomUtil.create(\"div\", \"\", mapEl);\n\t\tDomEvent.disableClickPropagation(div);\n\t\tDomEvent.disableScrollPropagation(div);\n\n\t\tconst isTop = position.startsWith(\"top\");\n\t\tObject.assign(div.style, {\n\t\t\tbottom: isTop ? \"auto\" : \"18px\",\n\t\t\tboxSizing: \"border-box\",\n\t\t\tleft: \"0\",\n\t\t\tpadding: isTop ? \"8px 8px 0\" : \"0 8px 8px\",\n\t\t\tposition: \"absolute\",\n\t\t\tright: \"0\",\n\t\t\ttop: isTop ? \"0\" : \"auto\",\n\t\t\tzIndex: \"1000\",\n\t\t});\n\n\t\tsetContainer(div);\n\t\treturn () => {\n\t\t\tdiv.remove();\n\t\t\tsetContainer(null);\n\t\t};\n\t}, [map, position]);\n\n\tconst handleStep = useCallback(\n\t\t(date: Date) => {\n\t\t\tsetActivePeriod(dateToDHIS2PeriodId(date, resolvedPeriodType));\n\t\t},\n\t\t[resolvedPeriodType, setActivePeriod],\n\t);\n\n\tif (!container) return null;\n\n\treturn createPortal(\n\t\t<TimelineUI\n\t\t\tautoplay={autoplay}\n\t\t\tbutton={button}\n\t\t\tdates={dates}\n\t\t\tinterval={interval}\n\t\t\tonStep={handleStep}\n\t\t/>,\n\t\tcontainer,\n\t);\n}\n"]}
|
|
@@ -4,34 +4,39 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
4
4
|
var reactLeaflet = require('react-leaflet');
|
|
5
5
|
var FullscreenControl = require('./components/FullscreenControl/index.js');
|
|
6
6
|
var DownloadControl = require('./components/DownloadControl/index.js');
|
|
7
|
+
var TimelineControl = require('./components/TimelineControl');
|
|
7
8
|
|
|
8
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
10
|
|
|
10
11
|
var FullscreenControl__default = /*#__PURE__*/_interopDefault(FullscreenControl);
|
|
11
12
|
var DownloadControl__default = /*#__PURE__*/_interopDefault(DownloadControl);
|
|
12
13
|
|
|
13
|
-
function MapControl({
|
|
14
|
-
type
|
|
15
|
-
options,
|
|
16
|
-
position,
|
|
17
|
-
mapId
|
|
18
|
-
}) {
|
|
14
|
+
function MapControl(props) {
|
|
15
|
+
const { type } = props;
|
|
19
16
|
switch (type) {
|
|
20
17
|
case "zoom":
|
|
21
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactLeaflet.ZoomControl, { position, ...options });
|
|
18
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactLeaflet.ZoomControl, { position: props.position, ...props.options });
|
|
22
19
|
case "scale":
|
|
23
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactLeaflet.ScaleControl, { position, ...options });
|
|
20
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactLeaflet.ScaleControl, { position: props.position, ...props.options });
|
|
24
21
|
case "fullscreen":
|
|
25
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
22
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
23
|
+
FullscreenControl__default.default,
|
|
24
|
+
{
|
|
25
|
+
position: props.position,
|
|
26
|
+
...props.options
|
|
27
|
+
}
|
|
28
|
+
);
|
|
26
29
|
case "print":
|
|
27
30
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28
31
|
DownloadControl__default.default,
|
|
29
32
|
{
|
|
30
|
-
mapId,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
mapId: props.mapId,
|
|
34
|
+
options: props.options,
|
|
35
|
+
position: props.position
|
|
33
36
|
}
|
|
34
37
|
);
|
|
38
|
+
case "timeline":
|
|
39
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TimelineControl.TimelineControl, { ...props });
|
|
35
40
|
default:
|
|
36
41
|
return null;
|
|
37
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/Map/components/MapControls/index.tsx"],"names":["
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/Map/components/MapControls/index.tsx"],"names":["ZoomControl","ScaleControl","jsx","FullscreenControl","DownloadControl","TimelineControl"],"mappings":";;;;;;;;;;;;;AAOe,SAAR,WAA4B,KAAA,EAAwC;AAC1E,EAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,EAAA,QAAQ,IAAA;AAAM,IACb,KAAK,MAAA;AACJ,MAAA,sCAAQA,wBAAA,EAAA,EAAY,QAAA,EAAU,MAAM,QAAA,EAAW,GAAG,MAAM,OAAA,EAAS,CAAA;AAAA,IAClE,KAAK,OAAA;AACJ,MAAA,sCACEC,yBAAA,EAAA,EAAa,QAAA,EAAU,MAAM,QAAA,EAAW,GAAG,MAAM,OAAA,EAAS,CAAA;AAAA,IAE7D,KAAK,YAAA;AACJ,MAAA,uBACCC,cAAA;AAAA,QAACC,kCAAA;AAAA,QAAA;AAAA,UACA,UAAU,KAAA,CAAM,QAAA;AAAA,UACf,GAAG,KAAA,CAAM;AAAA;AAAA,OACX;AAAA,IAEF,KAAK,OAAA;AACJ,MAAA,uBACCD,cAAA;AAAA,QAACE,gCAAA;AAAA,QAAA;AAAA,UACA,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,SAAS,KAAA,CAAM,OAAA;AAAA,UACf,UAAU,KAAA,CAAM;AAAA;AAAA,OACjB;AAAA,IAEF,KAAK,UAAA;AACJ,MAAA,uBAAOF,cAAA,CAACG,+BAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,CAAA;AAAA,IACpC;AACC,MAAA,OAAO,IAAA;AAAA;AAEV","file":"index.js","sourcesContent":["import React from \"react\";\nimport { ScaleControl, ZoomControl } from \"react-leaflet\";\nimport { MapControls } from \"../MapArea/interfaces\";\nimport FullscreenControl from \"./components/FullscreenControl/index.js\";\nimport DownloadControl from \"./components/DownloadControl/index.js\";\nimport { TimelineControl } from \"./components/TimelineControl\";\n\nexport default function MapControl(props: MapControls & { mapId: string }) {\n\tconst { type } = props;\n\tswitch (type) {\n\t\tcase \"zoom\":\n\t\t\treturn <ZoomControl position={props.position} {...props.options} />;\n\t\tcase \"scale\":\n\t\t\treturn (\n\t\t\t\t<ScaleControl position={props.position} {...props.options} />\n\t\t\t);\n\t\tcase \"fullscreen\":\n\t\t\treturn (\n\t\t\t\t<FullscreenControl\n\t\t\t\t\tposition={props.position}\n\t\t\t\t\t{...props.options}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"print\":\n\t\t\treturn (\n\t\t\t\t<DownloadControl\n\t\t\t\t\tmapId={props.mapId}\n\t\t\t\t\toptions={props.options}\n\t\t\t\t\tposition={props.position}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"timeline\":\n\t\t\treturn <TimelineControl {...props} />;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n"]}
|
package/dist/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var react = require('react');
|
|
|
6
6
|
var utils = require('../../../../../utils');
|
|
7
7
|
var appRuntime = require('@dhis2/app-runtime');
|
|
8
8
|
var asyncEs = require('async-es');
|
|
9
|
+
var helpers_js = require('../../../../../utils/helpers.js');
|
|
9
10
|
var colors_js = require('../../../../../utils/colors.js');
|
|
10
11
|
var index_js = require('../../../../MapLayer/components/GoogleEngineLayer/hooks/index.js');
|
|
11
12
|
var useBoundaryData_js = require('../../../../MapLayer/components/BoundaryLayer/hooks/useBoundaryData.js');
|
|
@@ -16,13 +17,13 @@ const analyticsQuery = {
|
|
|
16
17
|
analytics: {
|
|
17
18
|
resource: "analytics",
|
|
18
19
|
params: ({ ou, pe, dx, startDate, endDate, analyticsOptions }) => {
|
|
19
|
-
const
|
|
20
|
+
const usingDateRange = !lodash.isEmpty(startDate) && !lodash.isEmpty(endDate);
|
|
21
|
+
const peDimension = !usingDateRange && !lodash.isEmpty(pe) ? `pe:${pe?.join(";")}` : void 0;
|
|
20
22
|
const ouDimension = !lodash.isEmpty(ou) ? `ou:${ou?.join(";")}` : void 0;
|
|
21
23
|
const dxDimension = !lodash.isEmpty(dx) ? `dx:${dx?.join(";")}` : void 0;
|
|
22
24
|
return {
|
|
23
25
|
dimension: lodash.compact([dxDimension, peDimension, ouDimension]),
|
|
24
|
-
startDate,
|
|
25
|
-
endDate,
|
|
26
|
+
...usingDateRange ? { startDate, endDate } : {},
|
|
26
27
|
displayProperty: "NAME",
|
|
27
28
|
...analyticsOptions ?? {}
|
|
28
29
|
};
|
|
@@ -79,24 +80,32 @@ function useThematicLayers({
|
|
|
79
80
|
const [loading, setLoading] = react.useState(false);
|
|
80
81
|
const { orgUnits, orgUnitSelection } = hooks.useMapOrganisationUnit();
|
|
81
82
|
const { periods, range } = hooks.useMapPeriods() ?? {};
|
|
83
|
+
const { activePeriod, periodType } = hooks.useMapPeriodFilter();
|
|
82
84
|
const ou = react.useMemo(
|
|
83
85
|
() => utils.getOrgUnitsSelection(orgUnitSelection),
|
|
84
86
|
[orgUnitSelection]
|
|
85
87
|
);
|
|
86
|
-
const
|
|
88
|
+
const timelinePeriods = react.useMemo(() => {
|
|
89
|
+
if (!range || !periodType) return null;
|
|
90
|
+
return helpers_js.computeTimelinePeriods(range, periodType);
|
|
91
|
+
}, [range, periodType]);
|
|
92
|
+
const pe = react.useMemo(() => {
|
|
93
|
+
if (timelinePeriods) return timelinePeriods;
|
|
94
|
+
return periods?.map((pe2) => pe2.id);
|
|
95
|
+
}, [periods, timelinePeriods]);
|
|
96
|
+
const toISODate = (date) => date.toISOString().slice(0, 10);
|
|
87
97
|
const { startDate, endDate } = react.useMemo(() => {
|
|
88
|
-
if (!range) {
|
|
89
|
-
return {
|
|
90
|
-
startDate: void 0,
|
|
91
|
-
endDate: void 0
|
|
92
|
-
};
|
|
98
|
+
if (timelinePeriods || !range) {
|
|
99
|
+
return { startDate: void 0, endDate: void 0 };
|
|
93
100
|
}
|
|
94
101
|
return {
|
|
95
|
-
startDate:
|
|
96
|
-
endDate:
|
|
102
|
+
startDate: toISODate(range.start),
|
|
103
|
+
endDate: toISODate(range.end)
|
|
97
104
|
};
|
|
98
|
-
}, [range]);
|
|
99
|
-
const
|
|
105
|
+
}, [range, timelinePeriods]);
|
|
106
|
+
const analyticsDataRef = react.useRef(null);
|
|
107
|
+
const legendSetsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
108
|
+
const sanitizeData = (data, layer, currentPeriod) => {
|
|
100
109
|
if (data) {
|
|
101
110
|
const { analytics } = data;
|
|
102
111
|
const rows = analytics?.rows;
|
|
@@ -109,18 +118,20 @@ function useThematicLayers({
|
|
|
109
118
|
const valueIndex = analytics.headers.findIndex(
|
|
110
119
|
(header) => header.name === "value"
|
|
111
120
|
);
|
|
121
|
+
const peIndex = analytics.headers.findIndex(
|
|
122
|
+
(header) => header.name === "pe"
|
|
123
|
+
);
|
|
112
124
|
if (!lodash.isEmpty(rows)) {
|
|
113
125
|
return lodash.sortBy(
|
|
114
|
-
orgUnits?.map((
|
|
115
|
-
const
|
|
116
|
-
(
|
|
126
|
+
orgUnits?.map((orgUnit) => {
|
|
127
|
+
const matchingRows = rows.filter(
|
|
128
|
+
(row) => row[ouIndex] === orgUnit.id && row[dxIndex] === layer.dataItem.id && (currentPeriod && peIndex >= 0 ? row[peIndex] === currentPeriod : true)
|
|
117
129
|
);
|
|
130
|
+
const values = matchingRows.map((row) => parseFloat(row[valueIndex])).filter((v) => !isNaN(v));
|
|
118
131
|
return {
|
|
119
|
-
orgUnit
|
|
120
|
-
data:
|
|
121
|
-
dataItem: {
|
|
122
|
-
...layer.dataItem
|
|
123
|
-
}
|
|
132
|
+
orgUnit,
|
|
133
|
+
data: values.length > 0 ? values.reduce((sum, v) => sum + v, 0) / values.length : void 0,
|
|
134
|
+
dataItem: { ...layer.dataItem }
|
|
124
135
|
};
|
|
125
136
|
}),
|
|
126
137
|
["data"]
|
|
@@ -137,15 +148,17 @@ function useThematicLayers({
|
|
|
137
148
|
try {
|
|
138
149
|
const legends = [];
|
|
139
150
|
if (layer.dataItem.legendSet) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
let legendSet = legendSetsRef.current.get(layer.dataItem.legendSet);
|
|
152
|
+
if (!legendSet) {
|
|
153
|
+
const legendSetData = await engine.query(
|
|
154
|
+
legendSetsQuery,
|
|
155
|
+
{ variables: { id: layer.dataItem.legendSet } }
|
|
156
|
+
);
|
|
157
|
+
legendSet = legendSetData?.legendSets;
|
|
158
|
+
if (legendSet) {
|
|
159
|
+
legendSetsRef.current.set(layer.dataItem.legendSet, legendSet);
|
|
146
160
|
}
|
|
147
|
-
|
|
148
|
-
const legendSet = legendSetData?.legendSets;
|
|
161
|
+
}
|
|
149
162
|
if (legendSet) {
|
|
150
163
|
legends.push(...legendSet.legends);
|
|
151
164
|
}
|
|
@@ -161,17 +174,11 @@ function useThematicLayers({
|
|
|
161
174
|
const autoLegends = utils.generateLegends(
|
|
162
175
|
lodash.last(sortedData)?.data ?? 0,
|
|
163
176
|
lodash.head(sortedData)?.data ?? 0,
|
|
164
|
-
{
|
|
165
|
-
classesCount: scale,
|
|
166
|
-
colorClass
|
|
167
|
-
}
|
|
177
|
+
{ classesCount: scale, colorClass }
|
|
168
178
|
);
|
|
169
179
|
legends.push(...autoLegends);
|
|
170
180
|
}
|
|
171
|
-
return {
|
|
172
|
-
...layer,
|
|
173
|
-
legends
|
|
174
|
-
};
|
|
181
|
+
return { ...layer, legends };
|
|
175
182
|
} catch (e) {
|
|
176
183
|
return layer;
|
|
177
184
|
}
|
|
@@ -182,38 +189,25 @@ function useThematicLayers({
|
|
|
182
189
|
try {
|
|
183
190
|
setLoading(true);
|
|
184
191
|
const layersWithoutData = layers?.filter((layer) => !layer.data);
|
|
185
|
-
const layersWithData = lodash.differenceBy(
|
|
186
|
-
layers,
|
|
187
|
-
layersWithoutData,
|
|
188
|
-
"id"
|
|
189
|
-
);
|
|
192
|
+
const layersWithData = lodash.differenceBy(layers, layersWithoutData, "id");
|
|
190
193
|
const dx = layersWithoutData.map((layer) => layer.dataItem.id);
|
|
191
194
|
let sanitizedLayersWithData = [];
|
|
192
195
|
if (!lodash.isEmpty(dx)) {
|
|
193
196
|
const data = await engine.query(analyticsQuery, {
|
|
194
|
-
variables: {
|
|
195
|
-
dx,
|
|
196
|
-
ou,
|
|
197
|
-
pe,
|
|
198
|
-
startDate,
|
|
199
|
-
endDate,
|
|
200
|
-
analyticsOptions
|
|
201
|
-
}
|
|
197
|
+
variables: { dx, ou, pe, startDate, endDate, analyticsOptions }
|
|
202
198
|
});
|
|
199
|
+
analyticsDataRef.current = data;
|
|
203
200
|
sanitizedLayersWithData = layersWithoutData.map((layer) => ({
|
|
204
201
|
...layer,
|
|
205
202
|
name: layer?.name ?? layer?.dataItem?.displayName ?? layer.id,
|
|
206
|
-
data: sanitizeData(data, layer)
|
|
203
|
+
data: sanitizeData(data, layer, activePeriod)
|
|
207
204
|
}));
|
|
208
205
|
}
|
|
209
206
|
const sanitizedLayersWithOrgUnits = layersWithData.map((layer) => ({
|
|
210
207
|
...layer,
|
|
211
208
|
data: layer.data?.map((datum) => ({
|
|
212
209
|
...datum,
|
|
213
|
-
orgUnit: lodash.find(orgUnits, [
|
|
214
|
-
"id",
|
|
215
|
-
datum.orgUnit
|
|
216
|
-
]),
|
|
210
|
+
orgUnit: lodash.find(orgUnits, ["id", datum.orgUnit]),
|
|
217
211
|
dataItem: layer.dataItem,
|
|
218
212
|
name: layer?.name ?? layer?.dataItem?.displayName ?? layer.id
|
|
219
213
|
}))
|
|
@@ -229,8 +223,21 @@ function useThematicLayers({
|
|
|
229
223
|
return [];
|
|
230
224
|
}
|
|
231
225
|
};
|
|
226
|
+
const refilterLayers = react.useCallback(
|
|
227
|
+
async (layers) => {
|
|
228
|
+
if (!analyticsDataRef.current) return [];
|
|
229
|
+
const processed = layers.filter((layer) => !layer.data).map((layer) => ({
|
|
230
|
+
...layer,
|
|
231
|
+
name: layer?.name ?? layer?.dataItem?.displayName ?? layer.id,
|
|
232
|
+
data: sanitizeData(analyticsDataRef.current, layer, activePeriod)
|
|
233
|
+
}));
|
|
234
|
+
return sanitizeLegends(processed);
|
|
235
|
+
},
|
|
236
|
+
[activePeriod, orgUnits]
|
|
237
|
+
);
|
|
232
238
|
return {
|
|
233
239
|
sanitizeLayers,
|
|
240
|
+
refilterLayers,
|
|
234
241
|
loading
|
|
235
242
|
};
|
|
236
243
|
}
|