I'm trying to fetch weather radar data for the UK, from a WMST server.
The client can get the Capabilities fine. After that, the browser (Chrome and Firefox) crashes after a while, with an out-of-memory error.
The only thing obviously different in my case, in comparison with simple examples, is that an API key is needed for all interactions with the server.
var parser = new ol.format.WMTSCapabilities();
var map;
//I pass the API key here
fetch('http://datapoint.metoffice.gov.uk/public/data/inspire/view/wmts?REQUEST=GetCapabilities&key=my_key_goes_here').then(function(response) {
return response.text();
}).then(function(text) {
console.log('Capabilities found.'); //ok
var result = parser.read(text);
var options = ol.source.WMTS.optionsFromCapabilities(result, {
layer: 'RADAR_UK_Composite_Highres',
matrixSet: 'EPSG:4326'
});
map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
opacity: 0.7
}),
new ol.layer.Tile({ //fails when this Tile is included
opacity: 1,
source: new ol.source.WMTS(options),
//I set this, figuring that the API key is still needed
url: 'http://datapoint.metoffice.gov.uk/public/data/inspire/view/wmts?my_key_goes_here'
})
],
target: 'mymap',
view: new ol.View({
center: ol.proj.fromLonLat([0, 52.0]), //near London, UK
zoom: 7
})
});
});
The crash happens without the client trying to fetch the tiles (because I can't see any HTTP requests in the debugger; the last one is the get-capabilities request).
Any hints as to what might be causing this?
First of all, note that ol.layer.Tile does not have an url option. Ideally, the GetCapabilities response would advertise a service url that has the key already. Since the server you are trying to access does not have that, you'll have to tweak the result you get from the GetCapabilities response:
result.OperationsMetadata.GetTile.DCP.HTTP.Get[0].href += 'key=my_key_goes_here&'
The second and more severe problem is that the GetCapabilities response advertises incorrect scale denominators and origins. To fix those, you have to tweak the result again:
result.Contents.TileMatrixSet[0].TileMatrix.forEach(function(m) {
m.ScaleDenominator *= 111319.49079327358;
m.TopLeftCorner = m.TopLeftCorner.reverse();
});
After applying these tweaks, you can pass the result to ol.source.WMTS.optionsFromCapabilities, and you will get a correct map.
I'd strongly recommend you contact the service provider (contact information can also be found in the GetCapabilities response) and let them know about the problems with their GetCapabilities response.
Related
I am creating a web page with Leaflet to access a WMS server.
The issue I have is that I access a paying WMS server that is "counting" the number of requests I make.
In the first attempt I made, since the default tileSize was 256px each of my requests generated 16 tiles requests and so I was "deducted" 16 requests on my account.
I then tried to modify my code as follow :
var wmsserver = L.tileLayer.wms('http://wmsserver/wms?', {
layers: 'mix:precip_24h:mm' ,
format: 'image/png',
tileSize: window.screen.width,
version: '1.3.0',
transparent: true,
});
Now I still have 2 requests logged, and the result on the screen is a little bit shifted.
There must be a cleaner way to do this.
I am trying to load two google map instances dynamically on a single page but it fetches below errors.
You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors.
providing below code for more help as I am using the load-google-maps-api node_module.
googleMapInit () {
let self = this,
mapElement = this.$refs.canvasy;
loadGoogleMapsAPI({
key: this.gmk,
language: this.language
})
.then( googleApi => {
self.contextMarkerLatLng = new google.maps.LatLng( self.contextMarkerCoords.lat, self.contextMarkerCoords.lng );
self.googleMap = new google.maps.Map( mapElement , {
disableDefaultUI: true,
styles: MapStylesObj.styles,
zoom: self.googleMapZoom,
minZoom: self.googleMapMinZoom,
center: self.contextMarkerLatLng
});
What about using load-google-maps-api-2:
https://www.npmjs.com/package/load-google-maps-api-2
It is built on top of load-google-maps-api, so should work the same and includes the following feature:
Added check whether API is already loaded. (Google API writes warnings into console when they are loaded multiple times.)
I am currently working on a GIS holding a large amount of layers (up to 20 / 30).
The map is rendering tiles in a really slow way.
It was previously written with OpenLayers 2.x, and we didn't face this performance bottleneck.
Our layers are using WMS sources & tiles, which are declared as follow
function createTileLayer(options){
let source = new ol.source.TileWMS({
url: serverURL, // Our GeoServer instance
params: {
'LAYERS': options.id
'BGCOLOR': options.backgroundColor,
'TRANSPARENT': options.transparent,
'VERSION': options.version,
'FORMAT': 'image/png'
},
serverType: 'geoserver',
projection: 'EPSG:2100', // Managed by Proj4J
transition: 0
});
let layerTile = new ol.layer.Tile({
source: source,
visible: options.visible,
});
return layerTile;
}
The map declaration in itself is quite simple:
let map = new ol.Map({
target: document.getElementById('app'),
layers: Layers, // All the layers we created before
view: new ol.View({
center: ol.proj.fromLonLat([5.497853028599662, 34.82203273834541]),
zoom: 18,
projection: 'EPSG:2100'
}),
loadTilesWhileAnimating: true,
loadTilesWhileInteracting: true,
renderer: 'canvas'
});
}
Problem with this approach is that the browser seems to spend far too much time in drawing every layer. Here is the profile of some tests on Chrome:
Results are an almost unusable map.
I am aware that the amount of layers is high, but the issue was not in OpenLayers 2.x (or at least, performances were better).
One possible workaround is using only one TileWMS source and pass it the list of all our layers in its 'LAYERS' param. This dramatically improve the speed because GeoServer does all the rendering work, but we lose some possibilities such as managing each layer transparency.
I might be doing something wrong in querying / rendering tiles this way, that I am not aware of. Thanks for any help.
The most likely issue is that you are not hitting the tile boundaries that GeoWebCache (which is what GeoServer) uses to render the tiles. See this page in the manual which lists the criteria that must be met for this to work.
A better way to do this is to use a WMTS request (where the tile grids etc are agreed on between the client and server rather than guessed at). You can even get OpenLayers to do the negotiation for you by asking for the getCapabilities document.
I'm creating a little web page containing a map using the Google Maps API and the OpenLayers JS library (v2.13). The base layer of the map is Google Street Maps, and that works fine, I can pan around the map, zoom in etc.
I'm adding a number of layers to the map, which come from a Web Mapping Service hosted on a remote server that I don't own or have access to (the code, I mean). And that works fine too, the layers overlay onto the Google Map just fine.
The problem is when I click on the layer features on the map, the WMSGetFeatureInfo controls are not working. No request is sent to the specified URL, no callback function is triggered, nothing happens at all. Here's some code:
var remoteGeoServer = "https://www.remotegeoserver.com/geoserver/wms";
var options = {
controls: [],
maxExtent: new OpenLayers.Bounds(420000, 485000, 770000, 985000),
projection: "EPSG:2157",
units: 'm',
scales: [5000000, 2500000, 1250000, 600000, 400000, 200000, 100000, 50000, 25000]
};
var map = new OpenLayers.Map('map-container', options);
// ... define styles, rules etc.
var overlayLayer = new OpenLayers.Layer.WMS("Overlayed Layer", remoteGeoServer, {<some_options>}); // other layers are created too...
var infoControls = {
click: new OpenLayers.Control.WMSGetFeatureInfo({
url: "/geoserver/wms",
title: 'Identify features by clicking',
layers: [overlayedLayer],
infoFormat: 'text/plain',
queryVisible: true
})
};
var baseLayer = new OpenLayers.Layer.Google("Google Streets", {numZoomLevels: 20});
map.addLayers( [baseLayer, overlayLayer] );
map.setBaseLayer( baseLayer );
for (var i in infoControls) {
infoControls[i].events.register("getfeatureinfo", this, showInfo);
map.addControl(infoControls[i]);
}
// ... and later
function showInfo(evt) {
console.log("Hurray!");
}
infoControls.click.activate();
I should explain that, even though the url in the infoControls is called "/geoserver/wms", there is no web mapping server running on my server. I just forward on the GetFeatureInfo request to the remote server that runs the actual geoserver. Otherwise the same-origin policy kicks in and the GetFeatureInfo requests are rejected.
But nothing happens, my "/geoserver/wms" endpoint never gets called. Am I doing something wrong? Also, and this isn't my main question, but why am I able to successfully give OpenLayers the remote server URL when creating the layers (should same-origin policy not apply - the map still works fine though, and the GET image requests to the remote server are successful).
Something else worth noting is that when I replace the local url path in infoControls with the remote server url, clicking the map triggers the same-origin policy error in the debug console.
I found a few different potential solutions for this problem that other people were having but none of them worked for me. In the end, the only thing that did work was this:
The URL used in the layer creation constructor(s) (in OpenLayers.Layer.WMS) MUST be the same as the URL used for the GetFeatureInfo constructor (in OpenLayers.Control.WMSGetFeatureInfo)
Otherwise, the map layers will work but the GetFeatureInfo requests will fail. I don't know if just the domain needs to be the same, or the full URL.
I'm not particularly happy about this. It means that I have to create an endpoint on my server that acts as a proxy and routes GetMap requests to the actual remote geoserver. I didn't need to do this before (why not - same-origin policy ??) and now it drives up latency for the layers showing up in the map (not to mention my server gets hammered with GetMap requests).
This seems to be an issue with OpenLayers (but I'm not sure of that). I'd be very interested in hearing about a solution if anyone knows of one.
I really hope someone can help with my problem. I have built a mobile web app http://ufa-ld-qa.azurewebsites.net/ (the QA site) with asp.net mvc4 using Bing Maps API for various functionality in the app. I am having problems with the directions module. When I view the site on my pc (Chrome and IE) it works fine and I see no errors but on mobile devices it is not working (but it did work fine yesterday when we launched to QA). I have used HTML5 geolocation (this may be the issue) to get user's location to allow them to get directions to a location. I will post my code below and if anyone could please help me it would be greatly appreciated. We have tested it on about 7 different mobile devices with different OS's and it doesn't work on any. Does anyone know if this is a Bing issue or my code below? Thanks so much in advance.
<script type="text/javascript">
var map = null;
var directionsManager = null;
var userLat = null;
var userLong = null;
var userPosition = null;
var latlng = new Microsoft.Maps.Location(#Model.latitude, #Model.longitude);
navigator.geolocation.getCurrentPosition(locationHandler);
function locationHandler(position)
{
userPosition = new Microsoft.Maps.Location(position.coords.latitude, position.coords.longitude);
}
function GetMap() {
// Initialize the map
map = new Microsoft.Maps.Map(document.getElementById("map"), { credentials: "Au_7giL-8dUbFkJ8zLjcQKy4dV2ftPfpMxQ0_sVBksoj4Y-1nBT00Z1oqUIU894_",
mapTypeId: Microsoft.Maps.MapTypeId.road});
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: directionsModuleLoaded });
}
function directionsModuleLoaded() {
// Initialize the DirectionsManager
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
// Create start and end waypoints
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: userPosition });
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: latlng });
directionsManager.addWaypoint(startWaypoint);
directionsManager.addWaypoint(endWaypoint);
// Set request options
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.driving });
// Set the render options
directionsManager.setRenderOptions({
itineraryContainer: document.getElementById('directionPanel'),
displayWalkingWarning: false,
walkingPolylineOptions: { strokeColor: new Microsoft.Maps.Color(200, 0, 255, 0) },
});
// Specify a handler for when an error occurs
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', displayError);
// Calculate directions, which displays a route on the map
directionsManager.calculateDirections();
}
function displayError(e) {
// Display the error message
alert(e.message);
}
</script>
A couple of things to try. First ensure that your app is allowed to access the users location. Most mobile platforms require you to mark that the app requires access to the GPS in the manifest. Another thing to look into is the possibility that the userLocation isn't populated before your callback for the directions manager is called. It's possible that the GPS takes a little longer on the mobile device to find the users location and as such the directions loaded function is firing before the users location is set, thus passing in a null starting . You might find it useful to have a flag to indicate that the directions manager has loaded and a simple function that runs after setting the flag and also runs after setting the use location that checks that both the directions manager has loaded and the user location has been set and then calls your directions loaded function.
My Windows Phone 8 App is experiencing similar behavior. (Nokia 920)
http://bing.com/maps/default.aspx?cp=47.677797~-122.122013&lvl=12
When the Website preference is set to 'desktop version' the map renders correctly.
When the Website preference is set to 'mobile version' the map renders incorrectly.
Just started happening about a week ago !