3
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?

More than 3 years have passed since last update.

ReactでLeafletの地図ライブラリを使う

Last updated at Posted at 2022-01-15

はじめに

JavaScript 地図ライブラリ Leaflet 基本処理サンプルのReact版です。
Reactになると、結構考え方が違うので、忘れないようにメモ。

パッケージ追加

yarn add leaflet react-leaflet

フォルダ構成

src
 ├ index.js 
 ├ App.js
 ├ util
 │  └ leafletCommon.js
 └ mapIcon
     ├ icon1.png
     └ icon2.png

フォルダ&ファイル構成のざっくり説明

  • util/leafletCommon.js は共通設定とか共通処理(現在地取得しかありませんが)とか
  • mapIcon はアイコン画像を格納しているフォルダ(この辺り良いパッケージがなかった、、、)
  • App.js 実際ページ(コンポーネント上で)上でどう使うか

    ※indexはデフォルトのやつです

コード

util/leafletCommon.js
// 地図の設定
export const mapOption = {
  startZoom: "13", // 開始時のズーム値
  maxZoom: "18", // 最大のズーム値
  minZoom: "5", // 最小のズーム値
};

// 現在地(緯度経度取得)関数
export const getCurrentPosition = () =>
  new Promise((resolve, reject) =>
    navigator.geolocation.getCurrentPosition(resolve, reject)
  );
App.js
import React, { useState, useEffect } from "react";
import "leaflet/dist/leaflet.css"; 
import Leaflet from "leaflet";
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";

import { mapOption, getCurrentPosition } from "./util/leafletCommon";

// 切り替え前データ
const tempPlaceData1 = [
  { id: "1", lat: 33.59513931435894, lng: 130.42419433593753, name: "地点A" },
  { id: "2", lat: 33.59260123175435, lng: 130.41131973266604, name: "地点B" },
  { id: "3", lat: 33.59517506146791, lng: 130.42694091796878, name: "地点C" },
  { id: "4", lat: 33.59653344063089, lng: 130.420138835907, name: "地点D" },
  { id: "5", lat: 33.592813804823924, lng: 130.42249917984012, name: "地点E" },
  { id: "6", lat: 33.590849553725455, lng: 130.4186797142029, name: "地点F" },
];
// 切り替え後データ
const tempPlaceData2 = [
  { id: "7", lat: 33.55513931435894, lng: 130.40419433593753, name: "地点G" },
  { id: "8", lat: 33.59260123175435, lng: 130.42131973266604, name: "地点H" },
  { id: "9", lat: 33.57517506146791, lng: 130.43694091796878, name: "地点I" },
  { id: "10", lat: 33.58653344063089, lng: 130.390138835907, name: "地点J" },
];

// 現在地アイコン
const currentIcon = Leaflet.icon({
  iconUrl: require("./mapIcon/icon1.png"),
  iconSize: [40, 40],
});
// 場所アイコン
const placeIcon = Leaflet.icon({
  iconUrl: require("./mapIcon/icon2.png"),
  iconSize: [40, 40],
});

const App = () => {
  // キー設定
  const [mapKey, setMapKey] = useState(0);
  // 現在地情報
  const [currentPosition, setCurrentPosition] = useState({
    lat: 0,
    lng: 0,
  });
  // 場所情報
  const [placeData, setPlaceData] = useState([]);

  // 初期処理
  useEffect(() => {
    moveCurrentPosition();
    setPlaceData([...tempPlaceData1]);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 現在地に移動
  const moveCurrentPosition = async () => {
    const location = await getCurrentPosition();
    setCurrentPosition({
      ...currentPosition,
      lat: location.coords.latitude,
      lng: location.coords.longitude,
    });
    // キーを設定して、再表示
    setMapKey(new Date().getTime());
  };

  // 検索処理
  const getLocationList = () => {
    // データ設定
    setPlaceData([...tempPlaceData2]);
    // 本当はfetchとかしてデータ取ってくる
    // const responce = await axios.get("http://localshot:8000/api/getLocation/...");
    // setPlaceData([...responce]);
  };

  return (
    <>
      {/* ボタン(機能操作) */}
      <div>
        <button onClick={() => moveCurrentPosition()}>現在地</button>
        <button onClick={() => getLocationList()}>検索</button>
      </div>
      {/* 地図表示 */}
      <MapContainer
        key={mapKey}
        center={currentPosition}
        zoom={mapOption.startZoom}
        style={{ height: "90vh", width: "100vw" }}
      >
        {/* 地図のタイル情報 */}
        <TileLayer
          attribution='&amp;copy <a href="http://osm.org/copyright";>OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          maxZoom={mapOption.maxZoom}
          minZoom={mapOption.minZoom}
        />
        {/* 現在地情報を出力 */}
        <Marker position={currentPosition} icon={currentIcon}>
          <Popup>現在地</Popup>
        </Marker>
        {/* 場所情報を出力 */}
        {placeData.length > 0
          ? placeData.map((item) => (
              <Marker key={item.id} position={item} icon={placeIcon}>
                <Popup>{item.name}</Popup>
              </Marker>
            ))
          : null}
      </MapContainer>
    </>
  );
};

export default App;

こんな感じ

leaflet.gif

最後に

自宅でアップすると、家の場所をさらした記事が出来上がってしまうので、危なかった、、
あと、画像のアップロード2M制限とかあったのか、、知らんかった

3
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
3
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?