5.3 TestsTop5.1 Preparation5.2 Implementation

Contents

German

5.2 Implementation

The ensuing description is based on the utilization of a tiled WMS layer, and is divided into implementation steps that build on each other. The steps will be described in separate sections.

The developed animated zooming und panning extension was updated to the OpenLayers Version 2.4 RC5 (as of May 25, 2007); it is available through:

All subsequently indicated source code references refer to Revision No. 3197. The sample demo demo.html contained in the root directly was updated according to Section 4.3 and can be run directly off the CD or the current sandbox version (http://dev.openlayers.org/sandbox/emanuel/animatedZooming/demo.html).

The classification diagram in Appendix 6.3 highlights in color all classes that have been changed for the purposes of implementing the animated zooming and panning extensions. In addition, all edited methods are listed. The diagram is also based on Version 2.4 RC5 of OpenLayers (as of May 25, 2007).

5.2.1 Zoom Slider Events

The three event steps necessary for the use of the zoom slider in the PanZoomBar.js are as follows: MouseDown - MouseMove - MouseUp.

In the MouseDown event the current zoom level (before zooming) is stored in the Map object property zoomlevel_startScale. This value forms the basis calculation for the scaling process.

If the MouseMove event is activated through a movement of the slider, the following three values are re-calculated with every change in movement:

  1. Slider position:
    The currently active mouse position forms a pixel value pair whose y-value indicates the slider position. Values located outside of the zoom bar are intercepted (see zoomBarDrag(); PanZoomBar.js).
  2. Zoom Level:
    The difference between slider start position and current slider position divided by the indicated slide raster gives the new zoom level deviation. Added to the starting value of the zoom level this results in the new zoom level zoomlevel_scale (see calculateNewZoomlevel(); Map.js):

    var deltaY_zoomlevel = this.zoomStart.y - sliderPosition.y;
    this.zoomlevel_scale = this.zoomlevel_startScale + deltaY_zoomlevel/zoomStopHeight;

  3. Tile Size:
    During scaling the tile size is doubled (or halved) with every change in zoom level (see Section 4.2 and calculateNewTileSize(); Map.js). For the zoom-in process the following applies for the tile width:

    this.tileSize_scale.w = Math.pow(2, (this.zoomlevel_scale - this.zoomlevel_startScale)) * this.tileSize_startScale.w;

    Similarly, for the zoom-out process:

    this.tileSize_scale.w = 1 / (Math.pow(2, (this.zoomlevel_startScale - this.zoomlevel_scale))) * this.tileSize_startScale.w;

Once the three values have been calculated, each tile is scaled to the newly determined tile size (a detailed description follows in the next section).

Once the mouse key has been released (MouseUp event) the slider stops on the next adjacent zoom level value, and all visible tiles are redrawn.

5.2.2 Scaling

Scaling is used only for the active base layer; other active layers are hidden during the scaling process (see prepareZoomAnimation(); Map.js). This measure became necessary when a noticeable decrease in performance was observed with just two active layers. Detailed measurements were not taken. As a result, the decision was made not to continue scaling more layers in order to obtain a faster (and more user-friendly) zoom-scaling process.

At the beginning of the zooming process the tile containing the centre of the visible area must be determined. If the center is located on the edge of several tiles, the first tile located is defined as the centerTile (see getCenterTile();Grid.js).

By moving the zoom slider the values defined in Section 5.2.1 are initially used to scale and position the center tile (see scaleTileTo(); Grid.js). The new tile size is used to set the width and height style parameter of the HTML-imgDiv element of the tile. The positioning algorithm is based on the theorem on intersecting lines. Through the elementary geometric line relationship between the tile center and the corner points of the original and scaled tiles the new top and left pixel positions of the tile graphic can be determined.

The remaining (visible) tiles are scaled and repositioned based on the scaled center tile.

During the scaling process the overview map is simultaneously updated (see updateOverview(); OverviewMap.js). The red border which highlights the selected area is increased/decreased during the zoom process and always indicates the exact section of the main map. During slider movement, the zoom level of the overview map adjusts to the current main map. New tiles for the reference map are loaded. This does not impair the zooming process.

5.2.3 ZoomOut Tiles

During intitialization of the current base layer a basis tile (larger by a factor of x) is loaded to prevent the formation of a white border around a shrinking map during the zoom-out process (see Section 4.2). A tile whose borders contain the full dimension of the map (maxExtent) is determined, ie. the map must be displayable on one single tile. Beginning with zoom level 0 the resolution is doubled (and the map shrunk accordingly) until the whole map fits on one tile (see setZoomOutTile_share; Layer.js).

After several days of testing, an optimal tile size factor x of 4 emerged. The standard tile size in OpenLayers is 256 pixels (px). This means that the zoom-out tile would be loaded with 1024 px. Background: Generally, many WMS servers (including MapServer) pre-define 2048 px as the maximum map size which should not be exceeded. Larger tiles result in better quality during scaling. However, taking into account load time it is better to choose a smaller tile with a smaller factor x. With a standard tile size of 512 px, a factor of 4 is still within the permitted size range (2048 px); at 1024 it also has a justifiable load time (in normal conditions). At smaller zoom level changes the quality at 1024 px is also considered acceptable. However, definite »pixelation« occurs during large zoom changes, which cannot be completed avoided even with a higher factor.

To request the ZoomOut tile in the defined size from the WMS server, the getURL method in WMS.js was expanded by one parameter tileSize.

5.2.4 Automatic Zoom Animation

All requirements described in Section 3.3.2 are taken into account and implemented accordingly (with the exception of overlay scaling). The animated zooming feature in the zoom bar is expanded with the mentioned should-have criteria (see Section 3.3.3).

After discussions with the PSC members of OpenLayers the animated panning patch which is currently in Review stage is used as the basis for the time-dependent calculation of the zoom animation steps. The easeInOutZoom method in Util.js is the result of the adaption of the analogously compiled animated panning function (see listing 5.2.4). Thereby delta is the difference between the zoom levels before and after animation, totalsteps is the pre-defined number of animation steps, step is the current »step counter«, and power is the pre-defined power factor for the acceleration curve override.

 
Listing: Power Movement Curve Algorithm for Zoom Animations; Util.js

OpenLayers.Util.easeInOutZoom = function(delta, totalSteps, step, power) {
    var stepVal = Math.pow(((1 / totalSteps) * step), power) * delta;
    return stepVal; 
}

After extensive testing with different values for the above-mentioned variables totalsteps = 4 and power = 0.7 were considered ideal values for the zooming process. Particular attention was paid to the speed of the animation, which should not exceed two seconds. For this reason a smaller step quantity was selected. For the power factor a value that would quickly accelerate the zoom movement in the beginning and gradually slow it down at the end was desired. The delay between user action and the first visible zoom movement is thus very small.

The window.setInterval method described in Section 4.5.1 is used as a »metronome« for the gradually proceeding animation; in the zoomSlide method it is retrieved from the Map.js. Clicking on the zoom bar (buttons), double-clicking on the map, moving the mouse wheel, pulling out the zoom box or pressing the +/- key starts the automatic zoom animation using the zoomTo method. An optional function parameter can be used to deactivate the animation and to perform a more jump-like zooming process.

Starting or repeating a new animation using the above-mentioned interactions is not possible while zoom animation is in process. Turning the mouse wheel numerous time will still only result in a one-level zoom change. An extension of this function is conceivable.

Zooming with double-click, mouse wheel and zoom box simultaneously adjusts the map to the new center (also with animation). Combining animated zooming and panning means that two window.setInterval methods are running independently of each other - one for zooming and one for panning.

5.2.5 Tile Configuration with smooth tile update

In OpenLayers the old map is deleted (white background appears) and subsquently re-assembled through a gradual reloading of tiles (default setting). This effect would greatly impair the forecasted improvement in user orientation during animated zooming. For this reason a solution whereby the scaled background layer stays visible until until the new tiles (in the layer above it) are completely loaded into the visible area is implemented. In this thesis, this effect is described as smooth tile update; in line with its definition it is also considered as a characteristic of Smart Map Browsing.

The actual implementation (see cloneBaseLayerDiv_share(); Layer.js):
First, the active base layer along with all its tiles is cloned (baseLayerDivClone) and added to the layer container. The z-index of baseLayerDivClone is decreased by one so that the layer lies directly under the original layer. Subsequently the ZoomOut tile of the original layer must be switched invisibly (hidden) so that it does not cover the underlying cloned layer during the tile assembly.

A loadend event in the Layer.js results when all tiles of the original layer are loaded into the visible area (see spiralTileLoad(); Grid.js). After the cloned layer is deleted, a new zoom animation may be started (see setLoadendVisibility(); Layer.js).

5.2.6 Supported Layers

After implementation, the animated zooming feature supports the layers Image, WMS Untiled as well as all derived layer classes of Grid, namely (WMS, MapServer, KaMap, TMS and WorldWind; compare also classification diagram in Appendix 6.3). On the other hand, TMS and WorldWind do not offer ZoomOut tile support, this requires a layer-specific adjustment of the getURL method (similar to WMS.js).

Applications currently unsuited for animated zooming include MapServer Untiled as well as layers of third-party providers (Google, VirtualEarth, Yahoo and MultiMap). Canvas serves only as an overlay and is therefore also not supported.

The possible expansion of new layer types described in Section 4.3 is provided for by the Layer base class. As conceptualized, new layer types do not by default support zoom animation. Through the implementation of layer-specific methods (getTileSize(), getCenterTile() and if applicable, cloneBaseLayerDiv()), the default properties of Layer.js are overwritten.

5.2.7 Animated Panning

The animated panning feature is used for combined zoom/pan operations (see Section 5.2.4). Other than correcting a rounding error in the getLonLatFromViewPortPx method (Layer.js) and supplementing the unit tests, the existing animated panning was not altered.

Panning control using arrow keys was expanded based on the Smart Map Browsing characteristics (see Section 3.2.2; heading Zooming/Panning with Keyboard). Accordingly, it is possible to reposition the map by 75% of the current map width/height at any one time, using the keys Home, End, Page or Page .

5.2.8 Source Code Structure

As the central object in OpenLayers, the Map class assumes the zoom animation control. The animated zooming source code is essentially divided into the functions prepareZoomAnimation(), runZoomAnimation() and finishZoomAnimation().

All zoom changes are done with the zoomTo method, from where the three above-mentioned animation functions are retrieved.

At the end of the implementation the complete written (respectively: modified) source code was divided into logically grouped patches. Table 5.2.8 shows the eight generated patch files with the corresponding number of total lines as well as the added and deleted source code lines. Listing 5.2.8 illustrates the principle of added and deleted files using as an example an excerpt of the patch file final_animatedZooming_PanZoomBar.patch. For space reasons the associated unit test changes (Line 1 - 53) are not illustrated here.

Lines
Nr. Patch File totaladded deleted
1final_animatedZooming_Core.patch18831293105
2final_animatedZooming_LayerImage.patch1541154
3final_animatedZooming_LayerWMSUntiled.patch3391293105
4final_animatedZooming_Mouse.patch32522034
5final_animatedZooming_OverviewMap.patch32913654
6final_animatedZooming_PanZoomBar.patch140778
7animatedPanning#2.patch38420745
8keyboardDefaults.patch18313910
Generated Patch Files for animated zooming und panning
Total3737<

b>2480

269

The eight patch files are found on the attached CD; they are also available online at OpenLayers under the following three tickets:

 
Listing: final_animatedZooming_PanZoomBar.patch


© June 1, 2007 | Emanuel Schütze | some rights reserved.
This work is licensed under the Creative Commons License Attribution-ShareAlike 2.0 Germany.


5.3 TestsTop5.1 Preparation5.2 ImplementationContentsGerman