Leafletjs dynamically bound to visible markers/clusters - javascript

This is related to a previous question: Leafletjs dynamically bound map to visible overlays.
I am now using the Leaflet.FeatureGroup.SubGroup plugin with the Leaflet.markercluster plugin. Trying to set map bound to all visible markers and marker clusters. I am using 3 co-ordinates to test:
[43.6425657, -79.38705569999999]
[43.7164673, -79.3395846]
[-41.3142772, 174.8135975]
This is the code so far:
var map = L.map("mapid");
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(map);
map.setView([43.6532, -79.3832], 2);
var parentGroup = L.markerClusterGroup().addTo(map),
consultingMarkers = L.featureGroup.subGroup(parentGroup).addTo(map),
otherMarkers = L.featureGroup.subGroup(parentGroup).addTo(map);
// subGroup1
L.marker([43.6425657, -79.38705569999999]).addTo(consultingMarkers);
L.marker([43.7164673, -79.3395846]).addTo(consultingMarkers);
// subGroup2
L.marker([-41.3142772, 174.8135975], {icon: otherIcon}).addTo(otherMarkers);
var overlays = {
'consulting': consultingMarkers,
'other': otherMarkers
};
L.control.layers(null, overlays, {
collapsed: false
}).addTo(map);
map.on('overlayadd overlayremove', function () {
var bounds = parentGroup.getBounds(),
southWest = bounds.getSouthWest();
// Fit bounds only if the Parent Group actually has some markers,
// i.e. it returns valid bounds.
if (southWest && !southWest.equals(bounds.getNorthEast())) {
map.fitBounds(parentGroup.getBounds());
}
});
So far, I am running into these problems:
Map does not bound to the [-41.3142772, 174.8135975] co-ordinate
Un-checking the "consulting" layer does not bound the map to the markers from the "other" layer which has the co-ordinate [-41.3142772, 174.8135975].
Update: it seems to have this bounding problem for single markers. I tried adding another marker co-ordinate [43.76089289999999, -79.4103427] which would be in the cluster. But if I remove "consulting" cluster and remove "other" layer. The map still does not bound to the last marker left on the map.

If I understand correctly, you are puzzled because when one of your SubGroups has only 1 marker, the map.fitBounds does not look to be executed?
In that case, that is simply the expected behaviour of the !southWest.equals(bounds.getNorthEast()) check: it avoids executing the next block when bounds represents a null area, i.e. there is 0 or 1 marker into it.
By replacing the check by bounds.isValid(), you avoid only the case when there is 0 marker, but in the case there is exactly 1 marker, it will allow executing the next block, therefore trying to fit bounds on a null area. In such case, Leaflet pans to that single marker and zooms to maxZoom.
map.on('overlayadd overlayremove', function () {
var bounds = parentGroup.getBounds();
if (bounds.isValid()) {
map.fitBounds(bounds);
}
});
Demo: https://jsfiddle.net/3v7hd2vx/355/

Related

Leaflet: remove previous layer and add new click layer when zoom is same

i have a click function for the data in the sidebar called 'zoomMarker'. when one of the data in the sidebar, it will panTo and show the marker. its working already but whenever i have zoom that is equal to maxzoom, the previous marker is not removing but its overlapping.
i need to remove the previous layer when i click another data in the sidebar. is there other way to remove the previous layer?
var maxZoom = findMapNo(no).map.setZoom(11);
var Oldzoom = findMapNo(no).map.getZoom();
marker = L.marker(latLng, {icon: customIcon}).bindTooltip(tooltp).addTo(groupMarker);
if(Oldzoom == maxZoom._zoom){
markerChecker = 0;
if(findMapNo(no).map.hasLayer(marker)){
findMapNo(no).map.removeLayer(marker);
}
console.log("add");
findMapNo(no).map.removeLayer(markersCluster);
findMapNo(no).map.addLayer(marker);
findMapNo(no).map.panTo(latLng);
findMapNo(no).map.openPopup(popup);
}

Hide markers from google maps when click an external link and only show its corresponding marker

How do i change my center for google maps with a link and remove other markers? i have this code
https://jsfiddle.net/m9ugbc7h/
So, i need to create a link for example
Ventura
In this case the function must change google maps center to focus the "ventura" marker and hide the other markes and when the user clicks on
Dolphinaris
the zoom will change and will hide every other marker and show only the ones of Dolphinaris
Thanks in advance
Make map visible outside of jQuery(document).ready.
Create var markers = []; array.
When crating markers, add custom property name to it, and push marker into markers array:
var marker = new google.maps.Marker({
position: new google.maps.LatLng(21.0241839, -86.8148164),
map: map,
visible: true,
icon: ventura,
name: 'ventura',
});
markers.push(marker);
On click, invoke resetMap() function:
Ventura
Inside resetMap function, set center and zoom to map, iterate markers, matching them by custom property name - matched one set visible, others set to invisible.
function resetMap(lat, lon, zoom, name) {
var newPos = new google.maps.LatLng(lat, lon);
map.setCenter(newPos);
map.setZoom(zoom);
markers.forEach(function(marker) {
if(marker.get('name') == name)
{
console.log('match');
marker.setVisible(true);
}
else
{
marker.setVisible(false);
}
});
Working fiddle: https://jsfiddle.net/m9ugbc7h/1/
EDIT:
Question: "is there any way to change smoothly the zoom and coordinates?"
Yes, use method:
panTo(latLng:LatLng|LatLngLiteral)
Changes the center of the map to the given LatLng. If the change is
less than both the width and height of the map, the transition will be
smoothly animated.
https://developers.google.com/maps/documentation/javascript/reference?csw=1
EDIT 2:
Implementing panTo is easy:
map.panTo(newPos);
instead of:
map.centerTo(newPos);
but as I have faced a bit 'flickering' effect due to hide/show markers that are close on the map, I have added some delay in functions invocation + markers show/hide:
function resetMap(lat, lon, zoom, name) {
var newPos = new google.maps.LatLng(lat, lon);
$.when( map.setZoom(zoom) ).done(function(){
$.when( map.panTo(newPos)).done(function(){
setMarkerVisibility(name);
});
});
}
And showing matched marker is now executed with 300 ms delay:
function setMarkerVisibility(name){
markers.forEach(function(marker) {
console.log(marker.get('name'));
if(marker.get('name') == name)
{
setTimeout(function(){ marker.setVisible(true); }, 300);
}
else
{
marker.setVisible(false);
}
});
}
It looks a bit smoother like this.
Working fiddle: https://jsfiddle.net/m9ugbc7h/3/

Google Map dynamics markers and polylines

The user insert the city of departure and destination in 2 text input, then click on the button to display on the Google Map 2 markers corresponding to the inserted cities and a Polyline between those 2 points.
Here is my code:
//Global array
var pathArray = [];
var cities = [ origin, destination ];
$('#button').on("click", function() {
reverseGeocodeCities(cities);
});
function reverseGeocodeCities(cities) {
$.each(cities, function(index, value) {
geocoder.geocode({'address': value}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
addMarkerCity(results[0].geometry.location);
}
});
});
//Create the polyline just after the loop.
addPolyline();
}
function addMarkerCity(cityPosition) {
var currentMarker = map.addMarker({
position: cityPosition
});
//Add the position of the marker into the global pathArray used by addPolylineCity function.
pathArray.push(currentMarker.getPosition());
}
function addPolylineCity() {
console.log(pathArray); //Display "[]" at the first click.
var polyline = map.drawPolyline({
path: pathArray,
});
I have 2 problems with this code: The first one is, when the user click once on the button, the markers are displayed well on the Google Map but not the polyline between the 2 markers. I have to click twice on the button to make the polyline visible. To create the polyline, I'm using the global array pathArray containing each markers position. It always display an empty array at the first click and then the proper position of the markers after the second click on the button.
The second problem is that I'm doing a simple symbol animation on the created polyline but the flow direction change time to time, if I want to do London to New York, the symbol should slide from London to New york and not the reverse (I removed this part for code simplicity). Please note that I'm using Gmaps wrapper to use Google Map features.
Thanks for your help if you know what I'm doing wrong with my code.
You are creating the polyline first and then the markers, so the polyline does not appear
if (pathArray.length == 2) {
addPolylineCity();
}; //hardcode
An example JSFiddle

Update marker position json Leaflet and WebGLEarth

This question is related to this question: Updating Leaflet Marker Position Every x Seconds with JSON. Only I want to project the map created with Leaflet onto a 3D globe with WebGLEarth. Normally you can combine Leaflet and WebGLEarth by replacing L.map, L.marker and so on with WE.map, WE.marker in your original Leaflet code.
I would like to have the current location of the International Space Station projected on my 3D globe, so I replaced the L.marker in the update_position function of this code...
var cloudmadeUrl = 'http://{s}.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg';
var subDomains = ['otile1','otile2','otile3','otile4'];
var cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 11, subdomains: subDomains});
var map = new L.Map('map', {layers : [cloudmade]}).fitWorld();
var iss;
function update_position() {
$.getJSON('http://open-notify-api.herokuapp.com/iss-now.json?callback=?', function(data) {
console.log(data);
var latitude = data["iss_position"]["latitude"];
var longitude = data["iss_position"]["longitude"];
if (!iss) {
iss = L.marker([latitude,longitude]).bindPopup("I am the ISS").addTo(map);
}
iss.setLatLng([latitude,longitude]).update();
setTimeout(update_position, 1000);
});
}
update_position();
DEMO
...by WE.marker. Unfortunately, the updating of the position doesn't work anymore on my 3D globe, whereas it did work on the 2D map.
I tried adding
setInterval(update_position,2000);
just above update_position();, then the marker gets updated a few times (~5) and then suddenly stops. If I interact with my mouse on the globe by panning, the marker gets updated to its current position and gets updated a few times afterwards, and eventually stops again.
Main Question:
Does anyone know how to fix this so that I have a continuous marker update?
Additional Question:
Ideally I would like the International Space Station track to look like https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=CZML.html&label=Showcases, with a colored path the station travelled in its last orbit around the earth. Any tips on how to do this?
Thanks in advance!
[Edit 23-1-2015:
I managed to update it continuously by making a new variable for iis, namely iis2. Why this works is not clear to my. Unfortunately, all 'old' markerpositions don't dissapear, so I get a blurred marker track.
var iss;
var iis2;
function update_position() {
$.getJSON('http://open-notify-api.herokuapp.com/iss-now.json?callback=?', function(data) {
console.log(data);
var latitude = data["iss_position"]["latitude"];
var longitude = data["iss_position"]["longitude"];
if (!iss) {
iss2 = WE.marker([latitude,longitude]).bindPopup("I am the ISS").addTo(map);
}
iss2.setLatLng([latitude,longitude]).update();
});
}
update_position();
setInterval(update_position,1000);
]
remove the marker
var iss;
var iis2;
function update_position() {
$.getJSON('http://open-notify-api.herokuapp.com/iss-now.json?callback=?', function(data) {
console.log(data);
map.removeLayer(iss2);
var latitude = data["iss_position"]["latitude"];
var longitude = data["iss_position"]["longitude"];
if (!iss) {
iss2 = WE.marker([latitude,longitude]).bindPopup("I am the ISS").addTo(map);
}
iss2.setLatLng([latitude,longitude]).update();
});
}
update_position();
setInterval(update_position,1000);

OpenLayers WMS layer doesn't load

I use the following block of JavaScript to try to show a WMS layer. I'm using OpenLayers 2.8.
The map's base layer (Openstreetmap) shows correctly, it zooms to the correct area, the "pyramid" layer is shown in the layer switcher, but no request to its WMS service is ever made (so the fact that the URL, styles and params are dummies shouldn't matter -- it never even attempts to get them).
OpenLayers does try to get a WMS layer once I pan or zoom far enough so that the Gulf of Guinea is in view (but all my data is in the Netherlands). This suggests a projection problem (WGS84's (0, 0) point is there), but I don't understand why OpenLayers doesn't even try to fetch a map layer elsewhere. My data is in EPSG:3857 (Web Mercator) projection.
/*global $, OpenLayers */
(function () {
"use strict";
$(function () {
$(".map").each(function () {
var div = $(this);
var data_bounds = div.attr("data-bounds");
console.log("data_bounds: " + data_bounds);
if (data_bounds !== "") {
var map = new OpenLayers.Map(div.attr("id"), {
projection: "EPSG:3857"});
var extent = JSON.parse(data_bounds);
var bounds = new OpenLayers.Bounds(
extent.minx, extent.miny,
extent.maxx, extent.maxy);
map.addLayer(
new OpenLayers.Layer.OSM(
"OpenStreetMap NL",
"http://tile.openstreetmap.nl/tiles/${z}/${x}/${y}.png",
{buffer: 0}));
map.addLayer(
new OpenLayers.Layer.WMS(
"pyramid", "http://rasterserver.local:5000/wms", {
layers: "test",
styles: "test"
}, {
singleTile: true,
isBaseLayer: false,
displayInLayerSwitcher: true,
units: 'm'
}));
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToExtent(bounds);
}
});
});
})();
Edit: the 'data_bounds' console print prints (with some added formatting):
data_bounds: {
"minx": 582918.5701295201,
"miny": 6923595.841021758,
"maxx": 821926.9006116659,
"maxy": 7079960.166533174
}
It zooms to the correct region in the north of the Netherlands, so I don't think the problem is there.
Since posting, I found out that if I don't use the OSM layer, and instead use the WMS layer as baselayer, it works. So perhaps there's some incompatibility with a OSM baselayer and a WMS layer added to it? But then I don't get that it does seem to do something near WGS84 (0, 0).
I eventually managed to fix this by giving the map an explicit maxExtent:
var extent = JSON.parse(data_bounds);
var bounds = new OpenLayers.Bounds(
extent.minx, extent.miny,
extent.maxx, extent.maxy);
var map = new OpenLayers.Map(div.attr("id"), {
projection: "EPSG:3857",
maxExtent: bounds
});
Oddly enough this doesn't limit the user's ability to pan and zoom around the world, but it does make the overlay work...

Categories

Resources