I am trying to make an Icon feature that I can click on easier on mobile phones. I have an icon set up nicely and when using a mouse to click on it there is no issue. However when using my finger or thumb on a mobile phone it is quite difficult to get an accurate click. I am using a ol.geom.Point and giving it an icon style. I tried an ol.geom.Circle but I can't get the icon style to work with it.
Here is an example of my working ol.geom.Point:
for (i in spots) {
var spot = spots[i];
var coords = spot['coords'];
var lat = parseFloat(coords.split(',')[0]);
var lng = parseFloat(coords.split(',')[1]);
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([lng, lat])),
type: 'spot'
});
iconFeature.setStyle(spotMarker);
features.push(iconFeature);
}
vectorSourceSpots = new ol.source.Vector({
features: features
});
var vectorLayer = new ol.layer.Vector({
source: vectorSourceSpots
});
map.addLayer(vectorLayer);
Here is the spotMarker style:
var spotMarker = new ol.style.Style({
image: new ol.style.Icon(({
src: 'images/spot.png'
}))
});
I've also tried with a ol.geom.Circle but I could not see my icon when I tried this:
for (i in spots) {
var spot = spots[i];
var coords = spot['coords'];
var lat = parseFloat(coords.split(',')[0]);
var lng = parseFloat(coords.split(',')[1]);
var iconFeature = new ol.Feature({
geometry: new ol.geom.Circle(ol.proj.fromLonLat([lng, lat]), 5),
type: 'spot'
});
iconFeature.setStyle(spotMarker);
features.push(iconFeature);
}
vectorSourceSpots = new ol.source.Vector({
features: features
});
var vectorLayer = new ol.layer.Vector({
source: vectorSourceSpots
});
map.addLayer(vectorLayer);
What I want is to have the icon remain the same size, but just to increase the click radius around the icon. Almost like an invisible circle a bit bigger than the icon with the same center.
Is this possible?
You will use forEachFeatureAtPixel to add event on the features, then you can set hitTolerance on its options parameter.
check this api document: forEachFeatureAtPixel
you may need to write:
var addEvent = function(map, evt) {
map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
}, {
hitTolerance: 10
});
};
map.on('click', function(evt) {
addEvent(map, evt);
});
Related
I am trying to draw linestring by holding the GeoJSON object. But when drawing process starts, the pointer can be selected everywhere on the map. My purpose is the pointer just be selected on the GeoJSON object
Here is some of the code.
var jsonSource = new ol.source.Vector({
url: 'https://raw.githubusercontent.com/Kardelennkayaa/ankr_tdelay/main/KAMAN.json',
format: new ol.format.GeoJSON(),
});
var vector = new ol.layer.Vector({
source: jsonSource,
background: 'white',
});
map.addLayer(vector)
var jsonSource_ank = new ol.source.Vector({
url: 'https://raw.githubusercontent.com/Kardelennkayaa/heroku_app/main/ankara_road.json',
format: new ol.format.GeoJSON(),
});
var vector_ank = new ol.layer.Vector({
source: jsonSource_ank,
background: 'white',
});
map.addLayer(vector_ank)
var draw_lineString = new ol.interaction.Draw({
type : 'LineString',
//source:drawSource_ls
source:jsonSource
})
draw_lineString.on('drawstart', function(evt){
drawSource_ls.clear()
//select.setActive(true);
})
draw_lineString.on('drawend',function(evt){
// alert('point is added')
clickedCoord_lineString = evt.feature.getGeometry().getCoordinates()
$('#ls_adding').modal('show');
console.log('clicked at', evt.feature.getGeometry().getCoordinates())
map.removeInteraction(draw_lineString)
})
function startDrawing_lineString(){
map.addInteraction(draw_lineString)
}
And here is the web interface
The goal is when clicking on the Add LineString, the polyline can be drawn with the relative GeoJSON object. How can I do that? Thanks in advance.
I am using the Openlayers extent interaction to allow the user to select an AOI. After the user does this and removes the drawn extent I would like the blue dot to also disappear. Currently it just hangs out on the map and then pops back to the mouse once the interactions key is pressed again.
This behavior can be seen in the Openlayers Extent Interaction example here. Shift+drag starts the extent interaction. Shift+click removes the extent but the blue dot is left there. Is there a way to remove this ?? Once the extent is removed there is no other interaction possible with the blue dot, so what is the purpose of it even being there ??
If you check out the API docs for ol.interaction.Extent
You can pass a style to pointerStyle to update the style of the dot.
var extent = new ol.interaction.Extent({
condition: ol.events.condition.platformModifierKeyOnly,
pointerStyle: [] // <-- Makes the dot invisible
});
var vectorSource = new ol.source.Vector({
url: 'https://openlayers.org/en/v3.20.1/examples/data/geojson/countries.geojson',
format: new ol.format.GeoJSON()
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: vectorSource
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
var extent = new ol.interaction.Extent({
condition: ol.events.condition.platformModifierKeyOnly,
pointerStyle: []
});
map.addInteraction(extent);
extent.setActive(false);
//Enable interaction by holding shift
this.addEventListener('keydown', function(event) {
if (event.keyCode == 16) {
extent.setActive(true);
}
});
this.addEventListener('keyup', function(event) {
if (event.keyCode == 16) {
extent.setActive(false);
}
});
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet" />
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<div id="map" class="map"></div>
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.
currently i have a vector map displayed using a KML file as the vector source.
what i want to do is have an image underlay this vector map.
The map is an indoor floormap, the image is the exact same as the vector map only there is more details in it, text written on it etc. What i need is for the map image to underlay the vector map so that the walls of the vector map align perfectly with the walls of the image. This can happen because the KML was created by tracing on top of the images using QGIS.
so far ive been able to have the KML vector map and png image appear on the map, but they are not alligned with each other and are not the same size. This is what i need help with!
here some code for what i currently have:
create the map, no layers yet (maps selected from dropdown boxes)
var map = new ol.Map({
layers: [],
target: 'floormap',
interactions: ol.interaction.defaults({mouseWheelZoom:false}),
view: new ol.View({
center: [0, 0],
zoom: 19,
minZoom: 15,
maxZoom: 30
})
});
add selected map (KML) to map
map.removeLayer(vector);
vector = new ol.layer.Vector({
source: new ol.source.Vector({
url: MAPS_URL + maps[map_id],
format: new ol.format.KML()
})
});
map.addLayer(vector);
setMapExtent(vector);
now i tried to add the image, which works but its not alligned
// this part here i feel may be the problem,
// i just copied and pasted from an example om openlayers.org,
// i dont actually know much about the extent and how to match it to
// the vector map
var extent = [0,0,1024,684];
var projection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: extent
});
image = new ol.layer.Image({
source: new ol.source.ImageStatic({
attributions: [
new ol.Attribution({
html: '© xkcd'
})
],
url: MAPS_URL + images[map_id],
projection: projection,
imageExtent: extent
})
});
map.addLayer(image);
the setMapExtent method
function setMapExtent(vectorMap) {
var vectorSource = vectorMap.getSource();
var listenerKey = vectorSource.on('change', function () {
if (vectorSource.getState() === 'ready') {
var extent = vectorSource.getExtent();
map.getView().fitExtent(extent, map.getSize());
vectorSource.unByKey(listenerKey);
}
});
}
at this point i have a vector map with an image sitting way above the map, and the image seems to be smaller too.
Can anyone help me with this issue?
*** Solution! ***
a working solution, although probably not the best way to do it, but it works none the less.
var map = new ol.Map({
layers: [],
target: 'floormap',
interactions: ol.interaction.defaults({mouseWheelZoom:false}),
view: new ol.View({
center: [0, 0],
zoom: 19,
minZoom: 15,
maxZoom: 30
})
});
add new map layer
map.removeLayer(vector);
vector = new ol.layer.Vector({
source: new ol.source.Vector({
url: MAPS_URL + maps[map_id],
format: new ol.format.KML()
})
});
map.addLayer(vector);
setMapExtent(vector);
// call image adding function pass in vector
// to get its extend
addImage(vector);
the addImage function
function addImage(vectorMap) {
var vectorSource = vectorMap.getSource();
// listen for one change on the vector to get the extent of it
// for use in setting the image extent. tried to use on.('load')
// but it didnt work
var listenerKey = vectorSource.once('change', function () {
var extent = vectorSource.getExtent();
var projection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: extent
});
image = new ol.layer.Image({
source: new ol.source.ImageStatic({
attributions: [],
url: MAPS_URL + images[map_id],
projection: projection,
imageExtent: extent
})
});
// remove vector layer else they keep stacking up
map.removeLayer(vector);
// add image
map.addLayer(image);
// re-add vector only push so it goes above the image
map.getLayers().push(vector);
});
}
seems to work pretty well! can anyone help me with layer ordering?
Your static image must be georeferenced correctly with the view's projection.
Default view's projection is EPSG:3857 (Spherical Mercator)., the extent of this projection is [-20026376.39, -20048966.10, 20026376.39, 20048966.10]
In your code you specify a projection in pixels for your static layer. You need to use the view's projection, something like this :
// Here the extent of your layer in EPSG:3857 -> [minx, miy, max, mayy]
var extent = [-10000000, -10000000, 10000000, 10000000];
image = new ol.layer.Image({
source: new ol.source.ImageStatic({
attributions: [
new ol.Attribution({
html: '© xkcd'
})
],
url: MAPS_URL + images[map_id],
imageSize: [1024, 684], // Don't forget the image size here
imageExtent: extent
})
});
map.addLayer(image);
Update:
For layer ordering if you want your vector layer on top use push:
http://openlayers.org/en/v3.8.2/apidoc/ol.Collection.html#push
map.getLayers().push(vector)
I am using Openlayers map. I want a feature when a user clicks on the map the marker should be created but at the same time the existing marker which is already on the map should be deleted or removed and only the latest one should be visible.
var markers = new OpenLayers.Layer.Markers( "Markers" );
markers.id = "Markers";
me.OpenLayers.addLayer(markers);
/*myMarker = new OpenLayers.Marker(new OpenLayers.Marker( 56.512438257836,27.335700987698 ));
markers.addMarker(myMarker);*/
var size = new OpenLayers.Size(30,30);
var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png',size,offset);
//map.setCenter (lonLat, zoom);
me.OpenLayers.events.register("click", kijs_map_container, function(evt) {
var lonlat = me.OpenLayers.getLonLatFromViewPortPx(evt.xy).transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
$("#edit-field-jena-seta-map-openlayers-wkt").val('GEOMETRYCOLLECTION(POINT('+lonlat.lat+' '+lonlat.lon+'))');
var pos = me.OpenLayers.getLonLatFromPixel(evt.xy);
alert(baltic_long);
var marker = new OpenLayers.Marker(new OpenLayers.LonLat(baltic_lat, baltic_long),icon);
markers.addMarker(marker);
marker.events.register("click", marker, function(e){
});
//updateMaker(myMarker, pos);
});
Remove all markers on layer before creating and adding new one:
markers.clearMarkers();
markers.addMarker(marker);
See clearMarkers for more details.
Probably when you place var marker and initialize icon outside of the me.OpenLayers.events.register(); scope it will possibly be reinitiated the moment you click again for a new marker.
var marker;
icon = new OpenLayers.Icon( ... );
me.OpenLayers.events.register("click", kijs_map_container, function(evt) {
var pos = me.OpenLayers.getLonLatFromPixel(evt.xy);
marker = new OpenLayers.Marker(pos, icon);
markers.addMarker(marker);
});
At least I haven't tested this particular example here, but was my experience with a map editor I'm making.