@vidro/map-handler 1.2.179 → 1.2.180

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.
@@ -1,40 +1,161 @@
1
+ import { useAuth } from "@/contexts/auth";
1
2
  import { useMaps } from "@/contexts/maps";
2
3
  import { useMessages } from "@/contexts/messages";
4
+ import { useEffect, useState } from "react";
3
5
 
4
6
  const MapButtons = () => {
5
- const { map } = useMaps();
6
- const { ZoomIn, ZoomOut, zoomToExtent } = useMessages();
7
+ const { logged } = useAuth();
8
+ const { map, mapReady, clickedCoordinates } = useMaps();
9
+ const {
10
+ ZoomIn,
11
+ ZoomOut,
12
+ zoomToExtent,
13
+ drawPoint,
14
+ Clear,
15
+ Highlight,
16
+ centerMap,
17
+ } = useMessages();
18
+ if (!logged) return null;
7
19
  return (
8
- <div>
9
- <button
10
- onClick={(e) => {
11
- console.log("Zoom +");
12
- ZoomIn();
13
- }}
14
- disabled={!map}
15
- className="border border-gray-300 bg-black text-white rounded-md p-2"
16
- >
17
- Zoom +
18
- </button>
19
- <button
20
- onClick={(e) => {
21
- console.log("Zoom -");
22
- ZoomOut();
23
- }}
24
- className="border border-gray-300 bg-black text-white rounded-md p-2"
25
- >
26
- Zoom -
27
- </button>
28
- <button
29
- onClick={(e) => {
30
- console.log("Zoom to extent");
31
- zoomToExtent();
20
+ <>
21
+ {!mapReady && <div>Waiting map...</div>}
22
+ {mapReady && (
23
+ <div className="flex gap-1 text-xs">
24
+ <button
25
+ onClick={(e) => {
26
+ console.log("Zoom +");
27
+ ZoomIn();
28
+ }}
29
+ disabled={!map}
30
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
31
+ >
32
+ Zoom +
33
+ </button>
34
+ <button
35
+ onClick={(e) => {
36
+ console.log("Zoom -");
37
+ ZoomOut();
38
+ }}
39
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
40
+ >
41
+ Zoom -
42
+ </button>
43
+ <button
44
+ onClick={(e) => {
45
+ console.log("Zoom to extent");
46
+ zoomToExtent();
47
+ }}
48
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
49
+ >
50
+ Zoom to extent
51
+ </button>
52
+ <button
53
+ onClick={(e) => {
54
+ console.log("Draw point");
55
+ drawPoint({});
56
+ }}
57
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
58
+ >
59
+ Add point
60
+ </button>
61
+ <button
62
+ onClick={(e) => {
63
+ console.log("Clear");
64
+ Clear();
65
+ }}
66
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
67
+ >
68
+ Clear
69
+ </button>
70
+ <button
71
+ onClick={(e) => {
72
+ console.log("Highlight clickedCoordinates", clickedCoordinates);
73
+ Highlight(
74
+ {
75
+ feature_type: "HIGHLIGHT",
76
+ geom: `POINT(${clickedCoordinates[0]} ${clickedCoordinates[1]})`,
77
+ },
78
+ 2,
79
+ {
80
+ duration: 1500,
81
+ repeat: true,
82
+ },
83
+ 0,
84
+ null
85
+ );
86
+ }}
87
+ disabled={!clickedCoordinates}
88
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
89
+ >
90
+ Highlight clicked coordinates
91
+ </button>
92
+ <button
93
+ onClick={(e) => {
94
+ console.log("Highlight clickedCoordinates", clickedCoordinates);
95
+ centerMap(clickedCoordinates);
96
+ }}
97
+ disabled={!clickedCoordinates}
98
+ className="border border-gray-300 bg-black text-white rounded-md p-2"
99
+ >
100
+ Center map to clicked coordinates
101
+ </button>
102
+ <ZoomToScaleButton />
103
+ </div>
104
+ )}
105
+ </>
106
+ );
107
+ };
108
+ export default MapButtons;
109
+
110
+ const ZoomToScaleButton = () => {
111
+ const { zoomToScale } = useMessages();
112
+ const { mapScale } = useMaps();
113
+ const scales = [
114
+ { id: "1:100", val: "1:100", label: "1:100" },
115
+ { id: "1:200", val: "1:200", label: "1:200" },
116
+ { id: "1:500", val: "1:500", label: "1:500" },
117
+ { id: "1:1000", val: "1:1000", label: "1:1000" },
118
+ { id: "1:2000", val: "1:2000", label: "1:2000" },
119
+ { id: "1:5000", val: "1:5000", label: "1:5000" },
120
+ { id: "1:10000", val: "1:10000", label: "1:10000" },
121
+ { id: "1:50000", val: "1:50000", label: "1:50000" },
122
+ ];
123
+
124
+ const [actualValue, setActualValue] = useState(mapScale ? mapScale : "-1");
125
+ useEffect(() => {
126
+ if (!mapScale) return;
127
+ const scale = scales.find((s) => s.val === mapScale);
128
+ if (scale) {
129
+ setActualValue(scale.val);
130
+ } else {
131
+ setActualValue("-1");
132
+ }
133
+ console.log("mapScale", mapScale, scale);
134
+ }, [mapScale]);
135
+ return (
136
+ <div className="mx-2 pt-2">
137
+ <label>Zoom to scale:</label>
138
+ <select
139
+ value={actualValue}
140
+ onChange={(e) => {
141
+ const newVal = !isNaN(e.target.value)
142
+ ? Number(e.target.value)
143
+ : e.target.value;
144
+ setActualValue(newVal);
145
+ zoomToScale(newVal);
32
146
  }}
33
- className="border border-gray-300 bg-black text-white rounded-md p-2"
34
147
  >
35
- Zoom to extent
36
- </button>
148
+ <option key={`opt_select_scale`} value="-1">
149
+ Select scale...
150
+ </option>
151
+ {scales.map((opt, index) => {
152
+ return (
153
+ <option key={`opt_${index}`} value={opt.val}>
154
+ {opt.label}
155
+ </option>
156
+ );
157
+ })}
158
+ </select>
37
159
  </div>
38
160
  );
39
161
  };
40
- export default MapButtons;
@@ -0,0 +1,120 @@
1
+ import { useAuth } from "@/contexts/auth";
2
+ import { useMaps } from "@/contexts/maps";
3
+ import { useMessages } from "@/contexts/messages";
4
+ import { useEffect, useState } from "react";
5
+
6
+ const MapFilters = () => {
7
+ const {
8
+ configuredFilters,
9
+ mapId,
10
+ filters,
11
+ activeFilters,
12
+
13
+ activeLayer,
14
+ mapLayers,
15
+ } = useMaps();
16
+ const { Filters } = useMessages();
17
+ const { logged } = useAuth();
18
+ const [currentFilter, setCurrentFilter] = useState("");
19
+ const [filterValue, setFilterValue] = useState("");
20
+ useEffect(() => {
21
+ if (!configuredFilters) return;
22
+ console.log("MapFilters configuredFilters", configuredFilters);
23
+ }, [configuredFilters]);
24
+
25
+ useEffect(() => {
26
+ if (!activeFilters) return;
27
+ console.log("MapFilters activeFilters", activeFilters);
28
+ }, [activeFilters]);
29
+
30
+ useEffect(() => {
31
+ if (!filters) return;
32
+ console.log("MapFilters filters", filters);
33
+ }, [filters]);
34
+
35
+ const applyFilter = () => {
36
+ if (!activeLayer) {
37
+ console.log("No active layer");
38
+ return;
39
+ }
40
+ console.log("Apply filter", {
41
+ currentFilter,
42
+ filterValue,
43
+ activeLayer,
44
+ });
45
+ //find layer info
46
+ const lay = mapLayers.find((l) => l.qgis_name === activeLayer);
47
+ console.log("Layer info", lay);
48
+ //format filter for mapComponent digest
49
+ const filter = [
50
+ {
51
+ layer_id: lay.id,
52
+ layer_name: lay.qgis_name,
53
+ filters: [
54
+ [
55
+ {
56
+ name: currentFilter,
57
+ condition: "=", //default condition - you can get condition from configuredFilters
58
+ value: filterValue,
59
+ value2: null,
60
+ layer_id: lay.id,
61
+ mapId: mapId,
62
+ },
63
+ ],
64
+ ],
65
+ },
66
+ ];
67
+ Filters(filter);
68
+ console.log("Filter", filter);
69
+ };
70
+
71
+ if (!logged) return null;
72
+ if (!mapId) return null;
73
+ return (
74
+ <>
75
+ <div>
76
+ {configuredFilters && configuredFilters.length === 0 && (
77
+ <div>No filters available</div>
78
+ )}
79
+
80
+ <div className="m-2 flex gap-2">
81
+ <label className="block text-sm font-medium text-gray-700 pt-2">
82
+ Filters
83
+ </label>
84
+ {configuredFilters && configuredFilters.length > 0 && (
85
+ <select
86
+ className="border border-gray-300 rounded-md p-2 w-60"
87
+ onChange={(e) => setCurrentFilter(e.target.value)}
88
+ value={currentFilter}
89
+ >
90
+ <option value="-1">Select filter...</option>
91
+ {configuredFilters.map((ele) => (
92
+ <option key={ele.id} value={ele.name}>
93
+ {ele.name}
94
+ </option>
95
+ ))}
96
+ </select>
97
+ )}
98
+ <input
99
+ type="text"
100
+ value={filterValue}
101
+ onChange={(e) => setFilterValue(e.target.value)}
102
+ className="border border-gray-300 rounded-md p-2 w-60"
103
+ />
104
+ <button
105
+ onClick={(e) => {
106
+ console.log("Apply filter");
107
+ applyFilter();
108
+ }}
109
+ disabled={filterValue === "" || currentFilter === "-1"}
110
+ className="border border-gray-300 bg-black text-white rounded-md p-2 mt-1 text-xs"
111
+ >
112
+ Apply filter
113
+ </button>
114
+ </div>
115
+ </div>
116
+ </>
117
+ );
118
+ };
119
+
120
+ export default MapFilters;
@@ -0,0 +1,36 @@
1
+ import { useMaps } from "@/contexts/maps";
2
+ import useMapEvents from "@/hooks/useMapEvents";
3
+ const MapInfo = () => {
4
+ useMapEvents();
5
+ const {
6
+ zoomLevel,
7
+ mapScale,
8
+ clickedCoordinates,
9
+ map,
10
+ displayedLayers,
11
+ mapResolution,
12
+ } = useMaps();
13
+ if (!map) return null;
14
+ return (
15
+ <div className="absolute bg-white/60 right-0 p-5">
16
+ <div className="flex flex-col gap-1 text-xs">
17
+ <div>Zoom level: {zoomLevel}</div>
18
+ <div>Map scale: {mapScale}</div>
19
+ <div>Map resolution: {mapResolution}</div>
20
+ <div>Clicked coordinates: {clickedCoordinates}</div>
21
+ </div>
22
+ <div className="bg-black/20 p-5 text-left mt-2">
23
+ <span>Displayed Layers:</span>
24
+
25
+ {displayedLayers && displayedLayers.length > 0 && (
26
+ <div className="mt-1 flex flex-col gap-1 text-xs">
27
+ {displayedLayers.map((layer) => (
28
+ <div key={`lay_${layer}`}> - {layer}</div>
29
+ ))}
30
+ </div>
31
+ )}
32
+ </div>
33
+ </div>
34
+ );
35
+ };
36
+ export default MapInfo;
@@ -0,0 +1,60 @@
1
+ import { useAuth } from "@/contexts/auth";
2
+ import { useMaps } from "@/contexts/maps";
3
+ import { useMessages } from "@/contexts/messages";
4
+ import { useEffect, useState } from "react";
5
+
6
+ const MapLayers = () => {
7
+ const { GetMapInfo, mapId, mapLayers, setActiveLayer } = useMaps();
8
+ const { ToggleLayer } = useMessages();
9
+ const { logged } = useAuth();
10
+ const [selectedLayer, setSelectedLayer] = useState("-1");
11
+
12
+ useEffect(() => {
13
+ if (!mapId) return;
14
+ GetMapInfo(mapId);
15
+ }, [mapId]);
16
+
17
+ if (!logged) return null;
18
+ if (!mapId) return null;
19
+ return (
20
+ <>
21
+ <div>
22
+ {mapLayers && mapLayers.length === 0 && <div>No layers available</div>}
23
+
24
+ <div className="m-2 flex gap-2">
25
+ <label className="block text-sm font-medium text-gray-700 pt-2">
26
+ Layers
27
+ </label>
28
+ {mapLayers && mapLayers.length > 0 && (
29
+ <select
30
+ className="border border-gray-300 rounded-md p-2 w-60"
31
+ onChange={(e) => setSelectedLayer(e.target.value)}
32
+ value={selectedLayer}
33
+ >
34
+ <option value="-1">Select layer...</option>
35
+ {mapLayers.map((ele) => (
36
+ <option key={ele.id} value={ele.qgis_name}>
37
+ {ele.qgis_name} - {ele.alias}
38
+ </option>
39
+ ))}
40
+ </select>
41
+ )}
42
+
43
+ <button
44
+ onClick={(e) => {
45
+ console.log("Toggle layer", selectedLayer);
46
+ setActiveLayer(selectedLayer);
47
+ ToggleLayer(selectedLayer);
48
+ }}
49
+ disabled={selectedLayer === "-1"}
50
+ className="border border-gray-300 bg-black text-white rounded-md p-2 mt-1 text-xs"
51
+ >
52
+ Toggle layer
53
+ </button>
54
+ </div>
55
+ </div>
56
+ </>
57
+ );
58
+ };
59
+
60
+ export default MapLayers;
@@ -0,0 +1,43 @@
1
+ import { useAuth } from "@/contexts/auth";
2
+ import { useMaps } from "@/contexts/maps";
3
+ import { useState } from "react";
4
+
5
+ const MapList = () => {
6
+ const { GetMap } = useMaps();
7
+ const { projects, logged } = useAuth();
8
+ const [selectedMap, setSelectedMap] = useState("-1");
9
+ if (!logged) return null;
10
+ return (
11
+ <div>
12
+ <div className="m-2 flex gap-2">
13
+ <label className="block text-sm font-medium text-gray-700 pt-2">
14
+ Maps
15
+ </label>
16
+ <select
17
+ className="border border-gray-300 rounded-md p-2 w-32"
18
+ onChange={(e) => setSelectedMap(e.target.value)}
19
+ value={selectedMap}
20
+ >
21
+ <option value="-1">Select a map</option>
22
+ {projects.map((projectId) => (
23
+ <option key={projectId} value={projectId}>
24
+ {projectId}
25
+ </option>
26
+ ))}
27
+ </select>
28
+
29
+ <button
30
+ onClick={(e) => {
31
+ GetMap(selectedMap);
32
+ }}
33
+ disabled={selectedMap === "-1"}
34
+ className="border border-gray-300 bg-black text-white rounded-md p-2 mt-1 text-xs"
35
+ >
36
+ Load map
37
+ </button>
38
+ </div>
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default MapList;
@@ -5,7 +5,9 @@ import { useRouter } from "next/navigation";
5
5
  const AuthContext = createContext({});
6
6
 
7
7
  export const AuthProvider = ({ children }) => {
8
- const [apiUrl, setApiUrl] = useState("");
8
+ const [apiUrl, setApiUrl] = useState(
9
+ process.env.NEXT_PUBLIC_APIURL ? process.env.NEXT_PUBLIC_APIURL : ""
10
+ );
9
11
  const [logged, setLogged] = useState(null);
10
12
  const [token, setToken] = useState(null);
11
13
  const [userId, setUserId] = useState(null);
@@ -1,28 +1,24 @@
1
1
  "use client";
2
2
  import { createContext, useContext, useState, useEffect } from "react";
3
-
4
- import MapService from "@/shared/maps-service";
5
3
  import { useAuth } from "./auth";
6
4
 
7
5
  const MapsContext = createContext({});
8
6
 
9
7
  export const MapsProvider = ({ children }) => {
10
8
  const { apiUrl, token } = useAuth();
11
- const [loading, setLoading] = useState(true);
12
9
  const [map, setMap] = useState(null);
13
10
  const [mapId, setMapId] = useState(null);
14
- const [mapToken, setMaptoken] = useState(null);
15
- const [mapInfo, setMapInfo] = useState(null);
11
+
16
12
  const [mapError, setMapError] = useState(null);
17
13
  const [mapReady, setMapReady] = useState(false);
18
- const [tiledReady, setTiledReady] = useState(false);
19
- const [componentUrl, setComponentUrl] = useState(null);
14
+
20
15
  const [sessionToken, setSessionToken] = useState(null);
21
16
  const [currentMapAction, setCurrentMapAction] = useState(null);
22
17
  const [clickedCoordinates, setClickedCoordinates] = useState(null);
23
18
  const [bboxCoordinates, setBboxcoordinates] = useState(null);
24
19
  const [zoomLevel, setZoomLevel] = useState(null);
25
20
  const [mapScale, setMapScale] = useState(null);
21
+ const [mapResolution, setMapResolution] = useState(null);
26
22
  const [srid, setSrid] = useState(null);
27
23
 
28
24
  //geolocations
@@ -36,9 +32,7 @@ export const MapsProvider = ({ children }) => {
36
32
  //layers
37
33
  const [displayedLayers, setDisplayedLayers] = useState([]);
38
34
  const [activeLayer, setActiveLayer] = useState(null);
39
- const [layerLabels, setLayerLabels] = useState([]); //layer list to be displayed on UI
40
- //preselected layers - shortcut to displayed layers (the pills)
41
- const [preselectedLayers, setPreselectedLayers] = useState([]);
35
+ const [mapLayers, setMapLayers] = useState(null);
42
36
 
43
37
  const [infoLayerSource, setInfoLayerSource] = useState([]); //layer from info is received
44
38
 
@@ -64,24 +58,46 @@ export const MapsProvider = ({ children }) => {
64
58
  });
65
59
  const data = await response.json();
66
60
  console.log("GetMap", data);
67
-
61
+ setMapId(id);
68
62
  setMapError(false);
69
- setSessionToken(data.message.essionToken);
63
+ setSessionToken(data.message.sessionToken);
70
64
  setMap(
71
65
  `${data.message.iframe}?sessionToken=${data.message.sessionToken}`
72
66
  );
73
- setComponentUrl(data.iframe);
74
67
  return;
75
68
  } catch (error) {
76
69
  console.error("Error fetching map:", error);
77
70
  setSessionToken(null);
78
71
  setMap(null);
79
- setComponentUrl(null);
80
- setMaptoken(null);
72
+ setMapId(null);
81
73
  throw error;
82
74
  }
83
75
  };
84
76
 
77
+ const GetMapInfo = async (id) => {
78
+ let url = `${apiUrl}map/detail/${id}`;
79
+
80
+ try {
81
+ const response = await fetch(url, {
82
+ method: "GET",
83
+ headers: {
84
+ "Content-Type": "application/json",
85
+ Authorization: `Bearer ${token}`,
86
+ },
87
+ });
88
+ const data = await response.json();
89
+ console.log("GetMapInfo", data);
90
+ console.log("Layers", data.message.layers);
91
+ setMapLayers(data.message.layers);
92
+ setConfiguredFilters(data.message.layerFilters);
93
+ return;
94
+ } catch (error) {
95
+ console.error("Error fetching map info:", error);
96
+
97
+ setMapLayers(null);
98
+ throw error;
99
+ }
100
+ };
85
101
  return (
86
102
  <MapsContext.Provider
87
103
  value={{
@@ -89,7 +105,6 @@ export const MapsProvider = ({ children }) => {
89
105
  setMapId,
90
106
  GetMap,
91
107
  map,
92
- mapInfo,
93
108
  sessionToken,
94
109
  mapError,
95
110
  mapReady,
@@ -129,6 +144,10 @@ export const MapsProvider = ({ children }) => {
129
144
  mapScale,
130
145
  setMapScale,
131
146
  setSessionToken,
147
+ mapLayers,
148
+ GetMapInfo,
149
+ mapResolution,
150
+ setMapResolution,
132
151
  }}
133
152
  >
134
153
  {children}
@@ -59,6 +59,7 @@ export const MessageProvider = ({ children }) => {
59
59
 
60
60
  const Filters = (filters) => {
61
61
  if (!communicator) return;
62
+ console.log("messages - Filters", filters);
62
63
  communicator.setFilters(filters);
63
64
  };
64
65
 
@@ -119,12 +120,6 @@ export const MessageProvider = ({ children }) => {
119
120
  communicator.toggleLayer(layer, properties);
120
121
  };
121
122
 
122
- const doSetActiveLayer = (name) => {
123
- if (!communicator) return;
124
- console.log("doSetActiveLayer", { name });
125
- communicator.setActiveLayer(name);
126
- };
127
-
128
123
  const removeLayer = (name) => {
129
124
  if (!communicator) return;
130
125
  console.log("removeLayer", { name });
@@ -0,0 +1,3 @@
1
+ NEXT_PUBLIC_APIURL="https://your api url"
2
+ NEXT_PUBLIC_USER="your user"
3
+ NEXT_PUBLIC_PWD="your password"