How to get marker based on latlng in leaflet? - javascript

I want to find and remove marker based on it's coordinates. Or remove all the markers in the given geometry. There are few solutions I'm aware of. First is to store all the markers in a map or array, and the second is to remove whole level with markers and add another one (updated) - both of this solutions are not performance friendly if we talking about thousands of markers. And I didn't found a way to get a marker by it's coordinates natively.
I'd be glad if someone had any ideas about it. Thank you for the attention!

I've finished with a structure like this for adding and removing markers:
let markerSet = {}
const saveMarker = (coords, marker) => {
const [ key1, key2 ] = coords
markerSet = {
...markerSet,
[key1]: {
...markerSet[key1],
[key2]: marker
}
}
}
const removePointer = (coords) => {
const [ key1, key2 ] = coords
const marker = markerSet[key1][key2]
if (!marker)
return
markers.removeLayer(marker)
delete markerSet[key1][key2]
}
coords is latlng array

Related

Getting the LayerGroup a layer belongs to with OpenLayers

I have quite a few Tile Layers in my map, and they are all organized into different groups (sometimes they are even nested).
I see in API there's a getLayer() method to retrieve the layer a Vector feature belongs to, and a getLayerGroup() to retrieve all groups associated with a Map.
However, I could not find anything on getting the layerGroup a layer is associated with.
Lets'say I have this situation:
var myGroup = new LayerGroup();
var myLayer = new TileLayer();
myGroup.getLayers().insertAt(0, myLayer);
Is there a way to get myGroup from myLayer?
To get the parent group of a layer would need to write your own search function, something like
function searchGroups(group, layer) {
var result;
var layers = group.getLayers().getArray();
for (var i = 0; i < layer.length; i++) {
if (layers[i] === layer) {
result = group;
} else if (layers[i] instanceof LayerGroup) {
result = searchGroup(layers[i], layer)
}
if (result) {
break;
}
}
return result;
}
then call
var myGroup = searchGroups(map.getLayerGroup(), mylayer);
The getLayers() function you linked only works for a select interaction, you cannot determine from a random feature which layer it belongs to (and it could be in more than one) without a similar search of the features in each vector layer source.
I realize this question has already been answered, but alternatively, you also have the properties attribute for your layers, so you could add an array of group names to the layer itself. For example:
let parent_group = "parent_group";
let sub_group = "sub_group";
let group = new LayerGroup({
name: parent_group,
layers: [
new LayerGroup({
name: sub_group,
layers: [
new TileLayer() {
properties: [
parent_group,
sub_group
]
}
]
})
]
})
Then it's just a matter of looking up the layer name and looking up its properties array - probably a bit more cumbersome to setup initially, but it would save having to recursively search through layerGroups.

leaflet place marker whenever position changes with watchposition?

In my Ionic app I would like to place a marker in the user position and change its position whenever the one of the user changes.
Is it possible to do that?
I thought I could do something like this:
let marker1;
let watch = this.geolocation.watchPosition();
watch.subscribe((data)=>{
var lat = data.coords.latitude
var lon = data.coords.longitude
let latlng = {lat: lat, lng: lon}
marker1 = L.marker(latlng)
let content1 = `<b>You are here</b>`;
marker1.bindPopup(content1)
marker1.addTo(this.map)
}, error => {
})
but I'm wondering if will be drawn on the map a series of markers for the different positions, instead of "overriding" the previous one.
I currently haven't tried it 'cause I can't simulate the change of position, but I was wondering if this is the right way to do that or I'm going completely wrong.

GoogleMapsAPI - create markers filter

I'm doing a dynamic map using the Google Maps API that uses the markers to mark a list of predefined locations, such as:
self.locations = [{
name: 'Foxtrot',
lat: 38.713905,
lng: -9.1518868,
type: 'Bar'
}
It also has a Search field that allows you to filter by the name of the locations (filteredNav). It should also filter the markers, but...that is the problem.
The recommendation that I have is the following:
Try writing console.log(self.location_array());.Because location and
marker data modal is separate, you'll have to loop through
self.location_array() to process and find which one to show, which one
to hide by calling setVisible (or setMap) on the marker object.
This is my code:
// Create observable array
self.nav = ko.observableArray(self.locations);
// Create empty observable string
self.filter = ko.observable('');
// Show nav and filter
self.filteredNav = ko.computed(function() {
var filter = self.filter().toLowerCase();
if (!filter) {
return self.nav();
}
return self.nav().filter(function(i) {
// Check for proper casing or lowercase
return i.name.toLowerCase().indexOf(filter) > -1 || i.name.indexOf(filter) > -1;
});
//THIS IS THE PROBLEM!
for (var i = 0; i < location_array()[i].length; i++) {
//??????
location_array()[i].setVisible(true);
}//?????
}
note: observable array implementation: vm.location_array()[i]
Link to the project
So...the question is...how can I do the loop? I've no idea how to do it....
First of all, the code you have presented has some 'mysterious' parts. For example, what is self, what is ko, what is observableArray etc. One can only guess what each of these are.
So I will simply describe to you the general logic of how to achieve what you want.
The logic is pretty straightforward.
The same way you filter the places in the sidebar, when you type, you should filter the array of markers to call setVisible with true or false
This means, that when you create the markers, you should store them to a separate array.
Also, when you create a marker, e.g.
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(latitude, longitude)
})
Add a name property, or something similar, to it, like so
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(latitude, longitude),
name: 'Foxtrot`
})
so that your created marker has a name property, which you can use to filter your array of markers.
Thus, in order to filter your markers array, you should simply iterate over the array and check the .name property of each marker object, and if the name does not match the search input, simply setVisible(false) on the marker, otherwise do setVisible(true)
Hope this helps.

Update coordinate of feature in openlayers 3

I have a model in javascript which has latitude and longitude value. I have to find a feature on the map by the ID of the element and update it's location and several other properties. My code looks like this:
function updateCoordinate(item) {
var features = source.getFeatures();
var featureToUpdate;
// find feature by custom property
for(var i=0; i< features.length; i++) {
if (features[i].get('ID') == item.ID) {
featureToUpdate = features[i];
break;
}
}
// get lon, lat from input item
var lon = item.Coordinate.Longitude;
var lat = item.Coordinate.Latitude;
// update geometry (not working)
featureToUpdate.set('Geometry', new ol.geom.Point(getPointFromLongLat(lon, lat)));
// update custom properties (working)
featureToUpdate.set('MapMarkerTitle', item.Title);
// ...
}
function getPointFromLongLat (long, lat) {
return ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857')
}
Am I doing something wrong? Is there a better way for this? Is there a better way to find feature by custom property?
By custom poperty I mean that the feature is getting initiated like this:
var fea = new ol.Feature({
geometry: new ol.geom.Point(getPointFromLongLat(lon, lat)),
MapMarkerTitle : 'AAA',
// ...
})
source.addFeatures([fea]);
The custom properties are getting updated but the coordinate doesn't seem to update. Will the feature be redrawn after updating position? The label is however redrawn so I think yes.
UPDATE
After some debugging I found out that, I mispelled the 'geometry' property with uppercase.
Actually:
featureToUpdate.set('geometry', new ol.geom.Point(getPointFromLongLat(lon, lat)));
does set the new position and update the location right away. I would still like to know if what I am doing is the good way or there is better. Thanks!
You can simplify it to:
function updateCoordinate(item) {
var featureToUpdate = source.getFeatureById(item.ID);
var coord = getPointFromLongLat(item.Coordinate.Longitude, item.Coordinate.Latitude);
featureToUpdate.getGeometry().setCoordinates(coord);
featureToUpdate.set('MapMarkerTitle', item.Title);
}

Markerclusterer customization google maps

I have a basic markerclusterer example which works very well.
var center = new google.maps.LatLng(37.4419, -122.1419);
var options = {
'zoom': 13,
'center': center,
'mapTypeId': google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), options);
var markers = [];
for (var i = 0; i < 100; i++) {
var latLng = new google.maps.LatLng(data.photos[i].latitude,
data.photos[i].longitude);
var marker = new google.maps.Marker({'position': latLng});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
What I would like to do is cluster the markers by country and then once you click on it they are still clustered until on3 further click. Currently they are clustered until you are down to one result. I have thousands of markers and would like them visible after one country click and then one more click.
I looked for a solution online and found this http://google-maps-utility-library-v3.googlecode.com/svn/tags/markermanager/1.0/examples/google_northamerica_offices.html
which is produced using this
var officeLayer = [
{
"zoom": [0, 3],
"places": [
{ "name": "US Offices", "icon": ["us", "flag-shadow"], "posn": [40, -97] },
{ "name": "Canadian Offices", "icon": ["ca", "flag-shadow"], "posn": [58, -101] }
]
},
...
};
function setupOfficeMarkers() {
allmarkers.length = 0;
for (var i in officeLayer) {
if (officeLayer.hasOwnProperty(i)) {
var layer = officeLayer[i];
var markers = [];
for (var j in layer["places"]) {
if (layer["places"].hasOwnProperty(j)) {
var place = layer["places"][j];
var icon = getIcon(place["icon"]);
var title = place["name"];
var posn = new google.maps.LatLng(place["posn"][0], place["posn"][1]);
var marker = createMarker(posn, title, getIcon(place["icon"]));
markers.push(marker);
allmarkers.push(marker);
}
}
mgr.addMarkers(markers, layer["zoom"][0], layer["zoom"][1]);
}
}
mgr.refresh();
updateStatus(mgr.getMarkerCount(map.getZoom()));
}
I'm not sure how to implement this into what I've currently got and if i need to include any other scripts/ libraries also.
You are looking at two totally different libraries, there. Your question is about the MarkerClusterer library, but your example solution is about the MarkerManager library.
The MarkerClusterer library automatically clumps markers together based on an algorithm that tries to decide when too markers would be so close together that you can't visibly distinguish one from another. You don't really have a lot of control over when and how it decides to merge markers together this way, so this library is idea when it doesn't matter to you how they get merged, as long as merging happens. Since you want to merge markers together by political boundaries (countries) and not by proximity to each other, this is not the library for you.
The MarkerManager library does not automatically merge markers together at all. What it does do is to selectively hide and reveal markers based on the zoom level of the current map viewport. What you would need to do is do your own merging, and then add to the MarkerManager all of the merged markers, as well as the detail markers, and the zoom levels where you want each marker to be visible. Doing your own merging means you will need an alternate way of determining which country each marker point falls within. Hopefully, you already know (or can get) that information, because it's not automatically provided by any of these libraries.
tl;dr - use the MarkerManager library and not the MarkerClusterer library for grouping by countries, and it's up to you to identify the location for each country and which marker goes with which one.

Categories

Resources