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
debounce rounding position on Marker #11167
Conversation
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.
The unit tests look great to me!
I just tested this out in browser, and unfortunately the bug still isn't fixed.
https://user-images.githubusercontent.com/14878684/141167735-a2739059-b954-409e-9082-e4cd513fb15a.mov
I think this is because of the map._forceMarkerUpdate()
, which I added to fix another marker bug here. The intention was to have markers update in response to map.setTerrain()
, but it seems to be calling excess updates as well. I think that fixing this will require checking if terrain actually changes on the call to painter.updateTerrain()
and only updating the markers if so.
EDIT: I'm wrong, this isn't the cause of the bug.
2021-11-10.23-27-53.mov@SnailBones good point, I think I catch it. but when i test it in my browser all thing is fine. |
I've copied the code from this example into a local html file, and tested in both Firefox and Chrome. Your video unfortunately doesn't seem to be working for me. |
actually i copied that code... |
|
@SnailBones here's a better format: marker.mp4 |
Thanks for the conversion @mourner! Screen.Recording.2021-11-10.at.1.59.58.PM.movHere's the code I used to create this: <!DOCTYPE html>
<html>
<head>
<title>Marker snapping test</title>
<meta charset='utf-8'>
<link rel='stylesheet' href='../dist/mapbox-gl.css' />
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>
<body>
<div id='map'></div>
<script src='../dist/mapbox-gl-dev.js'></script>
<script src='../debug/access_token_generated.js'></script>
<script>
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
zoom: 0
});
const marker = new mapboxgl.Marker({color: '#F84C4C'});
function animateMarker(timestamp) {
const radius = 5;
marker.setLngLat([
Math.cos(timestamp / 1000) * radius,
Math.sin(timestamp / 1000) * radius
]);
marker.addTo(map);
requestAnimationFrame(animateMarker);
}
requestAnimationFrame(animateMarker);
</script>
</body>
</html> |
src/ui/marker.js
Outdated
@@ -282,7 +283,7 @@ export default class Marker extends Evented { | |||
remove() { | |||
if (this._map) { | |||
this._map.off('click', this._onMapClick); | |||
this._map.off('move', this._update); | |||
this._map.off('move', () => this._update(true)); |
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 won't actually remove the listener that was added previously, because this is a different function. You need to pass the exact reference — e.g. by creating a separate _updateMoving
that internally calls _update(true)
.
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.
Done!
Thank you @SnailBones , I check the code. if you see in function <!DOCTYPE html>
<html>
<head>
<title>Marker snapping test</title>
<meta charset='utf-8'>
<link
href="https://api.mapbox.com/mapbox-gl-js/v2.4.1/mapbox-gl.css"
rel="stylesheet"
/> <style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>
<body>
<div id='map'></div>
<script src='./mapbox-gl-unminified.js'></script>
<script>
mapboxgl.accessToken =
"ACCESS_TOKEN";
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
zoom: 0
});
const marker = new mapboxgl.Marker({color: '#F84C4C'}).setLngLat([0,0]).addTo(map);
function animateMarker(timestamp) {
const radius = 5;
marker.setLngLat([
Math.cos(timestamp / 10000) * radius,
Math.sin(timestamp / 10000) * radius
]);
requestAnimationFrame(animateMarker);
}
requestAnimationFrame(animateMarker);
</script>
</body>
</html> |
Good catch @malekeym! That works for me, you're correct that the issue results from the repeated calls to if (map === this._map) { return this; } |
@SnailBones very good idea, i changed the code, |
I'm glad you noticed that issue @malekeym! The cause is that |
add Unit test to check this
Thank you @SnailBones for finding the reason that bug happened I made changes and add a unit test to check move events and the issue is fixed but I have a problem with flow test, I can fix it with define property |
I think you have the right idea with assigning a property with an arrow function! Because besides the flow error, I think the current approach runs into the same issue that @mourner mentioned above because |
I use the arrow function, but just one question, if we use bind and then assign the new function to a method, so the references are the same, so the @mourner issue is fixed, am I right? |
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.
Looks good to me!
@SnailBones any blocker for this merge request? should I change anything? |
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 looks great to me now!
src/ui/marker.js
Outdated
this._updateFrameId = window.requestAnimationFrame(() => { | ||
if (this._element && this._pos && this._anchor) { | ||
this._pos = this._pos.round(); | ||
DOM.setTransform(this._element, `${anchorTranslate[this._anchor]} translate(${this._pos.x}px, ${this._pos.y}px) ${pitch} ${rotation}`); |
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.
Nit: I wonder if we could deduplicate this long line of code that's duplicated below, but not a big deal.
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.
Yes, but I don't have any idea, do you have?
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.
Maybe seperate that line into something like:
function _updateDOM(){ DOM.setTransform(this._element, `${anchorTranslate[this._anchor]} translate(${this._pos.x}px, ${this._pos.y}px) ${pitch} ${rotation}`);}
If you move the pitch and location calculating code into this function, then it can live in the marker's scope.
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.
I separate some methods, I appreciate reviewing changes and giving your feedback
4434ebf
to
dc792c3
Compare
@SnailBones and @mourner , when I merge the main branch to my branch, I see that |
src/ui/marker.js
Outdated
@@ -446,41 +452,59 @@ export default class Marker extends Evented { | |||
position.y >= 0 && position.y < tr.height; | |||
} | |||
|
|||
_update(e?: {type: 'move' | 'moveend'}) { | |||
if (!this._map) return; | |||
_updateDOM(pos: Point) { |
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.
Great work @malekeym!
One more tiny nit: Why does this function take in the position as an argument? Given it's directly accessing class variables like this._anchor
, I think that it would be more consistent and prevent potential confusion to either remove this argument, or else pass in the other variables as arguments.
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.
@SnailBones Done!
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.
Looks great!
Merging it in, thanks for your work on this @malekeym! 🙏 |
Launch Checklist
In this PR we debounce rounding position for cases that we need to animate
Marker
Close #11135
@mapbox/map-design-team
@mapbox/static-apis
if this PR includes style spec API or visual changes@mapbox/gl-native
if this PR includes shader changes or needs a native portmapbox-gl-js
changelog:<changelog>Animated markers are smoother in most browsers (h/t [@malekeym](https://github.com/malekeym))</changelog>