React-Leaflet: Intro singkat, dengan animasi.

Mar 30 2023
Saya penggemar berat memvisualisasikan data — apakah itu melacak suhu, stempel waktu, atau bahkan memplot lokasi di peta. Saya telah bermain-main dengan Leaflet dalam proyek hobi terbaru saya, dan karena saya suka menggunakan React, saya pikir saya akan mencoba React-Leaflet.

Saya penggemar berat memvisualisasikan data — apakah itu melacak suhu, stempel waktu, atau bahkan memplot lokasi di peta. Saya telah bermain-main dengan Leaflet dalam proyek hobi terbaru saya, dan karena saya suka menggunakan React, saya pikir saya akan mencoba React-Leaflet .

Dalam panduan ini saya akan menggunakan proyek saya sebagai referensi, Anda dapat memeriksa halamannya di sini . Konsep halamannya sangat sederhana, hanya kumpulan ulasan makanan yang dikaitkan dengan toko dengan lokasi. Lokasi ditampilkan di peta. Fungsi peta utama yang saya gunakan di sini adalah flyTo, dan perpustakaan bernama Leaflet.SmoothMarkerBouncing untuk menambahkan animasi ke penanda yang dipilih.

Untuk mengawali panduan ini, saya ingin memperjelas bahwa struktur React bukanlah praktik terbaik dan hanya berfungsi untuk menguji teknologi lain yang ingin saya pelajari dalam proyek ini.

Untuk singkatnya, saya tidak menyertakan beberapa bagian kode, seperti pengambilan data dan login, karena hal itu berada di luar cakupan panduan ini.

Versi paket yang digunakan dalam artikel ini meliputi:

"react": "^18.2.0",
    "react-scripts": "5.0.1",
    "react-dom": "^18.2.0",
    "react-leaflet": "^4.2.0",
    "leaflet": "^1.9.3",
    "leaflet.smooth_marker_bouncing": "^3.0.2",

Data saya ada di reviewDataobjek, di mana setiap entri memiliki properti bernama location. Data lokasi mengikuti L.LatLngformat yang ditentukan oleh Leaflet, di sini .

import React, { useState } from "react";
import { MapContainer, TileLayer, Marker} from "react-leaflet";
import { MapController } from "./components/map/MapController";

function App() {
  // my data which includes the location
  const [reviewData, setReviewData] = useState<Review[]>([]);
  const [selectedReview, selectReview] = useState<Review | null>();

  return (
    <div>
      {/* other components ... */}

      <MapContainer
        id="map"
        // where the map should start, this is for Oslo
        center={[59.914, 10.734]} 
      >
        <TileLayer
           attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
           url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />

        <MapController
          selectedReview={selectedReview}
        />

        {reviewData.map((review) => {
          return (
            <Marker
              position={review.location}
              eventHandlers={{
                click: () => {selectReview(review)},
              }}
            ></Marker>
          );
        })}
      </MapContainer>
    </div>
  );
}

export default App;

Perhatikan juga bahwa TileLayer dalam kode menggunakan set default, sedangkan halaman saya menggunakan outdoors-v9 from Mapbox .

Jadi ketika kita memiliki pengaturan React-Leaflet dasar, kita dapat mulai membuat MapController, seperti yang disebutkan di atas untuk mengakses konteks Leaflet, kita harus berada dalam keturunan peta.

Kami akan mulai dengan menambahkan fungsionalitas sederhana terbang ke mana pun ulasan yang dipilih. Untuk mengakses peta kami menggunakan useMappengait yang diimpor dari react-leaflet. Cara paling sederhana adalah menggunakan an useEffectuntuk memeriksa ulasan yang dipilih dan terbang ke lokasinya atau ke "pusat" yang ditentukan saat tidak ada ulasan yang dipilih.

import React, { FC, useEffect } from "react";
import { useMap } from "react-leaflet";

const MapController: FC<{ selectedReview: Review }> = ({selectedReview}) => {
  const map = useMap();
  const flyToDuration = 1.5;

  const flyTo = (location: LatLngTuple) => {
    map.flyTo(location, 15, {
      animate: true,
      duration: flyToDuration,
    });
  };

  const flyToCenter = () => {
    map.flyTo([59.914, 10.734], 13, {
      animate: true,
      duration: flyToDuration,
    });
  };

  useEffect(() => {
    if(selectedReview) {
      flyTo(selectedReview.location);
    } else {
      flyToCenter();
    }
  }, [selectedReview])

  return null;
});

export { MapController };

Fungsionalitas yang dijelaskan di atas akan terlihat seperti ini, minus animasi memantul yang akan segera kami tambahkan.

Untuk menambahkan animasi memantul kita perlu menginstal Leaflet.SmoothMarkerBouncing dengan menjalankan perintah dan mengimpornya.

npm install leaflet.smooth_marker_bouncing

const MapController: FC<{ selectedReview: Review }> = ({selectedReview}) => {
  const map = useMap();
  const flyToDuration = 1.5;

  // [ flyTo code... ]

  useEffect(() => {
    map.eachLayer(async (layer) => {
      if (layer instanceof L.Marker) {
        if (layer.position == props.selectedReview.location) {
          await sleep(flyToDuration * 1000 + 100);
          layer.bounce();
        } else {
          layer.stopBouncing();
        }
      }
    });
  }, [props.selectedReview]);
});

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));