Adding fractionalZoom property to the map. This allows zooming to an arbitrary level, making it possible to have non-discrete resolutions for layers that support it. This property should not be set to true for layers with fixed zoom levels (commercial layers or others with cached tiles). r=elemoine,crschmidt,ahocevar (closes #1243)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@5982 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
69
examples/fractional-zoom.html
Normal file
69
examples/fractional-zoom.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
#map {
|
||||
width: 512px;
|
||||
height: 256px;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
</style>
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script type="text/javascript">
|
||||
var map;
|
||||
|
||||
function init() {
|
||||
map = new OpenLayers.Map('map');
|
||||
var wms = new OpenLayers.Layer.WMS(
|
||||
"OpenLayers WMS",
|
||||
"http://labs.metacarta.com/wms/vmap0",
|
||||
{layers: 'basic'}
|
||||
);
|
||||
map.addLayers([wms]);
|
||||
|
||||
map.events.register("moveend", null, displayZoom);
|
||||
map.addControl( new OpenLayers.Control.LayerSwitcher() );
|
||||
|
||||
map.zoomToMaxExtent();
|
||||
|
||||
update(document.getElementById("fractional"));
|
||||
|
||||
}
|
||||
|
||||
function displayZoom() {
|
||||
document.getElementById("zoom").innerHTML = map.zoom.toFixed(4);
|
||||
}
|
||||
|
||||
function update(input) {
|
||||
map.fractionalZoom = input.checked;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1 id="title">Fractional Zoom Example</h1>
|
||||
|
||||
<div id="tags">
|
||||
</div>
|
||||
<p id="shortdesc">
|
||||
Shows the use of a map with fractional (or non-discrete) zoom levels.
|
||||
</p>
|
||||
|
||||
<div id="map"></div>
|
||||
<input type="checkbox" name="fractional"
|
||||
id="fractional" checked="checked" onclick="update(this)" />
|
||||
<label for="fractional">Fractional Zoom</label>
|
||||
(zoom: <span id="zoom"></span>)
|
||||
<br /><br />
|
||||
<div id="docs">
|
||||
<p>
|
||||
Setting the map.fractionalZoom property to true allows zooming to
|
||||
an arbitrary level (between the min and max resolutions). This
|
||||
can be demonstrated by shift-dragging a box to zoom to an arbitrary
|
||||
extent.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
|
||||
var size = this.map.getSize();
|
||||
var deltaX = size.w/2 - evt.xy.x;
|
||||
var deltaY = evt.xy.y - size.h/2;
|
||||
var newRes = this.map.baseLayer.resolutions[newZoom];
|
||||
var newRes = this.map.baseLayer.getResolutionForZoom(newZoom);
|
||||
var zoomPoint = this.map.getLonLatFromPixel(evt.xy);
|
||||
var newCenter = new OpenLayers.LonLat(
|
||||
zoomPoint.lon + deltaX * newRes,
|
||||
|
||||
@@ -758,7 +758,7 @@ OpenLayers.Layer = OpenLayers.Class({
|
||||
*/
|
||||
getResolution: function() {
|
||||
var zoom = this.map.getZoom();
|
||||
return this.resolutions[zoom];
|
||||
return this.getResolutionForZoom(zoom);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -812,6 +812,29 @@ OpenLayers.Layer = OpenLayers.Class({
|
||||
//to be implemented by subclasses
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getResolutionForZoom
|
||||
*
|
||||
* Parameter:
|
||||
* zoom - {Float}
|
||||
*
|
||||
* Returns:
|
||||
* {Float} A suitable resolution for the specified zoom.
|
||||
*/
|
||||
getResolutionForZoom: function(zoom) {
|
||||
zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));
|
||||
var resolution;
|
||||
if(this.map.fractionalZoom) {
|
||||
var low = Math.floor(zoom);
|
||||
var high = Math.ceil(zoom);
|
||||
resolution = this.resolutions[high] +
|
||||
((zoom-low) * (this.resolutions[low]-this.resolutions[high]));
|
||||
} else {
|
||||
resolution = this.resolutions[Math.round(zoom)];
|
||||
}
|
||||
return resolution;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getZoomForResolution
|
||||
*
|
||||
@@ -831,6 +854,32 @@ OpenLayers.Layer = OpenLayers.Class({
|
||||
* value and the 'closest' specification.
|
||||
*/
|
||||
getZoomForResolution: function(resolution, closest) {
|
||||
var zoom;
|
||||
if(this.map.fractionalZoom) {
|
||||
var lowZoom = 0;
|
||||
var highZoom = this.resolutions.length - 1;
|
||||
var highRes = this.resolutions[lowZoom];
|
||||
var lowRes = this.resolutions[highZoom];
|
||||
var res;
|
||||
for(var i=0; i<this.resolutions.length; ++i) {
|
||||
res = this.resolutions[i];
|
||||
if(res >= resolution) {
|
||||
highRes = res;
|
||||
lowZoom = i;
|
||||
}
|
||||
if(res <= resolution) {
|
||||
lowRes = res;
|
||||
highZoom = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var dRes = highRes - lowRes;
|
||||
if(dRes > 0) {
|
||||
zoom = lowZoom + ((resolution - lowRes) / dRes);
|
||||
} else {
|
||||
zoom = lowZoom;
|
||||
}
|
||||
} else {
|
||||
var diff;
|
||||
var minDiff = Number.POSITIVE_INFINITY;
|
||||
for(var i=0; i < this.resolutions.length; i++) {
|
||||
@@ -846,7 +895,9 @@ OpenLayers.Layer = OpenLayers.Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
return Math.max(0, i-1);
|
||||
zoom = Math.max(0, i-1);
|
||||
}
|
||||
return zoom;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,6 +66,14 @@ OpenLayers.Map = OpenLayers.Class({
|
||||
*/
|
||||
id: null,
|
||||
|
||||
/**
|
||||
* Property: fractionalZoom
|
||||
* {Boolean} For a base layer that supports it, allow the map resolution
|
||||
* to be set to a value between one of the values in the resolutions
|
||||
* array. Default is false.
|
||||
*/
|
||||
fractionalZoom: false,
|
||||
|
||||
/**
|
||||
* APIProperty: events
|
||||
* {<OpenLayers.Events>} An events object that handles all
|
||||
@@ -1266,10 +1274,7 @@ OpenLayers.Map = OpenLayers.Class({
|
||||
if(zoom == null) {
|
||||
zoom = this.getZoom();
|
||||
}
|
||||
var resolution = null;
|
||||
if(this.baseLayer != null) {
|
||||
resolution = this.baseLayer.resolutions[zoom];
|
||||
}
|
||||
var resolution = this.getResolutionForZoom(zoom);
|
||||
var extent = this.calculateBounds(lonlat, resolution);
|
||||
if(!this.restrictedExtent.containsBounds(extent)) {
|
||||
var maxCenter = this.restrictedExtent.getCenterLonLat();
|
||||
@@ -1326,7 +1331,7 @@ OpenLayers.Map = OpenLayers.Class({
|
||||
|
||||
if (zoomChanged) {
|
||||
this.zoom = zoom;
|
||||
this.resolution = this.baseLayer.getResolution();
|
||||
this.resolution = this.getResolutionForZoom(zoom);
|
||||
// zoom level has changed, increment viewRequestID.
|
||||
this.viewRequestID++;
|
||||
}
|
||||
@@ -1594,6 +1599,24 @@ OpenLayers.Map = OpenLayers.Class({
|
||||
return zoom;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getResolutionForZoom
|
||||
*
|
||||
* Parameter:
|
||||
* zoom - {Float}
|
||||
*
|
||||
* Returns:
|
||||
* {Float} A suitable resolution for the specified zoom. If no baselayer
|
||||
* is set, returns null.
|
||||
*/
|
||||
getResolutionForZoom: function(zoom) {
|
||||
var resolution = null;
|
||||
if(this.baseLayer) {
|
||||
resolution = this.baseLayer.getResolutionForZoom(zoom);
|
||||
}
|
||||
return resolution;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getZoomForResolution
|
||||
*
|
||||
|
||||
@@ -176,9 +176,10 @@
|
||||
|
||||
function test_06_Layer_getZoomForResolution(t) {
|
||||
|
||||
t.plan(8);
|
||||
t.plan(12);
|
||||
|
||||
var layer = new OpenLayers.Layer('Test Layer');
|
||||
layer.map = {};
|
||||
|
||||
//make some dummy resolutions
|
||||
layer.resolutions = [128, 64, 32, 16, 8, 4, 2];
|
||||
@@ -194,6 +195,16 @@
|
||||
t.eq(layer.getZoomForResolution(65, true), 1, "closest res");
|
||||
t.eq(layer.getZoomForResolution(63, true), 1, "closest res");
|
||||
|
||||
layer.map.fractionalZoom = true;
|
||||
t.eq(layer.getZoomForResolution(64), 1,
|
||||
"(fractionalZoom) correct zoom for res in array");
|
||||
t.eq(layer.getZoomForResolution(48).toPrecision(6), (1.5).toPrecision(6),
|
||||
"(fractionalZoom) linear scaling for res between entries");
|
||||
t.eq(layer.getZoomForResolution(200).toPrecision(6), (0).toPrecision(6),
|
||||
"(fractionalZoom) doesn't return zoom below zero");
|
||||
t.eq(layer.getZoomForResolution(1).toPrecision(6), (layer.resolutions.length - 1).toPrecision(6),
|
||||
"(fractionalZoom) doesn't return zoom above highest index");
|
||||
|
||||
}
|
||||
|
||||
function test_07_Layer_redraw(t) {
|
||||
@@ -302,6 +313,41 @@
|
||||
t.ok(layer.imageSize.equals(desiredImageSize), "image size correctly calculated");
|
||||
}
|
||||
|
||||
function test_Layer_getResolution(t) {
|
||||
t.plan(1);
|
||||
var layer = new OpenLayers.Layer("test");
|
||||
layer.map = {
|
||||
getZoom: function() {return "foo";}
|
||||
};
|
||||
layer.getResolutionForZoom = function(zoom) {
|
||||
t.eq(zoom, "foo", "getResolution calls getResolutionForZoom");
|
||||
}
|
||||
layer.getResolution();
|
||||
layer.map = null;
|
||||
layer.destroy();
|
||||
}
|
||||
|
||||
function test_Layer_getResolutionForZoom(t) {
|
||||
t.plan(5);
|
||||
var layer = new OpenLayers.Layer("test");
|
||||
layer.map = {fractionalZoom: false};
|
||||
layer.resolutions = ["zero", "one", "two"];
|
||||
t.eq(layer.getResolutionForZoom(0), "zero",
|
||||
"(fractionalZoom false) returns resolution for given index");
|
||||
t.eq(layer.getResolutionForZoom(0.9), "one",
|
||||
"(fractionalZoom false) returns resolution for float index");
|
||||
|
||||
layer.resolutions = [2, 4, 6, 8];
|
||||
layer.map.fractionalZoom = true;
|
||||
t.eq(layer.getResolutionForZoom(1).toPrecision(6), (4).toPrecision(6),
|
||||
"(fractionalZoom true) returns resolution for integer zoom");
|
||||
t.eq(layer.getResolutionForZoom(1.5).toPrecision(6), (5).toPrecision(6),
|
||||
"(fractionalZoom true) returns resolution for float zoom");
|
||||
t.eq(layer.getResolutionForZoom(3.5).toPrecision(6), (8).toPrecision(6),
|
||||
"(fractionalZoom true) returns resolution for zoom beyond res length - 1");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******
|
||||
|
||||
@@ -959,6 +959,22 @@
|
||||
"map extent not restricted with null restrictedExtent for se");
|
||||
}
|
||||
|
||||
function test_Map_getResolutionForZoom(t) {
|
||||
t.plan(2);
|
||||
var map = new OpenLayers.Map("map");
|
||||
var res = map.getResolutionForZoom();
|
||||
t.eq(res, null, "getResolutionForZoom returns null for no base layer");
|
||||
map.fractionalZoom = true;
|
||||
var layer = new OpenLayers.Layer("test", {isBaseLayer: true});
|
||||
layer.getResolutionForZoom = function() {
|
||||
t.ok(true, "getResolutionForZoom calls base layer getResolutionForZoom");
|
||||
}
|
||||
map.addLayer(layer);
|
||||
var res = map.getResolutionForZoom();
|
||||
layer.destroy();
|
||||
map.destroy();
|
||||
}
|
||||
|
||||
function test_99_Map_destroy (t) {
|
||||
t.plan( 3 );
|
||||
map = new OpenLayers.Map('map');
|
||||
|
||||
Reference in New Issue
Block a user