如何在每个区域的反应谷歌地图中添加和编辑多边形

时间:2021-06-03 07:38:35

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

我在 React js 工作。我需要使用具有给定功能的 react-google-map 来实现地图。

  1. 点击“Zone”(比如Zone 1)按钮对应区域的地图 应该显示(例如,如果您单击区域 1 显示区域的地图等 上)。
  2. 每个区域会有多个多边形。我们可以编辑多边形,如果 需要。
  3. 我们可以通过点击“添加区域”来创建新的地图区域(空地图) 按钮

下面给出的是我尝试过的代码。我试图编辑多边形坐标并将它们存储在本地存储中,但它没有正确更新,而且我无法在单击“添加区域”按钮时新建空地图。新地图中将显示本地保存的多边形。 我觉得思路很清楚。有任何疑问,请务必提问。

UI Layout

示例 JSON 格式



{
      "area": "Zone2",
      "cartamount": "",
      "extra_shippingamount": "",
      "polygon": [
         {
            "id_polygon": 1,
            "coord": [
               {
                  "lat": 11.174036305817275,
                  "lng": 76.3754534171875
               },
               {
                  "lat": 10.526644973776667,
                  "lng": 76.6061663078125
               },
               {
                  "lat": 10.75339097376777,
                  "lng": 77.47957939375
               }
            ]
         },
         {
            "id_polygon": 2,
            "coord": [
               {
                  "lat": 11.28179683077826,
                  "lng": 75.89857811201172
               },
               {
                  "lat": 10.774977003245414,
                  "lng": 76.16774315107422
               },
               {
                  "lat": 11.292570666429365,
                  "lng": 76.91481346357422
               }
            ]
         }
      ],
      "shippingamount": ""
   },
   {
      "area": "Zone3",
      "cartamount": "",
      "extra_shippingamount": "",
      "polygon": [
         {
            "id_polygon": 1,
            "coord": [
               {
                  "lat": 11.174036305817275,
                  "lng": 76.3754534171875
               },
               {
                  "lat": 10.526644973776667,
                  "lng": 76.6061663078125
               },
               {
                  "lat": 10.75339097376777,
                  "lng": 77.47957939375
               }
            ]
         },
         {
            "id_polygon": 2,
            "coord": [
               {
                  "lat": 11.28179683077826,
                  "lng": 75.89857811201172
               },
               {
                  "lat": 10.774977003245414,
                  "lng": 76.16774315107422
               },
               {
                  "lat": 11.292570666429365,
                  "lng": 76.91481346357422
               }
            ]
         }
      ],
      "shippingamount": ""
   }
]

代码

const MapContainer = withGoogleMap((props: any) => {
    const { mainStore } = useStore();
    const [curLocation, setCurLocation] = useState<any>()
    const [loading, setLoading] = useState(true);
    const [coordinates, setCoordinates] = useState<any>([]);
    const [path, setPath] = useState<any>()    
    const polygonRef = useRef<any>(null);
    const listenersRef = useRef([]);

    let coord = coordIndex

    let localCoordinates: any = [];
    let getLocalCoordinates = localStorage.getItem("polygons");
    if (typeof getLocalCoordinates == 'string') {
        localCoordinates = JSON.parse(getLocalCoordinates);
    }
    console.log(" localCoordinates", localCoordinates)

    useEffect(() => {       
        setLoading(true)
        getGeoLocation()


    }, [])

    const getGeoLocation = () => {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(
                position => {
                    // console.log(position.coords);
                    setCurLocation({ lat: position.coords.latitude, lng: position.coords.longitude })

                })
            setLoading(false)
        }
        else {
            console.log("error")
            // (err: any => console.log(error) ),
        }
    }
    

    const getPaths = (polygon: any) => {
        var polygonCount = localCoordinates.length == 0 ? 1 : localCoordinates.length + 1
        var polygonBounds = polygon.getPath();
        var bounds = [];
        for (var i = 0; i < polygonBounds.length; i++) {
            var point = {
                lat: polygonBounds.getAt(i).lat(),
                lng: polygonBounds.getAt(i).lng()
            };
            bounds.push(point);     
        }

        localCoordinates?.push({
            "id_polygon": polygonCount,
            "coord": bounds
        });
        localStorage.setItem('polygons', JSON.stringify(localCoordinates))
        console.log("bounds", bounds);
        // mainStore.coorindates.push(bounds);
        mainStore.isLatLng = true;
        polygonCount++
    }
    console.log(" coordinates", coordinates)
   
    const onEdit = useCallback((key: any) => {
        console.log("polygonRef", polygonRef)
        console.log("key", key)
        if (polygonRef.current) {
            const nextPath = polygonRef?.current
                .getPath()
                .getArray()
                .map((latLng: any) => {
                    return { lat: latLng.lat(), lng: latLng.lng() };
                });
            console.log("nextPath", nextPath)
            // setPath(nextPath);
        }
    }, [])

    // Bind refs to current Polygon and listeners
    const onLoad = useCallback(
        polygon => {
            polygonRef.current = polygon;
            const path = polygon.getPath();
            (listenersRef as any).current.push(
                path.addListener("set_at", onEdit),
                path.addListener("insert_at", onEdit),
                path.addListener("remove_at", onEdit)
            );
        },
        [onEdit]
    );
    
    return (
        <div className="p-grid p-fluid">
            <div className="p-col-12">
                <div className="p-grid">

                    <div className="p-md-2">

                    </div>
                    {loading ? <div>Loading</div> :
                        curLocation?.lat && curLocation?.lng &&

                        <>

                            < GoogleMap
                                defaultZoom={8}
                                defaultCenter={{ lat: curLocation?.lat, lng: curLocation?.lng }}
                            >
                                {console.log("cooedIndex", path)}
                                {localCoordinates?.map((items: any, key: any) =>

                                    <Polygon
                                        key={items?.id_polygon}
                                        editable
                                        draggable
                                        path={items.coord}
                                        ref={polygonRef}
                                        onMouseUp={() => onEdit(items.id_polygon)}
                                        onDrag={() => onEdit(items.id_polygon)}
                                        // onClick={(e: any) => console.log("polygon key", items.id_polygon)}
                                        options={{
                                            strokeColor: "#FF0000",
                                            strokeOpacity: 0.8,
                                            strokeWeight: 2,
                                            fillColor: "#FF0000",
                                            fillOpacity: 0.35,
                                            geodesic: true,
                                            editable: true
                                        }}
                                    />
                                )}

                                <DrawingManager
                                    defaultDrawingMode={google.maps.drawing.OverlayType.POLYGON}
                                    defaultOptions={{
                                        drawingControl: true,
                                        drawingControlOptions: {
                                            position: google.maps.ControlPosition.TOP_CENTER,
                                            drawingModes: [google.maps.drawing.OverlayType.POLYGON]
                                        },
                                        polygonOptions: { editable: true, draggable: true }
                                    }}
                                    onPolygonComplete={value => getPaths(value)}

                                />

                                <Marker position={{ lat: curLocation?.lat, lng: curLocation?.lng }} />

                            </GoogleMap>
                            <div>

                            </div>


                        </>
                    }
                </div>

                <div className="p-md-3">

                </div>

            </div>
        </div >

    )
})

1 个答案:

答案 0 :(得分:1)

您可以在下面查看我的 code 内嵌注释以了解每个函数的说明。这是一个简短的解释:

您需要将多边形数据中的区域映射到按钮中。因此,对于每个区域,都应该创建一个按钮。然后,该按钮将在单击时调用一个函数,该函数将传递当前区域详细信息并设置多边形、中心和 zoneIndex 状态的值。一旦多边形状态不为空,它将映射当前区域的所有多边形。我们将获取每个多边形的 ref 并将其放入一个数组中,使多边形可编辑并调用 onMouseDown 函数。 onMouseDown 函数将捕获编辑多边形时所做的更改。然后,您可以更改 json 数据,而不是在 json 文件中,而是在您传递 json 数据的状态中。有关详细信息,请参阅内嵌评论。

至于附加区域按钮,您的按钮将在单击时调用一个函数,它应该处理您如何传递区域数据。在我的代码中,我只为我的 addNewZone 状态设置了一个值,我将它用作一个条件,当它不为空时将显示 DrawingManager。有关详细信息,请参阅内嵌注释。

import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, Polygon } from 'react-google-maps';
import { DrawingManager } from 'react-google-maps/lib/components/drawing/DrawingManager';
import data from './data.json';


let polygonRef = [];
class Map extends Component {
  constructor(props) {
    super(props);

    this.state = {
      drawingControlEnabled: true,
      polygon: null,
      visible: true,
      polygonData: data,
      zoneIndex: null,
      center: { lat: 40.756795, lng: -73.954298 },
      addNewZone:null
    };
  }
  componentDidMount = () => {
    console.log('original value of your json data', this.state.polygonData);
  };

//function will be called when the zone button will be clicked. If your zone are in different locations, you can put the logic in this function to change the state of the center to that zone coords. 
  zoneBtnClicked = (zone, index) => {
    console.log("current zone", zone);

    this.setState({
      polygon: zone.polygon,
      //I just use random coordionagtes from the polygon path to set as the center. You can also put a zone center coordinate in your json data and used it as the center of the zone where you want your map to recenter when you clicked a zone button.
      center: zone.polygon[0].coord[2],
      zoneIndex: index
    });
  };

//function will be called when the add new zone button will be clicked. You can put your code on how you can pass new details of the Zone base on your json data.
  newZoneBtnClicked =()=>{
    //this will set the value of addNewZone state that will make the Drawing Manager visible. 
    this.setState({
     addNewZone:true
    });
  }

  _onMousedown = ref => {
    //get the reference of the polygon then used the ref as it's index so that you can get the specific polygon
    const polygon = polygonRef[ref].getPath();
    console.log(polygon);
    //add event listeners for the polygon changes and pass the polygon as parameter to the function you need, you also need to pass the ref (or index)
    google.maps.event.addListener(polygon, 'set_at', () => {
      this._getPolygonNewPaths(polygon, ref);
    });
    google.maps.event.addListener(polygon, 'insert_at', () => {
      this._getPolygonNewPaths(polygon, ref);
    });
    google.maps.event.addListener(polygon, 'remove_at', () => {
      this._getPolygonNewPaths(polygon, ref);
    });
  };

  _getPolygonNewPaths = (polygon, ref) => {
    let polygonPaths = [];
    polygon.getArray().forEach((path) => {
      const line = {
        lat: path.lat(),
        lng: path.lng()
      };
      polygonPaths.push(line);
    });
    //this is the new polygon paths which includes what you editted
    console.log('new polygonpaths', polygonPaths);
    //you will see the current value of that polygon paths in your state
    console.log('current polygonpaths from state',
      this.state.polygonData[this.state.zoneIndex].polygon[ref].coord
    );
    //put this current value of your polygonData to a variable holder
    const newPolygon = this.state.polygonData;
    //change the value of the polygon path to the variable that holds yout current polygonData
    newPolygon[this.state.zoneIndex].polygon[ref].coord = polygonPaths;
    //This is now the value of your changed polygonData
    console.log('changed polygon data in variable hiolder', newPolygon);
//now change the polygon Data state to the changed polygonData
    this.setState({
      polygonData: newPolygon
    });
    console.log('changed Polygon Data in state', this.state.polygonData);
  };

 
//function that will put all the polygon ref in the array since polygons will be iterated base on the json data
  _polyRef = ref => {
    polygonRef.push(ref);
  };

  render() {
    const GoogleMapExample = withGoogleMap(props => (
      <GoogleMap
      
        defaultZoom={8}
        center={this.state.center}
      >
      {this.state.addNewZone === true && (
        <DrawingManager
          defaultDrawingMode={google.maps.drawing.OverlayType.POLYGON}
          defaultOptions={{
            drawingControl: true,
            drawingControlOptions: {
              position: google.maps.ControlPosition.TOP_CENTER,
              drawingModes: [google.maps.drawing.OverlayType.POLYGON]
            },
            polygonOptions: { editable: true, draggable: true }
          }}
          onPolygonComplete={value => getPaths(value)}
        />)}

        {this.state.polygon !== null &&
          this.state.polygon.map((poly, index) => (
            <Polygon
              ref={ref => {
                this._polyRef(ref);
              }}
              paths={poly.coord}
              onMouseDown={() => {
                this._onMousedown(index);
              }}
              editable
            />
          ))}
      </GoogleMap>
    ));

    return (
      <div>
        {this.state.polygonData.map((zone, index) => (
          <button
            id={zone.area}
            onClick={() => this.zoneBtnClicked(zone, index)}
          >
            {zone.area}
          </button>
        ))}
        <button onClick={() => this.newZoneBtnClicked()}>Add New Zone</button>
        <GoogleMapExample
          containerElement={<div style={{ height: `500px`, width: '500px' }} />}
          mapElement={<div style={{ height: `100%` }} />}
        />
      </div>
    );
  }
}

export default Map;
相关问题