Source: maps/MapMarkerOqt.js

import React, { useMemo, useRef, useEffect, useState } from "react";
import { Marker, Popup, useMap } from 'react-leaflet';
import icon from "./Marker1.svg";
import L from 'leaflet';

/**
 * Componente que renderiza una marca dentro de un mapa
 * @name Reactor.Components.Maps.MapMarkerOqt
 * @param {string!} name Nombre del input
 * @param {string!} lat 
 *    Valor de latitud actual
 * @param {string!} lng 
 *    Valor de longitud actual
 * @param {string?} text 
 *    Un texto que aparece en un popup
 * @param {"true"|"false"} [readonly = "false"] 
 *    Si es true deshabilita la posibilidad de modificar la ubicación de la marca.
 * @param {"true"|"false"} [use_change = "true"] 
 *    Si es true, al modificarse su valor desencadena el evento change del form que lo contiene
 * @class 
 * @returns {MapMarkerOqtResult}
 * @example 
<map_marker name="marca" lat="38.2111" lng="54.0121" text="una marca" readonly="false" use_change="true"></map_marker>
 */

const getIcon = (icon) => {
  return icon 
  ? new L.divIcon({
    html: icon,
    iconAnchor: null,
    popupAnchor: null,
    shadowUrl: null,
    shadowSize: null,
    shadowAnchor: null,
    iconSize: new L.Point(60, 75),
    className: 'leaflet-div-icon'
  })
  : markerIcon;
}

const geoOptions = {
  enableHighAccuracy: true
}

export const MapMarkerOqt = ({ name, lat, lng, text, readonly, use_change, icon }) => {

  const map = useMap();
  const [ state, setState ] = useState({ lat: 0, lng: 0 });
  const markerRef = useRef(null);
  const customIcon = useMemo(()=>getIcon(icon), [icon]);

  const handleChangeLocation = (latLng) => {
    setState(state => ({...state, ...latLng }))
  }  

  const eventMarkerHandlers = useMemo(
    () => ({
      dragend() {
        const marker = markerRef.current
        if (marker != null) {
          handleChangeLocation(marker.getLatLng());
        }
      }
    }),
    [],
  );

  useEffect(()=>{
    if(state.lat === lat && state.lng === lng) return;
    if(!lat && !lng){

      map.addEventListener("move", mapLoaded)
     
      //handleChangeLocation(map.getCenter());
    }else{
      handleChangeLocation({lat, lng});
    }
  }, [lat, lng])

  const mapLoaded = ()=>{
    const center = map.getCenter()
    map.removeEventListener("move", mapLoaded);
    handleChangeLocation(center);
  }

  return (
    <>
      <input type="hidden" value={state.lat} name={`${name}.lat`} use_change={use_change}/>
      <input type="hidden" value={state.lng} name={`${name}.lng`} use_change={use_change}/>
      {customIcon && 
        <Marker 
          draggable={readonly !== "true"} 
          position={[state.lat, state.lng]} 
          icon={customIcon} 
          eventHandlers={readonly !== "true" ? eventMarkerHandlers : undefined}
          ref={markerRef}> 
          {text &&
            <Popup>
              {text}
            </Popup>
          }
        </Marker> 
      }
    </>
  )

}

const markerIcon = new L.Icon({
  iconUrl: icon,
  iconRetinaUrl: icon,
  iconAnchor: null,
  popupAnchor: null,
  shadowUrl: null,
  shadowSize: null,
  shadowAnchor: null,
  iconSize: new L.Point(60, 75),
  className: 'leaflet-div-icon'
});

/**
 * @typedef {Object} MapMarkerOqtResult
 * @property {number} lat Latitud
 * @property {number} lng Longitud
 */