How to make a draggable Tooltip in React-Leaflet v4?

202 Views Asked by At

I would like to implement a Tooltip attached to a Marker, then be able to drag that Tooltip anywhere on the map and draw a Polyline connecting the Tooltop to its parent marker. Is this possible? I can’t see any such behavior in the RL documentation.

2

There are 2 best solutions below

0
On

you can easily track your popup or tooltip using eventHandles and get event to element and use leaflet draggable function

 <Popup
                // permanent
                className="bg-white "
                direction="bottom"
                // offset={[-3, -2]}
                ref={markerDiv}
                interactive={true}
                eventHandlers={{ 
                  mouseover: (e) => {
                  // console.log('over',e.target.getElement())
                    const element = e.target.getElement();
                    const draggable = new L.Draggable(element)
                    draggable.enable()
                  }
                }}
              
              >
Your text here
</Popup>
3
On

first you need to get your popup or tooltip element when its created using useRef and after set popup or tooltip you must get elelemt using userRef.current.getElement() after this you will get the div element and use leaflet Dragrable function and enable it you must try to you own testing area you will understood very well

import { toJS } from 'mobx';
import { inject, observer } from 'mobx-react'
import React, { useEffect, useRef, useState } from 'react'
import L from 'leaflet'
import { Marker, Popup, Tooltip, useMap } from 'react-leaflet';
import { svgIcon } from '../MarkerIcons/makerIcons';
import { LIVE_CAMERA_IMAGE } from 'config';
import moment from 'moment';

const DragableTooltip = () => {
  const { filterLapseImages } = props.lapseImageStore;
  const { forecast } = props.forecastStore;
  const [imgIndx, setImgIndx] = useState(0)
  const map = useMap();
  const markerDiv = useRef()

  useEffect(() => {
    let intervel;
    if(forecast.lapse_images) {
      intervel = setInterval(() => {
        if(imgIndx >= 3) return setImgIndx(0);
        setImgIndx(imgIndx + 1)
      }, 10000)
    }else{
      setImgIndx(0)
      clearInterval(intervel)
    }
    return () => clearInterval(intervel)

  }, [imgIndx, forecast.lapse_images])
  // console.log(imgIndx)


 useEffect(() => {
    if(markerDiv){
      console.log(markerDiv.current.getElement())
      const tooltip = markerDiv.current;
      const tooltipElement = tooltip.getElement();
      const draggable = new L.Draggable(tooltipElement)
      draggable.enable()
      console.log(tooltip)
    }
  }, [markerDiv])


return (
    <>
    <div >
      {toJS(filterLapseImages).map((item, indx) => {
        // console.log(toJS(item))
        const files = toJS(item.files).slice().sort((a, b) => {
          return new Date(b.date_taken) - new Date(a.date_taken);
        })
        const imageList = files.slice(0, 4)
        // console.log(imageList)
        return(
          <Marker key={indx} position={[item.latitude, item.longitude]} icon={L.divIcon({html: svgIcon(indx, 'orange', "8", 'none', 2)})}>
            <Tooltip permanent className='bg-white' direction='bottom' offset={[-3, -2]} interactive={true} ref={markerDiv}   >
              <div className='text-sm font-bold p-1'>{item.name}</div>
              <div className='flex flex-row justify-between'>
                <span>{imageList[imgIndx]?.date_taken && moment(new Date(imageList[imgIndx].date_taken)).format("YY DD MMM, hh:mm:ss")}</span>
                <span>{imageList[imgIndx].album_code}</span>
              </div>
              <div className='h-full w-full'>
                <img 
                src={`${LIVE_CAMERA_IMAGE}/idaq-files/${imageList[imgIndx].source}`}
                alt="pop-images" 
                className='h-full w-full object-cover object-center'
                />
              </div>
            </Tooltip>
          </Marker>
        )
      })}
      </div>
    </>
  )
}