diff --git a/examples/mobile-wmts-vienna.css b/examples/mobile-wmts-vienna.css new file mode 100644 index 0000000000..a5e3f5e167 --- /dev/null +++ b/examples/mobile-wmts-vienna.css @@ -0,0 +1,160 @@ +html, body, #map { + margin: 0; + height: 100%; + width: 100%; +} +#map { + cursor: move; +} +#title, #tags, #shortdesc { + display: none; +} +div.olControlAttribution { + position: absolute; + font-size: 10px; + text-align: right; + color: #BFEFFF; + bottom: 0; + right: 0; + background: rgba(0,0,100,0.2); + font-family: Arial, Helvetica, sans-serif; + font-weight: bold; + padding: 2px 4px; + border-radius: 5px 0 0 0; +} +.olControlAttribution a { + font-weight: bold; + color: #BFEFFF; + text-decoration: none; +} +div.olControlZoomPanel { + height: 108px; + width: 36px; + position: absolute; + top: 20px; + left: inherit; + right: 20px; +} +div.olControlZoomPanel div { + cursor: pointer; + width: 36px; + height: 36px; + left: 0; + background-color: #ccc; + background-image: none; +} +div.olControlZoomPanel .olControlZoomInItemInactive, +div.olControlZoomPanel .olControlZoomOutItemInactive { + top: 0; + background: rgba(0,0,100,0.4); + position: absolute; +} +div.olControlZoomPanel .olControlZoomInItemInactive { + border-radius: 5px 5px 0 0; +} +div.olControlZoomPanel .olControlZoomOutItemInactive { + border-radius: 0 0 5px 5px; + top: 37px; +} +div.olControlZoomPanel .olControlZoomOutItemInactive:after, +div.olControlZoomPanel .olControlZoomInItemInactive:after { + font-weight: bold; + content: '+'; + font-size: 36px; + padding: 7px; + z-index: 2000; + color: #BFEFFF; + line-height: 1em; +} +div.olControlZoomPanel .olControlZoomOutItemInactive:after { + content: '–'; + line-height: 0.9em; + padding: 0 8px; +} +div.olControlZoomPanel .olControlZoomToMaxExtentItemInactive { + display: none; +} +div.olControlZoomPanel div.olControlGeolocateItemInactive, +div.olControlZoomPanel div.olControlGeolocateItemActive { + position: absolute; + right: 20px; + top: 98px; + border-radius: 5px 5px 5px 5px; + background: #ccc url(img/locate.png) center no-repeat; + background-color: rgba(0,0,100,0.4); +} +div.olControlZoomPanel div.olControlGeolocateItemActive { + background-color: rgba(0,0,100,0.2); +} +div.olControlGeolocateItemInactive:after { + font-weight: bold; + font-size: 36px; + padding: 7px; + z-index: 2000; + color: #BFEFFF; + line-height: 1em; + background: none; +} +.layerPanel { + position: absolute; + top: 20px; + right: 82px; +} +div.layerPanel div { + display: inline; + margin-left: 5px; + cursor: pointer; +} +div.layerPanel div:after { + font-weight: bold; + font-size: 18px; + font-family: arial; + padding: 8px; + color: #BFEFFF; + line-height: 36px; + border-radius: 5px 5px 5px 5px; + background-color: #ccc; + background: rgba(0,0,100,0.4); +} +div.layerPanel div.labelButtonItemInactive:after, +div.layerPanel div.labelButtonItemActive:after { + content: 'Labels'; +} +:lang(de) div.layerPanel div.labelButtonItemInactive:after, +:lang(de) div.layerPanel div.labelButtonItemActive:after { + content: 'Text'; +} +div.layerPanel div.labelButtonItemActive:after { + text-decoration: underline; + background: rgba(0,0,100,0.2); +} +div.layerPanel div.aerialButtonItemInactive:after, +div.layerPanel div.aerialButtonItemActive:after { + content: 'Aerial'; + border-radius: 5px 0 0 5px; +} +:lang(de) div.layerPanel div.aerialButtonItemInactive:after, +:lang(de) div.layerPanel div.aerialButtonItemActive:after { + content: 'Luftbild'; +} +div.layerPanel div.aerialButtonItemActive:after { + text-decoration: underline; + background: rgba(0,0,100,0.2); +} +div.layerPanel div.mapButtonItemInactive:after, +div.layerPanel div.mapButtonItemActive:after { + content: 'Map'; + border-radius: 0 5px 5px 0; +} +:lang(de) div.layerPanel div.mapButtonItemInactive:after, +:lang(de) div.layerPanel div.mapButtonItemActive:after { + content: 'Karte'; +} +div.layerPanel div.mapButtonItemActive:after { + text-decoration: underline; + background: rgba(0,0,100,0.2); +} +div.layerPanel div.mapButtonItemInactive, +div.layerPanel div.mapButtonItemActive { + margin-left: 1px; +} \ No newline at end of file diff --git a/examples/mobile-wmts-vienna.html b/examples/mobile-wmts-vienna.html new file mode 100644 index 0000000000..280f66ce74 --- /dev/null +++ b/examples/mobile-wmts-vienna.html @@ -0,0 +1,27 @@ + + + + City of Vienna WMTS with REST Encoding and Geolocate + + + + + + + + +

City of Vienna WMTS for Desktop and Mobile Devices

+
+ mobile, vienna, ogdwien, rest, restful, wmts, geolocate, permalink +
+

+ A full-screen map for both desktop and mobile devices. Uses + language dependent CSS content and the WMTSCapabilities format to + retrieve layers from the ogdwien open data initiative of the City + of Vienna. Also has a lightweight custom anchor permalink + functionality and uses the Geolocate control. +

+
+ + + diff --git a/examples/mobile-wmts-vienna.js b/examples/mobile-wmts-vienna.js new file mode 100644 index 0000000000..595897051f --- /dev/null +++ b/examples/mobile-wmts-vienna.js @@ -0,0 +1,230 @@ +var map; + +(function() { + OpenLayers.ProxyHost = "proxy.cgi?url="; + + // Set document language for css content + document.documentElement.lang = (navigator.userLanguage || navigator.language).split("-")[0]; + + // A panel for switching between Aerial and Map, and for turning labels + // on and off. + var layerPanel = new OpenLayers.Control.Panel({ + displayClass: "layerPanel", + autoActivate: true + }); + var aerialButton = new OpenLayers.Control({ + type: OpenLayers.Control.TYPE_TOOL, + displayClass: "aerialButton", + eventListeners: { + activate: function() { + if (aerial) {map.setBaseLayer(aerial);} + } + } + }); + var mapButton = new OpenLayers.Control({ + type: OpenLayers.Control.TYPE_TOOL, + displayClass: "mapButton", + eventListeners: { + activate: function() { + if (fmzk) {map.setBaseLayer(fmzk);} + } + } + }); + var labelButton = new OpenLayers.Control({ + type: OpenLayers.Control.TYPE_TOGGLE, + displayClass: "labelButton", + eventListeners: { + activate: function() { + if (labels) {labels.setVisibility(true);} + }, + deactivate: function() { + if (labels) {labels.setVisibility(false);} + } + } + }); + layerPanel.addControls([aerialButton, mapButton, labelButton]); + + var zoomPanel = new OpenLayers.Control.ZoomPanel(); + + // Geolocate control for the Locate button - the locationupdated handler + // draws a cross at the location and a circle showing the accuracy radius. + zoomPanel.addControls([ + new OpenLayers.Control.Geolocate({ + type: OpenLayers.Control.TYPE_TOGGLE, + geolocationOptions: { + enableHighAccuracy: false, + maximumAge: 0, + timeout: 7000 + }, + eventListeners: { + activate: function() { + map.addLayer(vector); + }, + deactivate: function() { + map.removeLayer(vector); + vector.removeAllFeatures(); + }, + locationupdated: function(e) { + vector.removeAllFeatures(); + vector.addFeatures([ + new OpenLayers.Feature.Vector(e.point, null, { + graphicName: 'cross', + strokeColor: '#f00', + strokeWidth: 2, + fillOpacity: 0, + pointRadius: 10 + }), + new OpenLayers.Feature.Vector( + OpenLayers.Geometry.Polygon.createRegularPolygon( + new OpenLayers.Geometry.Point(e.point.x, e.point.y), + e.position.coords.accuracy / 2, 50, 0 + ), null, { + fillOpacity: 0.1, + fillColor: '#000', + strokeColor: '#f00', + strokeOpacity: 0.6 + } + ) + ]); + map.zoomToExtent(vector.getDataExtent()); + } + } + }) + ]); + + // Map with navigation controls optimized for touch devices + map = new OpenLayers.Map({ + div: "map", + theme: null, + projection: "EPSG:3857", + units: "m", + maxExtent: new OpenLayers.Bounds( + -20037508.34, -20037508.34, 20037508.34, 20037508.34 + ), + maxResolution: 156543.0339, + numZoomLevels: 20, + controls: [ + new OpenLayers.Control.TouchNavigation({ + mouseWheelOptions: { + cumulative: false, + interval: 20 + }, + dragPanOptions: { + enableKinetic: { + deceleration: 0.02 + } + }, + zoomBoxEnabled: false + }), + new OpenLayers.Control.Attribution(), + zoomPanel, + layerPanel + ], + eventListeners: { + moveend: function() { + // update anchor for permalinks + var ctr = map.getCenter(); + window.location.hash = "x="+ctr.lon+"&y="+ctr.lat+"&z="+map.getZoom(); + } + } + }); + layerPanel.activateControl(mapButton); + layerPanel.activateControl(labelButton); + + // Vector layer for the location cross and circle + var vector = new OpenLayers.Layer.Vector("Vector Layer"); + + // The WMTS layers we're going to add + var fmzk, aerial, labels; + + // The WMTSCapabilities format and the default options for the layers + var format = new OpenLayers.Format.WMTSCapabilities(), defaults = { + requestEncoding: "REST", + matrixSet: "google3857", + transitionEffect: "resize", + tileLoadingDelay: 0, + attribution: 'Datenquelle: Stadt Wien - data.wien.gv.at' + }; + + // Request capabilities and create layers + OpenLayers.Request.GET({ + url: "http://maps.wien.gv.at/wmts/1.0.0/WMTSCapabilities.xml", + success: function(request) { + var doc = request.responseText, + caps = format.read(doc); + fmzk = format.createLayer(caps, OpenLayers.Util.applyDefaults( + {layer:"fmzk", requestEncoding:"REST"}, defaults + )); + aerial = format.createLayer(caps, OpenLayers.Util.applyDefaults( + {layer:"lb", requestEncoding:"REST"}, defaults + )); + labels = format.createLayer(caps, OpenLayers.Util.applyDefaults( + {layer:"beschriftung", requestEncoding:"REST", isBaseLayer: false}, + defaults + )); + map.addLayers([fmzk, aerial, labels]); + + // zoom to initial extent or restore position from permalink + var extent = fmzk.tileFullExtent, + ctr = extent.getCenterLonLat(), + zoom = map.getZoomForExtent(extent, true), + params = OpenLayers.Util.getParameters("?"+window.location.hash.substr(1)); + OpenLayers.Util.applyDefaults(params, {x:ctr.lon, y:ctr.lat, z:zoom}); + map.setCenter(new OpenLayers.LonLat(params.x, params.y), params.z); + } + }); +})(); + +// Reliably hide the address bar on Android and iOS devices. From +// http://blog.nateps.com/how-to-hide-the-address-bar-in-a-full-screen +(function() { + var page = document.getElementById("map"), + ua = navigator.userAgent, + iphone = ~ua.indexOf('iPhone') || ~ua.indexOf('iPod'), + ipad = ~ua.indexOf('iPad'), + ios = iphone || ipad, + // Detect if this is running as a fullscreen app from the homescreen + fullscreen = window.navigator.standalone, + android = ~ua.indexOf('Android'), + lastWidth = 0; + + if (android) { + // Android's browser adds the scroll position to the innerHeight, just to + // make this really fucking difficult. Thus, once we are scrolled, the + // page height value needs to be corrected in case the page is loaded + // when already scrolled down. The pageYOffset is of no use, since it always + // returns 0 while the address bar is displayed. + window.onscroll = function() { + page.style.height = window.innerHeight + 'px'; + }; + } + var setupScroll = window.onload = function() { + // Start out by adding the height of the location bar to the width, so that + // we can scroll past it + if (ios) { + // iOS reliably returns the innerWindow size for documentElement.clientHeight + // but window.innerHeight is sometimes the wrong value after rotating + // the orientation + var height = document.documentElement.clientHeight; + // Only add extra padding to the height on iphone / ipod, since the ipad + // browser doesn't scroll off the location bar. + if (iphone && !fullscreen) height += 60; + page.style.height = height + 'px'; + } else if (android) { + // The stock Android browser has a location bar height of 56 pixels, but + // this very likely could be broken in other Android browsers. + page.style.height = (window.innerHeight + 56) + 'px'; + } + // Scroll after a timeout, since iOS will scroll to the top of the page + // after it fires the onload event + setTimeout(scrollTo, 0, 0, 1); + }; + (window.onresize = function() { + var pageWidth = page.offsetWidth; + // Android doesn't support orientation change, so check for when the width + // changes to figure out when the orientation changes + if (lastWidth == pageWidth) return; + lastWidth = pageWidth; + setupScroll(); + })(); +})(); diff --git a/examples/proxy.cgi b/examples/proxy.cgi index c668218c48..4358e2ca03 100755 --- a/examples/proxy.cgi +++ b/examples/proxy.cgi @@ -21,7 +21,8 @@ allowedHosts = ['www.openlayers.org', 'openlayers.org', 'sigma.openplans.org', 'demo.opengeo.org', 'www.openstreetmap.org', 'sample.azavea.com', 'v2.suite.opengeo.org', 'v-swe.uni-muenster.de:8080', - 'vmap0.tiles.osgeo.org', 'www.openrouteservice.org'] + 'vmap0.tiles.osgeo.org', 'www.openrouteservice.org', + 'maps.wien.gv.at'] method = os.environ["REQUEST_METHOD"]