Openlayers - select only one feature and disable the rest - javascript

I have a WFS layer:
var sourceVector = new ol.source.Vector({
format: new ol.format.GeoJSON(),
url: function(extent) {
return 'http://myserver:8080/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=mygroup:mylayer&' +
'outputFormat=application/json&srsname=EPSG:4326&';
},
});
var layerVector = new ol.layer.Vector({
source: sourceVector
});
I have a interaction select for the features:
var interactionSelect = new ol.interaction.Select({
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#EAEA1A'
})
})
});
And, programmatically I selected one feature:
var listenerKey = sourceVector.on('change', function(e) {
if (sourceVector.getState() == 'ready') {
interactionSelect.getFeatures().clear()
interactionSelect.getFeatures().push(sourceVector.getFeatureById('mylayer.1853'))
map.addInteraction(interactionSelect);
}
});
How can I leave that feature already selected and disable the other features from the same wfs layer? I did this way so far because there's only one feature selected at the beginning, but also I want to let the user modify that feature, but it has to be that particular feature; with this code above, the user gets the feature selected in red but he can select other features
How can I do this?

If you just want to modify a subset of the features of a source, what you can do is set features property instead of source of the modify interaction. In that way you control which are the features that can be modified.
Take a look at the example I made for you. It uses the countries.geojson source of OL. I pick Uruguay as the only feature that can be modified.
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.3.1/css/ol.css"
type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.3.1/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var modifyFeatures = new ol.Collection();
var source = new ol.source.Vector({
url: 'https://openlayers.org/en/latest/examples/data/geojson/countries.geojson',
format: new ol.format.GeoJSON(),
wrapX: false
});
source.on('change', function(e) {
if (source.getState() === 'ready') {
var feature = source.getFeatures().find(f => f.get('name') === 'Uruguay');
modifyFeatures.push(feature);
}
});
var vector = new ol.layer.Vector({
source
});
var select = new ol.interaction.Select({
wrapX: false
});
var modify = new ol.interaction.Modify({
features: modifyFeatures
});
var map = new ol.Map({
interactions: ol.interaction.defaults().extend([select, modify]),
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([-55.75, -32.85]),
zoom: 6
})
});
</script>
</body>
</html>

Related

Build custom library based on OpenLayers

I'm trying to build my personal gis library using OpenLayers; it is the first time that I do this.
Usually I build a simple map using this code:
var map = new ol.Map({
target: 'map'
});
var view = new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
});
map.setView(view);
var osm = new ol.layer.Tile({
source: new ol.source.OSM()
});
map.addLayer(osm);
Now I've created a static file called gislibraries.js and here I initialize my map:
function MapInizialized(mapTarget) {
const map = new ol.Map({
target: mapTarget
});
return map;
};
function MapSetView(longitude, latitude, zoomLevel) {
const view = new ol.View({
center: ol.proj.fromLonLat([longitude, latitude]),
zoom: zoomLevel
});
map.setView(view);
return view;
};
function MapTile() {
const osm = new ol.layer.Tile({
source: new ol.source.OSM()
});
map.addLayer(osm);
return osm;
};
Using the code below inside index.html I can see my map.
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Base Map | GeoDjango</title>
<link rel="stylesheet" href="/static/css/map.css">
<script src="/static/js/mapscripts.js" type="text/javascript"></script>
<!-- OpenLayers 6 -->
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.3.1/css/ol.css"
type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.3.1/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
var map = new MapInizialized('map');
MapSetView(0.0, 0.0, 2);
MapTile();
</script>
</body>
</html>
When I use:
MapInizialized('map');
MapSetView(0.0, 0.0, 2);
MapTile();
My map doesn't work and I can see this error:
Uncaught TypeError: map.setView is not a function
MapSetView http://127.0.0.1:8000/static/js/mapscripts.js:17
http://127.0.0.1:8000/:51
Why I can't invoke MapInizialized('map');?
For map to be available to all the function it must be declared outside the functions
let map;
function MapInizialized(mapTarget) {
map = new ol.Map({
target: mapTarget
});
return map;
};

change openlayers map color (dark and light style)

I like to use openlayers map with dark and light styles. so how can I change map color or map style?
My friend(Dear morteza) found a simple way that I answered in this post.
my html file is:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.1.1/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 50%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.1.1/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<h2>My Map</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
// function applies greyscale to every pixel in canvas
</script>
</body>
</html>
openlayes shows maps in <canvas>. and <canvas> will be add to <div> container with openlayers library. So add bellow codes to add map and change it's color:
var map = new ol.Map({
target: 'map',//div with map id
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([61.2135, 28.2331]),
zoom: 13
})
});
//change map color
map.on('postcompose',function(e){
document.querySelector('canvas').style.filter="invert(90%)";
});
you can also test other filters
The ol-ext library lets you set filters on openlayers layers. It uses canvas composite operations to achieve the effects.
See code sample online: https://viglino.github.io/ol-ext/examples/filter/map.filter.colorize.html
const tile = new TileLayer({
source: new OSM()
});
tile.on('prerender', (evt) => {
// return
if (evt.context) {
const context = evt.context as CanvasRenderingContext2D;
context.filter = 'grayscale(80%) invert(100%) ';
context.globalCompositeOperation = 'source-over';
}
});
tile.on('postrender', (evt) => {
if (evt.context) {
const context = evt.context as CanvasRenderingContext2D;
context.filter = 'none';
}
});
Before the tile layer rendered set the canvas filter and reset back to none after the rendering, by doing this, the following layers will not be affected in any way, Here is the effect:

Openlayers 3 Coords

I'm newbee of OL. I need just to put some point on the map and ideally make some request for writting info about this point to db, but now i just want to alert(coords) of point. So, i found an example, where i can put some point, line and polygone to the map.
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [raster],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var features = new ol.Collection();
var featureOverlay = 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.2)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#ffcc33'
})
})
})
});
featureOverlay.setMap(map);
var modify = new ol.interaction.Modify({
features: features,
// the SHIFT key must be pressed to delete vertices, so
// that new vertices can be drawn at the same position
// of existing vertices
deleteCondition: function(event) {
//var feature = event.element;
//var coord = event.feature.getGeometry().getCoordinates();
//coord = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
// alert(coord);
return ol.events.condition.shiftKeyOnly(event) &&
ol.events.condition.singleClick(event);
}
});
map.addInteraction(modify);
var draw; // global so we can remove it later
var typeSelect = document.getElementById('type');
function addInteraction() {
draw = new ol.interaction.Draw({
features: features,
type: /** #type {ol.geom.GeometryType} */ (typeSelect.value)
/*draw.on('drawend', function (event) {
// get the feature
var feature = event.element;
var coord = event.feature.getGeometry().getCoordinates();
alert(coord);*/
});
map.addInteraction(draw);
}
/**
* Handle change event.
*/
typeSelect.onchange = function() {
map.removeInteraction(draw);
addInteraction();
};
addInteraction();
// Code of adding to DB our features
//
<?php
/* #var $this yii\web\View */
use yii\helpers\Html;
use sibilino\yii2\openlayers\ol;
use sibilino\yii2\openlayers\OpenLayers;
?>
<!DOCTYPE html>
<html>
<head>
<title>Draw and Modify Features</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.18.2/css/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="http://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="http://openlayers.org/en/v3.18.2/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<form class="form-inline">
<label>Geometry type </label>
<select id="type">
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
</select>
</form>
<script>
</script>
</body>
</html>
It works normally with all libs, and I can put points, lines and polygones to the map, but I can't get coord of the points, which I put. I tried to create some listener, it's commented in this code, looks like
//var feature = event.element;
//var coord = event.feature.getGeometry().getCoordinates();
//coord = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
// alert(coord);
But this method as I understood listens mouse moving too, and I'm getting some errors like:
Uncaught TypeError: Cannot read property 'getGeometry' of undefined
If somebody have time to read this long question, what can I do, and how to do right for getting my coords and saving this to DB?
I just needed to redact this code:
function addInteraction() {
draw = new ol.interaction.Draw({
features: features,
type: /** #type {ol.geom.GeometryType} */ (typeSelect.value)
/*draw.on('drawend', function (event) {
// get the feature
var feature = event.element;
var coord = event.feature.getGeometry().getCoordinates();
alert(coord);*/
});
map.addInteraction(draw);
}
To:
function addInteraction() {
draw = new ol.interaction.Draw({
features: features,
type: /** #type {ol.geom.GeometryType} */ (typeSelect.value)
});
// Code of adding to DB our features
draw.on('drawend', function (event) {
var feature = event.element;
var coord = event.feature.getGeometry().getCoordinates();
alert(coord);
var title=document.getElementById('type');
var url = "http://localhost/basic/web/index.php?r=sggis/create&title="+title.value+"&point="+coord;
function lol(){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.send();
}
lol();
});
And in yii2 Controller i have written an action which just gets title and coords just from the request. It's unsafe, but then I'll redact this one.
At all, every point, line or poly which i put on the map saves their coords to postgresSQL's DataBase.

Put a simple point at OpenStreetMap-tile using OpenLayers

I've read in many threads trying to put a simple point (vector layer) at my OpenStreetMap. I'm guessing it is som kind of problem with different projections but i canĀ“t figure it out by myself.
What am i doing wrong in the code below?
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://openlayers.org/en/v3.13.1/build/ol.js" type="text/javascript"></script>
<title>Openstret</title>
</head>
<body>
<div id="map">
<script type="text/javascript">
var vectorSource = new ol.source.Vector();
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point([0, 0])
});
vectorSource.addFeature(iconFeature);
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
var olmap = new ol.Map({
view: new ol.View({
center: [0, 0],
zoom: 2
}),
target: 'map'
});
var bakgrund = new ol.layer.Tile({source: new ol.source.OSM()});
olmap.addLayer(bakgrund,vectorLayer);
</script>
</div>
</body>
</html>
ol.Map.addLayer only takes one parameter. You'll have to add the two layers separately.
Change
olmap.addLayer(bakgrund,vectorLayer);
to
olmap.addLayer(bakgrund);
olmap.addLayer(vectorLayer);
You're also not including the ol.css file anywhere. Make sure you add that in. Here's a working JSFiddle.

Multiple info boxes showing up when I click on map (GeoServer layers)

I have created a map using layers I added in GeoServer.
I created GetFeatureInfoUrl function to get the attribute table when clicking on layer.
But when I click on the map, all the info boxes of all the layers show up. Even if a layer (which is on top of another layer) is turned off, its attribute information comes up.
How can I make it so that only one info box shows up at a time? (So if two layers are on top of each other and user click on the map, the attribute information of the layer which is on top of the other will show up.)
One user online explained me how to do it but did not provide code. He offered the following explanation:
loop over the layers list
call get("visible") on each layer to get the visibility status set by the layer switcher
for each visible layer, append its name to a list of visible layer names
join the list of visible layer names into a single string containing comma-separated layer names
pass the string of comma-separated visible layer names as an additional parameter QUERY_LAYERS in the map in the last argument of testSource.getGetFeatureInfoUrl"
How can I create this code?
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Map</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.12.1/css/ol.css">
<link rel="stylesheet" href="ol3-layerswitcher.css">
<script src="http://openlayers.org/en/v3.12.1/build/ol.js"></script>
<script src="ol3-layerswitcher.js"></script>
</head>
<body>
<div id="map" style="width:100%;"></div>
<script src="javascript4.js"></script>
<div id="info2"></div>
<div id="info3"></div>
</body>
</html>
JavaScript:
var testSource2 = new ol.source.TileWMS({
url: 'http://localhost:8080/geoserver/wms',
params: {'LAYERS': 'Marine:Great_Britain', 'TILED': true},
serverType: 'geoserver'
});
var testSource3 = new ol.source.TileWMS({
url: 'http://localhost:8080/geoserver/wms',
params: {'LAYERS': 'Marine:Bedrock_Geology', 'TILED': true},
serverType: 'geoserver'
});
var layers = [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'osm'})
}),
new ol.layer.Group({
title: 'Layers',
layers: [
//Implementing layers
new ol.layer.Tile({
title: 'Great Britain',
source: testSource2
}),
new ol.layer.Tile({
title: 'Geology - Bedrock',
source: testSource3
}),
]
})
];
var map = new ol.Map({
layers: layers,
target: 'map',
view: new ol.View({
center: [51480.6, 7216744.2], //UK
zoom: 5
})
});
//Function to get features from layer
map.on('singleclick', function(evt) {
document.getElementById('info2').innerHTML = '';
viewResolution = map.getView().getResolution();
var url = testSource2.getGetFeatureInfoUrl(
evt.coordinate, viewResolution, 'EPSG:3857',
{'INFO_FORMAT': 'text/html'});
if (url) {
document.getElementById('info2').innerHTML =
'<iframe seamless src="' + url + '"></iframe>';
}
});
//Function to get features from layer
map.on('singleclick', function(evt) {
document.getElementById('info3').innerHTML = '';
viewResolution = map.getView().getResolution();
var url = testSource3.getGetFeatureInfoUrl(
evt.coordinate, viewResolution, 'EPSG:3857',
{'INFO_FORMAT': 'text/html'});
if (url) {
document.getElementById('info3').innerHTML =
'<iframe seamless src="' + url + '"></iframe>';
}
});
//Layer switcher to turn layers on and off
var layerSwitcher = new ol.control.LayerSwitcher({
tipLabel: 'Legend'
});
map.addControl(layerSwitcher);
I believe the issue lies that you do not check in your map.on('singleclick') for what layer is being clicked on. Create a single map.on('singleclick') handler, since your code in both listeners are exactly the same.
map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
var source = layer.getSource();
...
});
Now you will get the source for the layer that you have clicked on and be able to use that with your mentioned code.

Categories