简体   繁体   中英

How do I get to the updated path of an editable PolyLine from react-google-maps/api?

I'm using the react-google-maps/api library, and I have an application where I need the user to edit a Polyline.

The problem I'm having is grabbing the path of the polyline after the user has finished editing.

If I use native react components, the path returned on the props from the polyline is the original path of the line - not the one edited by the user.

The code below is a cutdown version of where I'm trying to get the path of the line from the react component. If you try it and edit the line, the return array is the original path. I've seen some examples using the getPath() method, but I just can't seem to get this to work on the React component (ie polylineRef.current.getPath() returns a no function error.

How should I be getting the path information of the edited line?

import React, { Fragment, useRef } from "react";
import { GoogleMap, Polyline, useLoadScript } from "@react-google-maps/api";

const MapTest = (props) => {
  const polylineRef = useRef();
  const mapRef = useRef();

  const mapContainerStyle = {
    width: "80vw",
    height: "80vh",
  };

  const showPath = () => {
    console.log(polylineRef.current.props.path); //What should be here to show the edited path if its possible to access?
  };

  const { isLoaded, loadError } = useLoadScript({
    googleMapsApiKey: process.env.REACT_APP_GOOGLE_KEY,
  });

  const centre = { lat: 51.999889, lng: -0.98807 };

  if (loadError) return "Error loading Google Map";
  if (!isLoaded) return "Loading Maps....";

  console.log(polylineRef.current.props.path);

  return (
    <Fragment>
      <GoogleMap
        mapContainerStyle={mapContainerStyle}
        ref={mapRef}
        zoom={10}
        center={centre}
      >
        <Polyline
          ref={polylineRef}
          key={1}
          path={[
            { lat: 51.9298274729133, lng: -1.0446431525421085 },
            { lat: 51.98483618577529, lng: -1.2423970587921085 },
          ]}
          options={{ editable: true, strokeColor: "#ff0000" }}
        />
      </GoogleMap>
      <button
        onClick={(event) => {
          showPath(event);
        }}
      >
        Show Path in Console
      </button>
    </Fragment>
  );
};

export default MapTest;

If I use the native google API, then I can see the updated path, but I can't get a reference to the map created by the map to place the polyline onto.

If I can't access the edited path through the react component, how should I provide a reference to the google maps native API, so when I do

polyline = new google.maps.Polyline(//polyline options)
polyline.setMap(map)  //Where do I get the handle for this map to put it on the map above?

/*I've tried using mapRef.current (not a map instance) and 
mapRef.current.getInstance() - this makes the original map disappear, for reasons I don't understand*/

When I build this using the native API, I can access the edited path using the getPath() method, but I can't render this polyline on the component rendered above.

Other than building the map out of the native API I'm struggling to do this at the moment - but the benefits of the ease of rendering of React make me want to continue down this path for a while longer - is anyone able to help please?

I think this is what you are trying to achieve: https://codesandbox.io/s/snowy-night-ony59?file=/src/App.js My answer is based on: https://codesandbox.io/s/reactgooglemapsapi-editing-a-polygon-popr2?file=/src/index.js:2601-2845 which I found by googling: react-google-maps-api editable polygon

Basically just copying and pasting the code referred by Daniele Cordano

import React, { useState, useRef, useCallback } from "react";
import ReactDOM from "react-dom";
import { LoadScript, GoogleMap, Polygon } from "@react-google-maps/api";

import "./styles.css";

// This example presents a way to handle editing a Polygon
// The objective is to get the new path on every editing event :
// - on dragging the whole Polygon
// - on moving one of the existing points (vertex)
// - on adding a new point by dragging an edge point (midway between two vertices)

// We achieve it by defining refs for the google maps API Polygon instances and listeners with `useRef`
// Then we bind those refs to the currents instances with the help of `onLoad`
// Then we get the new path value with the `onEdit` `useCallback` and pass it to `setPath`
// Finally we clean up the refs with `onUnmount`

function App() {
  // Store Polygon path in state
  const [path, setPath] = useState([
    { lat: 52.52549080781086, lng: 13.398118538856465 },
    { lat: 52.48578559055679, lng: 13.36653284549709 },
    { lat: 52.48871246221608, lng: 13.44618372440334 }
  ]);

  // Define refs for Polygon instance and listeners
  const polygonRef = useRef(null);
  const listenersRef = useRef([]);

  // Call setPath with new edited path
  const onEdit = useCallback(() => {
    if (polygonRef.current) {
      const nextPath = polygonRef.current
        .getPath()
        .getArray()
        .map(latLng => {
          return { lat: latLng.lat(), lng: latLng.lng() };
        });
      setPath(nextPath);
    }
  }, [setPath]);

  // Bind refs to current Polygon and listeners
  const onLoad = useCallback(
    polygon => {
      polygonRef.current = polygon;
      const path = polygon.getPath();
      listenersRef.current.push(
        path.addListener("set_at", onEdit),
        path.addListener("insert_at", onEdit),
        path.addListener("remove_at", onEdit)
      );
    },
    [onEdit]
  );

  // Clean up refs
  const onUnmount = useCallback(() => {
    listenersRef.current.forEach(lis => lis.remove());
    polygonRef.current = null;
  }, []);

  console.log("The path state is", path);

  return (
    <div className="App">
      <LoadScript
        id="script-loader"
        googleMapsApiKey=""
        language="en"
        region="us"
      >
        <GoogleMap
          mapContainerClassName="App-map"
          center={{ lat: 52.52047739093263, lng: 13.36653284549709 }}
          zoom={12}
          version="weekly"
          on
        >
          <Polygon
            // Make the Polygon editable / draggable
            editable
            draggable
            path={path}
            // Event used when manipulating and adding points
            onMouseUp={onEdit}
            // Event used when dragging the whole Polygon
            onDragEnd={onEdit}
            onLoad={onLoad}
            onUnmount={onUnmount}
          />
        </GoogleMap>
      </LoadScript>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

For some reason, the useRef hook doesn't accept the function getPath/getPaths() with the typescript error: TS2339: Property 'getPath' does not exist on type 'MutableRefObject '

const handleNewPolygonPath = useCallback(() => { const newPath = polygonRef.getPath(); dispatch(setNewPolygonPath(newPath)); console.log(newPolygonPath); }, [dispatch, newPolygonPath]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM