如何在具有多个点(纬度和经度)的原生地图上绘制多边形?

时间:2017-11-20 10:16:08

标签: javascript reactjs react-native react-native-maps

我一直关注此documentation以在地图上绘制多边形。现在我尝试从API获取纬度和经度值并绘制它。对于少量的值,这不是问题,因为我只是直接使用状态编写它。

以下是我的渲染功能

import React, { Component } from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import { Card, Button } from 'react-native-elements';
import { MapView } from 'expo';
import { connect } from 'react-redux';

const window = Dimensions.get('window');

class PolygonPage extends Component {
    constructor(props) {
        super(props);

        this.state = {
            polygon: [
            {
                latitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][0][1],
                longitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][0][0]
            },
            {
                latitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][1][1],
                longitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][1][0]
            },
            {
                latitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][2][1],
                longitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][2][0]
            },
            {
                latitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][3][1],
                longitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][3][0]
            }
        ]
    };
}

onButtonPressClose = () => {
    this.props.navigation.navigate('Home');
}

render() {
    const { polygon } = this.state;
    return (
        <View style={styles.container}>
            <MapView 
                provider={this.props.provider}
                style={styles.map}
                zoomEnabled
                initialRegion={{
                    latitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][0][1],
                    longitude: this.props.points.data.routeGeoJSON.features[0].geometry.coordinates[0][0][0],
                        latitudeDelta: 0.0922,
                        longitudeDelta: 0.0421,
                    }}
            >
                <MapView.Polygon
                    coordinates={polygon}
                    fillColor="rgba(0, 200, 0, 0.5)"
                    strokeColor="rgba(0,0,0,0.5)"
                    strokeWidth={2}
                />
            </MapView>
            <View style={stylesContainer.topContainer}>
                <Card title="Route Information">
                    <View>
                        <Text>Name: {this.props.points.data.name}</Text>
                        <Text>Description: {this.props.routes.data.description}</Text>
                    </View>
                </Card>
            </View>
            <View style={stylesContainer.buttonBottomContainer}>
                    <Button
                        medium
                        title="Back"
                        backgroundColor="#94b8b8"
                        onPress={this.onButtonPressClose}
                    />
            </View> 
        </View>
    );
    }
}

PolygonPage.propTypes = {
    provider: MapView.ProviderPropType,
}; 

const styles = StyleSheet.create({
    container: {
        ...StyleSheet.absoluteFillObject,
        justifyContent: 'flex-end',
        alignItems: 'center',
    },
    map: {
        flex: 1,
        height: window.height,
        width: window.width
    }
});

function mapStateToProps({ points }) {
    return { points };
}

export default connect(mapStateToProps)(PolygonPage);

这适用于我,因为它从我从API获得的点呈现多边形。

我的API响应是JSON。这是示例

{
"timestamp": 000111,
"verb": "GET",
"object": "route",
"data": {
    "description": "describe",
    "routeGeoJSON": {
        "type": "FeatureCollection",
        "features": [
            {
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [
                        [
                            [
                                122.18919, // this is longitude
                                4.82948294 // this is latitude
                            ],
                            [
                                124.17318,
                                5.9319319
                            ],
                            [
                                101.131191,
                                2.92492
                            ],
                            [
                                106.01010192,
                                4.492472492
                            ]
                        ]
                    ]
                },
                "type": "Feature",
                "properties": {}
            }
        ]
    },
    "id": 1,
    "routeType": "point",
    "name": "Test"
    }
}

如果点/坐标小于10,那么我可能会像在渲染函数中那样输入它。但是如果有超过10个点(纬度和经度)怎么办?我无法想象如何在map内使用forthis.state = { polygon: [....]}循环函数。

我在网上搜索了一些例子,例如thisthis,但未能理解它。

如果有人有任何想法或善意在这里分享他的建议或样板,我非常感谢。

谢谢。

2 个答案:

答案 0 :(得分:0)

您必须<property>完成您的回复,然后将您的坐标转换为documentation

中给出的map
type

假设您的API响应已保存在type LatLng { latitude: Number, longitude: Number, } 中,请尝试此操作。 您可以使用apiResponse和数组位置访问对象,并通过坐标数组进行映射。

keys

const polygon = apiResponse.data.routeGeoJSON[0].geometry.coordinates[0].map(coordsArr => { let coords = { latitude: coordsArr[1], longitude: coordsArr[0], } return coords; }); 是您提供的

const polygon

答案 1 :(得分:0)

这是最终代码:

只需创建一个Maps.js文件并粘贴代码,然后从导航器中调用它

import React, { Component } from 'react'
import {
  StyleSheet,
  View,
  Text,
  Dimensions,
  TouchableOpacity
} from 'react-native'

import MapView, {
  MAP_TYPES,
  Polygon,
  ProviderPropType,
  PROVIDER_GOOGLE
} from 'react-native-maps'

const { width, height } = Dimensions.get('window')

const ASPECT_RATIO = width / height
const LATITUDE = 37.78825
const LONGITUDE = -122.4324
const LATITUDE_DELTA = 0.0922
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO
let id = 0

class Maps extends Component {
  constructor(props) {
    super(props)
    this.state = {
      region: {
        latitude: LATITUDE,
        longitude: LONGITUDE,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA
      },
      polygons: [],
      editing: null,
      creatingHole: false
    }
  }

  finish() {
   const { polygons, editing } = this.state;
   this.setState({
   polygons: [...polygons, editing],
   editing: null,
   creatingHole: false,
  });
  }

  clear = () => {
    this.setState({
      polygons: [],
      editing: null,
      creatingHole: false
    })
  }

  createHole() {
    const { editing, creatingHole } = this.state
    if (!creatingHole) {
      this.setState({
        creatingHole: true,
        editing: {
          ...editing,
          holes: [...editing.holes, []]
        }
      })
    } else {
      const holes = [...editing.holes]
      if (holes[holes.length - 1].length === 0) {
        holes.pop()
        this.setState({
          editing: {
            ...editing,
            holes
          }
        })
      }
      this.setState({ creatingHole: false })
    }
  }

  onPress(e) {
    console.log(this.state.polygons)
    const { editing, creatingHole } = this.state
    if (!editing) {
      this.setState({
        editing: {
          id: id++,
          coordinates: [e.nativeEvent.coordinate],
          holes: []
        }
      })
    } else if (!creatingHole) {
      this.setState({
        editing: {
          ...editing,
          coordinates: [...editing.coordinates, e.nativeEvent.coordinate]
        }
      })
    } else {
      const holes = [...editing.holes]
      holes[holes.length - 1] = [
        ...holes[holes.length - 1],
        e.nativeEvent.coordinate
      ]
      this.setState({
        editing: {
          ...editing,
          id: id++, // keep incrementing id to trigger display refresh
          coordinates: [...editing.coordinates],
          holes
        }
      })
    }
  }

  render() {
    const mapOptions = {
      scrollEnabled: true
    }

    if (this.state.editing) {
      mapOptions.scrollEnabled = false
      mapOptions.onPanDrag = e => this.onPress(e)
    }

    return (
      <View style={styles.container}>
        <MapView
          provider={PROVIDER_GOOGLE}
          style={styles.map}
          mapType={MAP_TYPES.SATELLITE}
          initialRegion={this.state.region}
          onPress={e => this.onPress(e)}
          {...mapOptions}
        >
          {this.state.polygons.map(polygon => (
            <Polygon
              key={polygon.id}
              coordinates={polygon.coordinates}
              holes={polygon.holes}
              strokeColor="#F00"
              fillColor="rgba(255,0,0,0.5)"
              strokeWidth={1}
            />
          ))}
          {this.state.editing && (
            <Polygon
              key={this.state.editing.id}
              coordinates={this.state.editing.coordinates}
              holes={this.state.editing.holes}
              strokeColor="#000"
              fillColor="rgba(255,0,0,0.5)"
              strokeWidth={1}
            />
          )}
        </MapView>

        <View style={styles.buttonContainer}>
          {this.state.editing && (
            <TouchableOpacity
              onPress={() => this.createHole()}
              style={[styles.bubble, styles.button]}
            >
              <Text>
                {this.state.creatingHole ? 'Finish Hole' : 'Create Hole'}
              </Text>
            </TouchableOpacity>
          )}
          {this.state.editing && (
            <TouchableOpacity
              onPress={() => this.finish()}
              style={[styles.bubble, styles.button]}
            >
              <Text>Finish</Text>
            </TouchableOpacity>
          )}
        </View>
        <TouchableOpacity
          onPress={() => this.clear()}
          style={[styles.bubble, styles.button]}
        >
          <Text>Clear</Text>
        </TouchableOpacity>
      </View>
    )
  }
}

Maps.propTypes = {
  provider: ProviderPropType
}

const styles = StyleSheet.create({
  container: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'flex-end',
    alignItems: 'center'
  },
  map: {
    ...StyleSheet.absoluteFillObject
  },
  bubble: {
    backgroundColor: 'rgba(255,255,255,0.7)',
    paddingHorizontal: 18,
    paddingVertical: 12,
    borderRadius: 20
  },
  latlng: {
    width: 200,
    alignItems: 'stretch'
  },
  button: {
    width: 80,
    paddingHorizontal: 12,
    alignItems: 'center',
    marginHorizontal: 10
  },
  buttonContainer: {
    flexDirection: 'row',
    marginVertical: 20,
    backgroundColor: 'transparent'
  }
})

export default Maps

不要忘记将依赖项添加到AndroidManifest.xml

在清单标记中:-

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

在应用程序标记中:-

<meta-data
     android:name="com.google.android.geo.API_KEY"
     android:value="Paste your API key from google maps [https://developers.google.com/maps/documentation/embed/get-api-key]"
/>