建立屬於你的 Google Map 地圖標記(四) - 建立可拖曳的地圖標記


Posted by mumu892101 on 2022-08-09

現在有地址的座標後,就是可以在地圖上放置標記在座標地址了。

我們會有三個情況下,會用到 renderMarker 這個 function,分別是:

  1. 輸入地址並按下搜尋按鈕,有回傳有效回應與 result,callback 會針對 result 進行標記渲染。
  2. 輸入部分地址,自動完成功能有回傳有效回應,使用者點選其中一項地址欄位後,地只會顯示該使用者點選的選項,並進行標記渲染。
  3. 由於該地圖為商家位置,因此地圖上只允許顯示一個標記,並必須已經經過第一次透過上述兩種方法之一建立過標記後,才能點擊地圖並創造標記,讓使用者體驗是透過點擊地圖方式移動標記。

因此在 function 最初,會先判斷標記存在的狀態是否為 true,如果為 true 代表地圖已有標記,因此會先將該標記從地圖上清除。
建立標記的方式,可以參考 Markers 文件,先 new 一個 instance new maps.Marker(),其中 position 為座標位置,並為建立的 Marker 增加可拖曳的屬性,並透過 map 參數將標記置於地圖上。

當該標記拖曳結束後,監聽到 dragend 並透過該標記的 getPosition() 取得停止位置的ˊ座標並儲存於 state。

但因為需要表單中需要儲存 placeId 的資料,這個 placeId 需要和座標吻合,因此拖曳後的新標記位置,會用他的座標進行反向查詢,也就是 maps.Geocoder() 中的 geocode method 第一個參數,不帶入地址而是帶入location,透過 status OK 的判斷將回傳的 result placeId 作為新的資料儲存起來。

  const renderMarker = useCallback(
    (map, maps, position, isMarker) => {
      // 如已存在標記,刪除原標記
      if (isMarker) {
        marker.current.setMap(null)
        marker.current = null
      }
     // 當標記清空後,就可以渲染新的標記
      if (!marker.current) {
        marker.current = new maps.Marker({
          position: position,
          draggable: true,
          map
        })
        // 為新的標記 DOM 加上 listener,拖曳完畢後取得新的座標位置
        marker.current.addListener('dragend', () => {
          const position = marker.current.getPosition()
          if (position) {
            // 儲存拖曳後座標
            setCoordsResult({
              lat: position.lat(),
              lng: position.lng()
            })

            // 儲存拖曳座標所查出之第一筆placeId
            const dragGeocoder = new mapApi.Geocoder()
            dragGeocoder.geocode(
              {
                location: {
                  lat: position.lat(),
                  lng: position.lng()
                }
              },
              function (results, status) {
                if (status === mapApi.GeocoderStatus.OK) {
                  setPlaceId(results[0].place_id)
                }
              })
          }})
      }},[mapApi])

接著要實踐點擊地圖可以建立新標記的功能,這個功能透過 isMarker 這個地圖上是否已經建立標記的狀態去判斷地圖是否可以加入 click 的 eventListener,因為當用戶尚未透過地址搜尋去建立第一個標記時,該地圖不能建立標記。當已經有標記後,就在地圖介面上新增點擊監聽,當點擊時會呼叫 renderMarker function,去執行前面我們解釋過的渲染標記功能,並且儲存新的座標及 placeId。

  useEffect(() => {
    if (isMarker) {
      mapInstance.addListener('click', (e) => {
        renderMarker(mapInstance, mapApi, e.latLng, isMarker)
        // 儲存點擊後座標
        setCoordsResult({
          lat: e.latLng.lat(),
          lng: e.latLng.lng()
        })

        // 查詢點擊座標最接近的placeId並儲存
        const clickGeocoder = new mapApi.Geocoder()
        clickGeocoder.geocode(
          {
            location: {
              lat: e.latLng.lat(),
              lng: e.latLng.lng()
            }
          },
          function (results, status) {
            if (status === mapApi.GeocoderStatus.OK) {
              setPlaceId(results[0].place_id)
            }
          }
        )
      })
    }
  }, [isMarker, mapInstance, mapApi, renderMarker, setCoordsResult, setPlaceId])

#React #GoogleMap #Google-Maps-APIs #google-map-react #React Hook







Related Posts

Single Page Application 單頁應用

Single Page Application 單頁應用

用後端好朋友們 express & sequelize 實作部落格

用後端好朋友們 express & sequelize 實作部落格

KIOPTRIX: LEVEL 1.2 (#3) 攻略紀錄

KIOPTRIX: LEVEL 1.2 (#3) 攻略紀錄


Comments