From 06645cdac4184f5c1cf50f2a4b94be3d72d634f0 Mon Sep 17 00:00:00 2001 From: Alexander NeonXP Kiryukhin Date: Mon, 10 Jun 2019 03:15:51 +0300 Subject: More improvements --- src/Actions/actions.ts | 2 + src/Actions/entity.ts | 13 ++++- src/Actions/settings.ts | 11 ++++ src/Api/api.ts | 8 +-- src/Components/Map.tsx | 29 ++++++++-- src/Components/MapObjects.tsx | 128 +++++++++++++++++++++++++----------------- src/Components/MapOverlay.tsx | 53 +++++++++++++---- src/Components/Settings.tsx | 32 +++++++++-- src/Store/store.ts | 50 ++++++++++++++--- src/constants.ts | 4 ++ src/helper.js | 23 +++++++- 11 files changed, 265 insertions(+), 88 deletions(-) create mode 100644 src/Actions/settings.ts (limited to 'src') diff --git a/src/Actions/actions.ts b/src/Actions/actions.ts index 988ba65..62abb96 100644 --- a/src/Actions/actions.ts +++ b/src/Actions/actions.ts @@ -1,9 +1,11 @@ import auth from './auth' import entity from './entity' +import settings from './settings'; export const actions = { ...auth, ...entity, + ...settings, } export default actions \ No newline at end of file diff --git a/src/Actions/entity.ts b/src/Actions/entity.ts index d23022a..8b01ea6 100644 --- a/src/Actions/entity.ts +++ b/src/Actions/entity.ts @@ -9,7 +9,7 @@ const entity = { 'update': (region: Region, width: number, refresh: boolean) => async (dispatch, getStore) => { const store = getStore() const queue = store.entities.loadQueue - const loadedAlready = refresh ? + const loadedAlready = !refresh ? [ ...Object.keys(store.entities.portals), ...queue, @@ -18,6 +18,7 @@ const entity = { dispatch(entity.setLoadQueue([...queue, ...tiles])) setImmediate(() => dispatch(entity.loadRutine())) }, + 'loadRutine': () => async (dispatch, getStore) => { const store = getStore() const queue = store.entities.loadQueue @@ -27,6 +28,8 @@ const entity = { loadTiles(chunk, params) .then(({ result, failed }) => { const queue = store.entities.loadQueue + dispatch(entity.linksGC(result.linksByTile)) + dispatch(entity.fieldsGC(result.fieldsByTile)) dispatch(entity.portalsSet(result.portals)) dispatch(entity.linksSet(result.links)) dispatch(entity.fieldsSet(result.fields)) @@ -73,6 +76,14 @@ const entity = { type: 'linksSet', links, }), + 'linksGC': (links: { [tile: string]: string[] }) => ({ + type: 'linksGC', + links, + }), + 'fieldsGC': (fields: { [tile: string]: string[] }) => ({ + type: 'fieldsGC', + fields, + }), 'fieldsSet': (fields: { [guid: string]: Field }) => ({ type: 'fieldsSet', fields, diff --git a/src/Actions/settings.ts b/src/Actions/settings.ts new file mode 100644 index 0000000..8dfc3fc --- /dev/null +++ b/src/Actions/settings.ts @@ -0,0 +1,11 @@ +const settings = { + 'setLevelFrom': (level: Number) => ({ + type: 'setLevelFrom', + level + }), + 'setLevelTo': (level: Number) => ({ + type: 'setLevelTo', + level + }) +} +export default settings \ No newline at end of file diff --git a/src/Api/api.ts b/src/Api/api.ts index 4c83252..1fd9435 100644 --- a/src/Api/api.ts +++ b/src/Api/api.ts @@ -153,11 +153,11 @@ const pointToTileId = (x: number, y: number, params: TileParameters): string => return params.zoom + "_" + x + "_" + y + "_" + params.level + "_8_100"; } -const getZoomByRegion = (width: number, region: Region): number => { +export const getZoomByRegion = (width: number, region: Region): number => { return Math.ceil(Math.log2(360 * ((width / 256) / region.longitudeDelta))) + 1 } -const getDataZoomForMapZoom = (zoom: number): number => { +export const getDataZoomForMapZoom = (zoom: number): number => { if (zoom > 21) { zoom = 21; } @@ -223,9 +223,9 @@ const getEntities = (tileKeys: string[], params: RequestParams): Promise { + return timeout(30000, promise.then(async r => { if (r.status != 200) { - return { result: { map: {} } } + throw Error(r.statusText) } return r.json() })) diff --git a/src/Components/Map.tsx b/src/Components/Map.tsx index bb0b660..db0bed9 100644 --- a/src/Components/Map.tsx +++ b/src/Components/Map.tsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { StyleSheet, View, Dimensions, ActivityIndicator } from 'react-native'; -import MapView, { Marker, Region, UrlTile } from 'react-native-maps'; +import MapView, { Marker, Region } from 'react-native-maps'; import { connect } from 'redux-su'; import { NavigationActions } from 'react-navigation'; @@ -10,6 +10,7 @@ import PortalPanel from './PortalPanel'; import { getBottomSpace } from '../helper'; import actions from '../Actions/actions'; import { LatLng } from '../Api/interfaces'; +import { getZoomByRegion, getDataZoomForMapZoom } from '../Api/api'; const { width, height } = Dimensions.get("screen") const draggableRange = { @@ -32,6 +33,7 @@ class Map extends Component { this.state = { user: undefined, region: null, + dataZoom: 15, } } componentDidMount() { @@ -63,7 +65,9 @@ class Map extends Component { ) } onRegionChange = (region: Region) => { - this.setState({ region }) + const zoom = getZoomByRegion(width, region) + const dataZoom = getDataZoomForMapZoom(zoom); + this.setState({ region, dataZoom }) setImmediate(() => this.load(false)) } @@ -79,7 +83,15 @@ class Map extends Component { } onPortalClick = (guid: string, coords: LatLng) => { - this.setState({ selectedPortal: { guid, coords } }) + if (this.state.selectedPortal && this.state.selectedPortal.guid == guid) { + this.setState({ selectedPortal: false }) + } else { + this.setState({ selectedPortal: { guid, coords } }) + } + } + + onPortalDismiss = () => { + this.setState({ selectedPortal: false }) } onOpenPortal = (guid: string, coords: LatLng) => { @@ -115,8 +127,13 @@ class Map extends Component { shouldRasterizeIOS renderToHardwareTextureAndroid > - - {this.state.selectedPortal && } + + {this.state.selectedPortal && } { @@ -31,60 +52,18 @@ class MapObjects extends PureComponent { const fields = this.props.fields const links = this.props.links const zoom = this.props.zoom - const renderPortal = Object.keys(portals) - .filter(guid => portals[guid].coords.latitude > lat1 && portals[guid].coords.latitude < lat2 && portals[guid].coords.longitude > lng1 && portals[guid].coords.longitude < lng2) - .map(guid => this.drawPortal(guid, portals[guid], this.props.onPortalClick)) - const renderLink = Object.keys(links) - .filter(guid => { - const l1 = links[guid].coords[0].latitude - const l2 = links[guid].coords[1].latitude - const n1 = links[guid].coords[0].longitude - const n2 = links[guid].coords[1].longitude - return !(l1 < lat1 && l2 < lat1 || l1 > lat2 && l2 > lat2 || n1 < lng1 && n2 < lng1 || n1 > lng2 && n2 > lng2) - }) - .map(guid => this.drawLink(guid, links[guid])) - const renderField = Object.keys(fields) - .filter(guid => { - const l1 = fields[guid].coords[0].latitude - const l2 = fields[guid].coords[1].latitude - const l3 = fields[guid].coords[2].latitude - const n1 = fields[guid].coords[0].longitude - const n2 = fields[guid].coords[1].longitude - const n3 = fields[guid].coords[2].longitude - return !( - l1 < lat1 && l2 < lat1 && l3 < lat1 || l1 > lat2 && l2 > lat2 && l3 > lat2 || - n1 < lng1 && n2 < lng1 && n3 < lng1 || n1 > lng2 && n2 > lng2 && n3 > lng2 - ) - }) - .map(guid => this.drawField(guid, fields[guid])) - - if (zoom <= 14) { - return [...renderField, ...renderLink] - } else { - return [...renderField, ...renderLink, ...renderPortal] - } + const renderPortal = this.props.renderPortal.map(guid => this.drawPortal(guid, portals[guid], this.props.onPortalClick)) + const renderLink = this.props.renderLink.map(guid => this.drawLink(guid, links[guid])) + const renderField = this.props.renderField.map(guid => this.drawField(guid, fields[guid])) + return [...renderField, ...renderLink, ...renderPortal] } drawPortal = (guid: string, entity: Portal, onPortalClick: Function) => { - const size = 20 return ( onPortalClick(guid, entity.coords)} - > - {/* */} - - {entity.level} - - ); + image={PORTALS[entity.fraction + entity.level]} + />); } drawField = (guid: string, entity: Field) => { return ({ portals: store.entities.portals, fields: store.entities.fields, links: store.entities.links }), {})(MapObjects) \ No newline at end of file +export default connect((store, props: Props) => { + const region = props.region + const lat1 = region.latitude - region.latitudeDelta / 2 + const lat2 = region.latitude + region.latitudeDelta / 2 + const lng1 = region.longitude - region.longitudeDelta / 2 + const lng2 = region.longitude + region.longitudeDelta / 2 + const minlvl = DEFAULT_ZOOM_TO_LEVEL[Math.min(props.zoom - 1, DEFAULT_ZOOM_TO_LEVEL.length - 1)] + const minlen = DEFAULT_ZOOM_TO_LINK_LENGTH[Math.min(props.zoom - 1, DEFAULT_ZOOM_TO_LINK_LENGTH.length - 1)] / 1000 + const renderPortal = Object + .keys(store.entities.portals) + .filter(guid => store.entities.portals[guid].level >= props.levels[0] && store.entities.portals[guid].level <= props.levels[1]) + .filter(guid => store.entities.portals[guid].coords.latitude > lat1 && store.entities.portals[guid].coords.latitude < lat2 && store.entities.portals[guid].coords.longitude > lng1 && store.entities.portals[guid].coords.longitude < lng2) + + const renderLink = Object + .keys(store.entities.links) + .filter(guid => { + const l1 = store.entities.links[guid].coords[0].latitude + const l2 = store.entities.links[guid].coords[1].latitude + const n1 = store.entities.links[guid].coords[0].longitude + const n2 = store.entities.links[guid].coords[1].longitude + return !(l1 < lat1 && l2 < lat1 || l1 > lat2 && l2 > lat2 || n1 < lng1 && n2 < lng1 || n1 > lng2 && n2 > lng2) && calcCrow(l1, n1, l2, n2) >= minlen + }) + //.map(guid => this.drawLink(guid, links[guid])) + const renderField = Object + .keys(store.entities.fields) + .filter(guid => { + const l1 = store.entities.fields[guid].coords[0].guid + const l2 = store.entities.fields[guid].coords[1].guid + const l3 = store.entities.fields[guid].coords[2].guid + return store.entities.portals[l1] && store.entities.portals[l1].level >= minlvl || + store.entities.portals[l2] && store.entities.portals[l2].level >= minlvl || + store.entities.portals[l3] && store.entities.portals[l3].level >= minlvl + }) + return { + portals: store.entities.portals, + fields: store.entities.fields, + links: store.entities.links, + renderPortal, + renderField, + renderLink + } +}, {})( + MapObjects +); \ No newline at end of file diff --git a/src/Components/MapOverlay.tsx b/src/Components/MapOverlay.tsx index faf484e..0e3624b 100644 --- a/src/Components/MapOverlay.tsx +++ b/src/Components/MapOverlay.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator, Linking } from 'react-native'; +import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator, Linking, TextInput, Slider } from 'react-native'; import { FontAwesome } from '@expo/vector-icons'; import { getStatusBarHeight, getBottomSpace } from '../helper'; import { LatLng } from '../Api/interfaces'; @@ -15,11 +15,6 @@ type Props = { export default (props: Props) => ( <> - {props.loading > 0 ? ( - - - - ) : null} {props.selectedPortal ? ( <> @@ -35,7 +30,7 @@ export default (props: Props) => ( backgroundColor={"#e3e3e3"} /> - + {/* ( size={25} backgroundColor={"#e3e3e3"} /> - + */} ) : null} + {props.loading > 0 ? ( + + + + ) : null} @@ -74,18 +74,23 @@ export default (props: Props) => ( /> + {props.selectedPortal ? ( + + {JSON.stringify(props.selectedPortal)} + + ) : null} ); const styles = StyleSheet.create({ overlayLeft: { position: 'absolute', - bottom: getBottomSpace(), + top: getStatusBarHeight() + 20, left: 8, }, overlayRight: { position: 'absolute', - bottom: getBottomSpace(), + top: getStatusBarHeight() + 20, right: 8, }, button: { @@ -93,9 +98,37 @@ const styles = StyleSheet.create({ alignItems: 'center', height: 48, width: 48, + }, buttonWrapper: { margin: 8, + //ios + shadowOpacity: 0.3, + shadowRadius: 3, + shadowOffset: { + height: 0, + width: 0 + }, + //android + elevation: 1 + }, + panel: { + position: 'absolute', + bottom: getBottomSpace(), + left: 8, + right: 8, + borderRadius: 8, + padding: 8, + backgroundColor: '#fff', + //ios + shadowOpacity: 0.3, + shadowRadius: 3, + shadowOffset: { + height: 0, + width: 0 + }, + //android + elevation: 1 }, icon: { marginRight: 0, diff --git a/src/Components/Settings.tsx b/src/Components/Settings.tsx index a99e46e..ca481a9 100644 --- a/src/Components/Settings.tsx +++ b/src/Components/Settings.tsx @@ -1,5 +1,5 @@ import React, { Component, PureComponent } from 'react'; -import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator } from 'react-native'; +import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator, Slider, SafeAreaView } from 'react-native'; // import { Button } from 'react-native-vector-icons/FontAwesome'; import { getStatusBarHeight } from '../helper'; import { connect } from 'react-redux'; @@ -20,15 +20,37 @@ class Settings extends PureComponent { }; render() { + const { filterLevel } = this.props.settings return ( - - {/* {JSON.stringify(this.props)} */} - + + Мин. Ур.: {filterLevel[0]} + + Макс. Ур.: {filterLevel[1]} + + ); } } -export default connect((store) => ({}), (dispatch) => bindActionCreators(actions, dispatch))(Settings) +export default connect((store) => ({ settings: store.settings }), (dispatch) => bindActionCreators(actions, dispatch))(Settings) const styles = StyleSheet.create({ overlay: { diff --git a/src/Store/store.ts b/src/Store/store.ts index b8f4169..581f14b 100644 --- a/src/Store/store.ts +++ b/src/Store/store.ts @@ -19,13 +19,12 @@ const reducers = { 'portalsSet': (store: any, action: { portals: Portal }) => { const portals = store.portals Object.keys(action.portals).forEach(guid => { - const portal: Portal = portals[guid] - const newPortal: Portal = action.portals[guid] - if (!portal) { - portals[guid] = newPortal - return + if (portals[guid]) { + portals[guid] = { ...portals[guid], fraction: action.portals[guid].fraction, level: action.portals[guid].level } + } else { + portals[guid] = action.portals[guid] } - portals[guid] = extend(portal, newPortal) + }) return { ...store, portals } }, @@ -35,8 +34,43 @@ const reducers = { ({ ...store, fields: { ...store.fields, ...action.fields } }), 'setLoad': (store: any, action: { queue: string[][] }) => ({ ...store, loadQueue: [...action.queue] }), - - }, { portals: {}, fields: {}, links: {}, loadQueue: [] }) + 'linksGC': (store: any, action: { links: { [tile: string]: string[] } }) => { + let linksCache = store.linksCache + let links = store.links + Object.keys(action.links).forEach(tileId => { + const oldLinks = linksCache[tileId] + if (oldLinks != undefined) { + oldLinks.forEach((guid: string) => { + delete links[guid] + }) + } + linksCache[tileId] = action.links[tileId] + }) + return ({ ...store, links: { ...links }, linksCache }) + }, + 'fieldsGC': (store: any, action: { fields: { [tile: string]: string[] } }) => { + let fieldsCache = store.fieldsCache + let fields = store.fields + Object.keys(action.fields).forEach(tileId => { + const oldFields = fieldsCache[tileId] + if (oldFields != undefined) { + oldFields.forEach((guid: string) => { + delete fields[guid] + }) + } + fieldsCache[tileId] = action.fields[tileId] + }) + return ({ ...store, fields: { ...fields }, fieldsCache }) + }, + }, { portals: {}, fields: {}, links: {}, loadQueue: [], linksCache: {}, fieldsCache: {} }), + 'settings': createReducer({ + 'setLevelFrom': (store: any, action: { level: number }) => ({ + ...store, filterLevel: [action.level, store.filterLevel[1]] + }), + 'setLevelTo': (store: any, action: { level: number }) => ({ + ...store, filterLevel: [store.filterLevel[0], action.level] + }) + }, { filterLevel: [0, 8] }) } function extend(obj: any, src: any) { diff --git a/src/constants.ts b/src/constants.ts index e24771a..288c907 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,6 +6,10 @@ export const COLORS_MOD = { VERY_RARE: '#b08cff', RARE: '#73a8ff', COMMON: '#8cf export const RESO_NRG = [0, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000]; export const MOD_TYPE = { RES_SHIELD: 'Shield', MULTIHACK: 'Multi-hack', FORCE_AMP: 'Force Amp', HEATSINK: 'Heat Sink', TURRET: 'Turret', LINK_AMPLIFIER: 'Link Amp' }; +export const DEFAULT_ZOOM_TO_LEVEL = [8,8,8,8,7,7,7,6,6,5,4,4,3,2,2,1,1,1,1,1,1,1,1]; +export const DEFAULT_ZOOM_TO_LINK_LENGTH = [200000,200000,200000,200000,200000,60000,60000,10000,5000,2500,2500,800,300,0,0]; + + export const NAVIGATORS = { "ymaps": "yandexnavi://build_route_on_map?lat_to=&lon_to=&no-balloon=0&desc=", "2gis": "dgis://2gis.ru/routeSearch/rsType/car/to/<lon>,<lat>", diff --git a/src/helper.js b/src/helper.js index 3bdbf7e..2242d91 100644 --- a/src/helper.js +++ b/src/helper.js @@ -43,4 +43,25 @@ export function timeConverter(UNIX_timestamp) { function formatInt(num) { return ("00" + num).slice(-2) -} \ No newline at end of file +} + +export function calcCrow(lat1, lon1, lat2, lon2) + { + var R = 6371; // km + var dLat = toRad(lat2-lat1); + var dLon = toRad(lon2-lon1); + var lat1 = toRad(lat1); + var lat2 = toRad(lat2); + + var a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + var d = R * c; + return d; + } + + // Converts numeric degrees to radians + function toRad(Value) + { + return Value * Math.PI / 180; + } \ No newline at end of file -- cgit v1.2.3