I'm trying to get started with OpenLayers3, to get access to weather data from the UK.
Their Datapoint service has a tiling WMTS server. I'm trying to access the radar/precipitation tiles. Receiving '501 - not implemented' errors.
<div id="map" class="map"></div>
<script>
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://datapoint.metoffice.gov.uk/public/data/inspire/view/wmts',
params: {
'LAYERS': 'RADAR_UK_Composite_Highres',
'VERSION': '1.0.0',
'key': '[your-api-access-key-goes-here]'
}
})
})
],
view: new ol.View({
projection: 'EPSG:4326',
center: [0, 0],
zoom: 0
})
});
</script>
Their Capabilities doc has ServiceTypeVersion OGC WMTS = 1.0.0, so I override the OL default of 1.3.0. The layer name seems fine too.
The OpenLayers setup generates 3 calls to the server, of the form
http://datapoint.metoffice.gov.uk/public/data/inspire/view/wmts?SERVICE=WMS&VERSION=1.0.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=RADAR_UK_Composite_Highres&key=my_key_goes_here&WIDTH=256&HEIGHT=256&SRS=EPSG%3A4326&STYLES=&BBOX=-180%2C-270%2C180%2C90
Repeated here as plain text (note that my API key has been removed from the URL):
http://datapoint.metoffice.gov.uk/public/data/inspire/view/wmts?SERVICE=WMS&VERSION=1.0.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=RADAR_UK_Composite_Highres&key=my_key_goes_here&WIDTH=256&HEIGHT=256&SRS=EPSG%3A4326&STYLES=&BBOX=-180%2C-270%2C180%2C90
In the Capabilities doc, there is an
Operation name="GetTile"
But there's no GetMap. That would explain the 501 error.
But if I try to force 'gettile', it gives a 400 error - bad request.
You are confused between TileWMS and ol.source.WMTS. The former is for accessing a WMS server, the latter for a WMTS server.
Related
Using the code below, I've been unable to get my single GeoJSON point feature to appear on the map. Or possibly if it does appear on the map in the correct location. It appears in Germany, whereas it should appear in Tasmania, Australia. Same location it appears at if I provide no projection at all. Therefore it seems that there is some problem with the way I'm setting the projection.
I have a feeling that I'm using defaultDataProjection and/or featureProjection incorrectly, but I find the documentation to be fairly unclear on how these should be used.
The same projection works on my other (non-GeoJSON) layers OK.
How can I correct my code to get this to work?
var geojsonObject = {"type":"FeatureCollection","features":[{"geometry":{"type":"Point","coordinates":[503619.026899999939,5420925.347199999727]},"properties":{"label":{}},"type":"Feature"}]};
proj4.defs('layerProj', '+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ')
var vectorSource = new ol.source.Vector({
features: (new ol.format.GeoJSON({
defaultDataProjection: 'layerProj',
}).readFeatures(geojsonObject, { featureProjection: 'layerProj' }))
})
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: new ol.style.Style({image: new ol.style.Circle({fill: new ol.style.Fill({color: '#8888FF'}), radius: 10, points: 0})}),
});
map.addLayer(vectorLayer);
Your format: should be features: Also defaultDataProjection in the GeoJSON options in OpenLayers 4 changes to dataProjection in later version, so it may be better to specify dataProjection in the readFeatures options where the name is the same in all versions. featureProjection should always be set to the view projection
features: new ol.format.GeoJSON().readFeatures(geojsonObject, {
dataProjection: 'layerProj',
featureProjection: map.getView().getProjection()
})
If you are using OpenLayers 5 or above you will also need to register proj4 after the layerproj definition
ol.proj.proj4.register(proj4);
I want to load a country specific map (say https://openstreetmap.in). I'm using the following code snippet, but it loads the map from https://www.openstreetmap.org:
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
]
Can anybody please tell me how I can load a country specific map?
You need to create a custom tile layer, either a so-called OSM layer or a XYZ layer. The OpenLayer examples Localized OpenStreetMap and XYZ explain how to specify a custom tile source.
The tile server URL for openstreetmap.in is https://{a-c}.tiles.mapbox.com/v4/openstreetmap.1b68f018/{z}/{x}/{y}#2x.png?access_token=pk.eyJ1IjoiamluYWxmb2ZsaWEiLCJhIjoiY2psejFtZG8wMWhnMjNwcGFqdTNjaGF2MCJ9.ZQVAZAw8Xtg4H2YSuG4PlA.
Your code should then look roughly like this:
var osmIndia = new TileLayer({
source: new OSM({
attributions: [
'© mapbox and OpenStreetMap'
],
url: 'https://{a-c}.tiles.mapbox.com/v4/openstreetmap.1b68f018/{z}/{x}/{y}#2x.png?access_token=pk.eyJ1IjoiamluYWxmb2ZsaWEiLCJhIjoiY2psejFtZG8wMWhnMjNwcGFqdTNjaGF2MCJ9.ZQVAZAw8Xtg4H2YSuG4PlA'
})
});
[...]
layers: [
osmIndia
]
I'm trying to build a map for the game Guild Wars 2, but having trouble getting openlayers to handle the coordinate system correctly and render the map completely.
Here's a fiddle of what I have: https://jsfiddle.net/ndqb8rqx/
The Guild Wars world is square and 49152 pixels on both axes. The origin ([0, 0]) of the coordinates should be the north-west. The south-east should be [49152, 49152]. The developer of the game makes the tiles for the map available as a service: https://wiki.guildwars2.com/wiki/API:Tile_service
I created a Projection based on Zoomify to try to handle this:
var gw2Projection = new ol.proj.Projection({
code: 'ZOOMIFY',
units: 'pixels',
extent: [0, -49152, 49152, 0]
})
And I also added the game tiles as a Tilelayer from an XYZ source, like this:
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://tiles.guildwars2.com/1/1/{z}/{x}/{y}.jpg',
projection: gw2Projection
}),
}),
The first problem is that openlayers doesn't render the complete map. The map actually extends further south and east than the fiddle shows. The bottom right edge which is actually shown in the fiddle is really [32768, 32768], but the map extends out to [49152, 49152]. It seems that openlayers simply shrinks the coordinate system to the area of a single tile when zoomed completely out. Instead I would like the coordinates to match 1:1 with the pixels.
The other problem is that currently the y-coordinate increase in the northern direction. I would like to invert the y-axis, such that the y-coordinates increase in the southern direction.
#ahocevar nudged me in the right direction. The suggestion of creating a custom tilegrid was necessary but instead of setting the zoom level, it was necessary to set the actual resolutions.
So by adding a tilegrid like this:
var tilegrid = new ol.tilegrid.TileGrid({
extent: extent,
resolutions: [128, 64, 32, 16, 8, 4, 2, 1]
});
Using it in the layer source like this:
source: new ol.source.XYZ({
tileGrid: tilegrid,
url: 'https://tiles.guildwars2.com/1/1/{z}/{x}/{y}.jpg',
projection: gw2Projection
}),
And finally adding it to the view as well:
view: new ol.View({
center: ol.extent.getCenter(extent),
zoom: 1,
projection: gw2Projection,
extent:extent,
resolutions: tilegrid.getResolutions()
})
The entire map is now shown, and the coordinates are correct. The Y-axis is still negative though.
Here's a fiddle with the result, I also included the TileDebug layer for good measure: https://jsfiddle.net/kay99yor/1/
The key to making this work is a custom tile grid definition, i.e. with the correct extent and maxZoom:
var tilegrid = new ol.tilegrid.createXYZ({
extent: gw2Projection.getExtent(),
maxZoom: 7
});
Then configure the XYZ source with that tilegrid:
source: new ol.source.XYZ({
url: 'https://tiles.guildwars2.com/1/1/{z}/{x}/{y}.jpg',
projection: gw2Projection,
tileGrid: tilegrid
})
Also configure the view with the resolutions of that tilegrid:
view: new ol.View({
center: ol.extent.getCenter(gw2Projection.getExtent()),
extent: gw2Projection.getExtent(),
zoom: 1,
resolutions: tilegrid.getResolutions()
}
I have created an updated fiddle that makes your map work: https://jsfiddle.net/kay99yor/.
Our's is a JavaFx application which utilizes the browser capability of WebView to render webpages. We were able to perform upcalls from JavaScript to JavaFX and vice versa. WebConsoleListener is added to log messages or error thrown from wepage.
To show few Map functionalities like coordinate selection, distance calculation etc in JavaFX application, we created a webpage and wrote the necessary javascript required utilizing OpenLayer v4.2.0 API. Everything worked in browser ( of course after removing upcalls to JavaFx) as well as in JavaFx application.
However when the application is deployed to customer, its logging error 'Cross-origin image load denied by Cross-Origin Resource Sharing policy' and the map tiles were not loaded. Customer is located in a different geographic location (Japan) and we dont have access to their machines.
Their is a 'crossOrigin' property for 'ol.source.OSM' and as mentioned in documentation its value remains 'anonymous'. We were able to reproduce a similar kind of issue when we set its value to 'use-credentials'.
Below is the code related to map rendering. If required we can post entire code which is related to adding geometry and various event handling
(depending on user action overlays were removed or added).
<link rel="stylesheet" href="ol.css" type="text/css">
<script src="polyfill.js"></script>
<script src="ol.js"></script>
var raster = new ol.layer.Tile({
source: new ol.source.OSM(
)
});
var coordinateOverlay = new ol.layer.Vector({
source: new ol.source.Vector({
}),
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#d12b19'
})
})
})
});
var map = new ol.Map({
layers: [raster, coordinateOverlay],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 5
})
});
var features = new ol.Collection();
var distanceOverlay = new ol.layer.Vector({
source: new ol.source.Vector({ features: features }),
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255,255,255,0.3)'
}),
stroke: new ol.style.Stroke({
color: '#d12b19',
width: 4
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: 'red'
})
})
})
});
Please help if anyone know the reason for this issue.
EDIT
Client is behind proxy. [ IMHO, Looks irrelevant here, as the request is already placed.]
I am trying to add the new ESRI Vector Basemaps in OpenLayers 3. I have gotten so far as to display the layer un-styled by modifying the Mapbox Example published by OpenLayers.
Clearly I had to remove the style: createMapboxStreetsV6Style() option to get the esri layer to display. So basically the map does not know the style information to display the layer correctly.
I think it should be possible to do it because ESRI's Leaflet port and example is doing this already. I think information on esri's style IDs is available in here Leaflet code.
OpenLayers should already be able to use all this information as it is able to display Mapbox Layer. What I need help with is, how to make it use ESRI's style information.
Here's what I have so far (codepen here):
var map = new ol.Map({
layers: [
new ol.layer.VectorTile({
source: new ol.source.VectorTile({
format: new ol.format.MVT(),
tileGrid: ol.tilegrid.createXYZ({maxZoom: 22}),
tilePixelRatio: 16,
url: 'https://basemaps.arcgis.com/v1/arcgis/rest/services/World_Basemap/VectorTileServer/tile/{z}/{y}/{x}.pbf'
})
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
.map {
background: #f8f4f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.1.0/ol.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.1.0/ol.css" rel="stylesheet"/>
<div id="map" class="map"></div>
There is a separate library, https://npmjs.com/package/ol-mapbox-style, which makes it easy to consume vector tile maps including their styles in OpenLayers. It reads the style doc and builds the whole map from it. For one of the ESRI maps you linked above, the code to get that map in OpenLayers would be
var map = new ol.Map({
target: 'map'
});
olms.apply(map, 'https://www.arcgis.com/sharing/rest/content/items/4f4843d99c34436f82920932317893ae/resources/styles/root.json?f=json');
You can replace 4f4843d99c34436f82920932317893ae with one of the other map ids listed in the Leaflet example to get the other maps.
You can also play with that code - I have created a CodePen: https://codepen.io/ahocevar/pen/xLaBVV.
#ahocevar's suggest is perfect,
esri's root.json, sprite and glyphs are not full URL, the are only last part as see below
In your example, those not full URL works, but, I have test it in mapbox js api, it failed, error is can't parse URL,
I have to change those url to a full URL, to make it works.
root_json = {
"version" : 8,
"name": "test",
//"sprite" : original_rootJson.sprite, // original is not a full URL, not work "../sprites/sprite"
// "sprite" : "https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/2020_USA_Median_Age/VectorTileServer/resources/sprites/sprite",
"sprite" : _sprite,
// "glyphs" : original_rootJson.glyphs, // original is not a full URL, not work "../fonts/{fontstack}/{range}.pbf"
// "glyphs" : "https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/2020_USA_Median_Age/VectorTileServer/resources/fonts/{fontstack}/{range}.pbf",
"glyphs" : _glyphs,
// root json specification : https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/
"sources" : {
"esri" : {
"type" : "vector",
// By supplying TileJSON properties such as "tiles", "minzoom", and "maxzoom" directly in the source:
"tiles": [
// "https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/2020_USA_Median_Age/VectorTileServer/tile/{z}/{y}/{x}.pbf"
_tile_pbf
],
// "maxzoom": 14
// By providing a "url" to a TileJSON resource
// not work,yet
// "url" : "https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/Esri_Childrens_Map/VectorTileServer/tile/{z}/{y}/{x}.pbf"
// "url": "http://api.example.com/tilejson.json"
}
},
"layers": original_rootJson.layers
} // root_json