diff --git a/examples/mobile-wmts-vienna.css b/examples/mobile-wmts-vienna.css index a8ccc14a97..48e83d8372 100644 --- a/examples/mobile-wmts-vienna.css +++ b/examples/mobile-wmts-vienna.css @@ -12,13 +12,29 @@ html, body, #map { #title, #tags, #shortdesc { display: none; } + +/* Turn on GPU support where available */ +.olTileImage { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -o-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000; + -moz-perspective: 1000; + -ms-perspective: 1000; + perspective: 1000; +} + .olLayerGrid .olTileImage { -webkit-transition: opacity 0.2s linear; -moz-transition: opacity 0.2s linear; -o-transition: opacity 0.2s linear; transition: opacity 0.2s linear; - /* workaround for strange border tile squeezing on Android 4.x */ - -webkit-transform: scale(1.001); } div.olControlAttribution { position: absolute; @@ -168,4 +184,4 @@ div.layerPanel div.mapButtonItemActive:after { div.layerPanel div.mapButtonItemInactive, div.layerPanel div.mapButtonItemActive { margin-left: 1px; -} \ No newline at end of file +} diff --git a/lib/OpenLayers/Control/Navigation.js b/lib/OpenLayers/Control/Navigation.js index 30cb268e2f..d50e131204 100644 --- a/lib/OpenLayers/Control/Navigation.js +++ b/lib/OpenLayers/Control/Navigation.js @@ -245,8 +245,7 @@ OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { * evt - {Event} */ defaultDblClick: function (evt) { - var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); - this.map.setCenter(newCenter, this.map.zoom + 1); + this.map.zoomTo(this.map.zoom + 1, evt.xy); }, /** @@ -256,8 +255,7 @@ OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { * evt - {Event} */ defaultDblRightClick: function (evt) { - var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); - this.map.setCenter(newCenter, this.map.zoom - 1); + this.map.zoomTo(this.map.zoom - 1, evt.xy); }, /** @@ -271,22 +269,14 @@ OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { if (!this.map.fractionalZoom) { deltaZ = Math.round(deltaZ); } - var currentZoom = this.map.getZoom(); - var newZoom = this.map.getZoom() + deltaZ; + var currentZoom = this.map.getZoom(), + newZoom = currentZoom + deltaZ; newZoom = Math.max(newZoom, 0); newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); if (newZoom === currentZoom) { return; } - 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.getResolutionForZoom(newZoom); - var zoomPoint = this.map.getLonLatFromPixel(evt.xy); - var newCenter = new OpenLayers.LonLat( - zoomPoint.lon + deltaX * newRes, - zoomPoint.lat + deltaY * newRes ); - this.map.setCenter( newCenter, newZoom ); + this.map.zoomTo(newZoom, evt.xy); }, /** diff --git a/lib/OpenLayers/Control/PinchZoom.js b/lib/OpenLayers/Control/PinchZoom.js index c510834527..13c1104958 100644 --- a/lib/OpenLayers/Control/PinchZoom.js +++ b/lib/OpenLayers/Control/PinchZoom.js @@ -4,7 +4,6 @@ * full text of the license. */ /** - * @requires OpenLayers/Util/vendorPrefix.js * @requires OpenLayers/Handler/Pinch.js */ @@ -105,27 +104,13 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { var current = (this.preserveCenter) ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; - var dx = Math.round((current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x)); - var dy = Math.round((current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y)); + var dx = Math.round((containerOrigin.x + current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x)); + var dy = Math.round((containerOrigin.y + current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y)); - this.applyTransform( - "translate(" + dx + "px, " + dy + "px) scale(" + scale + ")" - ); + this.map.applyTransform(dx, dy, scale); this.currentCenter = current; }, - - /** - * Method: applyTransform - * Applies the given transform to layers. - */ - applyTransform: function(transform) { - var style = this.map.layerContainerDiv.style; - var transformProperty = OpenLayers.Util.vendorPrefix.style("transform"); - if (transformProperty) { - style[transformProperty] = transform; - } - }, - + /** * Method: pinchDone * @@ -137,7 +122,7 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { * of the pinch gesture. This give us the final scale of the pinch. */ pinchDone: function(evt, start, last) { - this.applyTransform(""); + this.map.applyTransform(); var zoom = this.map.getZoomForResolution(this.map.getResolution() / last.scale, true); if (zoom !== this.map.getZoom() || !this.currentCenter.equals(this.pinchOrigin)) { var resolution = this.map.getResolutionForZoom(zoom); diff --git a/lib/OpenLayers/Control/TouchNavigation.js b/lib/OpenLayers/Control/TouchNavigation.js index c436694b1e..cd5f9264b7 100644 --- a/lib/OpenLayers/Control/TouchNavigation.js +++ b/lib/OpenLayers/Control/TouchNavigation.js @@ -175,8 +175,7 @@ OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { * evt - {Event} */ defaultDblClick: function (evt) { - var newCenter = this.map.getLonLatFromViewPortPx(evt.xy); - this.map.setCenter(newCenter, this.map.zoom + 1); + this.map.zoomTo(this.map.zoom + 1, evt.xy); }, CLASS_NAME: "OpenLayers.Control.TouchNavigation" diff --git a/lib/OpenLayers/Control/ZoomBox.js b/lib/OpenLayers/Control/ZoomBox.js index d3ec81adf9..217a90a434 100644 --- a/lib/OpenLayers/Control/ZoomBox.js +++ b/lib/OpenLayers/Control/ZoomBox.js @@ -69,7 +69,8 @@ OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { */ zoomBox: function (position) { if (position instanceof OpenLayers.Bounds) { - var bounds; + var bounds, + targetCenterPx = position.getCenterPixel(); if (!this.out) { var minXY = this.map.getLonLatFromPixel({ x: position.left, @@ -87,8 +88,7 @@ OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { var zoomFactor = Math.min((this.map.size.h / pixHeight), (this.map.size.w / pixWidth)); var extent = this.map.getExtent(); - var center = this.map.getLonLatFromPixel( - position.getCenterPixel()); + var center = this.map.getLonLatFromPixel(targetCenterPx); var xmin = center.lon - (extent.getWidth()/2)*zoomFactor; var xmax = center.lon + (extent.getWidth()/2)*zoomFactor; var ymin = center.lat - (extent.getHeight()/2)*zoomFactor; @@ -96,18 +96,27 @@ OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax); } // always zoom in/out - var lastZoom = this.map.getZoom(); - this.map.zoomToExtent(bounds); + var lastZoom = this.map.getZoom(), + size = this.map.getSize(), + centerPx = {x: size.w / 2, y: size.h / 2}, + zoom = this.map.getZoomForExtent(bounds), + oldRes = this.map.getResolution(), + newRes = this.map.getResolutionForZoom(zoom), + zoomOriginPx = { + x: targetCenterPx.x + + (targetCenterPx.x - centerPx.x) * newRes / oldRes, + y: targetCenterPx.y + + (targetCenterPx.y - centerPx.y) * newRes / oldRes + }; + this.map.zoomTo(zoom, zoomOriginPx); if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){ this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); } } else if (this.zoomOnClick) { // it's a pixel if (!this.out) { - this.map.setCenter(this.map.getLonLatFromPixel(position), - this.map.getZoom() + 1); + this.map.zoomTo(this.map.getZoom() + 1, position); } else { - this.map.setCenter(this.map.getLonLatFromPixel(position), - this.map.getZoom() - 1); + this.map.zoomTo(this.map.getZoom() - 1, position); } } }, diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 57a19f9c91..2e09885e94 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -650,7 +650,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { if(!backBuffer) { return; } - this.div.insertBefore(backBuffer, this.div.firstChild); + if (resolution === this.gridResolution) { + this.div.insertBefore(backBuffer, this.div.firstChild); + } else { + this.map.layerContainerDiv.insertBefore(backBuffer, this.map.baseLayer.div); + } this.backBuffer = backBuffer; // set some information in the instance for subsequent @@ -731,7 +735,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { delete this._transitionElement; } if(this.backBuffer) { - this.div.removeChild(this.backBuffer); + if (this.backBuffer.parentNode) { + this.backBuffer.parentNode.removeChild(this.backBuffer); + } this.backBuffer = null; this.backBufferResolution = null; if(this.backBufferTimerId !== null) { diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index c7aea333c9..e42a2b0aac 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -6,6 +6,7 @@ /** * @requires OpenLayers/BaseTypes/Class.js * @requires OpenLayers/Util.js + * @requires OpenLayers/Util/vendorPrefix.js * @requires OpenLayers/Events.js * @requires OpenLayers/Tween.js * @requires OpenLayers/Projection.js @@ -395,12 +396,6 @@ OpenLayers.Map = OpenLayers.Class({ */ autoUpdateSize: true, - /** - * Property: panTween - * {} Animated panning tween object, see panTo() - */ - panTween: null, - /** * APIProperty: eventListeners * {Object} If set as an option at construction, the eventListeners @@ -410,6 +405,12 @@ OpenLayers.Map = OpenLayers.Class({ */ eventListeners: null, + /** + * Property: panTween + * {} Animated panning tween object, see panTo() + */ + panTween: null, + /** * APIProperty: panMethod * {Function} The Easing function to be used for tweening. Default is @@ -427,6 +428,28 @@ OpenLayers.Map = OpenLayers.Class({ */ panDuration: 50, + /** + * Property: zoomTween + * {} Animated zooming tween object, see zoomTo() + */ + zoomTween: null, + + /** + * APIProperty: zoomMethod + * {Function} The Easing function to be used for tweening. Default is + * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off + * animated zooming. + */ + zoomMethod: OpenLayers.Easing.Quad.easeOut, + + /** + * Property: zoomDuration + * {Integer} The number of steps to be passed to the + * OpenLayers.Tween.start() method when the map is zoomed. + * Default is 20. + */ + zoomDuration: 20, + /** * Property: paddingForPopups * {} Outside margin of the popup. Used to prevent @@ -598,6 +621,7 @@ OpenLayers.Map = OpenLayers.Class({ this.layerContainerDiv = OpenLayers.Util.createDiv(id); this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1; this.layerContainerOriginPx = {x: 0, y: 0}; + this.applyTransform(); this.viewPortDiv.appendChild(this.layerContainerDiv); @@ -693,6 +717,13 @@ OpenLayers.Map = OpenLayers.Class({ this.setCenter(options.center, options.zoom); } } + + if (this.panMethod) { + this.panTween = new OpenLayers.Tween(this.panMethod); + } + if (this.zoomMethod && this.applyTransform.transform) { + this.zoomTween = new OpenLayers.Tween(this.zoomMethod); + } }, /** @@ -761,6 +792,11 @@ OpenLayers.Map = OpenLayers.Class({ this.panTween.stop(); this.panTween = null; } + // make sure zooming doesn't continue after destruction + if(this.zoomTween) { + this.zoomTween.stop(); + this.zoomTween = null; + } // map has been destroyed. dont do it again! OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy); @@ -1681,10 +1717,7 @@ OpenLayers.Map = OpenLayers.Class({ * lonlat - {} */ panTo: function(lonlat) { - if (this.panMethod && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) { - if (!this.panTween) { - this.panTween = new OpenLayers.Tween(this.panMethod); - } + if (this.panTween && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) { var center = this.getCachedCenter(); // center will not change, don't do nothing @@ -1735,7 +1768,12 @@ OpenLayers.Map = OpenLayers.Class({ * TBD: reconsider forceZoomChange in 3.0 */ setCenter: function(lonlat, zoom, dragging, forceZoomChange) { - this.panTween && this.panTween.stop(); + if (this.panTween) { + this.panTween.stop(); + } + if (this.zoomTween) { + this.zoomTween.stop(); + } this.moveTo(lonlat, zoom, { 'dragging': dragging, 'forceZoomChange': forceZoomChange @@ -1776,17 +1814,16 @@ OpenLayers.Map = OpenLayers.Class({ } this.center = null; if (dx) { - this.layerContainerDiv.style.left = - (this.layerContainerOriginPx.x -= dx) + "px"; + this.layerContainerOriginPx.x -= dx; this.minPx.x -= dx; this.maxPx.x -= dx; } if (dy) { - this.layerContainerDiv.style.top = - (this.layerContainerOriginPx.y -= dy) + "px"; + this.layerContainerOriginPx.y -= dy; this.minPx.y -= dy; this.maxPx.y -= dy; } + this.applyTransform(); var layer, i, len; for (i=0, len=this.layers.length; i without a lonlat argument. * * Parameters: * zoom - {Integer} */ - zoomTo: function(zoom) { - if (this.isValidZoomLevel(zoom)) { - this.setCenter(null, zoom); + zoomTo: function(zoom, xy) { + // non-API arguments: + // xy - {} optional zoom origin + + var map = this; + if (map.isValidZoomLevel(zoom)) { + if (map.baseLayer.wrapDateLine) { + zoom = map.adjustZoom(zoom); + } + if (map.zoomTween) { + var currentRes = map.getResolution(), + targetRes = map.getResolutionForZoom(zoom), + start = {scale: 1}, + end = {scale: currentRes / targetRes}; + if (map.zoomTween.playing && map.zoomTween.duration < 3 * map.zoomDuration) { + // update the end scale, and reuse the running zoomTween + map.zoomTween.finish = { + scale: map.zoomTween.finish.scale * end.scale + }; + } else { + if (!xy) { + var size = map.getSize(); + xy = {x: size.w / 2, y: size.h / 2}; + } + map.zoomTween.start(start, end, map.zoomDuration, { + minFrameRate: 50, // don't spend much time zooming + callbacks: { + eachStep: function(data) { + var containerOrigin = map.layerContainerOriginPx, + scale = data.scale, + dx = ((scale - 1) * (containerOrigin.x - xy.x)) | 0, + dy = ((scale - 1) * (containerOrigin.y - xy.y)) | 0; + map.applyTransform(containerOrigin.x + dx, containerOrigin.y + dy, scale); + }, + done: function(data) { + map.applyTransform(); + var resolution = map.getResolution() / data.scale, + zoom = map.getZoomForResolution(resolution, true) + map.moveTo(map.getZoomTargetCenter(xy, resolution), zoom, true); + } + } + }); + } + } else { + var center = xy ? + map.getZoomTargetCenter(xy, map.getResolutionForZoom(zoom)) : + null; + map.setCenter(center, zoom); + } } }, - + /** * APIMethod: zoomIn * @@ -2508,7 +2590,32 @@ OpenLayers.Map = OpenLayers.Class({ return px; }, - + /** + * Method: getZoomTargetCenter + * + * Parameters: + * xy - {} The zoom origin pixel location on the screen + * resolution - {Float} The resolution we want to get the center for + * + * Returns: + * {} The location of the map center after the + * transformation described by the origin xy and the target resolution. + */ + getZoomTargetCenter: function (xy, resolution) { + var lonlat = null, + size = this.getSize(), + deltaX = size.w/2 - xy.x, + deltaY = xy.y - size.h/2, + zoomPoint = this.getLonLatFromPixel(xy); + if (zoomPoint) { + lonlat = new OpenLayers.LonLat( + zoomPoint.lon + deltaX * resolution, + zoomPoint.lat + deltaY * resolution + ); + } + return lonlat; + }, + // // CONVENIENCE TRANSLATION FUNCTIONS FOR API // @@ -2668,6 +2775,76 @@ OpenLayers.Map = OpenLayers.Class({ return this.getLayerPxFromViewPortPx(px); }, + /** + * Method: applyTransform + * Applies the given transform to the . This method has + * a 2-stage fallback from translate3d/scale3d via translate/scale to plain + * style.left/style.top, in which case no scaling is supported. + * + * Parameters: + * x - {Number} x parameter for the translation. Defaults to the x value of + * the map's + * y - {Number} y parameter for the translation. Defaults to the y value of + * the map's + * scale - {Number} scale. Defaults to 1 if not provided. + */ + applyTransform: function(x, y, scale) { + scale = scale || 1; + var origin = this.layerContainerOriginPx, + needTransform = scale !== 1; + x = x || origin.x; + y = y || origin.y; + + var style = this.layerContainerDiv.style, + transform = this.applyTransform.transform, + template = this.applyTransform.template; + + if (transform === undefined) { + transform = OpenLayers.Util.vendorPrefix.style('transform'); + this.applyTransform.transform = transform; + if (transform) { + // Try translate3d, but only if the viewPortDiv has a transform + // defined in a stylesheet + var computedStyle = OpenLayers.Element.getStyle(this.viewPortDiv, + OpenLayers.Util.vendorPrefix.css('transform')); + if (!computedStyle || computedStyle !== 'none') { + template = ['translate3d(', ',0) ', 'scale3d(', ',1)']; + style[transform] = [template[0], '0,0', template[1]].join(''); + } + // If no transform is defined in the stylesheet or translate3d + // does not stick, use translate and scale + if (!template || !~style[transform].indexOf(template[0])) { + template = ['translate(', ') ', 'scale(', ')']; + } + this.applyTransform.template = template; + } + } + + // If we do 3d transforms, we always want to use them. If we do 2d + // transforms, we only use them when we need to. + if (transform !== null && (template[0] === 'translate3d(' || needTransform === true)) { + // Our 2d transforms are combined with style.left and style.top, so + // adjust x and y values and set the origin as left and top + if (needTransform === true && template[0] === 'translate(') { + x -= origin.x; + y -= origin.y; + style.left = origin.x + 'px'; + style.top = origin.y + 'px'; + } + style[transform] = [ + template[0], x, 'px,', y, 'px', template[1], + template[2], scale, ',', scale, template[3] + ].join(''); + } else { + style.left = x + 'px'; + style.top = y + 'px'; + // We previously might have had needTransform, so remove transform + if (transform !== null) { + style[transform] = ''; + } + } + }, + CLASS_NAME: "OpenLayers.Map" }); diff --git a/tests/Control/Navigation.html b/tests/Control/Navigation.html index 70428f5a7b..e73ee42d14 100644 --- a/tests/Control/Navigation.html +++ b/tests/Control/Navigation.html @@ -148,6 +148,7 @@ var nav = new OpenLayers.Control.Navigation({zoomWheelEnabled: false}); var map = new OpenLayers.Map({ div: "map", + zoomMethod: null, controls: [nav], layers: [ new OpenLayers.Layer(null, {isBaseLayer: true}) diff --git a/tests/Control/NavigationHistory.html b/tests/Control/NavigationHistory.html index b766b0e5ae..c992ff2b7a 100644 --- a/tests/Control/NavigationHistory.html +++ b/tests/Control/NavigationHistory.html @@ -170,7 +170,7 @@ function test_clear(t) { t.plan(7); - var map = new OpenLayers.Map("map"); + var map = new OpenLayers.Map("map", {zoomMethod: null}); var layer = new OpenLayers.Layer( "test", {isBaseLayer: true} ); diff --git a/tests/Control/PanZoomBar.html b/tests/Control/PanZoomBar.html index b14ec2adba..28327768f5 100644 --- a/tests/Control/PanZoomBar.html +++ b/tests/Control/PanZoomBar.html @@ -77,7 +77,7 @@ function test_Control_PanZoomBar_onButtonClick (t) { t.plan(2); - map = new OpenLayers.Map('map', {controls:[]}); + map = new OpenLayers.Map('map', {controls:[], zoomMethod: null}); var layer = new OpenLayers.Layer.WMS("Test Layer", "http://octo.metacarta.com/cgi-bin/mapserv?", {map: "/mapdata/vmap_wms.map", layers: "basic"}); @@ -97,7 +97,8 @@ t.plan(1); map = new OpenLayers.Map('map', { controls: [], - fractionalZoom: true + fractionalZoom: true, + zoomMethod: null }); var layer = new OpenLayers.Layer.WMS("Test Layer", "http://octo.metacarta.com/cgi-bin/mapserv?", { map: "/mapdata/vmap_wms.map", @@ -127,7 +128,8 @@ var map = new OpenLayers.Map('map', { controls: [], - fractionalZoom: true + fractionalZoom: true, + zoomMethod: null, }); var layer = new OpenLayers.Layer.WMS("Test Layer", "http://octo.metacarta.com/cgi-bin/mapserv?", { map: "/mapdata/vmap_wms.map", diff --git a/tests/Control/PinchZoom.html b/tests/Control/PinchZoom.html index 1aa68f9c04..3fc5ba6851 100644 --- a/tests/Control/PinchZoom.html +++ b/tests/Control/PinchZoom.html @@ -45,8 +45,8 @@ }); var log = []; - control.applyTransform = function(transform) { - log.push(transform); + map.applyTransform = function(x, y, scale) { + log.push([x, y, scale]); } map.layerContainerOriginPx = { @@ -58,12 +58,12 @@ }; var cases = [ - {x: 100, y: 60, scale: 1, transform: "translate(0px, 10px) scale(1)"}, - {x: 150, y: 60, scale: 1, transform: "translate(50px, 10px) scale(1)"}, - {x: 150, y: 60, scale: 2, transform: "translate(-100px, -90px) scale(2)"}, - {x: 50, y: 20, scale: 2.5, transform: "translate(-275px, -180px) scale(2.5)"}, - {x: 150, y: 60, scale: 2, transform: "translate(-100px, -90px) scale(2)"}, - {x: 50, y: 20, scale: 0.25, transform: "translate(63px, 45px) scale(0.25)"} + {x: 100, y: 60, scale: 1, transform: [-50, -40, 1]}, + {x: 150, y: 60, scale: 1, transform: [0, -40, 1]}, + {x: 150, y: 60, scale: 2, transform: [-150, -140, 2]}, + {x: 50, y: 20, scale: 2.5, transform: [-325, -230, 2.5]}, + {x: 150, y: 60, scale: 2, transform: [-150, -140, 2]}, + {x: 50, y: 20, scale: 0.25, transform: [13, -5, 0.25]} ]; var len = cases.length; diff --git a/tests/Control/Scale.html b/tests/Control/Scale.html index 804ceb5622..1d43b25e08 100644 --- a/tests/Control/Scale.html +++ b/tests/Control/Scale.html @@ -22,7 +22,7 @@ control = new OpenLayers.Control.Scale('scale'); t.ok( control instanceof OpenLayers.Control.Scale, "new OpenLayers.Control returns object" ); - map = new OpenLayers.Map('map'); + map = new OpenLayers.Map('map', {zoomMethod: null}); layer = new OpenLayers.Layer.WMS('Test Layer', "http://octo.metacarta.com/cgi-bin/mapserv", {map: '/mapdata/vmap_wms.map', layers: 'basic', format: 'image/jpeg'}); map.addLayer(layer); map.zoomTo(0); @@ -38,7 +38,7 @@ t.plan(2); control = new OpenLayers.Control.Scale(); t.ok( control instanceof OpenLayers.Control.Scale, "new OpenLayers.Control returns object" ); - map = new OpenLayers.Map('map'); + map = new OpenLayers.Map('map', {zoomMethod: null}); layer = new OpenLayers.Layer.WMS('Test Layer', "http://octo.metacarta.com/cgi-bin/mapserv", {map: '/mapdata/vmap_wms.map', layers: 'basic', format: 'image/jpeg'}); map.addLayer(layer); map.zoomTo(0); diff --git a/tests/Control/Zoom.html b/tests/Control/Zoom.html index c27161dab8..cfeb082cc4 100644 --- a/tests/Control/Zoom.html +++ b/tests/Control/Zoom.html @@ -43,7 +43,8 @@ var map = new OpenLayers.Map({ div: "map", - layers: [new OpenLayers.Layer(null, {isBaseLayer: true})] + layers: [new OpenLayers.Layer(null, {isBaseLayer: true})], + zoomMethod: null }); var control = new OpenLayers.Control.Zoom(); map.addControl(control); @@ -60,7 +61,8 @@ var map = new OpenLayers.Map({ div: "map", - layers: [new OpenLayers.Layer(null, {isBaseLayer: true})] + layers: [new OpenLayers.Layer(null, {isBaseLayer: true})], + zoomMethod: null }); var control = new OpenLayers.Control.Zoom(); map.addControl(control); diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index 4296aba64a..68c65ecfbe 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -22,7 +22,7 @@ function test_constructor (t) { - t.plan( 8 ); + t.plan( 7 ); layer = new OpenLayers.Layer.Grid(name, url, params, null); t.ok( layer instanceof OpenLayers.Layer.Grid, "returns OpenLayers.Layer.Grid object" ); @@ -31,7 +31,6 @@ t.eq( layer.numLoadingTiles, 0, "numLoadingTiles starts at 0"); t.ok( layer.tileClass === OpenLayers.Tile.Image, "tileClass default is OpenLayers.Tile.Image"); t.eq( layer.className, 'olLayerGrid', "className default is olLayerGrid"); - t.eq( layer.removeBackBufferDelay, 2500, "removeBackBufferDelay default is 2500"); var obj = {}; var func = function() {}; @@ -627,7 +626,7 @@ } function test_Layer_Grid_getTileBounds(t) { t.plan(2); - var map = new OpenLayers.Map("map2"); + var map = new OpenLayers.Map("map2", {zoomMethod: null}); var url = "http://octo.metacarta.com/cgi-bin/mapserv"; layer = new OpenLayers.Layer.WMS(name, url, params); @@ -824,7 +823,8 @@ t.plan(11); var map = new OpenLayers.Map('map', { - resolutions: [32, 16, 8, 4, 2, 1] + resolutions: [32, 16, 8, 4, 2, 1], + zoomMethod: null }); var layer = new OpenLayers.Layer.WMS('', '', {}, { isBaseLayer: true, @@ -885,7 +885,8 @@ t.plan(4); var map = new OpenLayers.Map('map', { - resolutions: [1, 0.5, 0.025] + resolutions: [1, 0.5, 0.025], + zoomMethod: null }); var resolution; var layer = new OpenLayers.Layer.WMS('', '', {}, { @@ -929,7 +930,8 @@ t.plan(4); var map = new OpenLayers.Map('map', { - resolutions: [1, 0.5, 0.025] + resolutions: [1, 0.5, 0.025], + zoomMethod: null }); var resolution; var layer = new OpenLayers.Layer.WMS('', '', {}, { @@ -998,7 +1000,7 @@ layer.applyBackBuffer(2); t.ok(layer.backBuffer === backBuffer, 'back buffer set in layer'); - t.ok(layer.div.firstChild === backBuffer, + t.ok(map.layerContainerDiv.firstChild === backBuffer, 'back buffer inserted as first child'); t.eq(layer.backBuffer.style.left, '250px', 'back buffer has correct left'); @@ -1018,32 +1020,32 @@ layer.applyBackBuffer(2); t.ok(layer.backBuffer === backBuffer, 'back buffer set in layer'); - t.ok(layer.div.firstChild === backBuffer, + t.ok(map.layerContainerDiv.firstChild === backBuffer, 'back buffer inserted as first child'); t.eq(layer.backBuffer.style.left, '230px', 'back buffer has correct left'); t.eq(layer.backBuffer.style.top, '295px', 'back buffer has correct top'); - // test #4 - // and a back buffer in the layer and do as if back buffer removal - // has been scheduled, and test that applyBackBuffer removes the - // back buffer and clears the timer - layer.createBackBuffer = function() { - return; - }; - backBuffer = document.createElement('div'); - layer.div.insertBefore(backBuffer, layer.div.firstChild); - layer.backBuffer = backBuffer; - layer.backBufferTimerId = 'fake'; - layer.applyBackBuffer(2); - t.ok(backBuffer.parentNode !== layer.div, - 'back buffer is not child node of layer div'); - t.eq(layer.backBuffer, null, - 'back buffer not set in layer'); - t.eq(layer.backBufferTimerId, null, - 'back buffer timer cleared'); - map.destroy(); + // test #4 + // and a back buffer in the layer and do as if back buffer removal + // has been scheduled, and test that applyBackBuffer removes the + // back buffer and clears the timer + layer.createBackBuffer = function() { + return; + }; + backBuffer = document.createElement('div'); + map.layerContainerDiv.insertBefore(backBuffer, map.baseLayer.div); + layer.backBuffer = backBuffer; + layer.backBufferTimerId = 'fake'; + layer.applyBackBuffer(2); + t.ok(backBuffer !== map.layerContainerDiv.firstChild, + 'back buffer is not first child of layer container div'); + t.eq(layer.backBuffer, null, + 'back buffer not set in layer'); + t.eq(layer.backBufferTimerId, null, + 'back buffer timer cleared'); + map.destroy(); } function test_createBackBuffer(t) { @@ -1095,7 +1097,7 @@ } function test_removeBackBuffer(t) { - t.plan(4); + t.plan(3); var map = new OpenLayers.Map('map'); var layer = new OpenLayers.Layer.WMS('', '', {}, {isBaseLayer: true}); @@ -1107,17 +1109,12 @@ layer.div.appendChild(backBuffer); layer.backBufferResolution = 32; - // add a fake back buffer removal timer - layer.backBufferTimerId = 'fake'; - layer.removeBackBuffer(); t.eq(layer.backBuffer, null, 'backBuffer set to null in layer'); t.eq(layer.backBufferResolution, null, 'backBufferResolution set to null in layer'); t.ok(backBuffer.parentNode !== layer.div, 'back buffer removed from layer'); - t.eq(layer.backBufferTimerId, null, - 'backBufferTimerId set to null in layer'); map.destroy(); } @@ -1181,7 +1178,7 @@ t.plan(4); - var map = new OpenLayers.Map('map'); + var map = new OpenLayers.Map('map', {zoomMethod: null}); var layer = new OpenLayers.Layer.WMS('', '', {}, { isBaseLayer: true, singleTile: true, @@ -1212,7 +1209,8 @@ // var map = new OpenLayers.Map('map', { - resolutions: [32, 16, 8, 4, 2, 1] + resolutions: [32, 16, 8, 4, 2, 1], + zoomMethod: null }); var layer = new OpenLayers.Layer.WMS( "WMS", @@ -1308,6 +1306,7 @@ OpenLayers.Tile.Image.prototype.createBackBuffer = origCreateBackBuffer } + function test_delayed_back_buffer_removal(t) { // // Test that the delaying of the back buffer removal behaves @@ -1319,7 +1318,8 @@ // set up var map = new OpenLayers.Map('map', { - resolutions: [32, 16, 8, 4, 2, 1] + resolutions: [32, 16, 8, 4, 2, 1], + zoomMethod: null }); var layer = new OpenLayers.Layer.WMS('', '', {}, { isBaseLayer: true, @@ -1330,11 +1330,12 @@ map.zoomTo(1); + t.ok(layer.backBuffer === map.layerContainerDiv.firstChild, + '[a] back buffer is first child of layer container div'); + // Mark one tile loaded, to see if back buffer removal gets scheduled. layer.grid[1][1].onImageLoad(); - t.ok(layer.backBuffer.parentNode === layer.div, - '[a] back buffer is a child of layer div'); t.ok(layer.backBufferTimerId !== null, '[a] back buffer scheduled for removal'); @@ -1344,8 +1345,8 @@ t.ok(layer.backBuffer !== backBuffer, '[b] a new back buffer was created'); - t.ok(layer.backBuffer.parentNode === layer.div, - '[b] back buffer is a child of layer div'); + t.ok(layer.backBuffer === map.layerContainerDiv.firstChild, + '[b] back buffer is first child of layer container div'); t.ok(layer.backBufferTimerId === null, '[b] back buffer no longer scheduled for removal'); @@ -1353,7 +1354,7 @@ map.destroy(); } - + function test_getGridData(t) { t.plan(12); diff --git a/tests/Layer/KaMap.html b/tests/Layer/KaMap.html index c6b5ba773c..a41e4ebd0b 100644 --- a/tests/Layer/KaMap.html +++ b/tests/Layer/KaMap.html @@ -233,7 +233,7 @@ } function test_Layer_KaMap_getTileBounds(t) { t.plan(2); - var map = new OpenLayers.Map("map"); + var map = new OpenLayers.Map("map", {zoomMethod: null}); var url = "http://octo.metacarta.com/cgi-bin/mapserv"; layer = new OpenLayers.Layer.KaMap(name, url, params); diff --git a/tests/Layer/Markers.html b/tests/Layer/Markers.html index 2db3052e60..07f699fedc 100644 --- a/tests/Layer/Markers.html +++ b/tests/Layer/Markers.html @@ -59,7 +59,7 @@ t.plan(6); - var map = new OpenLayers.Map("map"); + var map = new OpenLayers.Map("map", {zoomMethod: null}); var layer = new OpenLayers.Layer.Markers("Base", {isBaseLayer: true}); map.addLayer(layer); map.setCenter(new OpenLayers.LonLat(0, 0), 1); diff --git a/tests/Layer/PointGrid.html b/tests/Layer/PointGrid.html index 22d85c7dea..6fb6ae2012 100644 --- a/tests/Layer/PointGrid.html +++ b/tests/Layer/PointGrid.html @@ -211,7 +211,8 @@ div: "map", layers: [layer], center: new OpenLayers.LonLat(0, 0), - zoom: 1 + zoom: 1, + zoomMethod: null }); t.eq(layer.features.length, 50, "50 features at zoom 1"); diff --git a/tests/Layer/WMTS.html b/tests/Layer/WMTS.html index e8d7a235f1..c6dcd4cfc0 100644 --- a/tests/Layer/WMTS.html +++ b/tests/Layer/WMTS.html @@ -245,7 +245,8 @@ layers: [layer], projection: "EPSG:4326", maxResolution: 0.3515625, - maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90) + maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90), + zoomMethod: null }); map.setCenter(new OpenLayers.LonLat(-97.0, 38.0), 1); t.eq(layer.getURL(new OpenLayers.Bounds(-135.0, 0.0, -90.0, 45.0)), diff --git a/tests/Map.html b/tests/Map.html index b072585a2b..0de10e7a56 100644 --- a/tests/Map.html +++ b/tests/Map.html @@ -216,6 +216,7 @@ t.plan(14); var log = []; map = new OpenLayers.Map('map', { + zoomMethod: null, eventListeners: { "movestart": function() {log.push("movestart");}, "move": function() {log.push("move");}, @@ -268,7 +269,7 @@ function test_Map_zoomend_event (t) { t.plan(2); - map = new OpenLayers.Map('map'); + map = new OpenLayers.Map('map', {zoomMethod: null}); var baseLayer = new OpenLayers.Layer.WMS("Test Layer", "http://octo.metacarta.com/cgi-bin/mapserv?", {map: "/mapdata/vmap_wms.map", layers: "basic"}); @@ -928,8 +929,13 @@ map.setBaseLayer(tmsLayer); map.zoomIn(); map.pan(0, -200, {animate:false}); + var log = []; + map.applyTransform = function(x, y, scale) { + log.push([x || map.layerContainerOriginPx.x, y || map.layerContainerOriginPx.y, scale]); + OpenLayers.Map.prototype.applyTransform.apply(this, arguments); + }; map.setBaseLayer(wmsLayer); - t.eq(map.layerContainerDiv.style.top, "0px", "layerContainer is recentered after setBaseLayer"); + t.eq(log[0][0], 0, "layerContainer is recentered after setBaseLayer"); map.destroy(); } @@ -1287,7 +1293,8 @@ extent = new OpenLayers.Bounds(8, 44.5, 19, 50); var options = { - restrictedExtent: extent + restrictedExtent: extent, + zoomMethod: null }; map = new OpenLayers.Map('map', options); @@ -1325,7 +1332,7 @@ function test_zoomTo(t) { t.plan(8); - var map = new OpenLayers.Map("map"); + var map = new OpenLayers.Map("map", {zoomMethod: null}); map.addLayer(new OpenLayers.Layer(null, { isBaseLayer: true })); @@ -1362,6 +1369,38 @@ map.destroy(); } + function test_zoomTo_animated(t) { + t.plan(2); + + var map = new OpenLayers.Map("map"); + map.addLayer(new OpenLayers.Layer(null, { + isBaseLayer: true + })); + + map.zoomToMaxExtent(); + + map.zoomTo(2); + map.zoomIn(); + map.zoomOut(); + map.zoomIn(); + t.delay_call(2, function() { + t.eq(map.getZoom(), 3, '[fractionalZoom: false] zoomTo(2) - zoomIn() - zoomOut() - zoomIn()'); + + // now allow fractional zoom + map.fractionalZoom = true; + + map.zoomTo(2.6); + map.zoomIn(); + map.zoomOut(); + map.zoomIn(); + }); + t.delay_call(4, function() { + t.eq(map.getZoom(), 3.6, '[fractionalZoom: true] zoomTo(2) - zoomIn() - zoomOut() - zoomIn()'); + map.destroy(); + }); + + } + function test_Map_getUnits(t) { t.plan(2); var map = new OpenLayers.Map("map"); @@ -1959,7 +1998,7 @@ } function test_moveByPx(t) { - t.plan(16); + t.plan(14); var moved; var Layer = OpenLayers.Class(OpenLayers.Layer, { @@ -1979,14 +2018,19 @@ {isBaseLayer: false, minResolution:2}) ] }); + var log = []; + map.applyTransform = function(x, y, scale) { + log.push([x || map.layerContainerOriginPx.x, y || map.layerContainerOriginPx.y, scale]); + OpenLayers.Map.prototype.applyTransform.apply(this, arguments); + }; moved = {}; map.zoomToExtent(new OpenLayers.Bounds(-1, -1, 1, 1)); // check initial state - t.eq(map.layerContainerDiv.style.left, '0px', + t.eq(log[0][0], 0, '[initial state] layer container left correct'); - t.eq(map.layerContainerDiv.style.top, '0px', + t.eq(log[0][1], 0, '[initial state] layer container top correct'); t.eq(moved['base'], undefined, '[initial state] base layer not moved'); @@ -1996,9 +2040,9 @@ // move to a valid position moved = {}; map.moveByPx(-455, 455); - t.eq(map.layerContainerDiv.style.left, '455px', + t.eq(log[1][0], 455, '[valid position] layer container left correct'); - t.eq(map.layerContainerDiv.style.top, '-455px', + t.eq(log[1][1], -455, '[valid position] layer container top correct'); t.eq(moved['base'], true, '[valid position] base layer moved'); @@ -2008,10 +2052,8 @@ // move outside the max extent moved = {}; map.moveByPx(-4500, 4500); - t.eq(map.layerContainerDiv.style.left, '455px', - '[outside max extent] layer container left correct'); - t.eq(map.layerContainerDiv.style.top, '-455px', - '[outside max extent] layer container top correct'); + t.eq(log.length, 2, + '[outside max extent] layer container offset unchanged'); t.eq(moved['base'], undefined, '[outside max extent] base layer not moved'); t.eq(moved['outofrange'], undefined, @@ -2020,10 +2062,8 @@ // move outside the restricted extent moved = {}; map.moveByPx(-500, 500); - t.eq(map.layerContainerDiv.style.left, '455px', - '[outside restricted extent] layer container left correct'); - t.eq(map.layerContainerDiv.style.top, '-455px', - '[outside restricted extent] layer container top correct'); + t.eq(log.length, 2, + '[outside restricted extent] layer container offset unchanged'); t.eq(moved['base'], undefined, '[outside restricted extent] base layer not moved'); t.eq(moved['outofrange'], undefined, @@ -2047,9 +2087,57 @@ map.zoomToExtent(new OpenLayers.Bounds(-11.25, 0, 11.25, 11.25)); + var log = []; + map.applyTransform = function(x, y, scale) { + log.push([x || map.layerContainerOriginPx.x, y || map.layerContainerOriginPx.y, scale]); + OpenLayers.Map.prototype.applyTransform.apply(this, arguments); + }; + map.moveByPx(-10, -10); - t.eq(map.layerContainerDiv.style.left, '10px', 'layer container left correct'); - t.eq(map.layerContainerDiv.style.top, '0px', 'layer container top correct'); + t.eq(log[0][0], 10, 'layer container left correct'); + t.eq(log[0][1], 0, 'layer container top correct'); + } + + function test_applyTransform(t) { + t.plan(10); + var origStylePrefix = OpenLayers.Util.vendorPrefix.style; + OpenLayers.Util.vendorPrefix.style = function(key) { return 'transform'; }; + + var map = new OpenLayers.Map('map'); + map.layerContainerDiv = {style: {}}; + delete map.applyTransform.transform; + delete map.applyTransform.template; + var origGetStyle = OpenLayers.Element.getStyle; + OpenLayers.Element.getStyle = function() { return 'foo'; } + map.applyTransform(1, 2, 3); + OpenLayers.Element.getStyle = origGetStyle; + t.eq(map.layerContainerDiv.style.transform, 'translate3d(1px,2px,0) scale3d(3,3,1)', '3d transform and scale used when available'); + + delete map.applyTransform.transform; + delete map.applyTransform.template; + var origIndexOf = String.prototype.indexOf; + String.prototype.indexOf = function() { return -1; }; + map.layerContainerOriginPx = {x: -3, y: 2}; + map.applyTransform(1, 2, 3); + String.prototype.indexOf = origIndexOf; + t.eq(map.layerContainerDiv.style.transform, 'translate(4px,0px) scale(3,3)', '2d translate and scale correct'); + t.eq(map.layerContainerDiv.style.left, '-3px', 'container origin x set as style.left'); + t.eq(map.layerContainerDiv.style.top, '2px', 'container origin y set as style.top'); + map.applyTransform(1, 2); + t.ok(!map.layerContainerDiv.style.transform, 'no transform set when no transform needed'); + t.eq(map.layerContainerDiv.style.left, '1px', 'style.left correct when no transform needed'); + t.eq(map.layerContainerDiv.style.top, '2px', 'style.top correct when no transform needed'); + + map.applyTransform.transform = null; + map.applyTransform(4, 5, 6); + t.eq(map.layerContainerDiv.style.left, '4px', 'style.left set when transform not available') + t.eq(map.layerContainerDiv.style.top, '5px', 'style.top set when transform not available') + t.ok(!map.layerContainerDiv.style.transform, 'no transform set, because not supported'); + + map.destroy(); + delete map.applyTransform.transform; + delete map.applyTransform.template; + OpenLayers.Util.vendorPrefix.style = origStylePrefix; } function test_options(t) { @@ -2112,6 +2200,24 @@ var center = map.getCenter(); t.ok(center.equals(new OpenLayers.LonLat(-13.25, 56)), "Center is correct and not equal to maxExtent's center"); } + + function test_getZoomTargetCenter(t) { + t.plan(1); + var map = new OpenLayers.Map({ + div: 'map', + layers: [ + new OpenLayers.Layer('', {isBaseLayer: true}) + ], + center: [0, 0], + zoom: 1 + }); + + var ll = map.getZoomTargetCenter({x: 44, y: 22}, map.getMaxResolution()); + + t.eq(ll.toShortString(), "180, -90", "getZoomTargetCenter works."); + + map.destroy(); + } function test_autoUpdateSize(t) { t.plan(1); diff --git a/tests/Strategy/BBOX.html b/tests/Strategy/BBOX.html index d45e8df068..6e409e6daf 100644 --- a/tests/Strategy/BBOX.html +++ b/tests/Strategy/BBOX.html @@ -51,7 +51,7 @@ }); // create a map with the layers and a center - var map = new OpenLayers.Map("map"); + var map = new OpenLayers.Map("map", {zoomMethod: null}); map.addLayers([dummy, layer]); map.zoomToMaxExtent(); @@ -206,7 +206,7 @@ function test_resFactor(t) { t.plan(2); - var map = new OpenLayers.Map("map"); + var map = new OpenLayers.Map("map", {zoomMethod: null}); var bbox = new OpenLayers.Strategy.BBOX(); var fakeProtocol = new OpenLayers.Protocol({ 'read': function() { diff --git a/tests/Strategy/Cluster.html b/tests/Strategy/Cluster.html index 05130bbfb7..d5f7a9b285 100644 --- a/tests/Strategy/Cluster.html +++ b/tests/Strategy/Cluster.html @@ -44,7 +44,8 @@ }); var map = new OpenLayers.Map('map', { resolutions: [4, 2, 1], - maxExtent: new OpenLayers.Bounds(-40, -40, 40, 40) + maxExtent: new OpenLayers.Bounds(-40, -40, 40, 40), + zoomMethod: null, }); map.addLayer(layer); diff --git a/theme/default/style.css b/theme/default/style.css index a3b75ba519..398df4bff9 100644 --- a/theme/default/style.css +++ b/theme/default/style.css @@ -487,6 +487,23 @@ a.olControlZoomOut { transition: opacity 0.2s linear; } +/* Turn on GPU support where available */ +.olTileImage { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -o-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000; + -moz-perspective: 1000; + -ms-perspective: 1000; + perspective: 1000; +} + /* when replacing tiles, do not show tile and backbuffer at the same time */ .olTileImage.olTileReplacing { display: none; diff --git a/theme/default/style.mobile.css b/theme/default/style.mobile.css index 2d4d39257a..fadff9e416 100644 --- a/theme/default/style.mobile.css +++ b/theme/default/style.mobile.css @@ -49,15 +49,19 @@ div.olControlZoom a:hover { -o-transition: opacity 0.2s linear; transition: opacity 0.2s linear; } -/* Enable 3d acceleration when operating on tiles, this is - known to yield better performance on IOS Safari. - http://osgeo-org.1803224.n2.nabble.com/Harware-accelerated-CSS3-animations-for-iOS-td6255560.html - - It also prevents tile blinking effects in iOS 5. - See https://github.com/openlayers/openlayers/issues/511 -*/ -@media (-webkit-transform-3d) { -img.olTileImage { - -webkit-transform: translate3d(0, 0, 0); -} +/* Turn on GPU support where available */ +.olTileImage { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -o-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000; + -moz-perspective: 1000; + -ms-perspective: 1000; + perspective: 1000; }