Im currently working on a cross platform app that has a google map that has a whole bunch of icons on it. I use an Ajax query to get a kendo ui mobile datasource that has a list of lat/lng values and a category of the object.
From there when the user selects turn on that category, those markers appear on the map. This currently works however removing them is the issue.
When I go to remove them, I do not know how to delete all markers with a specific label. Is there a global array of markers that I can iterate through to find the appropriate markers to remove?
If there is I can simply set these particular markers map to null to remove them.
My code for adding markers is below:
var dataItem;
var facData = new kendo.data.DataSource({
........
});
facData.fetch(function() {
if (e.checked == 1) {
for (var i = 0;i < facData.view().length;i++) {
dataItem = facData.view()[i];
dataItemLatLng = new google.maps.LatLng(dataItem.lat, dataItem.lon);
createMarker(dataItemLatLng, "Toilets", toiletIcon);
}
}
else {
Code for removing all markers with label "Toilets"
}
})
}
In some outer scope :
var markers = [];
And your function that creates/removes markers :
function foo() {
var facData = new kendo.data.DataSource({
........
});
facData.fetch(function() {
if (e.checked == 1) {
for (var i = 0; i < facData.view().length; i++) {
var dataItem = facData.view()[i];
var dataItemLatLng = new google.maps.LatLng(dataItem.lat, dataItem.lon);
var marker = createMarker(dataItemLatLng, "Toilets", toiletIcon);
markers.push(marker);
}
}
else {
while(markers.length) {
markers.pop().setMap(null);
}
}
});
}
You need to ensure that createMarker() returns the created marker.
As written, the markers array is emptied as the markers are removed from the map. This seems sensible, otherwise, next time round the array would still contain references to the old markers plus references to all the new ones - much of the time, this would mean duplicate markers created from the same data as last time ... and so on, and so on.
I created a global array that each marker, when added is pushed into. Then the remove code is simply:
for(var i=0; i< markerArray.length;i++){
if(markerArray[i].getTitle()=="Toilets"){
markerArray[i].setMap(null);
}
}
Related
I'm trying to create a straight line network in Leaflet, which at each junction has a marker, and on drag of each marker, update the position of the corresponding polyline which connects to it.
I've done some research (mostly this question) & reworked a fiddle to strip it down a bit to try & get it to do what I want. I am able to draw the network with individual polylines, however, I need to add multiple parentLines to the marker which is connected to two polylines. I can't find it in the Leaflet documentation, but punted with this:
marker_arr[1].parentLine = [polyline_a,polyline_b];
My issue is when I call the dragstart/drag/dragend handlers, it doesn't work with multiple polylines. (Edit) I have made some headway in capturing the parentLines as an array, but can only make it work for the first parentLine
function dragHandler(e) {
var polyline=[]
console.log("drag")
if(e.target.parentLine.length){
polyline.push(e.target.parentLine[0]);
} else {
polyline.push(e.target.parentLine);
}
if(polyline){
var latlngPoly = polyline[0].getLatLngs(), // Get the polyline's latlngs
latlngMarker = this.getLatLng(); // Get the marker's current latlng
latlngPoly.splice(this.polylineLatlng, 1, latlngMarker); // Replace the old latlng with the new
polyline[0].setLatLngs(latlngPoly); // Update the polyline with the new latlngs
}
}
Can anyone point me to either the documentation about parentLine, or how I might make this work? Using Leaflet v1.6.0 and cannot use more recent versions as this is to extend an already existing implementation of Leaflet based on 1.6.
Fiddle here
Here is a sample.
Add to the marker the parentLines always as array:
marker_arr[0].parentLine = [polyline_a];
marker_arr[1].parentLine = [polyline_a,polyline_b];
marker_arr[2].parentLine = [polyline_b];
and then loop through all parentLines in the dragstart handler:
// Now on dragstart you'll need to find the latlng from the polyline which corresponds
// with your marker's latlng and store it's key in your marker instance so you can use it later on:
function dragStartHandler(e) {
var marker = e.target;
marker.polylineLatlng = {};
e.target.parentLine.forEach((line)=>{
var latlngPoly = line.getLatLngs(), // Get the polyline's latlngs
latlngMarker = marker.getLatLng(); // Get the marker's current latlng
for (var i = 0; i < latlngPoly.length; i++) { // Iterate the polyline's latlngs
if (latlngMarker.equals(latlngPoly[i])) { // Compare marker's latlng ot the each polylines
marker.polylineLatlng[L.stamp(line)] = i; // If equals store key in marker instance
}
}
})
}
And in the drag handler:
// Now you know the key of the polyline's latlng you can change it
// when dragging the marker on the dragevent:
function dragHandler(e) {
var marker = e.target;
e.target.parentLine.forEach((line)=>{
var latlngPoly = line.getLatLngs(), // Get the polyline's latlngs
latlngMarker = marker.getLatLng(); // Get the marker's current latlng
latlngPoly.splice(marker.polylineLatlng[L.stamp(line)], 1, latlngMarker); // Replace the old latlng with the new
line.setLatLngs(latlngPoly); // Update the polyline with the new latlngs
})
}
And clean it in the dragend handler:
// Just to be clean and tidy remove the stored key on dragend:
function dragEndHandler(e) {
var marker = e.target;
delete marker.polylineLatlng;
console.log("end");
}
I am trying to getBounds of dynamically added markers to the map. My goal is to dynamically add markers to a map and have the view automatically zoom to fit the bounds of all the markers on the map. Below is my current code and what I have tried so far:
The starting point is an array of lat & lng:
The web page offers a list of addresses and checkboxes that a user can select and deselect. When the desired addresses are selected the user can click view on map and the makrers will appear on the map (this is working perfectly, I just can't get the view to zoom to the bounds of these markers)
I have a loop that pulls the lat and lng for each checked address and pushes it into an array like this:
latLng.push(42.9570316,-86.04564429999999);
latLng.push(43.009381,-85.890041);
...this is in a loop so it always contains the desired amount of values and outputs this:
latLng = [42.9570316,-86.04564429999999,43.009381,-85.890041,43.11996200000001,-85.42854699999998,43.153376,-85.4730639,42.8976947,-85.88893200000001];
var thisLatLng = L.latLng(latLng);
console.log(thisLatLng); // this returns Null
mymap.fitBounds(group); // returns Error: Bounds are not Valid
mymap.fitBounds(group.getBounds()); // returns group.getBounds() is not a function
I have also tried this as a starting point:
latlng.push(L.marker([42.9570316,-86.04564429999999]));
latlng.push(L.marker([43.009381,-85.890041]));
...this is contained in a loop that results in the output below
latLng = [L.marker([42.9570316,-86.04564429999999]),L.marker([43.009381,-85.890041]),L.marker([43.11996200000001,-85.42854699999998]),L.marker([43.153376,-85.4730639]),L.marker([42.8976947,-85.88893200000001])];
console.log(latLng); // this returns makrers with the correct lat & lng above
var group = new L.featureGroup(latLng);
console.log(group); //this returns a Null featureGroup
mymap.fitBounds(group); // returns Error: Bounds are not valid
mymap.fitBounds(group.getBounds()); // returns Error: Bounds are not valid
I am at a loss on how to make this work I have tried several answers posted on stackoverflow and attempted to try and follow the documentation but nothing seems to give the desired outcome.
Update
I removed latLng.push(L.marker([42.9570316,-86.04564429999999])); loop and replaced with the following:
I created a featuregroup with var group = new L.featureGroup(); then added markers to it in the loop by using marker.addTo(group); this pushed all of the markers into the featuregroup as I would expect but was unable to get bounds.
mymap.fitBounds(group.getBounds()); // returns Error: Bounds are not valid
here is what console.log(group); outputs:
I don't think at all that
latLng = [L.marker([42.9570316,-86.04564429999999]),L.marker([43.009381,-85.890041]),L.marker([43.11996200000001,-85.42854699999998]),L.marker([43.153376,-85.4730639]),L.marker([42.8976947,-85.88893200000001])];
Can work. In leaflet you can't just create a variable and say that it's a marker object. You need to use method like L.marker()
What you need to do is create a single marker and add it to a featureGroup
var group = new L.featureGroup();
for (var i = 0; i < yourMarkers.length; i++) {
L.marker([51.5, -0.09]).addTo(group);
}
map.fitBounds(group.getBounds());
group will now contains multiple markers.
And you can also try this :
var coordinates = new Array();
for (var i = 0; i < yourMarkers.length; i++) {
var marker = L.marker([51.5, -0.09]);
coordinates.push(marker);
}
var group = new L.featureGroup(coordinates);
map.fitBounds(group.getBounds());
UPDATE
The concerned function was this one :
function showResult(lat, lng) {
var marker = L.marker([lat, lng])
.bindPopup('yourPopup').on("popupopen", onPopupOpen).addTo(group);
map.addLayer(group);
map.fitBounds(group.getBounds());
}
You only need to add the fitBounds() inside it.
I currently have an app that creates an array of markers. But it is not useful, because I would like to see a group of markers and a custom property summed based on the distance between markers (depending on the zoom level).
I've said that maybe with MarkerClusterPlus I could accomplish something like this:
This even shows a custom icon, I don't need that, I only need the number over the cluster.
But I don't know where to start. Could someone place an example or a link?
You must define a custom property on the Marker object, so you can override the Calculator function in markercluster.js
MarkerClusterer.CALCULATOR = function (markers, numStyles) {
var index = 0;
var title = "";
var count = markers.length.toString();
var valueToSum=0;
for(var m=0;m<markers.length;m++){
//This is the custom property called MyValue
valueToSum+=Number(markers[m].MyValue);
}
var dv = val;
while (dv !== 0) {
dv = parseInt(dv / 10, 10); //you could define your own rules
index++;
}
index = Math.min(index, numStyles);
return {
text: valueToSum,
index: index,
title: title
};
};
I want to be able to filter markers on the map using 3 listboxes, each of which may have multiple selections.
I haven't found anything on the web about filtering Google Maps as close to what I want as this example with checkboxes.
I have borrowed all the code from there, except for the show() and hide() functions, and made a couple for myself:
// grabs values of all selected items inside a listbox
// pushes them into an array and returns it.
// 'listbox' string parameter is mandatory
function grabSelectedItems(listbox) {
if(document.getElementById(listbox)){
var selectedOptions = [];
var listBoxInstitutions = document.getElementById(listbox);
for(var i = 0; i < listBoxInstitutions.options.length; i++) {
if(listBoxInstitutions.options[i].selected) {
selectedOptions.push(listBoxInstitutions.options[i].value);
}
}
return selectedOptions;
}
alert(listbox + " couldn't be found");
}
// uses 'grabSelectedItems()' to get selected values
// from multiple listboxes, puts the returned arrays into
// one, big array and returns it.
// accepts minimum 1 string parameter(mandatory) or more
// treating each parameter as the name of a listboxe
// to grab selected values from
function grabAllSelectedItems() {
if(arguments.length > 0) {
var allSelectedOptions = [];
for(var i = 0; i < arguments.length; i++) {
allSelectedOptions.push(grabSelectedItems(arguments[i]));
}
return allSelectedOptions;
}
alert("Please pass at least one string parameter");
}
And for now I use it to return the big array of selected values when the input button with id of filter is clicked:
$(function() {
$("#filter").click(function() {
grabAllSelectedItems('listbox1', 'listbox2', 'listbox3');
});
});
But I'm stuck now and can't figure out how to plot the markers based on my selections in the listboxes.
I have this one big XML file that contains all the data and I want to use it to generate and plot the markers on the map based on what I've selected in the listbox(es). All markers have lat and lng coords, but these markers also contain these sub-markers that also have their own lat and lng coords. I've done it this way because their information is interconnected.
Anyone done something like this before?
I have a Google Map with a bunch of markers.
I add markers to the map one-by-one and need to remove individual markers one-by-one too when required, using individual IDs.
Currently I have some horrible, verbose code, involving a global array of markers, an ID added as metadata to each marker, and a clunky method for looking up a marker's position within the array, as follows:
var markersArray = [];
function getPositionById(markerId, arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].metadata.id === markerId) {
return i;
}
}
return null;
}
function removeMarker(markerId) {
var marker_position = getPositionById(markerId, markersArray);
if (marker_position !== null) {
markersArray[marker_position].setMap(null);
markersArray.splice(marker_position,1);
}
}
function setMarker(position, markerId) {
removeMarker(markerId);
var temp_marker = new google.maps.Marker({
position: position
});
temp_marker.setMap(map);
temp_marker.metadata = { id: markerId };
markersArray.push(temp_marker);
}
Could anyone suggest an even slightly more elegant way to do it?
Given that to remove a marker from the Map you need to use setMap(null), means that you need to have a reference to that marker.
The way you presented in your question doesn't look as horrible as you think, but another way to do it is to use a map instead of an array (not sure if map is the best term to use here since we are already working with the Google maps Map), nonetheless, using a map would rid you from the getPositionById() function, off course this assumes that all your markerIds are unique.
Your code would look something like this.
var markers = {};
function removeMarker(markerId) {
if(markers[markerId]){
markers[markerId].setMap(null);
delete markers[markerId];
}
}
function setMarker(position, markerId) {
removeMarker(markerId);
var temp_marker = new google.maps.Marker({
position: position
});
temp_marker.setMap(map);
temp_marker.metadata = { id: markerId };
markers[markerId] = temp_marker;
}