forked from cemaden-educacao/WPD-MobileApp
GabrielTrettel
4 years ago
4 changed files with 240 additions and 59 deletions
-
68src/app/components/map/Map.html
-
90src/app/components/map/OpenStreetMap.js
-
138src/app/screens/MapFeedScreen.js
-
3src/package.json
@ -0,0 +1,68 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Mobile tutorial - Leaflet</title> |
||||
|
<meta charset="utf-8" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
|
|
||||
|
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" /> |
||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/> |
||||
|
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script> |
||||
|
<style> |
||||
|
html, body { |
||||
|
height: 100%; |
||||
|
margin: 0; |
||||
|
} |
||||
|
#map { |
||||
|
width: 600px; |
||||
|
height: 400px; |
||||
|
} |
||||
|
</style> |
||||
|
<style>body { padding: 0; margin: 0; } #map { height: 100%; width: 100vw; }</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id='map'></div> |
||||
|
<script> |
||||
|
var mymap = L.map('map').setView([51.505, -0.09], 13); |
||||
|
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoiZ2FicmllbC10cmV0dGVsIiwiYSI6ImNrb2RjNWIzYjAwczIyd25yNnUweDNveTkifQ.xRASmGTYm0ieS-FjVrXSjA', { |
||||
|
maxZoom: 18, |
||||
|
attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, ' + |
||||
|
'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>', |
||||
|
id: 'mapbox/streets-v11', |
||||
|
tileSize: 512, |
||||
|
zoomOffset: -1 |
||||
|
}).addTo(mymap); |
||||
|
L.circle([51.508, -0.11], 500, { |
||||
|
color: 'red', |
||||
|
fillColor: '#f03', |
||||
|
fillOpacity: 0.5 |
||||
|
}).addTo(mymap).bindPopup("I am a circle."); |
||||
|
L.polygon([ |
||||
|
[51.509, -0.08], |
||||
|
[51.503, -0.06], |
||||
|
[51.51, -0.047] |
||||
|
]).addTo(mymap).bindPopup("I am a polygon."); |
||||
|
var popup = L.popup(); |
||||
|
function onMapClick(e) { |
||||
|
var payload = { |
||||
|
code: 1, |
||||
|
content: { |
||||
|
latitude: e.latlng.lat.toString().slice(0,8), |
||||
|
longitude: e.latlng.lng.toString().slice(0,8), |
||||
|
} |
||||
|
} |
||||
|
window.ReactNativeWebView.postMessage(JSON.stringify(payload)); |
||||
|
} |
||||
|
function onPopupClick(e) { |
||||
|
var payload = { |
||||
|
code: 2, |
||||
|
content: "marker selecionado" |
||||
|
} |
||||
|
window.ReactNativeWebView.postMessage(JSON.stringify(payload)); |
||||
|
} |
||||
|
mymap.on("popupopen", onPopupClick); |
||||
|
mymap.on('click', onMapClick); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
||||
|
|
@ -0,0 +1,90 @@ |
|||||
|
import React, { useEffect, useState } from "react"; |
||||
|
import { View } from "react-native"; |
||||
|
import WebView from "react-native-webview"; |
||||
|
import { Asset } from "expo-asset"; |
||||
|
import * as FileSystem from "expo-file-system"; |
||||
|
|
||||
|
const HTML_FILE_PATH = require(`./Map.html`); |
||||
|
|
||||
|
const loadHTMLFile = async () => { |
||||
|
try { |
||||
|
const [{ localUri }] = await Asset.loadAsync(HTML_FILE_PATH); |
||||
|
const fileString = await FileSystem.readAsStringAsync(localUri); |
||||
|
|
||||
|
return fileString; |
||||
|
} catch (error) { |
||||
|
console.warn(error); |
||||
|
console.warn("Unable to resolve index file"); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const code_to_function = { |
||||
|
"1": clickCallback, |
||||
|
"2": clickCallback, |
||||
|
}; |
||||
|
|
||||
|
function clickCallback(payload, props) { |
||||
|
console.log(payload.content); |
||||
|
props.clickListener(JSON.stringify(payload.content)); |
||||
|
} |
||||
|
|
||||
|
function parseInput(event, props) { |
||||
|
// console.log(event);
|
||||
|
const payload = JSON.parse(event); |
||||
|
// console.log(payload);
|
||||
|
|
||||
|
code_to_function[payload.code](payload, props); |
||||
|
} |
||||
|
|
||||
|
function insertMarker(mapRef, props) { |
||||
|
console.log(props); |
||||
|
mapRef.injectJavaScript(`
|
||||
|
var layer = L.marker([${props.cords.lat}, ${props.cords.long}], {ID: ${props.ID}} ) |
||||
|
layer.ID = ${props.ID} |
||||
|
layer.addTo(mymap).bindPopup("<b>${props.title}</b><br />I am a popup.");`);
|
||||
|
} |
||||
|
|
||||
|
function goToPosition(mapRef, lat, long) { |
||||
|
mapRef.injectJavaScript(`mymap.setView([${lat}, ${long}], 13);`); |
||||
|
} |
||||
|
|
||||
|
export default function OpenStreetMap(props) { |
||||
|
const [mapRef, setMapRef] = useState(null); |
||||
|
const [finishedLoad, setFinishedLoad] = useState(false); |
||||
|
const [webviewContent, setWebviewContent] = useState(null); |
||||
|
|
||||
|
loadHTMLFile() |
||||
|
.then((html) => setWebviewContent(html)) |
||||
|
.catch((e) => console.warn(e)); |
||||
|
|
||||
|
props.animateToPosition != null && |
||||
|
goToPosition(mapRef, ...props.animateToPosition); |
||||
|
|
||||
|
const onLoad = () => { |
||||
|
props.markersList != null && |
||||
|
props.markersList.length > 0 && |
||||
|
props.markersList.map((m) => insertMarker(mapRef, m)); |
||||
|
}; |
||||
|
|
||||
|
useEffect(() => { |
||||
|
mapRef != null && onLoad(); |
||||
|
}, [finishedLoad]); |
||||
|
|
||||
|
return ( |
||||
|
<View flex={1}> |
||||
|
<WebView |
||||
|
ref={(webViewRef) => { |
||||
|
setMapRef(webViewRef); |
||||
|
}} |
||||
|
onMessage={(event) => { |
||||
|
parseInput(event.nativeEvent.data, props); |
||||
|
}} |
||||
|
javaScriptEnabled={true} |
||||
|
source={{ html: webviewContent }} |
||||
|
onLoad={() => { |
||||
|
setFinishedLoad(true); |
||||
|
}} |
||||
|
/> |
||||
|
</View> |
||||
|
); |
||||
|
} |
@ -1,74 +1,96 @@ |
|||||
import React, { useContext } from "react"; |
|
||||
import { StyleSheet, View } from "react-native"; |
|
||||
import MapView from "react-native-maps"; |
|
||||
|
import React, { useRef, useState } from "react"; |
||||
|
import { Button, StyleSheet, Text, TouchableOpacity, View } from "react-native"; |
||||
|
import OpenStreetMap from "../components/map/OpenStreetMap"; |
||||
|
|
||||
import colors from "../config/colors"; |
|
||||
import { screen_width, screen_height } from "../config/dimensions"; |
|
||||
import attachFocusToQuery from "../hooks/useFocus"; |
|
||||
import { CurrentLocationContext } from "../context/CurrentLocationContext"; |
|
||||
import { MapMarkerList } from "../components/MapMarkerList"; |
|
||||
import FloatButton from "../components/FloatButton"; |
|
||||
import { MapDataContext } from "../context/MapDataContext"; |
|
||||
import MapPolygons from "../components/MapPolygons"; |
|
||||
|
export default function MapFeedScreen() { |
||||
|
const [position, setPosition] = useState(null); |
||||
|
const [clickListener, setClickListener] = useState(""); |
||||
|
|
||||
function MapFeedScreen(props) { |
|
||||
const context = useContext(CurrentLocationContext); |
|
||||
const datas = useContext(MapDataContext); |
|
||||
const location = context.currentCoordinates; |
|
||||
const focusChanged = attachFocusToQuery(); |
|
||||
|
const markers = [ |
||||
|
{ |
||||
|
ID: "1", |
||||
|
title: "Casa da Lívia", |
||||
|
cords: { |
||||
|
lat: 51.505, |
||||
|
long: -0.09, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
ID: "2", |
||||
|
title: "Casa do Daniel", |
||||
|
cords: { |
||||
|
lat: 51.5032, |
||||
|
long: -0.09589, |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
return ( |
||||
|
<View style={styles.container}> |
||||
|
<OpenStreetMap |
||||
|
animateToPosition={position} |
||||
|
clickListener={setClickListener} |
||||
|
markersList={markers} |
||||
|
/> |
||||
|
|
||||
const default_location = { |
|
||||
latitude: -12.901799, |
|
||||
longitude: -51.692116, |
|
||||
latitudeDelta: 70, |
|
||||
longitudeDelta: 70 * (screen_width / screen_height), |
|
||||
}; |
|
||||
|
<View style={styles.btn}> |
||||
|
<TouchableOpacity |
||||
|
style={styles.btns} |
||||
|
onPress={() => { |
||||
|
setPosition([-23.644957, -46.528012]); |
||||
|
}} |
||||
|
> |
||||
|
<Text style={styles.txt}>UFABC</Text> |
||||
|
</TouchableOpacity> |
||||
|
|
||||
const map_scale = 0.003; |
|
||||
const lat_long_delta = { |
|
||||
latitudeDelta: map_scale, |
|
||||
longitudeDelta: map_scale * (screen_width / screen_height), |
|
||||
}; |
|
||||
|
<TouchableOpacity |
||||
|
style={styles.btns} |
||||
|
onPress={() => { |
||||
|
setPosition([51.505, -0.09]); |
||||
|
}} |
||||
|
> |
||||
|
<Text style={styles.txt}>Londres</Text> |
||||
|
</TouchableOpacity> |
||||
|
</View> |
||||
|
|
||||
return ( |
|
||||
<View style={styles.container}> |
|
||||
<MapView |
|
||||
style={styles.mapStyle} |
|
||||
showsUserLocation={true} |
|
||||
initialRegion={{ ...default_location }} |
|
||||
region={{ |
|
||||
latitude: location["latitude"], |
|
||||
longitude: location["longitude"], |
|
||||
...lat_long_delta, |
|
||||
}} |
|
||||
> |
|
||||
<MapMarkerList |
|
||||
reload={focusChanged} |
|
||||
renderRain={datas.rain} |
|
||||
renderFlood={datas.flood} |
|
||||
renderPluviometer={datas.pluviometer} |
|
||||
renderRiver={datas.river} |
|
||||
renderOfficialPluviometer={datas.officialPluviometer} |
|
||||
/> |
|
||||
{datas.floodAreas && <MapPolygons />} |
|
||||
</MapView> |
|
||||
<FloatButton /> |
|
||||
|
<View style={styles.callback}> |
||||
|
<Text style={styles.txt}>{clickListener}</Text> |
||||
|
</View> |
||||
</View> |
</View> |
||||
); |
); |
||||
} |
} |
||||
|
|
||||
const styles = StyleSheet.create({ |
const styles = StyleSheet.create({ |
||||
container: { |
container: { |
||||
backgroundColor: colors.black, |
|
||||
flex: 1, |
flex: 1, |
||||
|
backgroundColor: "#FFF", |
||||
}, |
}, |
||||
mapStyle: { |
|
||||
|
callback: { |
||||
position: "absolute", |
position: "absolute", |
||||
top: 0, |
|
||||
left: 0, |
|
||||
right: 0, |
|
||||
bottom: 0, |
|
||||
|
bottom: 30, |
||||
|
alignSelf: "center", |
||||
|
alignItems: "center", |
||||
|
backgroundColor: "gray", |
||||
|
width: "80%", |
||||
|
padding: 10, |
||||
|
}, |
||||
|
btn: { |
||||
|
width: "80%", |
||||
|
position: "absolute", |
||||
|
top: 30, |
||||
|
flexDirection: "row", |
||||
|
justifyContent: "space-evenly", |
||||
|
alignItems: "center", |
||||
|
alignSelf: "center", |
||||
|
}, |
||||
|
btns: { |
||||
|
backgroundColor: "dodgerblue", |
||||
|
borderRadius: 10, |
||||
|
width: 100, |
||||
|
padding: 10, |
||||
|
margin: 4, |
||||
|
alignItems: "center", |
||||
|
}, |
||||
|
txt: { |
||||
|
color: "white", |
||||
}, |
}, |
||||
}); |
}); |
||||
|
|
||||
export default MapFeedScreen; |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue