2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】地図のマーカー表示が更新されない

Posted at

はじめに

ユーザーが移動しても地図上に表示されたマーカーが移動しない症状につまずいたため記事にします。


【修正前のコード】
.tsx

import L from 'leaflet'; // Lはleafletグローバルオブジェクト
import markerIcon from '../../node_modules/leaflet/dist/images/marker-icon.png'
import markerShadow from '../../node_modules/leaflet/dist/images/marker-shadow.png'

import { MapContainer, Marker, Popup, TileLayer, useMap } from 'react-leaflet'
import '../../node_modules/leaflet/dist/leaflet.css'; // 追加
import { useAtom, useAtomValue } from 'jotai';
import { latitudeAtom, longitudeAtom, manualLatitudeAtom, manualLongitudeAtom, watchedLatitudeAtom, watchedLongitudeAtom } from './Atom';
import { CenterMapButton } from './CenterMapButton';
import { ToHomeButton } from './ToHomeButton';
import { AutoFlyTo } from './AutoFlyTo';
import { CurrentCoordinate } from './CurrentCoordinate';

import { useGeoWatcher } from './useGeoWatcher';
import { useEffect } from 'react';

const DefaultIcon = L.icon({ // .iconカスタムアイコン作成のクラス
  iconUrl: markerIcon, // iconとして表示する画像のURL
  shadowUrl: markerShadow, // マーカーに影を表示する場合その影のURL
  iconSize: [25, 41], // アイコン画像の幅と高さピクセル単位
  iconAnchor: [12, 41], // アイコン画像のどの点が地図上の座標と一致するか ピクセル単位
  popupAnchor: [1, -34], // ポップアップウィンドウがアイコン画像からどのくらい離れるか
  shadowSize: [41, 41] // 影画像の幅と高さ
});

L.Marker.prototype.options.icon = DefaultIcon;

export const MapPage = () => {

  const latitude = useAtomValue(latitudeAtom);
  const longitude = useAtomValue(longitudeAtom);
  const [ watchedLatitude , setWatchedLatitude ] = useAtom(watchedLatitudeAtom);
  const [ watchedLongitude , setWatchedLongitude ] = useAtom(watchedLongitudeAtom);
  const manualLatitude = useAtomValue(manualLatitudeAtom);

  // 位置管理ロジック
  useEffect(() => {
    const watchId = navigator.geolocation.watchPosition((position) => {
      console.log('watchのpositon値', position);
      if (manualLatitude === null) {
        setWatchedLatitude(position.coords.latitude);
        setWatchedLongitude(position.coords.longitude);
      }
    },
    (error) => console.error('watch位置情報取得エラー', error),
    { enableHighAccuracy: true }
  );
  return () => navigator.geolocation.clearWatch(watchId);
  }, [manualLatitude]);

  return (
    <>
      <MapContainer
        center={
          latitude && longitude ? [latitude, longitude] : [35.681641, 139.766921]
        }
        zoom={17}
        scrollWheelZoom={true} // scrollでzoom可
        zoomSnap={0.5} // zoomの段階調整
        style={{ height: '100vh', width: '100vw' }} // 追加
        >
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
          <CurrentCoordinate /> {/* 座標表示 */}
          <CenterMapButton /> {/* 現在地に移動ボタン */}

          <ToHomeButton />
          <AutoFlyTo/> {/* 追従 */}
        <Marker
          key={`${latitude}-${longitude}`}
          position={
            latitude && longitude ? [latitude, longitude] : [35.681641, 139.766921]
          }
        >
          <Popup>
           現在地: <br /> {latitude?.toFixed(6)}, {longitude?.toFixed(6)}
          </Popup>
        </Marker>
      </MapContainer>
    </>
  )
}

解決方法

watchPositionで取得した座標をマーカーに渡す

.tsx

import L from 'leaflet'; // Lはleafletグローバルオブジェクト
import markerIcon from '../../node_modules/leaflet/dist/images/marker-icon.png'
import markerShadow from '../../node_modules/leaflet/dist/images/marker-shadow.png'

import { MapContainer, Marker, Popup, TileLayer, useMap } from 'react-leaflet'
import '../../node_modules/leaflet/dist/leaflet.css'; // 追加
import { useAtom, useAtomValue } from 'jotai';
import { latitudeAtom, longitudeAtom, manualLatitudeAtom, manualLongitudeAtom, watchedLatitudeAtom, watchedLongitudeAtom } from './Atom';
import { CenterMapButton } from './CenterMapButton';
import { ToHomeButton } from './ToHomeButton';
import { AutoFlyTo } from './AutoFlyTo';
import { CurrentCoordinate } from './CurrentCoordinate';

import { useGeoWatcher } from './useGeoWatcher';
import { useEffect } from 'react';

const DefaultIcon = L.icon({ // .iconカスタムアイコン作成のクラス
  iconUrl: markerIcon, // iconとして表示する画像のURL
  shadowUrl: markerShadow, // マーカーに影を表示する場合その影のURL
  iconSize: [25, 41], // アイコン画像の幅と高さピクセル単位
  iconAnchor: [12, 41], // アイコン画像のどの点が地図上の座標と一致するか ピクセル単位
  popupAnchor: [1, -34], // ポップアップウィンドウがアイコン画像からどのくらい離れるか
  shadowSize: [41, 41] // 影画像の幅と高さ
});

L.Marker.prototype.options.icon = DefaultIcon;

export const MapPage = () => {

  const latitude = useAtomValue(latitudeAtom);
  const longitude = useAtomValue(longitudeAtom);
  const [ watchedLatitude , setWatchedLatitude ] = useAtom(watchedLatitudeAtom);
  const [ watchedLongitude , setWatchedLongitude ] = useAtom(watchedLongitudeAtom);
  const manualLatitude = useAtomValue(manualLatitudeAtom);

  // 位置管理ロジック
  useEffect(() => {
    const watchId = navigator.geolocation.watchPosition((position) => {
      console.log('watchのpositon値', position);
      if (manualLatitude === null) {
        setWatchedLatitude(position.coords.latitude);
        setWatchedLongitude(position.coords.longitude);
      }
    },
    (error) => console.error('watch位置情報取得エラー', error),
    { enableHighAccuracy: true }
  );
  return () => navigator.geolocation.clearWatch(watchId);
  }, [manualLatitude]);

  return (
    <>
      <MapContainer
        center={
          watchedLatitude && watchedLongitude ? [watchedLatitude, watchedLongitude] : [35.681641, 139.766921]
        }
        zoom={17}
        scrollWheelZoom={true} // scrollでzoom可
        zoomSnap={0.5} // zoomの段階調整
        style={{ height: '100vh', width: '100vw' }} // 追加
        >
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
          <CurrentCoordinate /> {/* 座標表示 */}
          <CenterMapButton /> {/* 現在地に移動ボタン */}

          <ToHomeButton />
          <AutoFlyTo/> {/* 追従 */}
        <Marker
          key={`${watchedLatitude}-${watchedLongitude}`}
          position={
            watchedLatitude && watchedLongitude ? [watchedLatitude, watchedLongitude] : [35.681641, 139.766921]
          } // ↑ このあたりの記述を修正
        >
          <Popup>
           現在地: <br /> {watchedLatitude?.toFixed(6)}, {watchedLongitude?.toFixed(6)}
          </Popup>
        </Marker>
      </MapContainer>
    </>
  )
}


参考

おわりに

単純な修正に気付くまでに1日かけてしまいました。


2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?