Ticket #3061 (closed task: fixed)

Opened 2 years ago

Last modified 19 months ago

Investigate, and if possible implement more efficient tile positioning

Reported by: ahocevar Owned by:
Priority: minor Milestone: 2.12 Release
Component: Layer.Grid Version: 2.10
Keywords: mobile Cc: bartvde, courriel@…, rangoy
State: Commit

Description

Currently, we position all tiles (Tile.js) with pixel values. If we ever implement zoom animations, this will be slow because every single tile has to be repositioned and resized.

This ticket is a placeholder for activities investigating the feasibility of alternative positioning (e.g. using percentages), which would leave the resizing job to the browser.

Attachments

openlayers-3061.patch Download (2.3 KB) - added by ahocevar 2 years ago.
Percentage based tile positioning
openlayers-3061.2.patch Download (121.4 KB) - added by ahocevar 23 months ago.
percentage based positioning, tile cleanup, better resize transitions
openlayers-3061.3.patch Download (129.5 KB) - added by ahocevar 22 months ago.
replaces openlayers-3061.2.patch - adds comments for sensible tileLoadingDelay and buffer defaults and uses them in examples, and makes vector layers (except when using the VML renderer) scale with other layers when map.layerContainerDiv.style.width/height is changed.
openlayers-3061.4.patch Download (8.9 KB) - added by ahocevar 22 months ago.
only the changes that bring percentage based positioning for Grid layers. Depends on #3419 and #3430.

Change History

  Changed 2 years ago by bartvde

  • cc bartvde added

Adding myself to the cc since I am very interested in having fractionalZoom: true support more layer types.

  Changed 2 years ago by ahocevar

  • owner set to euzuro
  • type changed from feature to task
  • component changed from general to Layer

  Changed 2 years ago by ahocevar

  • owner euzuro deleted

  Changed 2 years ago by erilem

  • keywords mobile added

Changed 2 years ago by ahocevar

Percentage based tile positioning

  Changed 2 years ago by sbrunner

  • cc courriel@… added

  Changed 2 years ago by rangoy

  • cc rangoy added

  Changed 2 years ago by erilem

  • status changed from new to closed
  • resolution set to wontfix

Andreas, I'm closing this one. Feel free to reopen it if it makes sense to you.

  Changed 2 years ago by ahocevar

  • status changed from closed to reopened
  • state set to Needs More Work
  • resolution wontfix deleted
  • milestone changed from 2.11 Release to 2.12 Release

Reopening, so we don't forget about this patch - it has the potential to add support for zoom levels that we don't have tiles for. But it needs more work.

follow-up: ↓ 11   Changed 23 months ago by ahocevar

  • state changed from Needs More Work to Review

openlayers-3061.2.patch Download adds many improvements and simplifications related to tile positioning and tile handling in general:

  • The size of the map's layerContainerDiv is now 100x100 pixels. By changing the size, the scale of all layers will be changed. Each layer's div has a size of 100%. By changing this value, the scale of an indivitual layer can be changed. This allows for both animated zooming and layers displayed at resolutions that are not available on the server.
  • The only downside of the new percentage based positioning is that IE6 needs a reflow after a tile is rendered to actually show it. This may cause some flicker while dragging.
  • Tiles don't need a clone method any more, because backBuffer tiles are not separate Tile instances any more. Instead, we have a new Tile.ImageMixin mixin, which provides backBuffer functionality and other things that are needed for image based tiles (i.e. currently Tile.Image and Tile.Google).
  • Tile.Image.imgDiv is renamed to Tile.Image.image, because it is actually the image element - even if the IE6 alpha hack is applied.
  • Layer subclasses don't need a setOpacity method any more, because the opacity can be set on the layer's div, instead of setting it on each tile or marker.
  • Error handling of loading images is no longer handled in Util.js, and no viewRequestID is required any more.
  • Both Tile.Image and Tile.Image.IFrame are more compact now, using less workarounds.
  • Tile.Google has now proper loadstart/loadend handling, and supports the resize transition effect. The workaround for the hybrid layer is also not needed any more.
  • The lag when dragging layers on mobile devices was caused by a reflow after a tile image was loaded. This reflow is not needed any more, so the tileLoadingDelay on the Grid layer has now a default of 0ms instead of 100ms.

All tests pass in Safari5, Firefox4, IE6 and IE8. All examples work in these browsers as well. Thanks for any review. If there is interest and it makes reviewing easier, I can set up a sandbox with this patch.

Changed 23 months ago by ahocevar

percentage based positioning, tile cleanup, better resize transitions

  Changed 23 months ago by sbrunner

Hello Andrea,

I take some hours to test your patch (it a quick review foe a so big patch ;-) ).

I test it on Firefox 5 and on Chomium, and on Android HTC Desire, Than it's relay great with kinetic, when the servers work well it's impressive ;-)

Fore me It seem to work better on Firefox than on Chomium ... strange usually it the inverse ! On Chomium I sometimes see some jump... I suspect that fore any reason the kinetic speed become too high...

It relay difficult if one patch like this haven't any side effect, than I thing that the good moment to commit it on version 2.12.

CU Stéphane

in reply to: ↑ 9 ; follow-up: ↓ 12   Changed 23 months ago by erilem

Replying to ahocevar:

This is impressive work! Thanks Andreas.

* The lag when dragging layers on mobile devices was caused by a reflow after a tile image was loaded. This reflow is not needed any more, so the tileLoadingDelay on the Grid layer has now a default of 0ms instead of 100ms.

Would you mind elaborating a bit? Why there was a reflow after a tile image was loaded? And why there's no reflow anymore?

My preliminary tests show that delaying tile loading still improves the panning experience.

All tests pass in Safari5, Firefox4, IE6 and IE8. All examples work in these browsers as well. Thanks for any review. If there is interest and it makes reviewing easier, I can set up a sandbox with this patch.

in reply to: ↑ 11   Changed 23 months ago by ahocevar

Replying to erilem:

Would you mind elaborating a bit? Why there was a reflow after a tile image was loaded? And why there's no reflow anymore?

This was the code that did the reflow:

-    show: function() {
-        this.frame.style.display = '';
-        // Force a reflow on gecko based browsers to actually show the element
-        // before continuing execution.
-        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, 
-                this.layer.transitionEffect) != -1) {
-            if (OpenLayers.IS_GECKO === true) { 
-                this.frame.scrollLeft = this.frame.scrollLeft; 
-            } 

Previously, visibility of the tile was set on the frame. Now it is set on the image. I did not encounter any difference when I added the same reflow to the new code, so I removed it.

My preliminary tests show that delaying tile loading still improves the panning experience.

This may well be - I had no opportunity to test on a mobile device, and the removal of the reflow above only affects layers where no transition effect is configured. The one thing that I saw is that kinetic dragging experience is really bad with a delay of 100ms, because no tiles will be loaded at all during the kinetic drag. So we may have to find a better default for this, or set the longer delay only on specific devices.

  Changed 23 months ago by ahocevar

The above should read "the removal of the reflow above only affects layers where a transition effect is configured".

  Changed 22 months ago by ahocevar

  • state changed from Review to Needs More Work

To make it easier to review this, I'm starting to provide the improvements from this patch in smaller chunks, with one ticket each.

  Changed 22 months ago by ahocevar

See #3419.

  Changed 22 months ago by ahocevar

See #3420.

Changed 22 months ago by ahocevar

replaces openlayers-3061.2.patch - adds comments for sensible tileLoadingDelay and buffer defaults and uses them in examples, and makes vector layers (except when using the VML renderer) scale with other layers when map.layerContainerDiv.style.width/height is changed.

  Changed 22 months ago by ahocevar

See #3430.

  Changed 22 months ago by ahocevar

See #3431.

  Changed 22 months ago by ahocevar

See #3434.

  Changed 22 months ago by ahocevar

  • state changed from Needs More Work to Review
  • component changed from Layer to Layer.Grid

The patches for #3419, #3420, #3430, #3431 and #3434 include everything from openlayers-3061.3.patch Download, except for the tileLoadingDelay changes, the name change of imgDiv to image, and some modifications in the examples.

openlayers-3061.4.patch Download depends on #3419 and #3430. Tests pass and examples work in Safari5, Firefox4, Opera11, IE6, IE8 and IE9. Thanks for any review.

Changed 22 months ago by ahocevar

only the changes that bring percentage based positioning for Grid layers. Depends on #3419 and #3430.

  Changed 22 months ago by ahocevar

  • state Review deleted

It does not make much sense to review or bring this in now. But folks working on either animated zooming or fractional zoom for layers with fixed server resolutions may find this patch helpful.

follow-up: ↓ 27   Changed 22 months ago by ahocevar

I'm sure there are other approaches to fractional zoom for layers with fixed server resolutions, but with this patch, it could work like this: 1. Change the default for Map.positioningUnits to "%" 1. In Layer.Grid::moveTo, when the zoom has changed, find the closest server resolution for the requested resolution, and calculate the ratio. 1. Finish moveTo with the closest server resolution, and save the origin and the center:

var origin = this.map.getViewPortPxFromLonLat(this.bounds.getCenterLonLat());
var center = this.map.getViewPortPxFromLonLat(this.map.getCenter());

1. Set the following styles on the layer's div:

style.left = (origin.x - center.x + (size.w - size.w * ratio) / 2) + "px";
style.top = (origin.y - center.y + (size.h - size.h * ratio) / 2) + "px";
style.width = (parseInt(style.width, 10) * ratio) + "%";
style.height = (parseInt(style.height, 10) * ratio) + "%";

follow-up: ↓ 24   Changed 22 months ago by ahocevar

Nicer formatting for the steps from the above comment:

  1. Change the default for Map.positioningUnits to "%"
  2. In Layer.Grid::moveTo, when the zoom has changed, find the closest server resolution for the requested resolution, and calculate the ratio.
  3. Finish moveTo with the closest server resolution, and save the origin and the center:
    var origin = this.map.getViewPortPxFromLonLat(this.bounds.getCenterLonLat());
    var center = this.map.getViewPortPxFromLonLat(this.map.getCenter());
    
  4. Set the following styles on the layer's div:
    style.left = (origin.x - center.x + (size.w - size.w * ratio) / 2) + "px";
    style.top = (origin.y - center.y + (size.h - size.h * ratio) / 2) + "px";
    style.width = (parseInt(style.width, 10) * ratio) + "%";
    style.height = (parseInt(style.height, 10) * ratio) + "%";
    

in reply to: ↑ 23   Changed 22 months ago by erilem

Andreas, I'm a bit confused. Do you plan to have this patch in trunk eventually? Also, do you want to make the positioning unit configurable, or will the positioningUnits option go away? Thank you.

  Changed 22 months ago by ahocevar

@erilem: I have the feeling that setting positioning units to % reduces panning performance. So I thought it would make sense to not bring this in now and wait and see if animated zooming and displaying tiled layers with fractional zoom can be addressed in a different way.

  Changed 21 months ago by erilem

Andreas, I've done experiments in several browsers, including mobile browsers. Positioning tiles using "%" as opposed to "px" doesn't seem to reduce pan performance.

I used the mobile.html for testing:  http://goo.gl/6iZ0O ("%") and  http://goo.gl/9eJeD ("px") for testing. I'd be cool if others can test these URLs and report back.

in reply to: ↑ 22   Changed 21 months ago by erilem

Replying to ahocevar:

I'm sure there are other approaches to fractional zoom for layers with fixed server resolutions [...]

First attempt. See [12279] and  http://dev.openlayers.org/sandbox/camptocamp/clientzoom/examples/wmts.html.

  Changed 20 months ago by erilem

  • status changed from reopened to closed
  • resolution set to fixed

  Changed 20 months ago by ahocevar

  • status changed from closed to reopened
  • resolution fixed deleted

The above change breaks IE6. What's missing is the reflowOldIE method and the listener that calls it. See openlayers-3061.4.patch Download.

follow-up: ↓ 31   Changed 20 months ago by erilem

Sorry Andreas, I forgot about this. I'll make a patch.

in reply to: ↑ 30   Changed 20 months ago by erilem

Replying to erilem:

Sorry Andreas, I forgot about this. I'll make a patch.

 https://github.com/openlayers/openlayers/pull/10

follow-up: ↓ 33   Changed 20 months ago by ahocevar

  • state set to Commit

in reply to: ↑ 32   Changed 20 months ago by erilem

  • status changed from reopened to closed
  • resolution set to fixed

follow-up: ↓ 35   Changed 19 months ago by rangoy

Great work with this patch.

I am trying to use this (I currently test from the OpenLayers 3 git-repo), and I am experiencing an a bit annoying artifact: In some browsers there is a white bar between the tiles.

I've tried two approaches to fix this; * I've tried to use translate: transform/scale on the div. The white bars dissappeared, but other elements ended up in the wrong place. (This is probably because i don't quite grasp how the positioning is done). * Setting the the tilesize=divsize (100px) seems to solve the issue also.

As I far as I can see, there are two things which might improve the issue; * Change the divsize to match the tilsize - it seems like the problem is an rounding error somewhere. * Implement it by using translate; transform (or even transform3d). I suspect that this approach needs to be implemented with an fallback as not all browsers support this.

in reply to: ↑ 34 ; follow-up: ↓ 36   Changed 19 months ago by ahocevar

Replying to rangoy:

I am trying to use this (I currently test from the OpenLayers 3 git-repo), and I am experiencing an a bit annoying artifact: In some browsers there is a white bar between the tiles.

Are you seeing this with fractional zoom levels (e.g. 17.1) only, or also with integer zoom levels? To try, use map.getZoom() in the debug console on the client-zoom example.

in reply to: ↑ 35   Changed 19 months ago by rangoy

Replying to ahocevar:

Replying to rangoy:

In some browsers there is a white bar between the tiles.

Are you seeing this with fractional zoom levels (e.g. 17.1) only, or also with integer zoom levels? To try, use map.getZoom() in the debug console on the client-zoom example.

Only in fractional levels. The integer zoom-levels are correct.

Note: See TracTickets for help on using tickets.