-2

I am working in react js. I need to implement map using react-google-map with given features.

  1. On clicking "Zone" (say Zone 1 ) button map corresponding to zone should displayed ( Eg if you click zone 1 dispay map of zone and so on).
  2. Each zone there will be multiple polygons .We can edit polygon if required.
  3. We can create new map zone (empty map) by clicking 'Add zone' button

Given below is the code that I tried . I tried to edit the polygon cordinates and store them in local storage , but it is not updating properly and also I am not able new create empty map on clicking "Add zone" button. There will be locally saved polygons displayed in new map. I think idea is clear . Please do ask doubts is any.

UI Layout

Sample JSON format



{
      "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": ""
   }
]

Code

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 >

    )
})

Happy bean
  • 89
  • 2
  • 16

1 Answers1

2

You can check my code below with inline comments for description of each function. Here's a short explanation:

You need to map your zone from your polygon data into a button. So for each zone, there should be a button that will be created. The button will then call a function when clicked that will pass the current zone details and will set value of the polygon, center and zoneIndex state. Once the polygon state is not null, it will maps all the polygon of the current zone. We will get the ref of each polygon and put it in an array, make the polygon editable and call a function onMouseDown. The onMouseDown function will capture the changes made when you edit the polygon. You can then change the json data not in the json file but in the state where you passed your json data. Please see inline comments for more info.

As for the additional zone button, your button shall call a function when clicked and it should handle how you pass the data of your zone. In my code I only set a value to my addNewZone state which I used as a condition that will show the DrawingManager when it is not null.Please see inline comments for more info.

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;
Pagemag
  • 2,779
  • 1
  • 7
  • 17