I have a featuregroup that adds circlemarkers and paths -- they are added in sequence and I need a way to create a function that will remove the last (2) in the _layers every time it's clicked.
I tried slicing but that doesn't work because it's not really an array.
Any thoughts on how to proceed? I've been searching stackoverflow for awhile and cannot find anything that matches what I'm trying to do.
Let's simply refer to Leaflet documentation:
You can use the methods the layerGroup/featureGroup provides to remove the last two layers from the group.
The getLayers method returns an array of all the layers added to the group.
The eachLayer method iterates over the layers of the group, optionally specifying context of the iterator function.
The removeLayer method removes the layer with the given internal ID from the group.
Leaflet's featureGroup is an extension of the layerGroup so all of these will work on featureGroup as well.
So, say that you have your layers set up like so:
// Layers:
var layers = L.layerGroup().addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(layers);
var circle = L.circle([51.508, -0.11], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 500,
}).addTo(layers);
var polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047],
]).addTo(layers);
You can use those layerGroup methods to remove the last two elements of the array:
// Pass the layerGroup to the function
function removeLastTwo(layerGroup) {
// Use getLayers to get the array
var layerArr = layerGroup.getLayers();
var minusOne = layerArr.length - 1;
var minusTwo = layerArr.length - 2;
// Use eachLayer to iterate the layerGroup
layerGroup.eachLayer((layer) => {
// Grab the index of the layer
var layerIndex = layerArr.indexOf(layer);
// Remove the last two elements of the layerGroup array
if (layerIndex === minusOne || layerIndex === minusTwo) {
layerGroup.removeLayer(layer);
}
});
}
Here is a live example, with this function attached to the click event listener of a button.
Related
I'm currently trying to link the markers on my leaflet map to a portion of text available to the left of the map. What I would like to have happen is when the user clicks on a marker, the site will scroll to that portion of text.
I should also note that my markers are derived from a separate geoJson file.
This is the code I intend to use once each of the markers have their unique IDs to be manipulated:
document.getElementById("A").addEventListener("click", function() {
window.location.href = "#B";
});
So in this case, "A" would be the unique ID given to one of the markers, and #B is the ID of the text I want to scroll to via the href.
*Edit
I should clarify that the primary issue is actually giving ID's to the markers from the geoJson elements I added onto the map.
The relevant code for this is here:
//convert points to circles in layer
function pointToLayer(feature, latlng, attributes){
var attribute = attributes[0];
// styling for the circles which are pink with white borders
var geojsonMarkerOptions = {
fillColor: "#800000",
color: "white",
weight: 1,
opacity: 1,
fillOpacity: 0.5,
};
var layer = L.circleMarker(latlng, geojsonMarkerOptions);
//returns layer with circle markers
return layer;
//function to fill the global attribute array variable at top of page
function processData(data){
//variable to store the first feature in the data
var properties = data.features[0].properties;
//for loop to push each attribute name into array
for (var attribute in properties){
//indexOf will only allow attributes with population values to be pushed
if (attribute.indexOf("Victims") > -1){
attributes.push(attribute);
};
};
return attributes; //returns attributes array to be used in callback
};
//function to retrieve the data from geojson
function getData(map){
//load the data and calls functions
$.getJSON("data/WarCrimes3.geojson");
};
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.
Similar to Search for markers in a markercluster group Leaflet-MarkerCluster
But i am using a Control group ontop of Marker Cluster so they will be displayed upon a radio button click.
var map = L.map("map"),
parentGroup = L.markerClusterGroup(options), // Could be any other Layer Group type.
// arrayOfMarkers refers to layers to be added under the parent group as sub group feature
mySubGroup = L.featureGroup.subGroup(parentGroup, arrayOfMarkers);
parentGroup.addTo( map );
mySubGroup.addTo( map );
I am attempting to implement Leaflet Search - but as per the documentation says it requires a group layer of markers as the second parameter for it work. Trouble is using L.featureGroup.subGroup requires an array of markers.
Attempted to iterate through mySubGroup at run time to get the layers of markers using Leaflet eachLayer but this will duplicate the amount of markers i have on the map for the search to work.
var markersLayer = new L.LayerGroup().addTo( this.map );
forEach( mySubGroup, layers => {
layers.eachLayer( function (layer ) {
console.log ( layer );
markersLayer.addLayer( layer );
})
});
map.addControl( new L.Control.Search({layer: markersLayer}) );
Solved this issue - though it's quite inefficient. If you can find a more elegant solution to avoid duplication then feel free to contribute it as an answer!
var title = layer.options.title;
// iterate through the cluster points
forEach( mySubGroup, layers => {
layers.eachLayer(function (layer) {
var title = layer.options.title; // match the search title to marker title
marker = new L.Circle(new L.LatLng(layer.getLatLng().lat,layer.getLatLng().lng),
{radius: 0, title: title, fill: 'red', fillOpacity: 0, opacity: 0 }); // Create an invisible L circle marker for each cluseter marker
markersLayer.addLayer(marker);
})
});
You then add the markersLayer to the Leaflet Search
In PaperJS, only regular types seem to be able to be added to a Group. Whenever I try to append the group with a custom object I get the error item._remove is not a function
Whenever I create my own object, for instance:
function textBox(point, width) {
this.box = new Path.Rectangle({
point: point,
size: new Size(width,40),
strokeColor: new Color(0,0,0,0.1),
fillColor: 'white',
strokeWidth: 1
});
this.box.onMouseUp = function(event) {
cursor = this.point + new Point(5,2);
}
}
and try to append this to a group:
var testGroup = new Group();
testGroup.appendTop(new textBox(new Point(0,0), 400));
The error shows up. My question is thus: how do I add custom objects to a group? Surely I can't be expected to either manually create each individual object or otherwise manipulate them all on an individual level without using Group dynamics. It seems I have to, just like every other type in PaperJS, make my object extend Item, but I so far have failed to get it to accept my constructor for it. I'm wondering what is required for it to be accepted.
Indeed, there currently is no built-in mechanism to extend Paper.js classes apart from compiling them along with the library.
So for simple cases like the one that you seem to encounter, I would use a factory function that instantiates my custom object and then interact with it as with any other Paper.js object.
For example, if your custom object is a box with a text in it, you can instantiate a group with a rectangle and a text in it and then just interact with this group.
Here is a sketch demonstrating the solution.
function createMyTextBox(point, content) {
// Create a text item
var text = new PointText({
point: point,
content: content,
fontSize: 36,
fillColor: 'red',
justification: 'center'
});
// Create a rectangle around the text
var rectangle = new Path.Rectangle({
rectangle: text.bounds.scale(1.2),
strokeColor: 'black'
});
// Create a Group that will wrap our items.
var group = new Group([text, rectangle]);
// Return the group
return group;
}
// Create 2 text boxes
var textBox1 = createMyTextBox(view.center, 'text 1');
var textBox2 = createMyTextBox(view.center + [0, 100], 'text 2');
// You can use text boxes like regular items.
textBox2.translate(100, 0);
textBox2.scale(0.8);
I have a map with various markers and i need to be able to draw a rectangle on the map and select the markers which are within the rectangle bounds.
So far i have found some great info here: How to get markers inside an area selected by mouse drag?
I have implemented the keymapzoom plugin ok. like so
$('#dispatcher').gmap3({action:'get'}).enableKeyDragZoom({
boxStyle: {
border: "dashed black",
//backgroundColor: "red",
opacity: 0.5
},
paneStyle: {
backgroundColor: "gray",
opacity: 0.2
}
});
var dz = $('#dispatcher').gmap3({action:'get'}).getDragZoomObject();
google.maps.event.addListener(dz, 'dragend', function (bnds) {
alert(bnds);
});
This gives me the following
((lat,long),(lat,long)) format from the alert(bnds);
I need to know how i can now check if any markers are within this?
I already have an object that is storing the markers for another reason. like:
markers[name] = {};
markers[name].lat = lati;
markers[name].lng = longi;
which might be useful?
I don't understand how to use the GLatLngBounds and containsLatLng(latlng:GLatLng) as suggested.
Your question is tagged with the v3 version of the Maps API, so I'll assume you are using that version (which you should as v2 is deprecated). Note that some classes and methods are named different than in your question.
Bounds are represented with the LatLngBounds class. You can perform the contains method on an instance of that class to determine if a point lies within those bounds.
If you have an object with all your markers, you can loop through them and check each marker, for example:
var bounds = new google.maps.LatLngBounds(sw, ne);
for (var a in markers) {
if (bounds.contains(new google.maps.LatLng(markers[a].lat, markers[a].lng)) {
// marker is within bounds
}
}
On a side note, I would store the LatLng object in the markers object when creating them. That way you don't have to create them wherever you need.
Box/Rectangle Draw Selection in Google Maps
This was my solution..
google.maps.event.addListener(dz, 'dragend', function(e) { //important listener
for(var i = 0; i < markers.length; i++){ // looping through my Markers Collection
if(e.contains(markers[i].position))
console.log("Marker"+ i +" - matched");
}
});