React Leaflet Routing Machine:在删除所有航点后,onClick 添加标记仅在第二次点击后触发

问题描述

我遵循了 Leaflet Routing Machine regarding interactions(即 onClicks)中的建议。

通过我的实现,我将航点保存在本地存储中——将我从地图点击中获得的纬度和经度 obj 保存到一个名为 markers 的数组

事件处理程序有一个条件,它将点击分为两个结果——添加(到标记数组)或更新它。

就像我在标题中所说的,初始交互很好,只是当我删除任何标记并尝试再次添加时,问题就出现了。我还注意到 markers 数组完全为空,并且下一个触发的事件是一个更新,显然它应该是一个补充:

这是路由机中的相关代码

class Routing extends MapLayer {
  static contextType = UserContextdispatch;

  constructor(props) {
    super(props);
    this.state = {
      showSpinner: false,localdispatch: null,};

    this.handleLoader = this.handleLoader.bind(this);
    this.handleRemoveWayPoint = this.handleRemoveWayPoint.bind(this);
    this.handleSetMarker = this.handleSetMarker.bind(this);
  }


  handleRemoveWayPoint() {

    var waypoints = this.control.getWaypoints();

    for (let i = waypoints.length - 1; i >= 0; i--) {
      console.log('waypoints[i].latLng !== null ',waypoints[i].latLng !== null);
      if (waypoints[i].latLng !== null) {
        waypoints[i].latLng = null;
        break;
      }
    }
    this.control.setWaypoints(waypoints);
  }

  createLeafletElement(props) {
    const { map } = this.props.leaflet;

    if (map && !this.control) {

      this.control = L.Routing.control({
        collapsible: true,show: false,position: 'bottomleft',lineOptions: {
          styles: [{ color: 'chartreuse',opacity: 1,weight: 5 }]
        },waypoints: [null],createMarker: function(i,wp,nWps) {
          if (i === 0) {
            return L.marker(wp.latLng,{
              icon: startIcon,draggable: true,keyboard: true,alt: 'current location'
            }).on('drag',function(e) {
              e.latlng.alt = 'current location';

              console.log('there be dragons start!!',e);
              RoutingMachineRef.handleSetMarker({
                ...e.oldLatLng,...e.latlng
              });
            });
          }
          if (i === nWps - 1) {
            return L.marker(wp.latLng,{
              icon: endIcon,alt: 'current destination'
            }).on('drag',function(e) {
              e.latlng.alt = 'current destination';

              console.log('there be dragons dest!!',...e.latlng
              });
            });
          }
        }
      });

      L.Routing.errorControl(this.control).addTo(map);
    }

    return this.control.getPlan();
  }

  componentDidMount() {
    const { map } = this.props.leaflet;

    console.log('markers ',markers);
    this.setState(prevstate => {
      localdispatch: prevstate.localdispatch = this.context.dispatch;
    });

    map.addControl(this.control);
  }

  updateLeafletElement(fromProps,toProps) {
    const { map } = this.props.leaflet;
    var self = this;
    self;
    var { markers } = this.props;

    function createButton(label,container) {
      var btn = L.DomUtil.create('button','',container);
      btn.setAttribute('type','button');
      btn.innerHTML = label;
      return btn;
    }

    var { localdispatch } = this.state;
    var container = L.DomUtil.create('div'),startBtn = createButton('Start from this location',container),destBtn = createButton('Go to this location',container);
    map.on(
      'click',function(e) {
        L.popup()
          .setContent(container)
          .setLatLng(e.latlng)
          .openOn(map);

        L.DomEvent.on(startBtn,'click',function() {
  
          if (e.latlng) {
            e.latlng.alt = 'current location';
            console.log('adding);
            localdispatch({
              type: 'addMarker',payload: {
                marker: e.latlng
              }
            });
          }

          if (markers.length === 0) {
            console.log('updating ');
            e.latlng.alt = 'current location';

            localdispatch({
              type: 'updateMarkers',payload: {
                marker: e.latlng
              }
            });
          }

          self.control.spliceWaypoints(0,1,e.latlng);
          map.closePopup();
        });

        L.DomEvent.on(
          destBtn,function() {
            console.log('e',e);
            if (markers[1] === undefined) {
              e.latlng.alt = 'current destination';
              console.log('e.latlng ',e.latlng);
              localdispatch({
                type: 'addMarker',payload: {
                  marker: e.latlng
                }
              });
            }
            if (toProps.markers[1] !== undefined) {
              console.log('updating ');
              e.latlng.alt = 'current destination';

              localdispatch({
                type: 'updateMarkers',payload: {
                  marker: e.latlng
                }
              });
            }

            this.control.spliceWaypoints(1,e.latlng);

            map.closePopup();
          }.bind(this)
        );
      }.bind(this)
    );


    if (toProps.removeRoutingMachine !== false) {
      this.control.setWaypoints([]);
    }
  }

  componentwillUnmount() {
    this.destroyRouting();
  }

  destroyRouting() {
    const { map } = this.props.leaflet;
    if (map) {
      map.removeControl(this.control);
    }
  }
}

export default withLeaflet(Routing);

提前致谢!

解决方法

如您所见,我有一些与 Map 本身中的 RoutingMachine(航点的 onClick)相关的代码;在考虑之后,我将其作为 Map 移至 handlerFunction 组件。现在它起作用了!

import React,{ useState,useEffect,useRef } from 'react';
import { Button,Dimmer,Loader } from 'semantic-ui-react';

import L from 'leaflet';
import * as ELG from 'esri-leaflet-geocoder';

import Control from 'react-leaflet-control';
// import MapboxLayer from '../MapboxLayer/MapboxLayer.jsx';
import Routing from '../RoutingMachine/RoutingMachine.jsx';

import { parse,stringify } from 'flatted';

import { userState,userDispatch } from '../Context/UserContext.jsx';
import UIContext from '../Context/UIContext.jsx';

function currentMapViewPropsAreEqual(prevProps,nextProps) {
  console.log('prevProps,nextProps ',prevProps,nextProps);
  console.log(
    'prevProps.currentMapView === nextProps.currentMapView && prevProps.Map === nextProps.Map && prevProps.TileLayer === nextProps.TileLayer ',prevProps.currentMapView === nextProps.currentMapView &&
      prevProps.Map === nextProps.Map &&
      prevProps.TileLayer === nextProps.TileLayer
  );
  return (
    prevProps.currentMapView === nextProps.currentMapView &&
    prevProps.Map === nextProps.Map &&
    prevProps.TileLayer === nextProps.TileLayer
  );
}

function MyMap({ currentMapView,Map,TileLayer }) {
  console.log('currentMapView; ',currentMapView);
  var [animate,setAnimate] = useState(false);
  var [userLocation,setUserLocation] = useState(null);

  const [myState,setMyState] = useState(null);

  var handleWaypointsOnMapRef = useRef(handleWaypointsOnMap);

  var mapRef = useRef();
  var mapRefForRoutingMachine = useRef();
  var { state } = userState();
  var { dispatch } = userDispatch();
  var {
    currentMap,isRoutingVisible,removeRoutingMachine,isLengthOfMarkersLessThanTwo,markers
  } = state;

  useEffect(() => {
    handleWaypointsOnMapRef.current = handleWaypointsOnMap;
  }); // update after each render

  useEffect(() => {
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;

    console.log('foo');

    console.log('currentMap ',currentMapView);
    map.locate({ setView: true });
    map.on('locationfound',handleOnLocationFound);
  },[]);

  useEffect(() => {
    var searchControl = new ELG.Geosearch({
      useMapBounds: false
    });
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;

    console.log('mapRef ',mapRef);

    searchControl.addTo(map);

    var cb = e => handleWaypointsOnMapRef.current(e); // then use most recent cb value

    searchControl.on('results',cb);

    if (Object.keys(currentMap).length === 0) {
      dispatch({
        type: 'setMap',payload: {
          currentMap: stringify(map)
        }
      });
    }

    return () => {
      searchControl.off('results',cb);
    };
  },[]);

  function handleOnClickClearOneMarkerAtTime() {
    dispatch({
      type: 'setIsRoutingVisible',payload: {
        isRoutingVisible: false
      }
    });
    mapRefForRoutingMachine.current.handleRemoveWayPoint();
    dispatch({
      type: 'deleteUserMarkers'
    });
  }

  function handleOnClickClearAllMarkers() {
    mapRefForRoutingMachine.current.handleClearWayPoints();
    dispatch({
      type: 'resetUserMarkers'
    });
  }

  function handleOnClickMarkerClick(e) {
    e.originalEvent.view.L.DomEvent.stopPropagation(e);
  }

  function handleWaypointsOnMap(e) {
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;
    dispatch({
      type: 'setIsRoutingVisible',payload: {
        isRoutingVisible: true
      }
    });
    dispatch({
      type: 'setRemoveRoutingMachine',payload: {
        removeRoutingMachine: false
      }
    });

    function createButton(label,container) {
      var btn = L.DomUtil.create('button','',container);
      btn.setAttribute('type','button');
      btn.innerHTML = label;
      return btn;
    }
    var container = L.DomUtil.create('div'),startBtn = createButton('Start from this location',container),destBtn = createButton('Go to this location',container);

    L.popup()
      .setContent(container)
      .setLatLng(e.latlng)
      .openOn(map);

    L.DomEvent.on(startBtn,'click',function() {
      if (markers.length === 0) {
        e.latlng.alt = 'current location';

        console.log('adding current location',e.latlng);

        dispatch({
          type: 'addMarker',payload: {
            marker: e.latlng
          }
        });
      }

      if (markers[0] != undefined) {
        e.latlng.alt = 'current location';
        console.log('updating current location',e.latlng);

        dispatch({
          type: 'updateMarkers',payload: {
            marker: e.latlng
          }
        });
      }

      mapRefForRoutingMachine.current.handleSpliceWaypoints(0,1,e.latlng);

      map.closePopup();
    });

    L.DomEvent.on(
      destBtn,function() {
        console.log('e',e);
        if (markers.length === 1) {
          e.latlng.alt = 'current destination';
          console.log('adding destination ',e.latlng);
          dispatch({
            type: 'addMarker',payload: {
              marker: e.latlng
            }
          });
        }
        if (markers.length === 2 && markers[1] !== undefined) {
          e.latlng.alt = 'current destination';
          console.log('updating destination',e.latlng);

          dispatch({
            type: 'updateMarkers',payload: {
              marker: e.latlng
            }
          });
        }

        mapRefForRoutingMachine.current.handleSpliceWaypoints(1,e.latlng);

        map.closePopup();
      }.bind(this)
    );
  }

  function handleOnViewportChanged(e) {
    console.log('viewport change',e);

    console.log('currentMapView ',currentMapView);
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;

    map.on('zoomend',function() {
      var zoom = map.getZoom();
      console.log('zoom ',zoom);

      console.log("'dispatch setMapZoom'; ");
      dispatch({
        type: 'setMapZoom',payload: {
          currentMapView: zoom
        }
      });
    });
  }

  function handleOnLocationFound(e) {
    console.log('e ',e);
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;
    map.setZoom(currentMapView);

    var latlng = e.latlng;
    var radius = e.accuracy;
    var circle = L.circle(latlng,radius);
    circle.addTo(map);
  }

  return (
    <Map
      preferCanvas={true}
      id="myMap"
      animate={animate}
      zoom={currentMapView}
      ref={mapRef}
      onViewportChanged={handleOnViewportChanged}
      onClick={e => handleWaypointsOnMap(e)}
    >
      <TileLayer
        url={`https://api.mapbox.com/styles/v1/${process.env.MAPBOX_USERNAME}/${
          process.env.MAPBOX_STYLE_ID
        }/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.MAPBOX_ACCESS_TOKEN}`}
        attribution='Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors,<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>,Imagery &copy; <a href="https://www.mapbox.com/">Mapbox</a>'
      />

      <Control position="bottomleft">
        <Button onClick={handleOnClickClearOneMarkerAtTime} color="orange" size="small">
          delete one marker!
        </Button>
      </Control>
      <Control position="bottomright">
        <Button onClick={handleOnClickClearAllMarkers} color="red" size="small">
          clear all!
        </Button>
      </Control>

      {mapRef && (
        <Routing
          isRoutingVisible={isRoutingVisible}
          ref={mapRefForRoutingMachine}
          markers={markers}
          stringify={stringify}
          isLengthOfMarkersLessThanTwo={isLengthOfMarkersLessThanTwo}
          removeRoutingMachine={removeRoutingMachine}
          userLocation={userLocation}
        />
      )}
    </Map>
  );
}

var MemoizedMyMap = React.memo(MyMap,currentMapViewPropsAreEqual);

export default MemoizedMyMap;

这是路由机器:

import { MapLayer } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet-routing-machine';
import { withLeaflet } from 'react-leaflet';
import UserContextDispatch from '../Context/UserContext.jsx';
import { Dimmer,Loader } from 'semantic-ui-react';
import { isEqual } from 'lodash';

import AwesomeDebouncePromise from 'awesome-debounce-promise';

class Routing extends MapLayer {
  static contextType = UserContextDispatch;

  constructor(props) {
    super(props);
    this.state = {
      showSpinner: false,localDispatch: null,markerIsBeingDragged: false,currentMarker: {}
    };

    this.handleLoader = this.handleLoader.bind(this);
    this.handleRemoveWayPoint = this.handleRemoveWayPoint.bind(this);
    this.handleClearWayPoints = this.handleClearWayPoints.bind(this);
    this.handleSpliceWaypoints = this.handleSpliceWaypoints.bind(this);
    this.handleSetMarker = this.handleSetMarker.bind(this);
  }

  handleSetMarker(marker) {
    var { markers } = this.props;

    if (markers[0] !== undefined && markers[0].alt === 'current location') {
      this.setState(prevState => ({
        currentMarker: { ...prevState.currentMarker,...marker }
      }));
    }
    if (markers[1] !== undefined && markers[1].alt === 'current destination') {
      this.setState(prevState => ({
        currentMarker: { ...prevState.currentMarker,...marker }
      }));
    }

    console.log('this.state ',this.state);
  }

  handleSpliceWaypoints(start,end,obj) {
    this.control.spliceWaypoints(start,obj);
  }

  handleLoader() {
    var { showSpinner } = this.state;

    if (this.state.showSpinner === false) {
      this.setState(function(prevState) {
        return { showSpinner: !prevState.showSpinner };
      });
      return (
        <Dimmer active inverted>
          <Loader />
        </Dimmer>
      );
    }
    this.setState(function(prevState) {
      return { showSpinner: (prevState.showSpinner = true) };
    });
  }

  handleRemoveWayPoint() {
    var waypoints = this.control.getWaypoints();

    for (let i = waypoints.length - 1; i >= 0; i--) {
      console.log('waypoints[i].latLng !== null ',waypoints[i].latLng !== null);
      if (waypoints[i].latLng !== null) {
        waypoints[i].latLng = null;
        break;
      }
    }
    console.log('waypoints ',waypoints);
    this.control.setWaypoints(waypoints);
  }

  handleClearWayPoints() {
    this.control.setWaypoints([L.latLng(null,null),L.latLng(null,null)]);
  }

  componentDidMount() {
    const { map } = this.props.leaflet;

    var { markers } = this.props;

    this.control.setWaypoints([L.latLng(markers[0]),L.latLng(markers[1])]);
    this.setState(prevState => {
      localDispatch: prevState.localDispatch = this.context.dispatch;
    });

    map.addControl(this.control);
  }

  createLeafletElement(props) {
    const { map } = this.props.leaflet;

    var startIcon = new L.Icon({
      iconUrl:
        'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',shadowUrl:
        'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',iconSize: [25,41],iconAnchor: [12,popupAnchor: [1,-34],shadowSize: [41,41]
    });

    var endIcon = new L.Icon({
      iconUrl:
        'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',41]
    });

    if (map && !this.control) {
      var RoutingMachineRef = this;

      this.control = L.Routing.control({
        collapsible: true,show: false,position: 'bottomleft',lineOptions: {
          styles: [{ color: 'chartreuse',opacity: 1,weight: 5 }]
        },waypoints: [null],createMarker: function(i,wp,nWps) {
          if (i === 0) {
            return L.marker(wp.latLng,{
              icon: startIcon,draggable: true,keyboard: true,alt: 'current location'
            }).on('move',function(e) {
              e.target._latlng.alt = 'current location';
              console.log('e.target._latlng',e.target._latlng);

              console.log('there be dragons start!!',e);
              RoutingMachineRef.setState(prevState => ({
                markerIsBeingDragged: !prevState.markerIsBeingDragged
              }));
              RoutingMachineRef.handleSetMarker(e.target._latlng);
            });
          }
          if (i === nWps - 1) {
            return L.marker(wp.latLng,{
              icon: endIcon,alt: 'current destination'
            }).on('move',function(e) {
              e.target._latlng.alt = 'current destination';

              console.log(' e.target._latlng',e.target._latlng);
              RoutingMachineRef.setState(prevState => ({
                markerIsBeingDragged: !prevState.markerIsBeingDragged
              }));
              console.log('there be dragons dest!!',e);
              RoutingMachineRef.handleSetMarker(e.target._latlng);
            });
          }
        }
      });

      L.Routing.errorControl(this.control).addTo(map);
    }

    return this.control.getPlan();
  }

  updateLeafletElement(fromProps,toProps) {
    var { currentMarker,localDispatch,markerIsBeingDragged } = this.state;

    // console.log('fromProps,toProps ',fromProps,toProps);
    if (markerIsBeingDragged && currentMarker.hasOwnProperty('alt')) {
      if (isEqual(toProps.markers[0],currentMarker) === false) {
        localDispatch({
          type: 'updateMarkers',payload: {
            marker: currentMarker
          }
        });
      }
      if (isEqual(toProps.markers[1],payload: {
            marker: currentMarker
          }
        });
      }

      this.setState(prevState => ({
        markerIsBeingDragged: !prevState.markerIsBeingDragged
      }));
    }

    if (toProps.removeRoutingMachine !== false) {
      this.control.setWaypoints([]);
    }
  }

  componentWillUnmount() {
    console.log("'unmount' ",'unmount');
    this.destroyRouting();
  }

  destroyRouting() {
    const { map } = this.props.leaflet;
    if (map) {
      map.removeControl(this.control);
    }
  }
}

export default withLeaflet(Routing);

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...