Skip to content
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

reduce symbol overlap when zooming out quickly #8628

Merged
merged 3 commits into from
Sep 30, 2019
Merged

Conversation

ansis
Copy link
Contributor

@ansis ansis commented Aug 13, 2019

fix #8627

When zooming out quickly labels could overlap for a lengthly period of time and produce and unwanted visual effect.

This PR reduces this overlap by:

  • reducing the time between collision calculations when zooming out quickly
  • reducing the fade duration when zooming out quickly

The collisions are discovered more quickly and eliminated more quickly.

Before:
https://bl.ocks.org/ansis/6d6aa89b8a5dbddb5e2031a29451c767

After:
https://bl.ocks.org/ansis/12665c0c885b6af9ed81c44fa7177078

After without automatic zooming
https://bl.ocks.org/ansis/6ad5fb3402d4ddec926b52af7f3f73fe

Launch Checklist

  • briefly describe the changes in this PR
  • post benchmark scores
  • manually test the debug page

@ansis ansis requested a review from mourner August 13, 2019 21:24
@chloekraw chloekraw added this to the release-queso milestone Aug 13, 2019
Copy link
Contributor

@asheemmamoowala asheemmamoowala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I played with these changes and found that on a macbook pro touchpad it still shows the overlap when zooming out fast. I'm not sure that this would be easy to reproduce on other platforms where the input devices are calibrated differently.

While this change performs well with the current mapbox streets style, would it cause jank on heavier styles, or style that use more dense tiles? In that case, should it be an option to configure this behavior?

}

zoomAdjustment(zoom: number) {
// When zooming out quickly labels can overlap each quickly. This
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: typo can overlap each quickly

// When zooming out quickly labels can overlap each quickly. This
// adjustment is used to reduce the fade duration when zooming out quickly and
// to reduce the interval between placement calculations. Discovering the
// collisions more quickly and fading them more quickly reduces the unwanted effect.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discovering the collisions more quickly and fading them more quickly reduces the unwanted effect.

nit: This part of the comment can be removed, or make it clearer. It is not clear how zoomAdjustment results in discovering the collisions more quickly.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear how zoomAdjustment results in discovering the collisions more quickly.

+1 to this - it took me reading through all the code to understand how the adjustment works. Perhaps merging the "Discovering" sentence into the previous one would make it clearer, something like:

"This adjustment is applied when zooming out quickly to reduce the interval between placement calculations so we can discover & correct label collisions sooner, and also to reduce the fade duration so that overlapping labels fade out more quickly."

Just a suggestion, not sure if that wording would make it any clearer to someone else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As is, it seems relatively clear to me that "reducing the interval between placement calculations" discovers collisions more quickly and "reducing the fade duration" fades them more quickly. I agree with @vakila that keeping the order of the clauses in the last sentence parallel to the previous sentence would improve clarity. I think shorter and simpler sentences are generally easier to follow than longer ones.

        // When zooming out quickly, labels can overlap each other. This
        // adjustment is used to reduce the interval between placement calculations
        // and to reduce the fade duration when zooming out quickly. Discovering the
        // collisions more quickly and fading them more quickly reduces the unwanted effect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the suggestions on how to make this better! I've committed chloe's version with shorter sentences.

@chloekraw
Copy link
Contributor

Thanks for investigating this, @ansis!

I played with these changes and found that on a macbook pro touchpad it still shows the overlap when zooming out fast. I'm not sure that this would be easy to reproduce on other platforms where the input devices are calibrated differently.

@asheemmamoowala I noticed the same thing using my macbook and touchpad, although I also found it to be a noticeable improvement from previous behavior.

@ansis, assuming the same approach works on native, could you open up a pr there too and allow us to test this change on mobile, where the reported behavior is a bit more urgent?

While this change performs well with the current mapbox streets style, would it cause jank on heavier styles, or style that use more dense tiles? In that case, should it be an option to configure this behavior?

Not sure about the first question, but on the second:

  1. My understanding is this PR is a stopgap measure that reduces the incidence of the reported behavior and that it will be replaced with a root cause fix. It wouldn't make sense to expose a public API for a temporary measure, unless we have reason to believe a root cause fix is not really possible.

  2. Even so: as a user, this is the type of decision I would expect Mapbox to get right, not something I'd like to configure and spend cycles testing with every style change. If we find that this causes a significant amount of jank on heavier styles, my inclination would be to not merge this PR.

@ansis
Copy link
Contributor Author

ansis commented Aug 14, 2019

I pushed another fix that improves this slightly further. I was using the zoom of when the placement is finished instead of started to do the adjustment which sometimes lead to regular fading after a fast zoom. This seems to help especially for zooms that load new tiles

While this change performs well with the current mapbox streets style, would it cause jank on heavier styles, or style that use more dense tiles? In that case, should it be an option to configure this behavior?

On -js, placement work is limited to 2ms each frame. This change means that we might have slightly more frames that pay that 2ms price. So if those new placements are pushing some frames over their frame budget, there were probably already many other frames that were already too long.

I played with these changes and found that on a macbook pro touchpad it still shows the overlap when zooming out fast. I'm not sure that this would be easy to reproduce on other platforms where the input devices are calibrated differently.

Yep, the limiting factors are:

  • placement isn't fast enough to do it instantly
  • we want to do some fading (some others do no fading)
  • we want to do placement at fractional zooms
  • we do not know if symbols will be in parent tiles

Looking closely there are also sometimes some frames where I see the effect but labels aren't actually colliding. Sometimes it's just increased density from zooming contrasting with a blank background before being replaced with a tile with lower density data.

In that case, should it be an option to configure this behavior?

My understanding is this PR is a stopgap measure that reduces the incidence of the reported behavior and that it will be replaced with a root cause fix.

It's a bit of both. The "real" fix would be cheap placement that we can run on every frame. But I think we would still need the fading acceleration here to avoid the effect.

Even so: as a user, this is the type of decision I would expect Mapbox to get right, not something I'd like to configure and spend cycles testing with every style change.

I completely agree. We shouldn't expose this.

@asheemmamoowala
Copy link
Contributor

On -js, placement work is limited to 2ms each frame. This change means that we might have slightly more frames that pay that 2ms price. So if those new placements are pushing some frames over their frame budget, there were probably already many other frames that were already too long.

With the latest changes, I am seeing significant jank when zooming out fast over Tokyo. This is even worse when viewing a pitched map. This is likely to affect flyTo/easeTo animations as well.

we want to do some fading (some others do no fading)

For smooth animations, fading is important, but if the user is zooming really fast - what is the value of fading - especially if the trade off is between some fading - that causes jank + overlapping symbols, vs no fading - no jank, no overlap?

Even so: as a user, this is the type of decision I would expect Mapbox to get right, not something I'd like to configure and spend cycles testing with every style change.

I completely agree. We shouldn't expose this.

👍

Copy link

@vakila vakila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ansis The code changes look good to me (though I have a question/comment below), but in the examples/debug page I'm afraid I'm not reliably able to observe different behavior vs. the original. Here's what I'm seeing as I watch the zoom loop in the "after" example:

  • Firefox & Chrome on Ubuntu Thinkpad: Occasionally the labels disappear faster than in the original, as intended, but in many cases they seem to spend just as long on the screen as in the original. In other words, the collision/fade speed seems to vary from run to run of the zoom out loop (though I have no idea why that is), and only sometimes is actually noticeably faster than the original.

  • Chrome on (old, bad) Samsung Android phone: Tiles/labels load so slowly in general that the map is too sparse to notice any change in the looping example. And if I load the default debug page or the non-auto-zoom example and wait for everything to load before zooming, I can't seem to manually zoom out fast enough to appreciate the effect. So in either case I can't really notice any difference between the two versions.

That said, if this change sometimes improves the desktop experience & has no effect on mobile, I don't see any harm in merging it. Assuming there are no negative effects on perf benchmarks.

// When zooming out quickly labels can overlap each quickly. This
// adjustment is used to reduce the fade duration when zooming out quickly and
// to reduce the interval between placement calculations. Discovering the
// collisions more quickly and fading them more quickly reduces the unwanted effect.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear how zoomAdjustment results in discovering the collisions more quickly.

+1 to this - it took me reading through all the code to understand how the adjustment works. Perhaps merging the "Discovering" sentence into the previous one would make it clearer, something like:

"This adjustment is applied when zooming out quickly to reduce the interval between placement calculations so we can discover & correct label collisions sooner, and also to reduce the fade duration so that overlapping labels fade out more quickly."

Just a suggestion, not sure if that wording would make it any clearer to someone else.

@@ -1215,7 +1215,7 @@ class Style extends Evented {
this.pauseablePlacement.continuePlacement(this._order, this._layers, layerTiles);

if (this.pauseablePlacement.isDone()) {
this.placement = this.pauseablePlacement.commit(browser.now());
this.placement = this.pauseablePlacement.commit(browser.now(), transform.zoom);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the zoom value is coming from the same transform that we passed to the PausablePlacement constructor in L1204, why do we need to add it as an argument for the commit method (here as well on Placement)? Same question for the stillRecent method as well. What am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the zoom value is coming from the same transform that we passed to the PausablePlacement constructor in L1204, why do we need to add it as an argument for the commit method (here as well on Placement)? Same question for the stillRecent method as well. What am I missing?

Thanks for catching this. The two values were different (one is when placement starts, the other is when placement ends). But using the one from when it starts is more correct.

stillRecent needs the latest zoom so that it can calculate how much the zoom has changed.

@awulkan
Copy link

awulkan commented Aug 22, 2019

Occasionally the labels disappear faster than in the original, as intended, but in many cases they seem to spend just as long on the screen as in the original.

@vakila For whatever it's worth, for me it's noticeably and consistently faster than the original. Using the latest Chrome and FireFox version on a PC with these specs: i7 8700, GTX 1060 3GB, 16GB DDR4.

- remove bug that eliminated all fading (left over from debugging)
- make the formula match -native
- only make placement more frequent after zooming has stopped
@ansis
Copy link
Contributor Author

ansis commented Sep 25, 2019

That said, if this change sometimes improves the desktop experience & has no effect on mobile, I don't see any harm in merging it. Assuming there are no negative effects on perf benchmarks.

Thanks for testing this on mobile @vakila !


I've pushed a couple adjustments.

  • improved comment
  • formula matches -native now (linear instead of exponential)
  • it only makes placement more frequent after zooming has stopped to avoid adding potential jank during zooming

If anyone could take a second look that would be great! I think this should be ready

Copy link
Contributor

@asheemmamoowala asheemmamoowala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Between @vakila and I we have tested on Linux Firefox and Chrome, an older Android device, and a recent Macbook with Chrome's CPU throttling.

On recent hardware it shows a clear improvement in fading out labels faster when zooming out quickly. On older hardware there is not a consistent improvement, but also no degradation.

Let's merge this and track further improvements separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

zooming out causes lengthy symbol overlap
8 participants