diff options
Diffstat (limited to 'src/Components/Map.tsx')
-rw-r--r-- | src/Components/Map.tsx | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/Components/Map.tsx b/src/Components/Map.tsx new file mode 100644 index 0000000..3e878f8 --- /dev/null +++ b/src/Components/Map.tsx @@ -0,0 +1,180 @@ +import React, { Component } from 'react'; +import { StyleSheet, View, Dimensions, ActivityIndicator } from 'react-native'; +import MapView, { Marker, Region, UrlTile } from 'react-native-maps'; +import { connect } from 'redux-su'; +import { NavigationActions } from 'react-navigation'; + +import MapOverlay from './MapOverlay'; +import MapObjects from './MapObjects'; +import PortalPanel from './PortalPanel'; +import { getBottomSpace } from '../helper'; +import actions from '../Actions/actions'; +import { LatLng } from '../Api/interfaces'; + +const { width, height } = Dimensions.get("screen") +const draggableRange = { + top: height / 1.75, + bottom: 120 + getBottomSpace() +} + +type Props = any +type State = any +class Map extends Component<Props, State> { + refresh: number | undefined + map!: MapView; + constructor(props: Props) { + super(props) + this.state = { + user: undefined, + followUser: true, + zoom: 15, + region: null, + loading: false, + objects: { links: {}, fields: {}, portals: {}, loaded: false }, + } + } + componentWillMount() { + navigator.geolocation.getCurrentPosition( + position => { + this.setState({ + followUser: true, + }); + }, + error => alert(error.message), + { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } + ); + navigator.geolocation.watchPosition( + position => { + this.setState({ + user: { + latitude: position.coords.latitude, + longitude: position.coords.longitude + }, + }); + }, + error => alert(error.message), + { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } + ) + } + onRegionChange = (region: Region) => { + const zoom = this.getZoomByRegion(width, region) + this.setState({ region, zoom }) + setImmediate(() => this.load(false)) + } + getZoomByRegion(width: number, region: Region): number { + return Math.ceil(Math.log2(360 * ((width / 256) / region.longitudeDelta))) + 1 + } + load = async (refresh: boolean) => { + if (this.state.region != null && this.props.entities.loading == 0) { + this.props.actions.update(this.state.region, width, refresh) + } + return null + } + + refreshByTime = () => { + setTimeout(() => { + this.load(true).then(this.refreshByTime) + }, 30000) + } + + componentDidMount() { + this.refreshByTime() + } + + onPortalClick = (guid: string, coords: LatLng) => { + this.setState({ selectedPortal: { guid, coords } }) + } + + onOpenPortal = (guid: string, coords: LatLng) => { + const navigateAction = NavigationActions.navigate({ + routeName: 'Portal', + params: { guid, coords }, + }); + this.props.navigation.dispatch(navigateAction); + } + + render() { + if (!this.state.user) { + return <View style={styles.spinnerContainer}><ActivityIndicator size={'large'} /></View> + } + const camera = { + center: this.state.user, + altitude: 1000, + heading: 0, + pitch: 30, + zoom: 15, + } + const goToMe = () => { + this.map.animateToCoordinate(this.state.user) + } + const refresh = () => { + setImmediate(() => this.load(true)) + } + return ( + <> + <MapView + ref={r => (r != null) ? this.map = r : null} + style={styles.container} + initialRegion={{ ...this.state.user, latitudeDelta: 0.002, longitudeDelta: 0.002 }} + onRegionChangeComplete={this.onRegionChange} + showsCompass={false} + showsScale + showsUserLocation + showsMyLocationButton + loadingEnabled + type={'hybrid'} + > + <MapObjects onPortalClick={this.onPortalClick} zoom={this.state.zoom} /> + {this.state.selectedPortal && <Marker coordinate={this.state.selectedPortal.coords} />} + </MapView> + <MapOverlay + goToMe={goToMe} + refresh={refresh} + loading={this.props.entities.loading} + selectedPortal={this.state.selectedPortal} + onOpenPortal={this.onOpenPortal} + /> + </> + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + spinnerContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + panel: { + flex: 1, + backgroundColor: '#fff', + position: 'relative', + borderTopLeftRadius: 20, + borderTopRightRadius: 20, + //ios + shadowOpacity: 0.3, + shadowRadius: 3, + shadowOffset: { + height: 0, + width: 0 + }, + //android + elevation: 1 + }, + panelHeader: { + height: 40, + alignItems: 'center', + justifyContent: 'center', + }, + dash: { + backgroundColor: 'rgba(200,200,200,0.9)', + height: 6, + width: 30, + borderRadius: 3 + } +}); + +export default connect({ 'entities': 'entities' }, actions)(Map)
\ No newline at end of file |