check if map markers are within selected bounds - javascript

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");
}
});

Related

Delete the last 2 additions to a featuregroup in Leaflet

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.

Mapbox marker clustering with JSON not GeoJSON

I am trying to use marker clustering because I have over 2000 markers being mapped currently, but I am not sure how to implement it with the way that I am loading the markers. Do I have to use a GeoJSON in order to use marker clustering? I would prefer to not use GeoJSON if possible, I am using a JSON file at the moment and looping through the data stored on Firebase. I would like to use the supercluster library if possible (https://github.com/mapbox/supercluster) but I am not sure what to load into index.load(points). Is clustering possible the way I have my code at the moment?
var markers = [];
allMarkers();
function allMarkers() {
for (var i = 0; i < data.length; i++) {
var marker = document.createElement("div");
marker.className = "marker";
marker.style.backgroundImage = "url(./icons/all.png)";
marker.style.backgroundSize = "100%";
marker.style.backgroundRepeat = "no-repeat";
marker.style.width = "25px";
marker.style.height = "25px";
marker.style.filter = "drop-shadow(0px 5px 6px #000000)";
new mapboxgl.Marker(marker)
.setLngLat([data[i].Long, data[i].Lat])
.setPopup(
new mapboxgl.Popup()
.setHTML(
""
).on("close", function() {
}).on("open", function() {
zoom = map.getZoom();
if (zoom < 17) {
map.flyTo({
center: [this._lngLat.lng, this._lngLat.lat],
zoom: 17
});
} else {
map.flyTo({
center: [this._lngLat.lng, this._lngLat.lat]
});
}
}).setMaxWidth("400px")
)
.addTo(map);
markers.push(marker);
}
}
The easiest way to do clustering in Mapbox-GL-JS is using a GeoJSON source with cluster: true as in this example. It doesn't matter that your data is being sent to the browser as some other format, you can convert it into GeoJSON easily and then add it.
Currently you are representing your points using Markers, rather than a layer within the map such as circle or symbol. That would be more complex to combine with clustering, as you would need to create and destroy markers on demand, as the user zooms in and out. It will be much simpler to manage with a map layer, although it will limit your ability to style the marker symbols.

Remove markers from map (Google Maps API v3)

I'm developing an app with Google maps that should display several categories on a map. Now I would like to have the possibility to add markers from several categories and delete them as well if necessary.
I've managed to figure out the whole thing. At least, almost... I'm having troubles with the removal of the markers of a category. I've created a live demo on jsfiddle to make this clear.
So here's how I attempt to do this:
CODE
First I initialize the map, etc. (but that is not relevant here). Then I add the markers on the map:
for(i in markers){
var marker = new google.maps.Marker({
map: map,
draggable: false,
position: new google.maps.LatLng(markers[i].latitude, markers[i].longitude),
visible: true,
data: category
});
newMarkers.push(marker);
}
As you can see I have 'data: category' in the object. This is something that's not google maps api, but it gives me no errors and gives me the possibility to search the array when I want to remove the markers. Here the removeMarker function:
function removeMarkers(category)
{
for(i in newMarkers) {
if(newMarkers[i]['data'] == category){
count ++;
newMarkers[i].setMap(null);
newMarkers.splice(i, 1);
}
}
}
It does remove markers, but not all of them...
Does anyone have solution to my problem?
LIVE DEMO
Thanks in advance,
Helena S.
Seems like the problem is that you are iterating the newMarkers array and at the same time removing elements from it.
Try this instead. It only sets the removed marker values in the array to null then, after the loop, filters those null values:
for(i in newMarkers) {
if(newMarkers[i]['data'] == category){
count ++
newMarkers[i].setMap(null);
newMarkers[i] = null;
}
}
newMarkers = newMarkers.filter(function(val){ return !!val; });
http://jsfiddle.net/GJUcy/

Google Maps - get values from location array based on the map's current viewpoint

Edit:
Question = "is there a way to loop through the array and check if each location (long/lat) falls within the current viewport directly" (failing that get all markers within the viewport)
Background:
I have an array of locations (lat, long, id).
I want to:
On a Google Map, use the location array to display markers.
The user can scroll/zoom the map.
Have a button underneath the map, so when the user has decided on an area, he can click the button, and the code will return the ids (from the location array) that are contained within the viewport / map bounds.
There is a .contains for Google, so I guess you could potentially use that with something like
map.getBounds().contains and somehow reference each marker.getPosition()
but I wonder if there's a way to loop through the array and check if each location (long/lat) falls within the current viewport directly
You mean something like this (not tested), map is the google.maps.Map object and needs to be in scope. markersArray is the array of markers.
for (var i=0; i< markersArray.length; i++) {
if (map.getBounds().contains(markersArray[i].getPosition())) {
// the marker is in view
} else {
// the marker is not in view
}
}
http://jsfiddle.net/UA2g2/1/
Thanks geocodezip, you gave me the idea on how to solve it via looping through the array. I don't know if this is the most efficient way, but I put together some code that seems to do what I want - if you check the jsfiddle above and view console you can see that it logs when and which points are in the viewport.
$(document).ready(function(){
var myOptions = {
center: new google.maps.LatLng(51, -2),
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var storeArray = new Array(["51.38254", "-2.362804", "ID1"], ["51.235249", "-2.297804","ID2"], ["51.086126", "-2.910767","ID3"]);
google.maps.event.addListener(map, 'idle', function() {
for (i = 0; i < storeArray.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(storeArray[i][0], storeArray[i][1]),
map: map
});
}
for (var i=0; i<storeArray.length; i++) {
if (map.getBounds().contains(new google.maps.LatLng(storeArray[i][0], storeArray[i][1]))) {
console.log("marker: " + storeArray[i][2]);
}
}
});
});

google maps middle of a polyline (centroid?)

I have a list of polylines, just like google maps does when I click on the polyline I want an infowindow to show up just where I clicked, and it works just fine with this function
function mapsInfoWindow(polyline, content) {
google.maps.event.addListener(polyline, 'click', function(event) {
infowindow.content = content;
infowindow.position = event.latLng;
infowindow.open(map);
});
}
the problem comes when I click on the list(using the same function for that), event obviously doesn't have the latLng, but I'd like infowindow to show up in the middle of the polyline anyway, just like it does when you click on the list in the google maps link I mentioned before.
Tried LatLngBounds(); but that gives the actuall center of the area the polylines create, not the middle I need.
Any idea how to do it?
So this is the(bit hacky) solution.
Use http://www.geocodezip.com/scripts/v3_epoly.js library, then count the total length of you polyline(various ways), divide it in half and call epoly's .GetPointsAtDistance() function upon it.
This should return LatLng point, but it acts a bit weird sometimes, returning two points or even turning that point somehow "broken". So the most secure thing you can do is probably this:
var pointInHalf = polyline.GetPointsAtDistance(polylineLength);
var pointCoordinate = new google.maps.LatLng(pointInHalf[0].lat(), pointInHalf[0].lng());
Well, better than nothing.
From http://www.geocodezip.com/v3_polyline_example_geodesic_proj.html
Without extensions and assuming the polyline is a straight line.
It is possible to convert the lat/lng coordinates to point plane (x,y) postions and calculate the average between the two. This will give you a central pixel position. You can then convert this position back to a latlng for map plotting.
var startLatLng = startMarker.getPosition();
var endLatLng = endMarker.getPosition();
var startPoint = projection.fromLatLngToPoint(startLatLng);
var endPoint = projection.fromLatLngToPoint(endLatLng);
// Average
var midPoint = new google.maps.Point(
(startPoint.x + endPoint.x) / 2,
(startPoint.y + endPoint.y) / 2);
// Unproject
var midLatLng = projection.fromPointToLatLng(midPoint);
var midMarker = createMarker(midLatLng, "text");
More information on changing the projection http://code.google.com/apis/maps/documentation/javascript/reference.html#Projection
So firstly you need to use the geometry library which calculates distances. Add libraries=geometry to your JS call, e.g.
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
Assuming you know the start point and end point for your polyline, you should be able to do this:
var inBetween = google.maps.geometry.spherical.interpolate(startLatlng, endLatlng, 0.5);
infowindow.position = inBetween;
I guess if you don't already know the start and end points, you could work it out from polyline.getPath().
to get the coordinates of your polyline you should do:
var widePath = new google.maps.Polyline({
path: waypointsCoordinates,
strokeColor: '#3366FF',
strokeOpacity: 0.0,
editable: true,
draggable: true,
strokeWeight: 3
});
and do:
var latLng [];
latLng = widePath.getPath().getArray();
Might be a bit old as well, but why not add the infobox on the click?
infowindow.setPosition(event.latLng);
infowindow.open(this.getMap());
If it's a click that is.

Categories

Resources