-
-
Notifications
You must be signed in to change notification settings - Fork 923
fix: popup detachment from marker during animation with world copies #5956
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Thanks for taking the time to solve this issue! |
|
Tested Popup with Marker at terrain on current branch: 02fa80ed7c19b15723a537b0ec8c7b48.mp4Test Code: <!DOCTYPE html>
<html lang="en">
<head>
<title>Test Terrain with Popup</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel='stylesheet' href='dist/maplibre-gl.css' />
<script src='dist/maplibre-gl-dev.js'></script>
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
.test-controls {
position: absolute;
top: 10px;
left: 10px;
background: white;
padding: 10px;
border-radius: 4px;
z-index: 1000;
}
button {
margin: 5px;
padding: 5px 10px;
}
</style>
</head>
<body>
<div class="test-controls">
<h4>Terrain Popup Test</h4>
<button onclick="addPopupOnTerrain()">Add Popup on Terrain</button>
<button onclick="movePopup()">Move Popup</button>
<button onclick="testTrackPointer()">Test Track Pointer</button>
<button onclick="testMarkerWithPopup()">Test Marker + Popup</button>
<button onclick="testMultipleMarkersPopups()">Multiple Markers + Popups</button>
<button onclick="clearAll()">Clear All</button>
<div id="status"></div>
</div>
<div id="map"></div>
<script>
const map = (window.map = new maplibregl.Map({
container: 'map',
zoom: 12,
center: [11.39085, 47.27574],
pitch: 70,
hash: true,
style: {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
attribution: '© OpenStreetMap Contributors',
maxzoom: 19
},
terrainSource: {
type: 'raster-dem',
url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
tileSize: 256
},
hillshadeSource: {
type: 'raster-dem',
url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
tileSize: 256
}
},
layers: [
{
id: 'osm',
type: 'raster',
source: 'osm'
},
{
id: 'hills',
type: 'hillshade',
source: 'hillshadeSource',
layout: {visibility: 'visible'},
paint: {'hillshade-shadow-color': '#473B24'}
}
],
terrain: {
source: 'terrainSource',
exaggeration: 1
},
sky: {}
},
maxZoom: 18,
maxPitch: 85
}));
let testPopup = null;
let testMarkers = [];
function addPopupOnTerrain() {
if (testPopup) {
testPopup.remove();
}
testPopup = new maplibregl.Popup()
.setLngLat([11.39085, 47.27574])
.setHTML('<h3>Popup on Terrain</h3><p>Testing _flatPos removal</p>')
.addTo(map);
updateStatus('Popup added on terrain');
}
function movePopup() {
if (!testPopup) {
updateStatus('No popup to move');
return;
}
// Move popup to a different location with terrain
const newLngLat = [11.40085, 47.28574];
testPopup.setLngLat(newLngLat);
updateStatus('Popup moved to new terrain location');
}
function testTrackPointer() {
if (testPopup) {
testPopup.remove();
}
testPopup = new maplibregl.Popup({ closeOnClick: false, closeButton: false })
.setHTML('<h3>Track Pointer Test</h3><p>Move mouse to test terrain tracking</p>')
.trackPointer()
.addTo(map);
updateStatus('Track pointer mode enabled - move mouse');
}
function testMarkerWithPopup() {
clearAll();
// Create marker with attached popup
const popup = new maplibregl.Popup({ offset: 25 })
.setHTML('<h3>Marker Popup on Terrain</h3><p>Click marker to toggle</p>');
const marker = new maplibregl.Marker({ color: '#FF0000' })
.setLngLat([11.39085, 47.27574])
.setPopup(popup)
.addTo(map);
testMarkers.push(marker);
// Test marker movement with popup
setTimeout(() => {
marker.setLngLat([11.40085, 47.28574]);
updateStatus('Marker moved with popup - test positioning');
}, 2000);
updateStatus('Marker with popup added on terrain');
}
function testMultipleMarkersPopups() {
clearAll();
const locations = [
{ lngLat: [11.39085, 47.27574], color: '#FF0000', title: 'Red Marker' },
{ lngLat: [11.40085, 47.28574], color: '#00FF00', title: 'Green Marker' },
{ lngLat: [11.38085, 47.26574], color: '#0000FF', title: 'Blue Marker' }
];
locations.forEach((loc, index) => {
const popup = new maplibregl.Popup({ offset: 25 })
.setHTML(`<h3>${loc.title}</h3><p>Terrain elevation test ${index + 1}</p>`);
const marker = new maplibregl.Marker({ color: loc.color })
.setLngLat(loc.lngLat)
.setPopup(popup)
.addTo(map);
testMarkers.push(marker);
});
// Test simultaneous popup movement
setTimeout(() => {
testMarkers.forEach((marker, index) => {
const currentLngLat = marker.getLngLat();
marker.setLngLat([currentLngLat.lng + 0.001, currentLngLat.lat + 0.001]);
});
updateStatus('All markers moved - testing popup positioning');
}, 3000);
updateStatus('Multiple markers with popups added on terrain');
}
function clearAll() {
if (testPopup) {
testPopup.remove();
testPopup = null;
}
testMarkers.forEach(marker => marker.remove());
testMarkers = [];
updateStatus('All markers and popups cleared');
}
function updateStatus(message) {
document.getElementById('status').innerHTML = '<small>' + message + '</small>';
}
map.addControl(
new maplibregl.NavigationControl({
visualizePitch: true,
showZoom: true,
showCompass: true
})
);
map.addControl(
new maplibregl.TerrainControl({
source: 'terrainSource',
exaggeration: 1
})
);
// Test click events on terrain
map.on('click', (e) => {
if (!testPopup || !testPopup._trackPointer) {
new maplibregl.Popup()
.setLngLat(e.lngLat)
.setHTML(`<h4>Clicked on terrain</h4><p>Lng: ${e.lngLat.lng.toFixed(5)}<br>Lat: ${e.lngLat.lat.toFixed(5)}</p>`)
.addTo(map);
}
});
updateStatus('Map loaded with terrain - ready for testing');
</script>
</body>
</html> |
|
If you know of any other cases I should test, please let me know! |
|
Can you find the original PR which introduced flatPos and see what it tired to solve and make sure this PR didn't create a regression? |
|
Sure! I looked into the flatPos in this repository. flatPos for src/ui/popup.ts has introduced in the following pull request:
|
|
@sbachinin can you take a look at this PR? I believe it changes code that you wrote, so you might have valid input here. |
| marker._pos = new Point(2999, 242); | ||
| marker._lngLat = map.unproject(marker._pos); | ||
| const newLngLat = map.unproject(new Point(2999, 242)); | ||
| marker.setLngLat(newLngLat); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't equivalent to the previous behavior - setting lnglat is not the same as placing it in a screen position. lnglat are wrapped and therefore might be placed in a different part of the screen.
Can you please share a video of the linked PR you mentioned after this fix (i.e click on a marker, drag to pass world copy and click again to open the popup in the new location)?
Launch Checklist
CHANGELOG.mdunder the## mainsection.Description
This PR fixes an issue where popups would detach from their associated markers during animation when the map displays multiple world copies (when zoomed out
significantly). The popup would appear separated from the marker by 360 degrees of longitude, creating a confusing and incorrect visual representation.
Root Cause:
The Popup class was resetting _flatPos to null in the setLngLat method, which prevented the smartWrap function from properly calculating the optimal longitude for the popup to maintain visual consistency with its marker across world copies.
Solution:
Related Issues
Changes Made
Impact
Testing
Screenshots
Before
4dbc1b0770a5418c4e1dce303cffbe9f.mp4
After
1ebcdc8f291762b9648f36d56d6495e3.mp4