11import { Map , Overlay } from 'ol'
22import { ContextMenuContent } from '@/map/ContextMenuContent'
3- import { useContext , useEffect , useRef , useState } from 'react'
3+ import { useCallback , useContext , useEffect , useRef , useState } from 'react'
44import { QueryPoint } from '@/stores/QueryStore'
55import { fromLonLat , toLonLat } from 'ol/proj'
66import styles from '@/layers/ContextMenu.module.css'
@@ -26,19 +26,14 @@ export default function ContextMenu({map, route, queryPoints}: ContextMenuProps)
2626 const container = useRef < HTMLDivElement | null > ( null )
2727 const settings = useContext ( SettingsContext )
2828
29- const queryPointsRef = useRef ( queryPoints )
30- queryPointsRef . current = queryPoints
31- const settingsRef = useRef ( settings )
32- settingsRef . current = settings
33-
34- const openContextMenu = ( e : any ) => {
29+ const openContextMenu = useCallback ( ( e : any ) => {
3530 e . preventDefault ( )
3631 const coordinate = map . getEventCoordinate ( e )
3732 const lonLat = toLonLat ( coordinate )
3833 setMenuCoordinate ( { lng : lonLat [ 0 ] , lat : lonLat [ 1 ] } )
39- }
34+ } , [ map ] )
4035
41- const handleClick = ( e : any ) => {
36+ const handleClick = useCallback ( ( e : any ) => {
4237 if ( e . dragging ) return
4338
4439 // If click is inside the context menu, do nothing
@@ -53,30 +48,29 @@ export default function ContextMenu({map, route, queryPoints}: ContextMenuProps)
5348 return
5449 }
5550
56- if ( ! settingsRef . current . addPointOnClick ) return
51+ if ( ! settings . addPointOnClick ) return
5752
5853 const lonLat = toLonLat ( e . coordinate )
5954 const myCoord = { lng : lonLat [ 0 ] , lat : lonLat [ 1 ] }
6055
61- const points = queryPointsRef . current
62- let idx = points . length
56+ let idx = queryPoints . length
6357 if ( idx == 2 ) {
64- if ( ! points [ 1 ] . isInitialized ) idx -- ;
58+ if ( ! queryPoints [ 1 ] . isInitialized ) idx -- ;
6559 }
6660 if ( idx == 1 ) {
67- if ( ! points [ 0 ] . isInitialized ) idx -- ;
61+ if ( ! queryPoints [ 0 ] . isInitialized ) idx -- ;
6862 }
6963 if ( idx < 2 ) {
7064 const setPoint = new SetPoint ( {
71- ...points [ idx ] ,
65+ ...queryPoints [ idx ] ,
7266 coordinate : myCoord ,
7367 queryText : coordinateToText ( myCoord ) ,
7468 isInitialized : true
7569 } , false ) ;
7670 Dispatcher . dispatch ( setPoint )
7771 } else
7872 Dispatcher . dispatch ( new AddPoint ( idx , myCoord , true , false ) )
79- }
73+ } , [ menuCoordinate , settings . addPointOnClick , queryPoints ] )
8074
8175 useEffect ( ( ) => {
8276 overlay . setElement ( container . current ! )
@@ -85,30 +79,43 @@ export default function ContextMenu({map, route, queryPoints}: ContextMenuProps)
8579 const longTouchHandler = new LongTouchHandler ( e => openContextMenu ( e ) )
8680
8781 function onMapTargetChange ( ) {
88- // it is important to set up new listeners whenever the map target changes, like when we switch between the
89- // small and large screen layout, see #203
90-
91- // we cannot listen to right-click simply using map.on('contextmenu') and need to add the listener to
92- // the map container instead
93- // https://github.com/openlayers/openlayers/issues/12512#issuecomment-879403189
94- map . getTargetElement ( ) . addEventListener ( 'contextmenu' , openContextMenu )
82+ const targetElement = map . getTargetElement ( )
83+ if ( ! targetElement ) {
84+ console . warn ( 'Map target element is null. Delaying event listeners setup.' ) ;
85+ return ;
86+ }
9587
96- map . getTargetElement ( ) . addEventListener ( 'touchstart' , e => longTouchHandler . onTouchStart ( e ) )
97- map . getTargetElement ( ) . addEventListener ( 'touchmove' , ( ) => longTouchHandler . onTouchEnd ( ) )
98- map . getTargetElement ( ) . addEventListener ( 'touchend' , ( ) => longTouchHandler . onTouchEnd ( ) )
88+ targetElement . addEventListener ( 'contextmenu' , openContextMenu )
89+ targetElement . addEventListener ( 'touchstart' , e => longTouchHandler . onTouchStart ( e ) )
90+ targetElement . addEventListener ( 'touchmove' , ( ) => longTouchHandler . onTouchEnd ( ) )
91+ targetElement . addEventListener ( 'touchend' , ( ) => longTouchHandler . onTouchEnd ( ) )
9992
10093 map . on ( 'singleclick' , handleClick )
10194 }
10295
96+ const cleanupMapTarget = ( ) => {
97+ const targetElement = map . getTargetElement ( )
98+ if ( targetElement ) {
99+ targetElement . removeEventListener ( 'contextmenu' , openContextMenu )
100+ targetElement . removeEventListener ( 'touchstart' , e => longTouchHandler . onTouchStart ( e ) )
101+ targetElement . removeEventListener ( 'touchmove' , ( ) => longTouchHandler . onTouchEnd ( ) )
102+ targetElement . removeEventListener ( 'touchend' , ( ) => longTouchHandler . onTouchEnd ( ) )
103+ }
104+ map . un ( 'singleclick' , handleClick )
105+ }
106+
107+ // Set up initial listeners
108+ onMapTargetChange ( )
109+
110+ // Listen for target changes
103111 map . on ( 'change:target' , onMapTargetChange )
104112
105113 return ( ) => {
106- map . getTargetElement ( ) . removeEventListener ( 'contextmenu' , openContextMenu )
107- map . un ( 'singleclick' , handleClick )
114+ cleanupMapTarget ( )
108115 map . removeOverlay ( overlay )
109116 map . un ( 'change:target' , onMapTargetChange )
110117 }
111- } , [ map ] )
118+ } , [ map , openContextMenu , handleClick ] )
112119
113120 useEffect ( ( ) => {
114121 overlay . setPosition ( menuCoordinate ? fromLonLat ( [ menuCoordinate . lng , menuCoordinate . lat ] ) : undefined )
0 commit comments