admin管理员组

文章数量:1394183

I have wrote a React project with react-leaflet and hook. My goal is to move and rotate marker every second. However, moving part is working fine. But the rotation of marker is not working. I am really stuck for last few days. I couldn't find a good solution. Please help me.

The map ponent is as follows.

import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import { useState, useEffect } from "react";
import L from 'leaflet';
import 'leaflet-marker-rotation';

const MySimpleMap = () => {
  const [lat, setLat] = useState(22.899397);
  const [lon, setLon] = useState(89.508279);
  const [heading, setHeading] = useState(30)

  useEffect(() => {
    const interval = setInterval(() => {
      myfun();
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, [lat]);

  const defaultIcon = L.icon({
    iconUrl: "/[email protected]/dist/images/marker-icon.png",
    iconSize: [20, 40],
    iconAnchor: [18, 18],
    popupAnchor: [0, -10],
    shadowAnchor: [10, 10]
  }); 

  const myfun = () => {    
    setLat(lat + 0.00001);
    setLon(lon + 0.00001);
    setHeading(heading+5);
    console.log("angle:" + heading);
  };
  return (
    <MapContainer className="map" center={[lat, lon]} zoom={21}>
      <TileLayer
        attribution='&amp;copy <a href=";>OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap/{z}/{x}/{y}.png"
      />
      <Marker position={[lat, lon]} icon={defaultIcon} rotationAngle={heading} rotationOrigin="center">
        <Popup>
          A pretty CSS3 popup. <br /> Easily customizable.
        </Popup>
      </Marker>
    </MapContainer>
  );
};

export default MySimpleMap;

The plete problem is in this sandbox: =/src/App.js

I have wrote a React project with react-leaflet and hook. My goal is to move and rotate marker every second. However, moving part is working fine. But the rotation of marker is not working. I am really stuck for last few days. I couldn't find a good solution. Please help me.

The map ponent is as follows.

import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import { useState, useEffect } from "react";
import L from 'leaflet';
import 'leaflet-marker-rotation';

const MySimpleMap = () => {
  const [lat, setLat] = useState(22.899397);
  const [lon, setLon] = useState(89.508279);
  const [heading, setHeading] = useState(30)

  useEffect(() => {
    const interval = setInterval(() => {
      myfun();
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, [lat]);

  const defaultIcon = L.icon({
    iconUrl: "https://unpkg./[email protected]/dist/images/marker-icon.png",
    iconSize: [20, 40],
    iconAnchor: [18, 18],
    popupAnchor: [0, -10],
    shadowAnchor: [10, 10]
  }); 

  const myfun = () => {    
    setLat(lat + 0.00001);
    setLon(lon + 0.00001);
    setHeading(heading+5);
    console.log("angle:" + heading);
  };
  return (
    <MapContainer className="map" center={[lat, lon]} zoom={21}>
      <TileLayer
        attribution='&amp;copy <a href="http://osm/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap/{z}/{x}/{y}.png"
      />
      <Marker position={[lat, lon]} icon={defaultIcon} rotationAngle={heading} rotationOrigin="center">
        <Popup>
          A pretty CSS3 popup. <br /> Easily customizable.
        </Popup>
      </Marker>
    </MapContainer>
  );
};

export default MySimpleMap;

The plete problem is in this sandbox: https://codesandbox.io/s/vigilant-wood-kgv4p?file=/src/App.js

Share Improve this question edited Feb 23, 2021 at 23:01 manjurul Islam asked Feb 23, 2021 at 22:43 manjurul Islammanjurul Islam 731 silver badge8 bronze badges 1
  • I have also created a sandbox here: codesandbox.io/s/vigilant-wood-kgv4p?file=/src/App.js – manjurul Islam Commented Feb 23, 2021 at 23:00
Add a ment  | 

2 Answers 2

Reset to default 4

Using some of the provided answers for rotating markers in this post , was able to get it to work with your provided codesandbox. The default Marker ponent does not have rotationAngle or rotationOrigin as valid props, you'd need to do something like done here to get that. So instead we can use re-use the rotation code and plug it into your code by lifting it into a re-usable function:

const applyRotation = (marker, _options) => {
  const oldIE = L.DomUtil.TRANSFORM === "msTransform";
  const options = Object.assign(_options, { rotationOrigin: "center" });
  const { rotationAngle, rotationOrigin } = options;

  if (rotationAngle && marker) {
    marker._icon.style[L.DomUtil.TRANSFORM + "Origin"] = rotationOrigin;

    if (oldIE) {
      // for IE 9, use the 2D rotation
      marker._icon.style[L.DomUtil.TRANSFORM] = `rotate(${rotationAngle} deg)`;
    } else {
      // for modern browsers, prefer the 3D accelerated version
      marker._icon.style[
        L.DomUtil.TRANSFORM
      ] += ` rotateZ(${rotationAngle}deg)`;
    }
  }
};

And then calling it once the rotation has been changed with a useEffect because we also want the Markers position to be updated otherwise the rotation won't work:

  useEffect(() => {
    applyRotation(markerRef.current, { rotationAngle: heading + 5 });
  }, [heading]);

When you call myFunc it updates the position (lat,lon) as well as the header (rotation) so by placing it in the useEffect, on next render Marker should have updated its position.

I have a codebox example here.

The above solution does have some issue's you'll need to sift through the leaflet-rotatedmarker library to get those missing edge cases. However if you can add that library a better solution would be importing that:

import L from "leaflet";
import "leaflet-rotatedmarker";

and using the extended setRotationAngle instead.

  useEffect(() => {
    if (markerRef.current) {
      markerRef.current.setRotationAngle(heading);
    }
  }, [heading]);

You can also use that to lift it into a RotatedMarker ponent so that your original use case of the props rotationAngle={heading} rotationOrigin="center" will work:

const RotatedMarker = forwardRef(({ children, ...props }, forwardRef) => {
  const markerRef = useRef();

  const { rotationAngle, rotationOrigin } = props;
  useEffect(() => {
    const marker = markerRef.current;
    if (marker) {
      marker.setRotationAngle(rotationAngle);
      marker.setRotationOrigin(rotationOrigin);
    }
  }, [rotationAngle, rotationOrigin]);

  return (
    <Marker
      ref={(ref) => {
        markerRef.current = ref;
        if (forwardRef) {
          forwardRef.current = ref;
        }
      }}
      {...props}
    >
      {children}
    </Marker>
  );
});

Here's the codepen where i tested the above out

To live rotate the marker when the rotation angle changes you must update the rotation value using the marker's refrence, you can update your code as follow:

/* your other code */
    const markerRef = useRef(null)

   useEffect(()=>{
      if(markerRef.current) 
        { markerRef.current.setRotationAngle(heading); }
    
     },[heading])
.....
....
<Marker ref={markerRef} rotationAngle={heading}> 
...other code
</Marker>

本文标签: javascriptHow to dynamically move and rotate marker in reactleafletStack Overflow