如何使用react-google-maps/api包绘制地图?

huangapple go评论81阅读模式
英文:

How to draw a Map using react-google-maps/api package?

问题

我正在尝试构建一个应用程序,该应用程序具有地图,每当用户点击地图时,该操作应在该点留下一个标记,但如果他点击多次,则应在这些坐标之间创建折线,如果他右键单击了一个他创建的标记,那么该标记后的所有内容都应该被删除。嗯,我在实现添加这些标记和折线方面遇到了问题,我正在使用@react-google-maps/api版本^2.17.1以及react ^18.2.0。
我尝试使用useEffect在使用<GoogleMap>组件中的onClick方法之前添加坐标的数组上,但什么都没有显示出来,该数组根本没有改变。我在YouTube和Google上进行了大量搜索,看看是否有@react-google-maps/api的教程可以帮助我解决这个问题,但没有找到。

这是我的Map.jsx文件:

import React from 'react'
import { GoogleMap, Marker, Polyline, useJsApiLoader } from '@react-google-maps/api'
import * as key from '../../constants/actions';
import { useEffect, useState } from 'react';

const Map = () => {

  let coordinates = [];
  const { isLoaded } = useJsApiLoader({
    id: 'google-map-script',
    googleMapsApiKey: key.MAPS_API_KEY
  })

  const [map, setMap] = React.useState(null)
  const onLoad = React.useCallback(function callback(map) {
    const bounds = new window.google.maps.LatLngBounds(center);
    setMap(map)
  }, [])

  const onUnmount = React.useCallback(function callback(map) {
    setMap(null)
  }, [])
  const containerStyle ={
    width: '100vw',
    height: '100vh',
    background: 'green'
  }
    
  const center = {
    lat: 44.087585,
    lng: -39.899556
  }
    
  const onLoadMarker = marker => {
    console.log('marker: ', marker)
  }
  const onLoadPoly = polyline => {
    console.log('polyline: ', polyline)
  };
  const options = {
    strokeColor: '#FF0000',
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: '#FF0000',
    fillOpacity: 0.35,
    clickable: false,
    draggable: false,
    editable: false,
    visible: true,
    radius: 30000,
    paths: coordinates,
    zIndex: 1
  };
  return isLoaded ? (
    <div style={{padding: '10px'}}>
      <GoogleMap mapContainerStyle={containerStyle}
       center={center}
       zoom={3}
      onLoad={onLoad}
      onUnmount={onUnmount}
      onClick={(e) => {
        coordinates.push({lat:e.latLng.lat(), lng: e.latLng.lng});
        <Marker position={{lat:e.latLng.lat(), lng: e.latLng.lng}} onLoad={onLoadMarker}/>;
        <Polyline path={coordinates} options={options} onLoad={onLoadPoly} />;
      }}
      >
      </GoogleMap>
    </div>
  ) : <></>
}

export default Map

我将非代码部分翻译成中文,希望这能帮助您解决问题。如果您有其他问题或需要进一步的帮助,请随时提出。

英文:

I'm trying to build an app that has a Map and every time a user clicks the map, that action should leave a marker on that point, but if he clicks more than once, that should create a polyline between those coordinates and if he rights click a marker that he made, everything after that marker should be deleted. Well, I have problems with implementing adding those markers and the polyline, I am using @react-google-maps/api version ^2.17.1
and react ^18.2.0.
I tried using useEffect on an array which holds coordinates added before using the onClick method in the <GoogleMap> component, but nothing shows up, that array didn't event change at all. I searched a lot on Youtube and Google to see if I get a tutorial for @react-google-maps/api that can help me with that, but no luck.

Here is my Map.jsx file:

import React from &#39;react&#39;
import {GoogleMap, Marker, Polyline, useJsApiLoader} from &#39;@react-google-maps/api&#39;
import * as key from &#39;../../constants/actions&#39;;
import { useEffect, useState } from &#39;react&#39;;
const Map = () =&gt; {
let coordinates = [];
const { isLoaded } = useJsApiLoader({
id:&#39;google-map-script&#39;,
googleMapsApiKey: key.MAPS_API_KEY
})
const [map, setMap] = React.useState(null)
const onLoad = React.useCallback(function callback(map) {
const bounds = new window.google.maps.LatLngBounds(center);
// map.fitBounds(bounds);
setMap(map)
}, [])
const onUnmount = React.useCallback(function callback(map) {
setMap(null)
}, [])
const containerStyle ={
width:&#39;100vw&#39;,
height:&#39;100vh&#39;,
background:&#39;green&#39;
}
const center = {
lat: 44.087585,
lng: -39.899556
}
const onLoadMarker = marker =&gt; {
console.log(&#39;marker: &#39;, marker)
}
const onLoadPoly = polyline =&gt; {
console.log(&#39;polyline: &#39;, polyline)
};
const options = {
strokeColor: &#39;#FF0000&#39;,
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: &#39;#FF0000&#39;,
fillOpacity: 0.35,
clickable: false,
draggable: false,
editable: false,
visible: true,
radius: 30000,
paths: coordinates,
zIndex: 1
};
return isLoaded ? (
&lt;div style={{padding:&#39;10px&#39;}}&gt;
&lt;GoogleMap mapContainerStyle={containerStyle}
center={center}
zoom={3}
onLoad={onLoad}
onUnmount={onUnmount}
onClick={(e) =&gt; {
coordinates.push({lat:e.latLng.lat(), lng: e.latLng.lng});
&lt;Marker position={{lat:e.latLng.lat(), lng: e.latLng.lng}} onLoad={onLoadMarker}/&gt;;
&lt;Polyline path={coordinates} options={options} onLoad={onLoadPoly} /&gt;
}}
&gt;
&lt;/GoogleMap&gt;
&lt;/div&gt;
) : &lt;&gt;&lt;/&gt;
}
export default Map

I'll appreciate any help. Thank you!

答案1

得分: 0

我尝试重现了你的代码,并成功使其运行。我注意到你试图将新的标记推送到一个数组中,但这不是在React中的工作方式。你需要利用State Hooksmap方法来修改你的数组并在每次点击时更新你的Google地图。以下是一些参考资料,可能对你未来的工作有所帮助:

在State中更新数组

了解ReactJS中的Map

现在,关于如何编写代码,这是你需要的State hooks:

// 用于中心的hook

// 这个hook用于在点击地图时更新中心
const [center, setCenter] = React.useState({
  lat: 44.087585,
  lng: -39.899556
});

// 用于折线路径的hook

// 这是一个用于存储点击序列的数组,稍后在双击地图时将用于渲染折线。
const [path, setPath] = React.useState([]);

// 这个数组是在你双击任何标记时将存储路径序列的地方。
const [loadPolyline, setLoadPolyline] = React.useState([]);

// 用于地图上每次点击的位置的hook

// 这是存储你点击位置的地方,用于渲染标记的数据,这是一个数组,每次点击都会更新。
const [location, setLocation] = React.useState({
  markers: [
    {
      title: "The marker's title will appear as a tooltip.",
      name: "",
      position: null
    }
  ]
});

然后是函数部分:

// 点击地图时的函数

// 这个函数更新位置hook数组,将在点击时存储新的标记。
const mapClicked = (e) => {
  const lat = e.latLng.lat();
  const lng = e.latLng.lng();
  const markerLoc = { lat: lat, lng: lng };
  const markerCoordinate = `lat: ${lat} lng: ${lng}`;
  setPath((previousState) => [...previousState, { lat: lat, lng: lng }]);
  setCenter({ lat: lat, lng: lng });
  setLocation((previousState) => {
    return {
      markers: [
        ...previousState.markers,
        {
          title: "",
          name: markerCoordinate,
          position: markerLoc
        }
      ]
    };
  });
};

// 处理右键点击

// 这是一个函数,将重置你的位置、路径、折线数组,从而删除所有存储和渲染的标记/折线。
const handleRightClick = () => {
  setLocation({
    markers: [
      {
        title: "The marker's title will appear as a tooltip.",
        name: "",
        position: null
      }
    ]
  });
  setLoadPolyline([]);
  setPath([]);
};

// 处理双击

const handleDoubleClick = (e) => {
  setLoadPolyline(path);
};

最后,这是你的<GoogleMap>组件的外观:

// 加载地图
return isLoaded ? (
  <div style={{ padding: "10px" }}>
    <GoogleMap
      mapContainerStyle={containerStyle}
      center={center}
      zoom={3}
      onLoad={onLoad}
      onUnmount={onUnmount}
      onClick={mapClicked}
    >
      {/* 这是你的标记数组的地图方法 */}
      {location.markers.map((markers, key) => (
        <Marker
          icon="https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png"
          key={key}
          title={markers.title}
          name={markers.name}
          position={markers.position}
          onRightClick={handleRightClick}
          onDblClick={handleDoubleClick}
        >
        </Marker>
      ))}
      <Polyline path={loadPolyline} options={options} />
    </GoogleMap>
  </div>
) : (
  <></>
);

这里有一个在codesandbox上的概念验证供你尝试。

P.S. 折线似乎与标记有一定的偏移,我已经试了很长时间,试图修复它。

但仍然希望这有所帮助!

英文:

I tried reproducing your code and made it work somehow. I noticed that you are trying to push the new markers into an array but that's not how it works in React. You need to utilize State Hooks and map method to be able to modify your array and update your Google Maps map whenever you click on it. Here's some references to read that might be helpful on your future endeavors:

Updating Arrays in State

Learn About Map in ReactJS

Now to how it was coded, here's the State hooks that you need:

  // Hook for center
// This hook is used for updating 
// the center whenever you click on the map
const [center, setCenter] = React.useState({
lat: 44.087585,
lng: -39.899556
});
// Hook for polyline path
// This is an array used for storing 
// the sequence of your clicks which 
// will be used later on when double clicking
// the map to render the polyline.
const [path, setPath] = React.useState([]);
// This array is where the path sequence
// will be stored once you
// double click any marker. 
const [loadPolyline, setLoadPolyline] = React.useState([]);
// Hook for the location per click on the MAP
// This is the where the location of your
// click is stored which is the data used
// for rendering your Marker, this is an
// array and is updated each click.
const [location, setLocation] = React.useState({
markers: [
{
title: &quot;The marker`s title will appear as a tooltip.&quot;,
name: &quot;&quot;,
position: null
}
]
});

Then here's for the functions:

  // Function when clicking on the MAP
// This is the function that updates
// the location hook array that will
// store new markers on click.
const mapClicked = (e) =&gt; {
const lat = e.latLng.lat();
const lng = e.latLng.lng();
const markerLoc = { lat: lat, lng: lng };
const markerCoordinate = `lat: ${lat} lng: ${lng}`;
setPath((previousState) =&gt; [...previousState, { lat: lat, lng: lng }]);
setCenter({ lat: lat, lng: lng });
setLocation((previousState) =&gt; {
return {
markers: [
...previousState.markers,
{
title: &quot;&quot;,
name: markerCoordinate,
position: markerLoc
}
]
};
});
};
// handle rightclick
// This is a function that will reset
// your locations, path, polyline arrays
//  which will remove all
// stored and rendered markers/polyline.
const handleRightClick = () =&gt; {
setLocation({
markers: [
{
title: &quot;The marker`s title will appear as a tooltip.&quot;,
name: &quot;&quot;,
position: null
}
]
});
setLoadPolyline([]);
setPath([]);
};
//handle doubleclicks
const handleDoubleClick = (e) =&gt; {
setLoadPolyline(path);
};

And here's how your &lt;GoogleMap&gt; component would look like:

  //Loads the MAP
return isLoaded ? (
&lt;div style={{ padding: &quot;10px&quot; }}&gt;
&lt;GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={3}
onLoad={onLoad}
onUnmount={onUnmount}
onClick={mapClicked}
&gt;
{&lt;!--Here&#39;s the map method for your markers array--&gt;}
{location.markers.map((markers, key) =&gt; (
&lt;Marker
icon={&quot;https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png&quot;}
key={key}
title={markers.title}
name={markers.name}
position={markers.position}
onRightClick={handleRightClick}
onDblClick={handleDoubleClick}
&gt;
&lt;/Marker&gt;
))}
&lt;Polyline path={loadPolyline} options={options} /&gt;
&lt;/GoogleMap&gt;
&lt;/div&gt;
) : (
&lt;&gt;&lt;/&gt;
);

Here's a proof of concept on codesanbox for you to try out.

P.S. The polyline seems to have an offset away from the marker and I've been banging my head on the wall for quite awhile trying to fix it.

But still, Hope this helps!

huangapple
  • 本文由 发表于 2023年1月6日 11:36:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75026691.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定