When I draw a polygon in an OpenLayers map, I want to know if the marker is inside the polygon or not. I searched in the OpenLayers API, but didn't find a solution.
And you can see my full code in this link.
I have the impression that I have to modify this function:
function addInteraction() {
var value = typeSelect.value;
if (value !== 'None') {
draw = new ol.interaction.Draw({
source: vectorSource,
type: /** #type {ol.geom.GeometryType} */ (typeSelect.value)
});
map.addInteraction(draw);
draw.on('drawend',function(e){
//Here
});
}
}
How can I do this?
You have a method 'intersectsCoordinate' for the ol.geom.Geometry.
So the code for that will look like:
var polygonGeometry = e.feature.getGeometry();
var coords = iconFeature.getGeometry().getCoordinates();
polygonGeometry.intersectsCoordinate(coords)
You can use the JSTS library, which implements simple geometry processing such as intersects, difference, etc. It contains an OL3 parser that allows the conversion of geometry from OL3 to JSTS and vice-versa.
See an example in OL3. Basically, you would use a process that checks if the geometry of your marker is within your polygon or not and do what you want from there.
Related
I got the Google Map and Drawing Tools displayed on the map. I can draw the shapes (circle, polygon, rectangle ...) on the map. For the start I am using the example code from Google Maps JavaScript get started page: https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/examples/drawing-tools
I was able to find a lot of examples on have to draw/make a shape object by providing all the properties and LatLng.
How do I get a LatLng for the shape that I just draw by using one of the drawing tools form Drawing Tools toolbar?
I am planing to make an application which will allow user to draw shapes on the map and save the LatLng in to database (i will be using MySql), so later the shape can be displayed again on the map as per request.
Please help.
There are a few ways to get the coordinates of the shapes you draw on the map. Specifically for polygons you can add an event listener to the map like so. The easiest way is to add an event listener to the map for when a polygon is finished drawing.
google.maps.event.addListener(drawingManager, 'polygoncomplete', function(polygon) {
const coords = polygon.getPath().getArray().map(coord => {
return {
lat: coord.lat(),
lng: coord.lng()
}
});
console.log(JSON.stringify(coords, null, 1));
// SAVE COORDINATES HERE
});
Each type of drawing has a different format for saving so for something like circles you'd do
google.maps.event.addListener(drawingManager, 'circlecomplete', function(circle) {
const radius = circle.getRadius();
// Save circle here
});
You also have the option of adding an event to listen for all of the events by listening to the overlaycomplete event but in that case you'd have to handle the different types inside the event.
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event) {
if (event.type == 'circle') {
// Handle Circle using event.overlay
}
if (event.type == 'polygon') {
// Handle Polygon using event.overlay
}
});
Here's an example:
https://jsfiddle.net/juop8q3n/1/
And here's my sources:
https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/drawinglayer#drawing_events
https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/reference#drawing-on-the-map
EDIT
Another way I've seen people save the data is by adding an event listener to the map to get the GeoJSON data, which is a standard format for saving drawing data.
Link: http://jsfiddle.net/y89rbfLo/
I'm a learner of JavaScript and have a problem with Mapbox GL JS: I have a style in Mapbox Studio, where there is one my layer — "locations". I've added it as a tileset. There are two GeoJSON-points in this layer, but I can't get them in GL JS.
I've found that I should use method querySourceFeatures(sourceID, [parameters]), but I have problems with correct filling its parameters. I wrote:
var allFeatures = map.querySourceFeatures('_id-of-my-tyleset_', {
'sourceLayer': 'locations'
});
..and it doesn't work.
More interesting, that later in the code I use this layer with method queryRenderedFeatures, and it's okay:
map.on('click', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['locations']
});
if (!features.length) {
return;
}
var feature = features[0];
flyToPoint(feature);
var popup = new mapboxgl.Popup({
offset: [0, -15]
})
.setLngLat(feature.geometry.coordinates)
.setHTML('<h3>' + feature.properties.name + '</h3>' + '<p>' +
feature.properties.description + '</p>')
.addTo(map);
});
I have read a lot about adding layers on a map and know that the answer is easy, but I can't realise the solution, so help, please :)
Here is the project on GitHub.
Your problem is that your map, like all maps created in Mapbox Studio by default, uses auto-compositing. You don't actually have a source called morganvolter.cj77n1jkq1ale33jw0g9haxc0-2haga, you have a source called composite with many sub layers.
You can find the list of layers like this:
map.getSource('composite').vectorLayerIds
Which reveals you have a vector layer called akkerman. ("locations" is the name of your style layer, not your source layer). Hence your query should be:
map.querySourceFeatures('composite', {
'sourceLayer': 'akkerman'
});
Which returns 4 features.
There are lots of questions about Mapbox get features after filter or Mapbox get features before filter. And I could see there are many posts are scattering around but none of them seem to have a FULL DETAILED solution. I spend some time and put both solution together under a function, try this in jsbin.
Here it is for someone interested:
function buildRenderedFeatures(map) {
// get source from a layer, `mapLayerId` == your layer id in Mapbox Studio
var compositeSource = map.getLayer(mapLayerId.toString()).source;
//console.log(map.getSource(compositeSource).vectorLayers);
var compositeVectorLayerLength = map.getSource(compositeSource).vectorLayers.length - 1;
//console.log(compositeVectorLayerLength);
// sourceId === tileset id which is known as vector layer id
var sourceId = map.getSource(compositeSource).vectorLayers[compositeVectorLayerLength].id;
//console.log(sourceId);
// get all applied filters if any, this will return an array
var appliedFilters = map.getFilter(mapLayerId.toString());
//console.log(appliedFilters);
// if you want to get all features with/without any filters
// remember if no filters applied it will show all features
// so having `filter` does not harm at all
//resultFeatures = map.querySourceFeatures(compositeSource, {sourceLayer: sourceId, filter: appliedFilters});
var resultFeatures = null;
// this fixes issues: queryRenderedFeatures getting previous features
// a timeout helps to get the updated features after filter is applied
// Mapbox documentation doesn't talk about this!
setTimeout(function() {
resultFeatures = map.queryRenderedFeatures({layers: [mapLayerId.toString()]});
//console.log(resultFeatures);
}, 500);
}
Then you call that function like: buildRenderedFeatures(map) passing the map object which you already have when you created the Mapbox map.
You will then have resultFeatures will return an object which can be iterated using for...in. You can test the querySourceFeatures() code which I commented out but left for if anyone needs it.
Recently I asked about referencing the data of an existing GeoJSON Leaflet object. My Leaflet map consists of data coming in a stream to my GeoJSON Leaflet object. User inputs can change a filter for the GeoJSON data, so to make the filter apply to both the existing and new data I am keeping track of my data in an array called myFeatures. Whenever the filters change or an item in myFeatures changes, I do the following:
myGeoJson.clearLayers();
myGeoJson.addData(myFeatures);
This is working to make my map update according to the newly updated feature data or the changes in the filter.
I am applying pop-ups to the GeoJSON object when I initialize my GeoJSON object:
var myGeoJson = L.geoJson(myFeatures, {
style: function(feature) {
...
},
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);
},
filter: function(feature, layer) {
...
},
onEachFeature: function(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
});
When I click on an individual feature, the pop-up appears. However, the pop-up dismisses pretty quickly, thanks to clearLayers and addData being called. :(
Is there some kind of way to stop the pop-up dismissing in this situation?
Or - better question - is there a way to modifying existing data in a GeoJSON object or remove some (not all) data from a GeoJSON object?
To provide some context, my GeoJSON shows circle markers for each feature. The circle markers are colored based on a property of the feature. The property can actually change over time, so the marker's styling needs to be updated. A marker also times out after a while and needs to be removed from the map, but the other markers need to stay on the map.
There are for sure better ways to do that, but if you don't want to modify your code architecture too much, you could just create your popups in a specific layer, which you won't clear when you add your new data.
To give you an idea (markers play below the role of myGeoJson in your example):
var popup_id = {};
var popup_layer = new L.layerGroup();
var markers = new L.layerGroup();
$.each(testData, function(index, p) {
var marker = L.marker(L.latLng(p.lat, p.lon));
markers.addLayer(marker);
popup = new L.popup({offset: new L.Point(0, -30)});
popup.setLatLng(L.latLng(p.lat, p.lon));
popup.setContent(p.text);
popup_id[p.id] = popup;
marker.on('click', function() {
popup_id[p.id].openPopup();
popup_layer.addLayer(popup_id[p.id]);
markers.clearLayers();
})
});
popup_layer.addTo(map);
markers.addTo(map);
You also keep track of all your popups in a dictionary popup_id.
Since you haven't provided us with a JSfiddle it is a bit difficult to find the perfect answer for your case, but I hope that the popup layer (also here in my fiddle) gives you a good direction.
I have a geojson feature I've created. After editing, I know there is a draw:edited event. How do I get the original points that the polygon consisted of, and is it possible to get the new polygon points? How? Is it possible to know which vertices were changed or added?
I tried the following, all of which does not work:
map.on('draw:edited', function (e) {
var type = e.layerType;
var layer = e.layer; // this is giving undefined errors
var shape = layer.toGeoJSON() // this is undefined
var shape_for_db = JSON.stringify(shape);
});
The draw:created event fired on L.Map returns a L.LayerGroup as e.layers, which contains all the features that just have been edited. This is because you can edit multiple features at once before pressing the save button. You can iterate the L.LayerGroup and then fetch the GeoJSON:
map.on('draw:edited', function (e) {
e.layers.eachLayer(function (layer) {
console.log(layer.toGeoJSON());
});
});
Here is the rest service I'm working from:
http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3
My current call for displaying the feature layer is as follows:
var recLayer = new FeatureLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",{
infoTemplate: recParkTemplate,
outFields: ["STATE_NAME"]
});
map.addLayer(recLayer);
However, instead of plotting the polygon on the map as this is an esriGeometricPolygon. I would rather have it plot on the map like a esriGeometryPoint. I know this method in getting the specific polygon's centroid:
https://developers.arcgis.com/javascript/jsapi/polygon-amd.html#getcentroid
My problem is I can't figure out how to cycle among all polygons in the feature layer and then plot those polygons. I can only point and click and display similar to how this ESRI sample works: https://developers.arcgis.com/javascript/jssamples/util_label_point.html
Thank you for your assistance.
Here is the current site if you would like to take a look at it: http://joshferrell.net/ece_project/
to cycle among all geometries in your feature layer you can do something like this:
recLayer.on("update-end", function changeHandler(evt) {
require(["dojo/_base/array"], function (array) {
array.forEach(recLayer.graphics, function (entry, i) {
console.debug(entry, "at index", i);
});
});
});
inside the loop use the getCentroid and add the result to the map