Browse Source

Fixing invariant hook errors while rendering markers in OSM

master
GabrielTrettel 3 years ago
parent
commit
d98ad66aa9
  1. 73
      src/app/components/MapMarker.js
  2. 36
      src/app/components/MapMarkerList.js
  3. 29
      src/app/components/MapModal.js
  4. 5
      src/app/components/SelfClosingModal.js
  5. 12
      src/app/components/map/LeafLetMap.js
  6. 62
      src/app/components/map/OpenStreetMap.js
  7. 123
      src/app/hooks/selectFromDB.js
  8. 15
      src/app/screens/MapFeedScreen.js

73
src/app/components/MapMarker.js

@ -1,76 +1,15 @@
import React, { useState } from "react";
import { View, StyleSheet, Image } from "react-native";
import MapView from "react-native-maps";
import colors from "../config/colors";
import { dimensions } from "../config/dimensions";
import React, { useState, useEffect } from "react";
import { View } from "react-native";
import MapModal from "./MapModal"; import MapModal from "./MapModal";
const imageScale = 0.025;
const markerSizeWidth = Math.floor(1667 * imageScale);
const markerSizeHeigth = Math.floor(2501 * imageScale);
export default function MapMarker(props) {
const [isModalVisible, setIsModalVisible] = useState(false);
export default function MapMarker(markerListener, setMarkerListener, markers) {
return ( return (
<MapView.Marker
coordinate={props.coordinate}
onPress={() => setIsModalVisible(!isModalVisible)}
>
<View> <View>
<Image
style={styles.markerPoint}
resizeMode="stretch"
source={props.image}
/>
<MapModal <MapModal
isVisible={isModalVisible}
setIsVisible={setIsModalVisible}
{...props}
markerToRender={}
setMarkerToRender={setIsModalVisible}
markers={markers}
/> />
</View> </View>
</MapView.Marker>
); );
} }
const styles = StyleSheet.create({
title: {
fontWeight: "bold",
fontSize: dimensions.text.secondary,
alignSelf: "center",
paddingBottom: dimensions.spacing.minimal_padding,
},
description: {
fontSize: dimensions.text.default,
},
arrow: {
alignSelf: "center",
borderTopWidth: 15,
borderRightWidth: 10,
borderBottomWidth: 0,
borderLeftWidth: 10,
borderTopColor: colors.lightGray,
borderRightColor: "transparent",
borderBottomColor: "transparent",
borderLeftColor: "transparent",
paddingBottom: 5,
},
container: {
flexDirection: "column",
alignSelf: "center",
backgroundColor: colors.lightestGray,
borderColor: colors.lightGray,
borderRadius: 6,
borderWidth: 4,
borderTopWidth: 2,
padding: dimensions.spacing.minimal_padding,
width: 200,
},
markerPoint: {
alignSelf: "center",
height: markerSizeHeigth,
width: markerSizeWidth,
},
});

36
src/app/components/MapMarkerList.js

@ -1,6 +1,4 @@
import React from "react";
import useMarkers from "../hooks/selectFromDB"; import useMarkers from "../hooks/selectFromDB";
import MapMarker from "../components/MapMarker";
function isRequestedValue( function isRequestedValue(
item, item,
@ -28,25 +26,21 @@ function MapMarkerList({
renderOfficialPluviometer = true, renderOfficialPluviometer = true,
}) { }) {
const markers = useMarkers(reload); const markers = useMarkers(reload);
console.log(markers.markers.size);
return (
<>
{[...markers.markers]
.filter((item) =>
isRequestedValue(
item,
renderRain,
renderFlood,
renderRiver,
renderPluviometer,
renderOfficialPluviometer
)
)
.map(({ ID, ...val }) => {
return <MapMarker key={ID.toString()} {...val} />;
})}
</>
);
// FIXME: Resolve this later!!!
return markers.markers;
// return [...markers.markers].filter(([k, item]) => {
// isRequestedValue(
// item,
// renderRain,
// renderFlood,
// renderRiver,
// renderPluviometer,
// renderOfficialPluviometer
// )
// }
// );
} }
export { MapMarkerList }; export { MapMarkerList };

29
src/app/components/MapModal.js

@ -24,7 +24,7 @@ function notImplemented() {
}); });
} }
function topBar(props) {
function topBar(setMarkerToRender) {
return ( return (
<View style={styles.topBar}> <View style={styles.topBar}>
<TouchableOpacity <TouchableOpacity
@ -53,7 +53,7 @@ function topBar(props) {
<TouchableOpacity <TouchableOpacity
style={styles.topBarIcon} style={styles.topBarIcon}
onPress={() => props.setIsVisible(!props.isVisible)}
onPress={() => setMarkerToRender(null)}
> >
<MaterialCommunityIcons <MaterialCommunityIcons
name="close" name="close"
@ -205,20 +205,29 @@ function isPluviometer(name) {
return name === "pluviometer" || name === "officialPluviometer"; return name === "pluviometer" || name === "officialPluviometer";
} }
function MapModal(props) {
function MapModal({markerToRender, setMarkerToRender, markers}) {
var currentMarker = undefined;
if (markers && markerToRender != null && markers.has(markerToRender)) {
currentMarker = markers.get(markerToRender);
}
if (currentMarker != undefined && markerToRender != null) {
return ( return (
<SelfClosingModal <SelfClosingModal
animationType="slide" animationType="slide"
transparent={true} transparent={true}
visible={props.isVisible}
setVisible={props.setIsVisible}
markerToRender={markerToRender}
setMarkerToRender={setMarkerToRender}
> >
{topBar(props)}
{componentBody(props)}
{isPluviometer(props.name) ? moreInfo(props) : null}
{!isPluviometer(props.name) ? reviews(props) : null}
{topBar(setMarkerToRender)}
{componentBody(currentMarker)}
{isPluviometer(currentMarker.name) ? moreInfo(currentMarker) : null}
{!isPluviometer(currentMarker.name) ? reviews(currentMarker) : null}
</SelfClosingModal> </SelfClosingModal>
);
);}
else {
return null;
}
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({

5
src/app/components/SelfClosingModal.js

@ -8,15 +8,16 @@ import {
import { screen_height, screen_width } from "../config/dimensions"; import { screen_height, screen_width } from "../config/dimensions";
export default function SelfClosingModal(props) { export default function SelfClosingModal(props) {
return ( return (
<View style={styles.centeredView}> <View style={styles.centeredView}>
<Modal <Modal
animationType={props.animationType} animationType={props.animationType}
transparent={props.transparent} transparent={props.transparent}
visible={props.visible}
visible={props.markerToRender != null}
> >
<TouchableWithoutFeedback <TouchableWithoutFeedback
onPress={() => props.setVisible(!props.visible)}
onPress={() => props.setMarkerToRender(null)}
> >
<View style={styles.modalOverlay} /> <View style={styles.modalOverlay} />
</TouchableWithoutFeedback> </TouchableWithoutFeedback>

12
src/app/components/map/LeafLetMap.js

@ -56,12 +56,12 @@ function handleEvent(event) {
return code_to_function[payload.code](payload); return code_to_function[payload.code](payload);
} }
async function insertMarker(mapRef, ID, cords, icon) {
var iconSvg = icon;
async function insertMarker(mapRef, ID, coordinate, icon) {
var iconSvg = `<svg height="100" width="100"> <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> </svg>`;
if (typeof icon !== 'string' && !(icon instanceof String)) {
iconSvg = await loadLocalAsset(icon);
}
// if (typeof icon !== 'string' && !(icon instanceof String)) {
// iconSvg = await loadLocalAsset(icon);
// }
mapRef.injectJavaScript(` mapRef.injectJavaScript(`
var customIcon = L.divIcon({ var customIcon = L.divIcon({
@ -73,7 +73,7 @@ async function insertMarker(mapRef, ID, cords, icon) {
// Check if there is no other marker with same ID already in map // Check if there is no other marker with same ID already in map
if (!(${ID} in markers)) { if (!(${ID} in markers)) {
// Creates marker object // Creates marker object
markers[${ID}] = L.marker([${cords.lat}, ${cords.long}], {icon: customIcon, ID: ${ID}});
markers[${ID}] = L.marker([${coordinate.latitude}, ${coordinate.longitude}], {icon: customIcon, ID: ${ID}});
// Add marker to map and bing callback event to its function // Add marker to map and bing callback event to its function
markers[${ID}].addTo(map).on('click', onPopupClick); markers[${ID}].addTo(map).on('click', onPopupClick);

62
src/app/components/map/OpenStreetMap.js

@ -1,5 +1,5 @@
import React, { useState } from "react";
import { View } from "react-native";
import React, { useState, useEffect } from "react";
import { View, StyleSheet, Text } from "react-native";
import WebView from "react-native-webview"; import WebView from "react-native-webview";
import { import {
loadHTMLFile, loadHTMLFile,
@ -7,14 +7,20 @@ import {
insertMarker, insertMarker,
goToRegion, goToRegion,
} from "./LeafLetMap"; } from "./LeafLetMap";
import MapModal from "../MapModal";
function bindEventsToListeners(event, clickListener, markerListener, moveEndListener) {
function bindEventsToListeners(
event,
clickListener,
setMarkerListener,
moveEndListener
) {
switch (event.object) { switch (event.object) {
case "click": case "click":
clickListener && clickListener(event.cords); clickListener && clickListener(event.cords);
break; break;
case "marker": case "marker":
markerListener && markerListener(event.id);
setMarkerListener(event.id);
break; break;
case "moveend": case "moveend":
moveEndListener && moveEndListener(event.id); moveEndListener && moveEndListener(event.id);
@ -24,25 +30,29 @@ function bindEventsToListeners(event, clickListener, markerListener, moveEndList
} }
} }
function notEmpy(lista) {
return lista && lista.size > 0;
}
export default function OpenStreetMap({ export default function OpenStreetMap({
markersList, markersList,
animateToPosition, animateToPosition,
clickListener, clickListener,
markerListener,
moveEndListener, moveEndListener,
}) { }) {
const [mapRef, setMapRef] = useState(null); const [mapRef, setMapRef] = useState(null);
const [webviewContent, setWebviewContent] = useState(null); const [webviewContent, setWebviewContent] = useState(null);
const [markerListener, setMarkerListener] = useState(null);
if (mapRef != null) { if (mapRef != null) {
animateToPosition != null && goToRegion(mapRef, animateToPosition); animateToPosition != null && goToRegion(mapRef, animateToPosition);
markersList != null &&
markersList.length > 0 &&
markersList.map(({ ID, cords, icon }) =>
insertMarker(mapRef, ID, cords, icon)
);
} }
markersList &&
mapRef &&
notEmpy(markersList) &&
markersList.forEach((val, key) => {
insertMarker(mapRef, val.ID, val.coordinate, val.icon);
});
loadHTMLFile() loadHTMLFile()
.then((html) => setWebviewContent(html)) .then((html) => setWebviewContent(html))
@ -58,13 +68,39 @@ export default function OpenStreetMap({
bindEventsToListeners( bindEventsToListeners(
handleEvent(event), handleEvent(event),
clickListener, clickListener,
markerListener,
moveEndListener,
setMarkerListener,
moveEndListener
); );
}} }}
javaScriptEnabled={true} javaScriptEnabled={true}
source={{ html: webviewContent }} source={{ html: webviewContent }}
/> />
<View>
<MapModal
markerToRender={markerListener}
setMarkerToRender={setMarkerListener}
markers={markersList}
/>
</View>
<View style={styles.callback}>
<Text style={styles.txt}>{markerListener}</Text>
</View>
</View> </View>
); );
} }
const styles = StyleSheet.create({
callback: {
position: "absolute",
top: 30,
alignSelf: "center",
alignItems: "center",
backgroundColor: "gray",
width: "80%",
padding: 10,
},
txt: {
color: "white",
},
});

123
src/app/hooks/selectFromDB.js

@ -194,21 +194,22 @@ function genericSelect(queriesToParsersMapper, dispatch, isFocused) {
}, [isFocused]); }, [isFocused]);
} }
const initialState = { markers: new Set() };
const initialState = { markers: new Map() };
function reducer(state = initialState, action) { function reducer(state = initialState, action) {
// NOTE: removing old pluviometer value to new data can be displayed // NOTE: removing old pluviometer value to new data can be displayed
state.markers.forEach((m) => {
state.markers.forEach((m, key) => {
if (m.name == "pluviometer" || m.name == "officialPluviometer") { if (m.name == "pluviometer" || m.name == "officialPluviometer") {
state.markers.delete(m);
state.markers.delete(key);
} }
}); });
action.increment.map((val) => { action.increment.map((val) => {
state.markers.add(val);
if (!state.markers.has(val.ID)) {
state.markers.set(val.ID, val);
}
}); });
console.log(state.markers);
return { return {
markers: state.markers, markers: state.markers,
}; };
@ -278,67 +279,67 @@ function useMarkers(isFocused) {
const location = context.currentCoordinates; const location = context.currentCoordinates;
const addr = context.currentLocation; const addr = context.currentLocation;
const parseOfficialPluviometers = () => {
return buildRandonData(location, addr);
};
const parsePluviometer = (db_result) => {
// if (db_result.rows.length <= 0) return [];
const points = [];
const info = {
pictures: "[]",
description: "",
date: "",
};
for (let i = 0; i < db_result.rows.length; ++i) {
var row = db_result.rows.item(i);
description = row["Description"] ? "\n\n" + row["Description"] : "";
info.date = row["Date"];
info.description =
row["Precipitation"] + "mm" + ", " + row["Date"] + description;
info.pictures = row["Images"];
points.push([row["Date"].slice(0, 5), parseInt(row["Precipitation"])]);
}
latestPoints = points.sort(compare).slice(-7);
if (latestPoints.length == 0) {
var labels = [];
var values = [];
}
var labels = latestPoints.map((i) => {
return i[0];
});
var values = latestPoints.map((i) => {
return i[1];
});
const result = {
image: custom_assets_pin.pluviometer,
logo: custom_assets.pluviometer,
ID: ++ID,
name: "pluviometer",
title: "Pluviometro 1",
coordinate: location,
address: addr,
data: {
labels: labels,
values: values,
},
...info,
};
return [result, ...parseOfficialPluviometers()];
};
// const parseOfficialPluviometers = () => {
// return buildRandonData(location, addr);
// };
// const parsePluviometer = (db_result) => {
// // if (db_result.rows.length <= 0) return [];
// const points = [];
// const info = {
// pictures: "[]",
// description: "",
// date: "",
// };
// for (let i = 0; i < db_result.rows.length; ++i) {
// var row = db_result.rows.item(i);
// description = row["Description"] ? "\n\n" + row["Description"] : "";
// info.date = row["Date"];
// info.description =
// row["Precipitation"] + "mm" + ", " + row["Date"] + description;
// info.pictures = row["Images"];
// points.push([row["Date"].slice(0, 5), parseInt(row["Precipitation"])]);
// }
// latestPoints = points.sort(compare).slice(-7);
// if (latestPoints.length == 0) {
// var labels = [];
// var values = [];
// }
// var labels = latestPoints.map((i) => {
// return i[0];
// });
// var values = latestPoints.map((i) => {
// return i[1];
// });
// const result = {
// image: custom_assets_pin.pluviometer,
// logo: custom_assets.pluviometer,
// ID: ++ID,
// name: "pluviometer",
// title: "Pluviometro 1",
// coordinate: location,
// address: addr,
// data: {
// labels: labels,
// values: values,
// },
// ...info,
// };
// return [result, ...parseOfficialPluviometers()];
// };
const queriesToParsersMapper = [ const queriesToParsersMapper = [
["SELECT * FROM FloodZones;", parseFloodZones, false], ["SELECT * FROM FloodZones;", parseFloodZones, false],
["SELECT * FROM RiverLevel;", parseRiverLevel, false], ["SELECT * FROM RiverLevel;", parseRiverLevel, false],
["SELECT * FROM RainLevel;", parseRainLevel, false], ["SELECT * FROM RainLevel;", parseRainLevel, false],
["SELECT * FROM PluviometerData;", parsePluviometer, true],
// ["SELECT * FROM PluviometerData;", parsePluviometer, true],
]; ];
genericSelect(queriesToParsersMapper, dispatch, isFocused); genericSelect(queriesToParsersMapper, dispatch, isFocused);

15
src/app/screens/MapFeedScreen.js

@ -1,15 +1,17 @@
import React, { useState, useEffect, useContext } from "react"; import React, { useState, useEffect, useContext } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
import { StyleSheet, Text, View } from "react-native";
import OpenStreetMap from "../components/map/OpenStreetMap"; import OpenStreetMap from "../components/map/OpenStreetMap";
import { CurrentLocationContext } from "../context/CurrentLocationContext"; import { CurrentLocationContext } from "../context/CurrentLocationContext";
import attachFocusToQuery from "../hooks/useFocus";
import {MapMarkerList} from "../components/MapMarkerList";
export default function MapFeedScreen() { export default function MapFeedScreen() {
const [position, setPosition] = useState(null); const [position, setPosition] = useState(null);
const [clickListener, setClickListener] = useState("");
const [markerListener, setMarkerListener] = useState("");
const context = useContext(CurrentLocationContext); const context = useContext(CurrentLocationContext);
const location = context.currentCoordinates; const location = context.currentCoordinates;
const focusChanged = attachFocusToQuery();
useEffect(() => { useEffect(() => {
setPosition({ setPosition({
@ -23,15 +25,10 @@ export default function MapFeedScreen() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<OpenStreetMap <OpenStreetMap
markersList={MapMarkerList({reload:focusChanged, renderRain:true})}
animateToPosition={position} animateToPosition={position}
clickListener={setClickListener}
markerListener={setMarkerListener}
/> />
<View style={styles.callback}>
<Text style={styles.txt}>{JSON.stringify(clickListener)}</Text>
<Text style={styles.txt}>{JSON.stringify(markerListener)}</Text>
</View>
</View> </View>
); );
} }

Loading…
Cancel
Save