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> |
|||
); |
|||
} |
|||
|
|||
const styles = StyleSheet.create({ |
|||
container: { |
|||
backgroundColor: colors.black, |
|||
flex: 1, |
|||
backgroundColor: "#FFF", |
|||
}, |
|||
mapStyle: { |
|||
callback: { |
|||
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