I am trying to use WMTS layers in opnelayers project. This is my firt time when I try to use WMTS instead of WMS. Unfortunatelly I am stuck. I have no idea how to set up.
PLease help me to set up correct settings:
WMTS url GetCapabilities
my code (I used template from example on opnelayers.org):
import Map from 'ol/Map.js';
import OSM from 'ol/source/OSM.js';
import TileLayer from 'ol/layer/Tile.js';
import View from 'ol/View.js';
import WMTS from 'ol/source/WMTS.js';
import WMTSTileGrid from 'ol/tilegrid/WMTS.js';
import {get as getProjection} from 'ol/proj.js';
import {getTopLeft, getWidth} from 'ol/extent.js';
const projection = getProjection('EPSG:4326');
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = new Array(19);
const matrixIds = new Array(19);
for (let z = 0; z < 19; ++z) {
// generate resolutions and matrixIds arrays for this WMTS
resolutions[z] = size / Math.pow(2, z);
matrixIds[z] = z;
}
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
new TileLayer({
opacity: 0.7,
source: new WMTS({
url: 'https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution?SERVICE=WMTS&REQUEST=GetCapabilities',
layer: 'ORTOFOTOMAPA',
matrixSet: 'EPSG:2180',
format: 'image/png',
projection: projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
// style: 'default',
wrapX: true,
}),
}),
],
target: 'map',
view: new View({
center: [2008582, 6753697],
zoom: 7,
}),
});
Thanks!
If you have a custom projection there will also be a custom tile grid, so it is easier to parse the capabilities and let OpenLayers obtain the options. You will also need to define and register the EPSG:2180 projection (including the N-E axis order) using proj4.
import Map from 'ol/Map.js';
import OSM from 'ol/source/OSM.js';
import TileLayer from 'ol/layer/Tile.js';
import View, {createRotationConstraint} from 'ol/View.js';
import WMTS, {optionsFromCapabilities} from 'ol/source/WMTS.js';
import WMTSCapabilities from 'ol/format/WMTSCapabilities.js';
import proj4 from 'proj4';
import {register} from 'ol/proj/proj4';
proj4.defs(
'EPSG:2180',
'+proj=tmerc +lat_0=0 +lon_0=19 +k=0.9993 +x_0=500000 +y_0=-5300000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs +axis=neu'
);
register(proj4);
const wmtsLayer = new TileLayer({
opacity: 0.7,
});
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
wmtsLayer,
],
target: 'map',
view: new View({
center: [2008582, 6753697],
zoom: 7,
}),
});
const parser = new WMTSCapabilities();
fetch(
'https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution?SERVICE=WMTS&REQUEST=GetCapabilities'
)
.then(function (response) {
return response.text();
})
.then(function (text) {
const result = parser.read(text);
const options = optionsFromCapabilities(result, {
layer: 'ORTOFOTOMAPA',
matrixSet: 'EPSG:2180',
});
wmtsLayer.setSource(new WMTS(options));
});
https://codesandbox.io/s/wmts-layer-from-capabilities-forked-6gu26y?file=/main.js
Related
I'm facing a problem with GetFeatureInfo from WMS layer (published by my own via geoserver). After singleClick I have response no value. The WMS layers is EPSG 3857 like map view as well.
I have been trying with example from openlayer and everything works fine.
I do not have any idea what is wrong. Please find below my main.js file
import './style.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import TileWMS from 'ol/source/TileWMS';
const wmsSource1 = new TileWMS({
url: 'https://portal.solarmap.pl/geoserver/ows?service=wms',
params: {'LAYERS': 'solarmap-swidnica:VEG_IRR_FIELD_4'},
serverType: 'geoserver',
// projection: 'EPSG:3857',
crossOrigin: 'anonymous',
});
const basemap = new TileLayer({
source: new OSM(),
});
const wmsLayer1 = new TileLayer({
source: wmsSource1,
});
const view = new View({
center: [0, 0],
zoom: 1,
});
const map = new Map({
layers: [basemap, wmsLayer1],
target: 'map',
view: new View({
projection: 'EPSG:3857',
center: [1833048, 6593400],
zoom: 18,
}),
})
map.on('singleclick', function (evt) {
// document.getElementById('info').innerHTML = '';
const viewResolution = /** #type {number} */ (view.getResolution());
const url = wmsSource1.getFeatureInfoUrl(
evt.coordinate,
viewResolution,
'EPSG:3857',
{'INFO_FORMAT': 'text/html'}
);
console.log(url);
if (url) {
fetch(url)
.then((response) => response.text())
.then((html) => {
document.getElementById('info').innerHTML = html;
});
}
});
I have chekced the WMS layer by goeserver - preview. There is a possibility to view feature value, so the problem is not in WMS I hope.
Link to the WMS preview:
preview WMS
I am a relative beginner to using OpenLayers so I was playing around with some of the examples given on the OpenLayers website. When trying the image-vector-layer example, I had a problem where it would work fine with a json online, but when using a local geojson file the response under the networks section for the geojson file would be an html instead, giving the error "Unexpected token < in JSON at position 0". Attached is my javascript below, the error is occurring at the "url: data/countries.geojson". Is there any way I can use a local file instead of an online link? Thank you!
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON';
import Map from 'ol/Map';
import VectorImageLayer from 'ol/layer/VectorImage';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Fill, Stroke, Style} from 'ol/style';
const style = new Style({
fill: new Fill({
color: '#eeeeee',
}),
});
const vectorLayer = new VectorImageLayer({
background: 'lightblue',
imageRatio: 2,
source: new VectorSource({
url: 'data/countries.geojson',
format: new GeoJSON(),
}),
style: function (feature) {
const color = feature.get('COLOR') || '#eeeeee';
style.getFill().setColor(color);
return style;
},
});
const map = new Map({
layers: [vectorLayer],
target: 'map',
view: new View({
center: [0, 0],
zoom: 1,
}),
});
const featureOverlay = new VectorLayer({
source: new VectorSource(),
map: map,
style: new Style({
stroke: new Stroke({
color: 'rgba(255, 255, 255, 0.7)',
width: 2,
}),
}),
});
let highlight;
const displayFeatureInfo = function (pixel) {
const feature = map.forEachFeatureAtPixel(pixel, function (feature) {
return feature;
});
const info = document.getElementById('info');
if (feature) {
info.innerHTML = feature.get('ECO_NAME') || ' ';
} else {
info.innerHTML = ' ';
}
if (feature !== highlight) {
if (highlight) {
featureOverlay.getSource().removeFeature(highlight);
}
if (feature) {
featureOverlay.getSource().addFeature(feature);
}
highlight = feature;
}
};
map.on('pointermove', function (evt) {
if (evt.dragging) {
return;
}
const pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
map.on('click', function (evt) {
displayFeatureInfo(evt.pixel);
});
How do you make it so wherever you click on the map, the Icon added on the map just instantly teleports to those coordinates? Currently in the official Open Layers 6 'Examples' page, it shows the drag and drop example with the following example:
import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import TileJSON from 'ol/source/TileJSON';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Icon, Style} from 'ol/style';
import {Modify} from 'ol/interaction';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
const iconFeature = new Feature({
geometry: new Point([0, 0]),
name: 'Null Island',
population: 4000,
rainfall: 500,
});
const iconStyle = new Style({
image: new Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'data/icon.png',
}),
});
iconFeature.setStyle(iconStyle);
const vectorSource = new VectorSource({
features: [iconFeature],
});
const vectorLayer = new VectorLayer({
source: vectorSource,
});
const rasterLayer = new TileLayer({
source: new TileJSON({
url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json?secure=1',
crossOrigin: '',
}),
});
const target = document.getElementById('map');
const map = new Map({
layers: [rasterLayer, vectorLayer],
target: target,
view: new View({
center: [0, 0],
zoom: 3,
}),
});
const modify = new Modify({
hitDetection: vectorLayer,
source: vectorSource,
});
modify.on(['modifystart', 'modifyend'], function (evt) {
target.style.cursor = evt.type === 'modifystart' ? 'grabbing' : 'pointer';
});
const overlaySource = modify.getOverlay().getSource();
overlaySource.on(['addfeature', 'removefeature'], function (evt) {
target.style.cursor = evt.type === 'addfeature' ? 'pointer' : '';
});
map.addInteraction(modify);
Their wiki does not mention about any convenient property like Icon.setPosition. Thank you.
You add a click listener to the map and change the geometry of the feature:
map.on('click', function (event) {
iconFeature.getGeometry().setCoordinates(event.coordinate);
});
I am working on two examples provides by the community of OpenLayers here: https://openlayers.org/en/latest/examples/
Here is the first script (Geolocation):
import 'ol/ol.css';
import Feature from 'ol/Feature';
import Geolocation from 'ol/Geolocation';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import View from 'ol/View';
import {Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style';
import {OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
var view = new View({
center: [0, 0],
zoom: 2,
});
var map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}) ],
target: 'map',
view: view,
});
var geolocation = new Geolocation({
// enableHighAccuracy must be set to true to have the heading value.
trackingOptions: {
enableHighAccuracy: true,
},
projection: view.getProjection(),
});
function el(id) {
return document.getElementById(id);
}
el('track').addEventListener('change', function () {
geolocation.setTracking(this.checked);
});
// update the HTML page when the position changes.
geolocation.on('change', function () {
el('accuracy').innerText = geolocation.getAccuracy() + ' [m]';
el('altitude').innerText = geolocation.getAltitude() + ' [m]';
el('altitudeAccuracy').innerText = geolocation.getAltitudeAccuracy() + ' [m]';
el('heading').innerText = geolocation.getHeading() + ' [rad]';
el('speed').innerText = geolocation.getSpeed() + ' [m/s]';
});
// handle geolocation error.
geolocation.on('error', function (error) {
var info = document.getElementById('info');
info.innerHTML = error.message;
info.style.display = '';
});
var accuracyFeature = new Feature();
geolocation.on('change:accuracyGeometry', function () {
accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
});
var positionFeature = new Feature();
positionFeature.setStyle(
new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#3399CC',
}),
stroke: new Stroke({
color: '#fff',
width: 2,
}),
}),
})
);
geolocation.on('change:position', function () {
var coordinates = geolocation.getPosition();
positionFeature.setGeometry(coordinates ? new Point(coordinates) : null);
});
new VectorLayer({
map: map,
source: new VectorSource({
features: [accuracyFeature, positionFeature],
}),
});
and here is the second script (Draw_features):
import 'ol/ol.css';
import Draw from 'ol/interaction/Draw';
import Map from 'ol/Map';
import View from 'ol/View';
import {OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
var raster = new TileLayer({
source: new OSM(),
});
var source = new VectorSource({wrapX: false});
var vector = new VectorLayer({
source: source,
});
var map = new Map({
layers: [raster, vector],
target: 'map',
view: new View({
center: [-11000000, 4600000],
zoom: 4,
}),
});
var typeSelect = document.getElementById('type');
var draw; // global so we can remove it later
function addInteraction() {
var value = typeSelect.value;
if (value !== 'None') {
draw = new Draw({
source: source,
type: typeSelect.value,
});
map.addInteraction(draw);
}
}
/**
* Handle change event.
*/
typeSelect.onchange = function () {
map.removeInteraction(draw);
addInteraction();
};
document.getElementById('undo').addEventListener('click', function () {
draw.removeLastPoint();
});
addInteraction();
My main goal is to use both scripts to create just one map that show the user his geolocation and enable him to draw some features.
I tried writing this index.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Draw Features</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<style>
.map {
width: 800px;
height:400px;
position : relative
}
</style>
</head>
<body>
<div>
</div>
<label for="track">
track position
<input id="track" type="checkbox"/>
</label>
<p>
position accuracy : <code id="accuracy"></code>
altitude : <code id="altitude"></code>
altitude accuracy : <code id="altitudeAccuracy"></code>
heading : <code id="heading"></code>
speed : <code id="speed"></code>
</p>
<form class="form-inline">
<label for="type">Geometry type: </label>
<select class="form-control mr-2 mb-2 mt-2" id="type">
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
<option value="Circle">Circle</option>
<option value="None">None</option>
</select>
<input class="form-control mr-2 mb-2 mt-2" type="button" value="Undo" id="undo">
</form>
<div id="map" class="map"></div>
<script src="draw_features.js"></script>
<script src="geolocation.js"></script>
</body>
</html>
But all i get is two maps one bellow the other and not one map : see image below
So my questions are :
Is it possible to combine both scripts to create one map (without merging the two scripts in one file)
How to avoid re importing modules in script 2 that were already imported in script 2
I've created a map with different Layers from OpenLayers, Openstreetmap and BingMaps.
Now I want to add the function, that if there is a new search entered, the map should zoom to the entered search result on the map. At the moment, the search result is entered into the layer, but it doesn't zoom to the result. Thanks.
Here is the code from my main.js.
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import Stamen from 'ol/source/Stamen';
import VectorLayer from 'ol/layer/Vector';
import Vector from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import Style from 'ol/style/Style';
import Circle from 'ol/style/Circle';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
import Overlay from 'ol/Overlay';
import {fromLonLat, toLonLat} from 'ol/proj';
import sync from 'ol-hashed';
import OSM from 'ol/source/OSM';
import Feature from 'ol/Feature';
import {circular} from 'ol/geom/Polygon';
import Point from 'ol/geom/Point';
import Control from 'ol/control/Control';
import * as olProj from 'ol/proj';
import XYZ from 'ol/source/XYZ';
// define the map
const map = new Map({
target: 'map',
view: new View({
center: fromLonLat([16.37, 48.2]),
zoom: 13
})
});
sync(map);
//Adresssuche
const searchResultSource = new Vector();
const searchResultLayer = new VectorLayer({
source: searchResultSource
});
searchResultLayer.setStyle(new Style({
image: new Circle({
fill: new Fill({
color: 'rgba(255,255,255,0.4)'
}),
stroke: new Stroke({
color: '#3399CC',
width: 1.25
}),
radius: 15
})
}));
var element = document.getElementById('search');
element.addEventListener('keydown', listenerFunction);
function listenerFunction(event) {
console.log(event);
console.log(event.keyCode);
if (event.keyCode === 13) {
const xhr = new XMLHttpRequest;
xhr.open('GET', 'https://photon.komoot.de/api/?q=' + element.value + '&limit=3');
xhr.onload = function() {
const json = JSON.parse(xhr.responseText);
const geoJsonReader = new GeoJSON({
featureProjection: 'EPSG:3857'
});
searchResultSource.clear();
const features = geoJsonReader.readFeatures(json);
console.log(features);
searchResultSource.addFeatures(features);
};
xhr.send();
}
}
var ZoomLayer = new ol.ZoomLayer({
layer: searchResultLayer,
colName: 'SearchLayer',
zoom: 10,
collapsed: true,
map: Map
zoomTo: layer(5,xy)
});
//OpenStreetMap
const OSMbaseLayer = new TileLayer({
type: 'base',
source: new OSM()
});
// Statellit
const satellitLayer = new TileLayer({
source: new XYZ ({
attributions: ['Powered by Esri', 'Source: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community'],
attributionsCollapsible: false,
url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
maxZoom: 30
})
});
//shape
const parkLayer = new VectorLayer({
source: new Vector({
url: 'data/park1.geojson',
format: new GeoJSON()
})
});
// Layer hinzufügen
map.addLayer(OSMbaseLayer);
map.addLayer(searchResultLayer);
map.addLayer(parkLayer);
const OSMbase = document.getElementById('OSMbase');
OSMbase.addEventListener('click', function(event) {
//contr.style.color = 'ffffff';
//Andere Layer entfernen
map.removeLayer(satellitLayer);
map.removeLayer(searchResultLayer);
//OSM Layer hinzufügen
map.addLayer(OSMbaseLayer);
map.addLayer(searchResultLayer);
});
// Get the satellit Base-Button
const satellit = document.getElementById('satellit');
satellit.addEventListener('click', function(event) {
//Andere Layer entfernen
map.removeLayer(OSMbaseLayer);
map.removeLayer(searchResultLayer);
//Satelliten Layer hinzufügen
map.addLayer(satellitLayer);
map.addLayer(searchResultLayer);
});
You can fit the view to the source extent when features are added to the source
searchResultSource.on('addfeature', function() {
map.getView().fit(searchResultSource.getExtent());
});