Remove markers out of viewport - javascript

I have to manage a map of about 80.000 markers concentrated in France.
To do that, I decided to get the bounds of the viewport and call a dynamic-JSON (with PHP) which contains the markers inside the viewport. And this on the "idle" event.
I faced a problem with this solution. Indeed, the markers which already exist was re-plotted (at the same position), which consequently weigh the map for nothing...
To solve it, the markers list before and after the JSON query are compared (thanks to jQuery), in order to plot only the new markers. And it works!
Now, I would want to remove the markers which are not currently shown on the map. Or a list of markers (I get it thanks to jQuery) designated by an ID which is also the title of the marker. So, how can a delete markers like that ? I specify that I am using MarkerManager.
Otherwise, you guess that if I do not remove these markers, they will be re-plotted in some cases... For example, you are viewing the city A, you move the map to view the city B, and you get back to the city A...
Here is the code:
var map;
var mgr;
var markers = [];
function initialize(){
var mapOptions = {
zoom: 6,
center: new google.maps.LatLng(46.679594, 2.109375)
};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var mgrOptions = { borderPadding: 50, maxZoom: 15, trackMarkers: false };
mgr = new MarkerManager(map, mgrOptions);
google.maps.event.addListener(map, 'idle', function() {
mapEvent();
});
}
function mapEvent(){
if( map.getZoom() >= 8 ){
var bounds = map.getBounds();
getSupports(bounds.getNorthEast(), bounds.getSouthWest());
} else {
// Todo
}
}
var markerslistID = new Array();
var markerslistData = {};
function getSupports(ne, sw){
newMarkerslistID = new Array();
newMarkerslistData = {};
// Getting the markers of the current view
$.getJSON('./markerslist.php?nelat='+ne.lat()+'&nelng='+ne.lng()+'&swlat='+sw.lat()+'&swlng='+sw.lng(), function(data) {
for (var i = 0; i < data.points.length; i++) {
var val = data.points[i];
newMarkerslistID.push(val.id);
newMarkerslistData[val.id] = new Array(val.lat, val.lng, val.icon);
}
// List of New Markers TO PLOT
var diffNewMarkers = $(newMarkerslistID).not(markerslistID).get();
// List of Old markers TO REMOVE
var diffOldMarkers = $(markerslistID).not(newMarkerslistID).get();
// Plotting the NEW MARKERS
for( var i = 0; i < diffNewMarkers.length; i++ ){
var marker = new google.maps.Marker({
position: new google.maps.LatLng(newMarkerslistData[diffNewMarkers[i]][0], newMarkerslistData[diffNewMarkers[i]][1]),
title : diffNewMarkers[i],
icon : './images/'+newMarkerslistData[diffNewMarkers[i]][2]+'.png'
});
mgr.addMarker(marker, 0);
}
/*****************************************
HERE WE HAVE TO REMOVE
THE MARKERS CONTAINED IN diffOldMarkers
*****************************************/
mgr.refresh();
// Switching the new list to the old, for the next event
markerslistID = newMarkerslistID;
markerslistData = newMarkerslistData;
});
}
Thank you for your help.

A one-liner to hide all markers that ar not in the current viewport.
!map.getBounds().contains(marker.getPosition()) && marker.setVisible(false);
Or,
if (map.getBounds().contains(marker.getPosition()) && !marker.getVisible()) {
marker.setVisible(true);
}
else if (!map.getBounds().contains(marker.getPosition()) && marker.getVisible()) {
marker.setVisible(false);
}

Related

Cant get my marker's latLng to use in L.Routing.control

guys
I been trying to get my markers latlon when user double click on it but still don't get any results. Been trying other methods but i think this is the most accurate since i dont get any error when executing js
Any recommendation pls
var places = [
["LOCATION_1", 8.9856146341374, -79.51102268985925],
["LOCATION_2", 8.984640842221594, -79.51383510471848],
["LOCATION_3", 8.972080043026754, -79.5529245611453],
["LOCATION_4", 9.052896045979661, -79.4515923525883],
["LOCATION_5", 9.053366385577624, -79.50832832626823]
];
var map = L.map('map', {
center: [9.352867999999996, -79.689331],//[35.791188, -78.636755],
zoom: 9,
layers:L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{
maxZoom: 20,
subdomains:['mt0','mt1','mt2','mt3']
})
});
for (var i = 0; i < places.length; i++) {
marker = new L.marker([places[i][1], places[i][2]])
.bindPopup(places[i][0])
.addTo(map);
}
function getdest(){
L.marker.on('dblclick',function(e){
var latlng_dest=e.latlng() });
console.log(latlng_dest)
return latlng_dest
}
navigator.geolocation.getCurrentPosition(function(location) {
var latlng_orig = new L.LatLng(location.coords.latitude, location.coords.longitude);
L.Routing.control({
waypoints: [
//L.latLng(9.10607301250145, -79.34754531445351),
L.latLng(latlng_orig)
//,L.latLng(latlng_dest)
//,L.latLng(9.100769244670843, -79.35099352767948)
,L.latLng(getdest())
]
}).addTo(map)
});
You have many common things wrong:
e.latlng() is not a function it is a property e.latlng
L.marker.on('dblclick',function(e){ this makes no sense. You creating a new instance of a Marker without coords and then adding a listener to it.
You can't return a value in a function from a listener. The listener is not called at the moment you return the value L.marker.on('dblclick',function(e){ var latlng_dest=e.latlng() }); return latlng_dest
Your code should look like that:
for (var i = 0; i < places.length; i++) {
marker = new L.marker([places[i][1], places[i][2]])
.bindPopup(places[i][0])
.addTo(map)
.on('dblclick', function(e) {
waypoints.push(e.latlng);
routeControl.setWaypoints(waypoints);
});
}
var routeControl = L.Routing.control({
waypoints: [],
}).addTo(map);
var waypoints = [];
navigator.geolocation.getCurrentPosition(function(location) {
var latlng_orig = new L.LatLng(location.coords.latitude, location.coords.longitude);
waypoints.push(latlng_orig);
});

Bing Maps v8 API - Zoom Level to show route and pushpin location

I am using the Bing Maps v8 API. I have a map that shows a driving route, and a pushpin of another location. I need to get the map to zoom out to show both the waypoint locations and the pushpin location. Right now, I can get the map to zoom to the waypoints of the pushpin location.
I am not sure how to get both to show on the map zoom. I know that I need to use the LocationRect class.
var searchManager;
var startingPoint = document.getElementById('startPoint').value;
var address = $("#addressLine").val();
var loc;
var patAddLoc;
var waypointLoc;
var pinsLocs = [];
// GET ROUTE BASED ON DIRECTION
function GetMap() {
var map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
//BING API KEY VIA AZURE
credentials: 'X',
zoom: 10,
});
// geocode patient address
geocodeQuery(address);
// look for patient address
function geocodeQuery(query) {
//If search manager is not defined, load the search module.
if (!searchManager) {
//Create an instance of the search manager and call the geocodeQuery function again.
Microsoft.Maps.loadModule('Microsoft.Maps.Search', function () {
searchManager = new Microsoft.Maps.Search.SearchManager(map);
geocodeQuery(query);
});
} else {
var searchRequest = {
where: query,
callback: function (r) {
//Add the first result to the map and zoom into it.
if (r && r.results && r.results.length > 0) {
var pin = new Microsoft.Maps.Pushpin(r.results[0].location);
// get patient address location
patAddLoc = r.results[0].location;
map.entities.push(pin);
// add patient location to pushpin array
pinsLocs.push(patAddLoc);
// view is set with route location
//map.setView({ bounds: r.results[0].bestView });
}
// directions manager
// addWaypoint
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function addWaypoint() {
var directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
// if less than 2 point on the map
if (directionsManager.getAllWaypoints().length < 2) {
directionsManager.clearAll();
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('startPoint').value });
directionsManager.addWaypoint(startWaypoint);
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('endPoint').value });
directionsManager.addWaypoint(endWaypoint);
}
// Insert a waypoint
if (document.getElementById('wayPoints').value !== null) {
var addressList = JSON.parse(document.getElementById('wayPoints').value);
var arrayLength = addressList.length;
// insert waypoints from schedule
for (var i = 0; i < arrayLength; i++) {
//alert(addressList[i]);
var hvaddress = addressList[i];
var newWP = new Microsoft.Maps.Directions.Waypoint({ address: hvaddress });
directionsManager.addWaypoint(newWP, 1);
}
}
// Set the element in which the itinerary will be rendered - set autoupdatemapview to false to override autozoom to route
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('printoutPanel'), autoUpdateMapView: false });
directionsManager.calculateDirections();
var allWaypoints = directionsManager.getAllWaypoints();
// add way point to pinsLocs array
for (var i = 0; i < allWaypoints.length; i++) {
// returns nulls
alert(allWaypoints);
loc = allWaypoints[i].getLocation();
var showMeLoc = loc;
// showMeLoc = undefined.....?
alert(showMeLoc);
pinsLocs.push(loc);
}
// only the address search location is added to the array, waypoint locations are null
alert(pinsLocs);
//Create a LocationRect from array of locations and set the map view.
map.setView({
bounds: Microsoft.Maps.LocationRect.fromLocations(pinsLocs),
padding: 100 //Add a padding to buffer map to account for pushpin pixel dimensions
});
});
},
errorCallback: function (e) {
//If there is an error, alert the user about it.
alert("No results found.");
}
};
//Make the geocode request.
searchManager.geocode(searchRequest);
}
}
}
UPDATE - HERE is the working code for those who have the same question!
var searchManager;
var startingPoint = document.getElementById('startPoint').value;
var address = $("#addressLine").val();
var patAddLoc;
// GET ROUTE BASED ON DIRECTION
function GetMap() {
var map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
//BING API KEY VIA AZURE
credentials: 'XXXXX',
zoom: 10,
});
// geocode patient address
geocodeQuery(address);
// look for patient address
function geocodeQuery(query) {
//If search manager is not defined, load the search module.
if (!searchManager) {
//Create an instance of the search manager and call the geocodeQuery function again.
Microsoft.Maps.loadModule('Microsoft.Maps.Search', function () {
searchManager = new Microsoft.Maps.Search.SearchManager(map);
geocodeQuery(query);
});
} else {
var searchRequest = {
where: query,
callback: function (r) {
//Add the first result to the map and zoom into it.
if (r && r.results && r.results.length > 0) {
locs = [];
var pin = new Microsoft.Maps.Pushpin(r.results[0].location);
// get patient address location
patAddLoc = r.results[0].location;
map.entities.push(pin);
// add patient location to pushpin array
locs.push(r.results[0].location);
// view is set with route location
//map.setView({ bounds: r.results[0].bestView });
}
// directions manager
// addWaypoint
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function addWaypoint() {
var directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
// if less than 2 point on the map
if (directionsManager.getAllWaypoints().length < 2) {
directionsManager.clearAll();
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('startPoint').value });
directionsManager.addWaypoint(startWaypoint);
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('endPoint').value });
directionsManager.addWaypoint(endWaypoint);
}
// Insert a waypoint
if (document.getElementById('wayPoints').value !== null) {
var addressList = JSON.parse(document.getElementById('wayPoints').value);
var arrayLength = addressList.length;
// insert waypoints from schedule
for (var i = 0; i < arrayLength; i++) {
//alert(addressList[i]);
var hvaddress = addressList[i];
var newWP = new Microsoft.Maps.Directions.Waypoint({ address: hvaddress });
directionsManager.addWaypoint(newWP, 1);
}
}
// Set the element in which the itinerary will be rendered - set autoupdatemapview to false to override autozoom to route
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('printoutPanel'), autoUpdateMapView: false });
//Add event handlers to directions manager.
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', directionsError);
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', directionsUpdated);
// Calculate directions, which displays a route on the map
directionsManager.calculateDirections();
// get route boundaries
function directionsUpdated(e) {
//Get the current route index.
var routeIdx = directionsManager.getRequestOptions().routeIndex;
// get northeast bounding box corner
var bBoxNE = e.routeSummary[routeIdx].northEast;
locs.push(bBoxNE);
// get southwest bounding box corner
var bBoxSW = e.routeSummary[routeIdx].southWest;
locs.push(bBoxSW);
//SET MAP VIEW
//Create a LocationRect from array of locations and set the map view.
map.setView({
bounds: Microsoft.Maps.LocationRect.fromLocations(locs),
padding: 50 //Add a padding to buffer map to account for pushpin pixel dimensions
});
}
function directionsError(e) {
alert('Error: ' + e.message + '\r\nResponse Code: ' + e.responseCode)
}
});
},
errorCallback: function (e) {
//If there is an error, alert the user about it.
alert("No results found.");
}
};
//Make the geocode request.
searchManager.geocode(searchRequest);
}
}
}
If I understand correctly, you want a view that the entirety of the route and the extra location are visible?
How about using directionsManager.getCurrentRoute().routePath to get all the locations on the route, and then using LocationRect.fromLocations(), which can take in an array of locations - in your case all locations of above plus the additional one.
Note that calculateDirections and geocode and asynchronous, so you may want to handle the dependency on patAddLoc (e.g. move the directions code into the geocode callback).
Reference:
https://msdn.microsoft.com/en-us/library/mt750375.aspx
https://msdn.microsoft.com/en-us/library/mt750645.aspx
https://msdn.microsoft.com/en-us/library/mt712644.aspx

api bing maps - multi layer (line and pic) on one point

I can't create multiple layers (images and lines) on the same coordinates.
Does anyone know how you can handle it?
example code:
for (; index_array < array_trip.length; index_array++) {
latVal = array_trip[index_array].latitude;
longVal = Microsoft.Maps.Location.normalizeLongitude(array_trip[index_array].longitude);
map.setView({ center: new Microsoft.Maps.Location(latVal, longVal) });
var pushpinOptions = { icon: path + 'car.png', width: 50, height: 50 };
var pushpin = new Microsoft.Maps.Pushpin({ latitude: latVal, longitude: longVal }, pushpinOptions);
map.entities.push(pushpin);
}
First off, don't set the map view in an array. This will only cause issues. Secondly, ensure that the URL to the pushpin icon is correct. Perhaps try removing that option for now until you see the default pushpins displayed on the map, then try adding a custom icon.
If you want to separate your data into layers you should use EntityCollection's: https://msdn.microsoft.com/en-us/library/gg427616.aspx
Here is a good blog post on layering: https://rbrundritt.wordpress.com/2011/10/13/multiple-pushpins-and-infoboxes-in-bing-maps-v7/
Use could initialize EntityCollection object to add multiple entities to the map at one time.
Example
function GetMap() {
var locations = [
new Microsoft.Maps.Location(60.173783, 24.941068),
new Microsoft.Maps.Location(59.338575, 18.065823),
new Microsoft.Maps.Location(59.922602, 10.749411),
new Microsoft.Maps.Location(55.675817, 12.570452)
];
var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), { credentials: "Bing Maps Key" });
//1. Add pushpins
for (var i = 0; i < locations.length; i++) {
var pin = new Microsoft.Maps.Pushpin(locations[i]);
// Add the pushpin
map.entities.push(pin);
}
//2. Add a polyline
var line = new Microsoft.Maps.Polyline(locations);
map.entities.push(line);
//3. Add a polygon
var polygoncolor = new Microsoft.Maps.Color(100, 100, 0, 100);
var polygon = new Microsoft.Maps.Polygon(locations, { fillColor: polygoncolor, strokeColor: polygoncolor });
map.entities.push(polygon);
var bestview = Microsoft.Maps.LocationRect.fromLocations(locations);
map.setView({ bounds: bestview });
}
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<body onload="GetMap();">
<div id='mapDiv' style="position:relative; width:600px; height:600px;"></div>
</body>

Google V3 Add click Listner

I am new to JavaScript, i want to migrate from Google V2 to Google v3, for this i am just changing methods which are used in V2 slightly all are working but when i am trying to change the addListener from V2 to V3 i am facing problems like in v2 same listener is used to put the marker on the map but when it comes to V3 i am not able to put a marker on the map.Here i am posting v2 code and V3 code.Please help me to over come the problem. V2 is :
GEvent.addListener(map, "click", function(marker, point) {
console.debug('after Click map is '+map+' marker is '+marker+' point is '+point);
if (marker) {
if(PolygonMarkers.length == 1){ //Only one marker in the array
map.removeOverlay(PolygonMarkers[0]);
map.removeOverlay(PolygonMarkers[0]);
PolygonMarkers = [];
if(Polygon){map.removeOverlay(Polygon)};
} else{ /*More then one marker*/
var RemoveIndex = -1;
var Remove;
//Search for clicked Marker in PolygonMarkers Array
for(var m=0; m<PolygonMarkers.length; m++)
{
if(PolygonMarkers[m].getPoint().equals(marker.getPoint()))
{
RemoveIndex = m; Remove = PolygonMarkers[m];
break;
}
}
//Shift Array elements to left
for(var n=RemoveIndex; n<PolygonMarkers.length-1; n++)
{
PolygonMarkers[n] = PolygonMarkers[n+1];
}
PolygonMarkers.length = PolygonMarkers.length-1 //Decrease Array length by 1
map.removeOverlay(Remove); //Remove Marker
geofencedetails.drawPolygon(); //Redraw Polygon
}
allMarkers = PolygonMarkers;
} else {
// Adds a new Polygon boundary marker
var markerOptions = { icon: icon, draggable: true };
var marker = new GMarker(point, markerOptions);
PolygonMarkers.push(marker); //Add marker to PolygonMarkers array
map.addOverlay(marker); //Add marker on the map
GEvent.addListener(marker,'dragstart',function(){ //Add drag start event
marker.setImage(icon.image);
polygon_resizing = true;
});
GEvent.addListener(marker,'drag',function(){
geofencedetails.drawPolygon();
}); //Add drag event
GEvent.addListener(marker,'dragend',function(){ //Add drag end event
marker.setImage(icon.image);
polygon_resizing = false;
geofencedetails.drawPolygon();
});
geofencedetails.drawPolygon();
allMarkers = PolygonMarkers;
}
});`
and V3 is
google.maps.event.addListener(map, "click", function(marker, point) {
if (marker) {
//console.debug('marker '+marker.toSource());
if(PolygonMarkers.length == 1){ //Only one marker in the array
map.removeOverlay(PolygonMarkers[0]);
map.removeOverlay(PolygonMarkers[0]);
PolygonMarkers = [];
if(Polygon){
map.removeOverlay(Polygon)
};
}else { /*More then one marker*/
//console.debug('PolygonMarkers.length is '+PolygonMarkers.length);
var RemoveIndex = -1;
var Remove;
//Search for clicked Marker in PolygonMarkers Array
for(var m=0; m<PolygonMarkers.length; m++){
//console.debug('PolygonMarkers['+m+'] '+PolygonMarkers[m]);
if(PolygonMarkers[m].getPosition().equals(marker.getPosition())){
//console.debug('Both are equal ');
RemoveIndex = m;
Remove = PolygonMarkers[m];
break;
}
}
//Shift Array elements to left
for(var n=RemoveIndex; n<PolygonMarkers.length-1; n++){
PolygonMarkers[n] = PolygonMarkers[n+1];
}
PolygonMarkers.length = PolygonMarkers.length-1 //Decrease Array length by 1
/*map.removeOverlay(Remove); //Remove Marker*/
for (var i = 0; i < allMarkers.length; i++ ) {
allMarkers[i].setMap(null);
}
geofencedetails.drawPolygon(); //Redraw Polygon
}
allMarkers = PolygonMarkers;
} else {
//console.debug('In else block');
// Adds a new Polygon boundary marker
var markerOptions = { icon: icon, draggable: true };
//console.debug('1');
var marker = new GMarker(point, markerOptions);
//console.debug('2');
PolygonMarkers.push(marker); //Add marker to PolygonMarkers array
//console.debug('3');
map.addOverlay(marker); //Add marker on the map
//console.debug('4');
GEvent.addListener(marker,'dragstart',function(){ //Add drag start event
//console.debug('5');
marker.setImage(icon.image);
//console.debug('6');
polygon_resizing = true;
});
GEvent.addListener(marker,'drag',function(){
geofencedetails.drawPolygon();
}); //Add drag event
GEvent.addListener(marker,'dragend',function(){ //Add drag end event
marker.setImage(icon.image);
polygon_resizing = false;
geofencedetails.drawPolygon();
});
geofencedetails.drawPolygon();
allMarkers = PolygonMarkers;
}
});
You need to bind the click event to the marker instead of the map.
google.maps.event.addListener(marker, "click", function(event) { .... } );
UI events within the Google Maps API V3 typically pass an event
argument, which can be accessed by the event listener, noting the UI
state when the event occurred. For example, a UI 'click' event
typically passes a MouseEvent containing a latLng property denoting
the clicked location on the map. Note that this behavior is unique to
UI events; MVC state changes do not pass arguments in their events.

GLatLngBounds - wrong center and zoom level

I'm trying to use GLatLngBounds to make all the markers on the map visible. Below is a small example of what I'm doing.
INV.createMap = function(containerId) {
var map = null;
var geocoder = null;
var bounds = new GLatLngBounds();
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById(containerId), {
size: new GSize(600, 300)
});
map.setCenter(new GLatLng(54.729378425601766, 25.279541015625), 15);
map.addControl(new GSmallZoomControl());
geocoder = new GClientGeocoder();
}
return {
markAdress: function(address, infoContentHtml) {
if (map !== null && geocoder !== null) {
geocoder.getLatLng(address, function(point) {
if (point) {
var marker = new GMarker(point);
GEvent.addListener(marker, 'mouseover', function() {
if (!map.getInfoWindow().getPoint().equals(this.getLatLng())) {
this.openInfoWindowHtml(infoContentHtml);
}
});
map.addOverlay(marker);
bounds.extend(point);
}
});
}
},
finalize: function() {
map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
}
};
};
Usage:
var m = INV.createMap('whatever');
var addresses = ...
for (var i = 0, l = addresses.length; i < l; i++) {
m.markAdress('address...', 'htmlInfo...');
}
m.finalize();
The problem is that the zoom level is completely wrong (waaay too zoomed out) and the markers appear on the left top corner of the map for some reason (but all of them are visible).
What am I doing wrong?
EDIT: Ignore this question. I've made a stupid mistake - I overlooked the fact that GClientGeocoder makes asynchronous requests so the finalize() method is called too early.
The last argument of the function call below specifies the zoom level:
map.setCenter(new GLatLng(54.729378425601766, 25.279541015625), 15);
This article talks a bit about zooming. So the zooming level is a bit too high.
Further this tutorial tells you how to fit the map zooming to properly display a set of markers.
Hope this helps

Categories

Resources