fix: prevent marker snap-back during drag via PubSub echo
All checks were successful
CI / Build and Test (push) Successful in 41s
CI / Build and Test (pull_request) Successful in 37s

When dragging a marker in a multi-client PubSub setup, the server echoes
position updates back to the originating client. The data-effect would
then call setLngLat with the stale echoed position, snapping the marker
back while the user had already dragged further.

Add a per-marker _dragging flag: set on dragstart, cleared after the
final dragend writeback. The signal→position effect skips setLngLat
(and rotation) while the flag is true.
This commit is contained in:
Ryan Hamamura
2026-02-20 16:00:26 -10:00
parent 63de5f997c
commit a6d18273e9

View File

@@ -273,7 +273,7 @@ func markerBodyJS(mapID, markerID string, mk Marker) string {
func dragHandlerJS(mapID string, mk Marker) string { func dragHandlerJS(mapID string, mk Marker) string {
// Shared writeback logic extracted into a local function for both handlers. // Shared writeback logic extracted into a local function for both handlers.
return fmt.Sprintf( return fmt.Sprintf(
`var _raf=0;`+ `var _raf=0;mk._dragging=false;`+
`function _wb(){`+ `function _wb(){`+
`var pos=mk.getLngLat();`+ `var pos=mk.getLngLat();`+
`var el=document.getElementById(%[1]s);if(!el)return;`+ `var el=document.getElementById(%[1]s);if(!el)return;`+
@@ -284,8 +284,9 @@ func dragHandlerJS(mapID string, mk Marker) string {
`if(sig===%[3]s){inp.value=pos.lat;inp.dispatchEvent(new Event('input',{bubbles:true}))}`+ `if(sig===%[3]s){inp.value=pos.lat;inp.dispatchEvent(new Event('input',{bubbles:true}))}`+
`});`+ `});`+
`}`+ `}`+
`mk.on('dragstart',function(){mk._dragging=true;});`+
`mk.on('drag',function(){if(_raf)return;_raf=requestAnimationFrame(function(){_raf=0;_wb()});});`+ `mk.on('drag',function(){if(_raf)return;_raf=requestAnimationFrame(function(){_raf=0;_wb()});});`+
`mk.on('dragend',function(){cancelAnimationFrame(_raf);_raf=0;_wb()});`, `mk.on('dragend',function(){cancelAnimationFrame(_raf);_raf=0;_wb();mk._dragging=false;});`,
jsonStr("_vwrap_"+mapID), jsonStr("_vwrap_"+mapID),
jsonStr(mk.LngSignal.ID()), jsonStr(mk.LngSignal.ID()),
jsonStr(mk.LatSignal.ID()), jsonStr(mk.LatSignal.ID()),
@@ -321,7 +322,7 @@ func markerEffectExpr(mapID, markerID string, mk Marker) string {
} }
b.WriteString(fmt.Sprintf( b.WriteString(fmt.Sprintf(
`var m=window.__via_maps&&window.__via_maps[%s];`+ `var m=window.__via_maps&&window.__via_maps[%s];`+
`if(m&&m._via_markers[%[2]s]){`+ `if(m&&m._via_markers[%[2]s]&&!m._via_markers[%[2]s]._dragging){`+
`m._via_markers[%[2]s].setLngLat([lng,lat])`, `m._via_markers[%[2]s].setLngLat([lng,lat])`,
jsonStr(mapID), jsonStr(markerID))) jsonStr(mapID), jsonStr(markerID)))
if mk.RotationSignal != nil && mk.Element != "" { if mk.RotationSignal != nil && mk.Element != "" {