OpenLayers OpenLayers

Ticket #1243: fractional.patch

File fractional.patch, 12.2 kB (added by tschaub, 1 year ago)

allow for non discrete zoom levels

  • tests/test_Map.html

    old new  
    958958             se.toString(), 
    959959             "map extent not restricted with null restrictedExtent for se"); 
    960960    } 
     961     
     962    function test_Map_getResolutionForZoom(t) { 
     963        t.plan(2); 
     964        var map = new OpenLayers.Map("map"); 
     965        var res = map.getResolutionForZoom(); 
     966        t.eq(res, null, "getResolutionForZoom returns null for no base layer"); 
     967        map.fractionalZoom = true; 
     968        var layer = new OpenLayers.Layer("test", {isBaseLayer: true}); 
     969        layer.getResolutionForZoom = function() { 
     970            t.ok(true, "getResolutionForZoom calls base layer getResolutionForZoom"); 
     971        } 
     972        map.addLayer(layer); 
     973        var res = map.getResolutionForZoom(); 
     974        layer.destroy(); 
     975        map.destroy(); 
     976    } 
    961977 
    962978    function test_99_Map_destroy (t) { 
    963979        t.plan( 3 );     
  • tests/test_Layer.html

    old new  
    176176 
    177177    function test_06_Layer_getZoomForResolution(t) { 
    178178 
    179         t.plan(8); 
     179        t.plan(12); 
    180180 
    181181        var layer = new OpenLayers.Layer('Test Layer'); 
    182              
     182        layer.map = {}; 
     183         
    183184        //make some dummy resolutions 
    184185        layer.resolutions = [128, 64, 32, 16, 8, 4, 2]; 
    185186         
     
    193194 
    194195        t.eq(layer.getZoomForResolution(65, true), 1, "closest res"); 
    195196        t.eq(layer.getZoomForResolution(63, true), 1, "closest res"); 
     197         
     198        layer.map.fractionalZoom = true; 
     199        t.eq(layer.getZoomForResolution(64), 1, 
     200             "(fractionalZoom) correct zoom for res in array"); 
     201        t.eq(layer.getZoomForResolution(48).toPrecision(6), (1.5).toPrecision(6), 
     202             "(fractionalZoom) linear scaling for res between entries"); 
     203        t.eq(layer.getZoomForResolution(200).toPrecision(6), (0).toPrecision(6), 
     204             "(fractionalZoom) doesn't return zoom below zero"); 
     205        t.eq(layer.getZoomForResolution(1).toPrecision(6), (layer.resolutions.length - 1).toPrecision(6), 
     206             "(fractionalZoom) doesn't return zoom above highest index"); 
    196207 
    197208    } 
    198209     
     
    301312        t.ok(layer.imageOffset.equals(desiredImageOffset), "image offset correctly calculated"); 
    302313        t.ok(layer.imageSize.equals(desiredImageSize), "image size correctly calculated"); 
    303314    } 
     315     
     316    function test_Layer_getResolution(t) { 
     317        t.plan(1); 
     318        var layer = new OpenLayers.Layer("test"); 
     319        layer.map = { 
     320            getZoom: function() {return "foo";} 
     321        }; 
     322        layer.getResolutionForZoom = function(zoom) { 
     323            t.eq(zoom, "foo", "getResolution calls getResolutionForZoom"); 
     324        } 
     325        layer.getResolution(); 
     326        layer.map = null; 
     327        layer.destroy(); 
     328    } 
     329     
     330    function test_Layer_getResolutionForZoom(t) { 
     331        t.plan(5); 
     332        var layer = new OpenLayers.Layer("test"); 
     333        layer.map = {fractionalZoom: false}; 
     334        layer.resolutions = ["zero", "one", "two"]; 
     335        t.eq(layer.getResolutionForZoom(0), "zero", 
     336             "(fractionalZoom false) returns resolution for given index"); 
     337        t.eq(layer.getResolutionForZoom(0.9), "one", 
     338             "(fractionalZoom false) returns resolution for float index"); 
     339         
     340        layer.resolutions = [2, 4, 6, 8]; 
     341        layer.map.fractionalZoom = true; 
     342        t.eq(layer.getResolutionForZoom(1).toPrecision(6), (4).toPrecision(6), 
     343             "(fractionalZoom true) returns resolution for integer zoom"); 
     344        t.eq(layer.getResolutionForZoom(1.5).toPrecision(6), (5).toPrecision(6), 
     345             "(fractionalZoom true) returns resolution for float zoom");              
     346        t.eq(layer.getResolutionForZoom(3.5).toPrecision(6), (8).toPrecision(6), 
     347             "(fractionalZoom true) returns resolution for zoom beyond res length - 1"); 
     348         
     349    } 
    304350 
    305351 
    306352 
  • lib/OpenLayers/Map.js

    old new  
    6767    id: null, 
    6868     
    6969    /** 
     70     * Property: fractionalZoom 
     71     * {Boolean} For a base layer that supports it, allow the map resolution 
     72     *     to be set to a value between one of the values in the resolutions 
     73     *     array.  Default is false. 
     74     */ 
     75    fractionalZoom: false, 
     76     
     77    /** 
    7078     * APIProperty: events 
    7179     * {<OpenLayers.Events>} An events object that handles all  
    7280     *                       events on the map 
     
    12661274            if(zoom == null) {  
    12671275                zoom = this.getZoom();  
    12681276            } 
    1269             var resolution = null; 
    1270             if(this.baseLayer != null) { 
    1271                 resolution = this.baseLayer.resolutions[zoom]; 
    1272             } 
     1277            var resolution = this.getResolutionForZoom(zoom); 
    12731278            var extent = this.calculateBounds(lonlat, resolution);  
    12741279            if(!this.restrictedExtent.containsBounds(extent)) { 
    12751280                var maxCenter = this.restrictedExtent.getCenterLonLat();  
     
    13261331 
    13271332            if (zoomChanged) { 
    13281333                this.zoom = zoom; 
    1329                 this.resolution = this.baseLayer.getResolution(); 
     1334                this.resolution = this.getResolutionForZoom(zoom); 
    13301335                // zoom level has changed, increment viewRequestID. 
    13311336                this.viewRequestID++; 
    13321337            }     
     
    15951600    }, 
    15961601 
    15971602    /** 
     1603     * APIMethod: getResolutionForZoom 
     1604     *  
     1605     * Parameter: 
     1606     * zoom - {Float} 
     1607     *  
     1608     * Returns: 
     1609     * {Float} A suitable resolution for the specified zoom.  If no baselayer 
     1610     *     is set, returns null. 
     1611     */ 
     1612    getResolutionForZoom: function(zoom) { 
     1613        var resolution = null; 
     1614        if(this.baseLayer) { 
     1615            resolution = this.baseLayer.getResolutionForZoom(zoom); 
     1616        } 
     1617        return resolution; 
     1618    }, 
     1619 
     1620    /** 
    15981621     * APIMethod: getZoomForResolution 
    15991622     *  
    16001623     * Parameter: 
  • lib/OpenLayers/Control/Navigation.js

    old new  
    137137        var size    = this.map.getSize(); 
    138138        var deltaX  = size.w/2 - evt.xy.x; 
    139139        var deltaY  = evt.xy.y - size.h/2; 
    140         var newRes  = this.map.baseLayer.resolutions[newZoom]
     140        var newRes  = this.map.baseLayer.getResolutionForZoom(newZoom)
    141141        var zoomPoint = this.map.getLonLatFromPixel(evt.xy); 
    142142        var newCenter = new OpenLayers.LonLat( 
    143143                            zoomPoint.lon + deltaX * newRes, 
  • lib/OpenLayers/Layer.js

    old new  
    758758     */ 
    759759    getResolution: function() { 
    760760        var zoom = this.map.getZoom(); 
    761         return this.resolutions[zoom]
     761        return this.getResolutionForZoom(zoom)
    762762    }, 
    763763 
    764764    /**  
     
    813813    }, 
    814814 
    815815    /** 
     816     * APIMethod: getResolutionForZoom 
     817     *  
     818     * Parameter: 
     819     * zoom - {Float} 
     820     *  
     821     * Returns: 
     822     * {Float} A suitable resolution for the specified zoom. 
     823     */ 
     824    getResolutionForZoom: function(zoom) { 
     825        zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1)); 
     826        var resolution; 
     827        if(this.map.fractionalZoom) { 
     828            var low = Math.floor(zoom); 
     829            var high = Math.ceil(zoom); 
     830            resolution = this.resolutions[high] + 
     831                ((zoom-low) * (this.resolutions[low]-this.resolutions[high])); 
     832        } else { 
     833            resolution = this.resolutions[Math.round(zoom)]; 
     834        } 
     835        return resolution; 
     836    }, 
     837 
     838    /** 
    816839     * APIMethod: getZoomForResolution 
    817840     *  
    818841     * Parameters: 
     
    831854     *     value and the 'closest' specification. 
    832855     */ 
    833856    getZoomForResolution: function(resolution, closest) { 
    834         var diff; 
    835         var minDiff = Number.POSITIVE_INFINITY; 
    836         for(var i=0; i < this.resolutions.length; i++) {             
    837             if (closest) { 
    838                 diff = Math.abs(this.resolutions[i] - resolution); 
    839                 if (diff > minDiff) { 
     857        var zoom; 
     858        if(this.map.fractionalZoom) { 
     859            var lowZoom = 0; 
     860            var highZoom = this.resolutions.length - 1; 
     861            var highRes = this.resolutions[lowZoom]; 
     862            var lowRes = this.resolutions[highZoom]; 
     863            var res; 
     864            for(var i=0; i<this.resolutions.length; ++i) { 
     865                res = this.resolutions[i]; 
     866                if(res >= resolution) { 
     867                    highRes = res; 
     868                    lowZoom = i; 
     869                } 
     870                if(res <= resolution) { 
     871                    lowRes = res; 
     872                    highZoom = i; 
    840873                    break; 
    841874                } 
    842                 minDiff = diff; 
     875            } 
     876            var dRes = highRes - lowRes; 
     877            if(dRes > 0) { 
     878                zoom = lowZoom + ((resolution - lowRes) / dRes); 
    843879            } else { 
    844                 if (this.resolutions[i] < resolution) { 
    845                     break; 
     880                zoom = lowZoom; 
     881            } 
     882        } else { 
     883            var diff; 
     884            var minDiff = Number.POSITIVE_INFINITY; 
     885            for(var i=0; i < this.resolutions.length; i++) {             
     886                if (closest) { 
     887                    diff = Math.abs(this.resolutions[i] - resolution); 
     888                    if (diff > minDiff) { 
     889                        break; 
     890                    } 
     891                    minDiff = diff; 
     892                } else { 
     893                    if (this.resolutions[i] < resolution) { 
     894                        break; 
     895                    } 
    846896                } 
    847897            } 
     898            zoom = Math.max(0, i-1); 
    848899        } 
    849         return Math.max(0, i-1)
     900        return zoom
    850901    }, 
    851902     
    852903    /** 
  • examples/fractional-zoom.html

    old new  
     1<html xmlns="http://www.w3.org/1999/xhtml"> 
     2  <head> 
     3    <style type="text/css"> 
     4        #map { 
     5            width: 512px; 
     6            height: 256px; 
     7            border: 1px solid gray; 
     8        } 
     9    </style> 
     10    <script src="../lib/OpenLayers.js"></script> 
     11    <script type="text/javascript"> 
     12        var map; 
     13 
     14        function init() { 
     15            map = new OpenLayers.Map('map'); 
     16            var wms = new OpenLayers.Layer.WMS( 
     17                "OpenLayers WMS", 
     18                "http://labs.metacarta.com/wms/vmap0", 
     19                {layers: 'basic'} 
     20            ); 
     21            map.addLayers([wms]); 
     22 
     23            map.events.register("moveend", null, displayZoom); 
     24            map.addControl( new OpenLayers.Control.LayerSwitcher() ); 
     25 
     26            map.zoomToMaxExtent(); 
     27             
     28            update(document.getElementById("fractional")); 
     29             
     30        } 
     31         
     32        function displayZoom() { 
     33            document.getElementById("zoom").innerHTML = map.zoom.toFixed(4); 
     34        } 
     35         
     36        function update(input) { 
     37            map.fractionalZoom = input.checked; 
     38        } 
     39    </script> 
     40  </head> 
     41  <body onload="init()"> 
     42    <h1 id="title">Fractional Zoom Example</h1> 
     43 
     44    <div id="tags"> 
     45    </div> 
     46    <p id="shortdesc"> 
     47            Shows the use of a map with fractional (or non-discrete) zoom levels. 
     48    </p> 
     49 
     50    <div id="map"></div> 
     51        <input type="checkbox" name="fractional" 
     52               id="fractional" checked="checked" onclick="update(this)" /> 
     53        <label for="fractional">Fractional Zoom</label> 
     54        (zoom: <span id="zoom"></span>) 
     55        <br /><br /> 
     56    <div id="docs"> 
     57            <p> 
     58            Setting the map.fractionalZoom property to true allows zooming to 
     59            an arbitrary level (between the min and max resolutions).  This 
     60            can be demonstrated by shift-dragging a box to zoom to an arbitrary 
     61            extent. 
     62            </p> 
     63    </div> 
     64  </body> 
     65</html> 
     66 
     67 
     68 
     69