Just discovered Leafletjs and loving it. I have been trying to remove all my makers when my json is empty or invalid and I just cant get it right. All the different approches I have tried blink/flash every time my json updates and this is the closest I have managed to get.
Any help would be greatfull. I am taken back at how little examples there are of makers moving and updating without blinking.... and I really dont want to use google maps!
I tried to reset the makers = {}; but this did nothing.
Thank you
data.BMS.forEach(function (obj) {
if (obj.lat !== undefined && obj.lng !== undefined) {
if (!markers.hasOwnProperty(obj.id)) {
markers[obj.id] = new L.Marker([obj.lat, obj.lng], {icon: panicNormal}).addTo(map) .bindTooltip(obj.name,
{
permanent: true,
direction: 'top',
offset: [0, 0]
});
markers[obj.id].previousLatLngs = [];
areaBounds.push([obj.lat, obj.lng]);
} else {
areaBounds.push([obj.lat, obj.lng]);
markers[obj.id].previousLatLngs.push(markers[obj.id].getLatLng());
if(obj.status == "TRUE"){
markers[obj.id].setIcon(panicAlarm);
}else{
if(obj.type == "MO"){
markers[obj.id].setIcon(panicNormal);
}else{
markers[obj.id].setIcon(lora);
}
}
markers[obj.id].setLatLng([obj.lat, obj.lng]);
}
}else{
//How do I remove the markers
}
});
You can use L.FeatureGroup() to add all markers to it and then remove all markers with .clearLayers()
var fg = L.featureGroup().addTo(map);
...
markers[obj.id] = new L.Marker([obj.lat, obj.lng], {icon: panicNormal}).addTo(fg) .bindTooltip
...
}else{
//How do I remove the markers
fg.clearLayers();
}
Related
I'm using Leaflet.Measure for measuring areas and distances and I also have several layers on a map. When you click on a layer, the onclick function is being fired and a popup appears. When I start to measure a new area and click on a map layer, the popup appears again and I cannot measure area further. Is there any possibility to mute layer's interactivity, while I'm using measurement tool?
I tired to import my Angular service class into a measuring plugin to change layer's onclick behaviour, but it didn't work.
Here's a part of Leaflet.Measure plugin code, which I have modified:
import { MapService} from './app/services/map.service';
L.MeasureAction = L.Handler.extend({
_onMouseClick: function (event) {
MapService.enablePopupOpen = false; // if it's set to false, then popup won't open
//default plugin code
var latlng = event.latlng || this._map.mouseEventToLatLng(event);
if (this._lastPoint && latlng.equals(this._lastPoint)) {
return;
}
if (this._trail.points.length > 0) {
var points = this._trail.points;
points.push(latlng);
var length = points.length;
this._totalDistance += this._getDistance(points[length - 2], points[length - 1]);
this._addMeasurePoint(latlng);
//this._addMarker(latlng);
if (this.options.model !== "area") {
this._addLable(latlng, this._getDistanceString(this._totalDistance), "leaflet-measure-lable");
}
} else {
this._totalDistance = 0;
this._addMeasurePoint(latlng);
this._addMarker(latlng);
if (this.options.model !== "area") {
this._addLable(latlng, L.Measure.start, "leaflet-measure-lable");
}
this._trail.points.push(latlng);
}
this._lastPoint = latlng;
this._startMove = false;
},
...
})
After loading geojson polygons, I want to implement a toggle menu to filter by a value. I assume the implementation is similar to this cartodb map which uses SQL statements.
I image I could use a layer-selector and pass a variable from a menu such as District 1.
My code just brings in and styles a layer of 15 polygons. I want to keep this, but add a filter. How is this done in leaflet? Examples much appreciated.
L.mapbox.accessToken = 'pk.eyJ1Ijoic2tvcmFzYXVydXMiLCJhIjoiaEdGTUZWTSJ9.osOC8tWU3bMaNprVNoEu7g';
var lamap = L.mapbox.map('mapid', 'skorasaurus.5eb85050')
.setView([34.000880, -118.04036], 10);
var featLayer = L.mapbox.featureLayer().addTo(lamap);
featLayer.loadURL('citycouncils.geojson');
function getMyColor(myargument) {
if (myargument === '1') {
return '#996767'
};
if (myargument === '2') {
return '#679967'
};
if (myargument === '10') {
return '#672799'
};
if (myargument === '14') {
return '#670099'
};
if (myargument === '15') {
return '#699799'
};
}
// styles each polygon based on its properties in the geojson file, using leaflet's setStyle
featLayer.on('ready', function() {
featLayer.eachLayer(function(polygon) {
polygon.bindPopup('District ' + polygon.feature.properties.DISTRICT);
console.log(typeof setStyle);
polygon.setStyle({
opacity: 0.55,
weight: 2,
opacity: 1,
fillOpacity: 0.55,
fillColor: getMyColor(polygon.feature.properties.DISTRICT),
color: 'white'
});
});
});
As documented filtering a L.mapbox.FeatureLayer is very simple to do. It's just a matter of setting a filter method using the setFilter method of the layer.
Reference of L.mapbox.FeatureLayer's setFilter method:
https://www.mapbox.com/mapbox.js/api/v2.1.5/l-mapbox-featurelayer/#section-featurelayer-setfilter
Complete working example is right on the Mapbox site:
https://www.mapbox.com/mapbox.js/example/v1.0.0/multiple-marker-filters/
I have been able to integrate markers to the mapbox we are using, but still wonder if we can get a click on them. If so how?
Following is my code:
<style>
/*
* Unlike other icons, you can style `L.divIcon` with CSS.
* These styles make each marker a circle with a border and centered text.
*/
.count-icon1 {
background:url(images/redpin.png);
color:#000;
font-weight:600;
text-align:center;
padding:19px 0 0 0px; font-size:180%;
}
.count-icon2 {
background:url(images/greenpin.png);
color:#000;
font-weight:600;
text-align:center;
padding:19px 0 0 0px; font-size:180%;
}
</style>
js code:
var defaultLat = 39.12367;
var defaultLon = -76.81229;
if($scope.currentLocDetails != null){
if($scope.currentLocDetails.Lat != null && $scope.currentLocDetails.Lon != null){
defaultLat = $scope.currentLocDetails.Lat;
defaultLon = $scope.currentLocDetails.Lon;
}
}
var x = 0;
if(map != null)
map.remove();
map = L.mapbox.map('map_view', 'your key here').setView([defaultLat, defaultLon], 9);
for (var i = 0; i < responseData.JobLocation.length; i++) {
var eachObj = responseData.JobLocation[i];
if(eachObj.Lat != null && eachObj.Lon != null){
x++;
// Use a little math to position markers.
// Replace this with your own code.
L.marker([
eachObj.Lat,
eachObj.Lon
], {
icon: L.divIcon({
// Specify a class name we can refer to in CSS.
className: ((currentSelectedIndex + 1) == i + 1)?'count-icon1':'count-icon2',
// Define what HTML goes in each marker.
html: i + 1,
// Set a markers width and height.
iconSize: [65, 94]
})
}).addTo(map);
}
}
I tried doing a bit R & D, but get to no where:
We need to use featureLayer, but dunno how.
For the click feature we need to follow this code, but how?
// Listen for individual marker clicks.
myLayer.on('click',function(e) {
// Force the popup closed.
e.layer.closePopup();
var feature = e.layer.feature;
var content = '<div><strong>' + feature.properties.title + '</strong>' +
'<p>' + feature.properties.description + '</p></div>';
info.innerHTML = content;
});
Any help with this is really appreciated.
Thanks
I believe there are various ways of doing this with Mapbox, unfortunately I don't have access to my project where I use it right now so I'm just going off the Mapbox documentation.
Following your example this looks the simplest - if you have added marker, for example:
var marker = L.marker([43.6475, -79.3838], {
icon: L.mapbox.marker.icon({
'marker-color': '#9c89cc'
})
})
.bindPopup('<p>Your html code here</p>')
.addTo(map);
You can pass whatever HTML you want in the bindPopup argument.
https://www.mapbox.com/mapbox.js/example/v1.0.0/clicks-in-popups/
Then it should be be pretty simple via 'addEventListener('click', function)' on that marker variable.
Or alternatively -
myLayer.on('click', function(e) {
resetColors();
e.layer.feature.properties['old-color'] = e.layer.feature.properties['marker-color'];
e.layer.feature.properties['marker-color'] = '#ff8888';
myLayer.setGeoJSON(geoJson);
});
map.on('click', resetColors);
Effectively add an event listener on the map variable - and then listen to what you've clicked on via the event argument passed to the event listener.
This may be useful: https://www.mapbox.com/mapbox.js/example/v1.0.0/change-marker-color-click/
Good luck!
I have two layers and switcher in openlayers. After init immediately I would like to set second layer to be visible, but still showed first added layer.
I tried: setVisibility, setBaseLayer, but without successful.
Here is part of code:
var gmapLayer = new OpenLayers.Layer.Google("Google sattelite", { type: google.maps.MapTypeId.SATELLITE, visibility: false });
var gmapStreetLayer = new OpenLayers.Layer.Google("Google streets", { visibility: false });
map.addLayer(gmapLayer);
map.addLayer(gmapStreetLayer);
map.addControl(new OpenLayers.Control.LayerSwitcher());
After init I tried:
map.setBaseLayer(selLayer);
//or
selLayer.setVisibility(true);
Ok I found problem. I used setBaseLayer wrong because called to array see:
var selLayer = map.getLayersByName(selectedLayer);
if (selLayer !== null) {
map.setBaseLayer(selLayer); //<---Wrong
}
Right solutions is:
var selLayer = map.getLayersByName(selectedLayer);
if (selLayer !== null) {
map.setBaseLayer(selLayer[0]); //<--Good
}
I spent this morning searching something simple but same time flexible to use for courier delivery like small companies or groups / to organize them selves and order/destinations in a map. While I gave up for searching after few hours going through trillion posts :) and reviewing many commercial software's. I spent last hour making my own and got my self working application however many questions raised in my mind so I was thinking to start opensource project of it and with this short intro and following code to share it with you guys, hoping that perhaps I find some good answers or great ideas. How to make it efficient to use on any browser, any device including over Mobile Internet . :).
I'm stuck with finding proper way how to keep map up to date basically in real-time.
setInterval!? Anyhow all my browsers freeze and stop updating after some period of time while I expect it to run 24/7/365 if needed. I would really appreciated if somebody can lead me at least right direction to make this sync more stable.
thanks advance!
Clobal Gonfig
/***********************************
* Config
************************************/
/* Master Server */ var master_server = {
url : 'https://0.0.0.0/',
status : false,
connectionFail : "Connection to Master Server Failed"
}
/* Slave Server */ var slave_server = {
url : 'https://0.0.0.0/',
status : false,
connectionFail : "Connection to Slave Server Failed"
}
/* Sync controller */ var sync_controller = '/datasync/';
/* Sync actions */
var sync_action = {
updateLatLng : 'updatewithgeo/'
}
/***********************************/
var car = false;
var order = false;
var order_icon = "static_icon.png";
var customMsg = {
PositionFail : "Because Default lat lng and getCurrentPosition are not set app will not try to sync! It will try again shotwhile"
}
// Can define default lat lng
var lat = false;
var lng = false;
/***********************************/
App
function syncData()
{
//Temporarly clearing markers to avoid marker[$i] to be duplicated if position is changed
if(markers){$('#map_canvas').gmap('clear', 'markers');}
// Exhange data with server
$('#map_canvas').gmap('getCurrentPosition', function(position, status) {
if ( status === 'OK' ) {
lat = position.coords.latitude;
lng = position.coords.longitude;
}
if (!lat){
console.log(customMsg.PositionFail);
setTimeout('syncData()', 10000);
throw new Error(customMsg.PositionFail);
return;
}
$.post(master_server.url+sync_controller+sync_action.updateLatLng, {latlng : lat+"#"+lng}, function(data, Server_1_Status) {
if(Server_1_Status != 'OK')
{
// If request to master server then here would be place to connect to slave server(s)
console.log(master_server.connectionFail);
setTimeout('syncData()', 10000);
throw new Error(master_server.connectionFail);
return;
}
// If there is no errors
$.each( data.couriers, function(i, courier) {
// If markers are identified correctly when they are returned from server
// then addMarker should only add new markers and
// existing markers shuld be updated (setPosition)
$('#map_canvas').gmap('addMarker', {
'position': new google.maps.LatLng(courier.latitude, courier.longitude),
'bounds': true,
'icon' : courier.icon,
'title' : courier.name
}).click(function() {
$('#map_canvas').gmap('openInfoWindow', { 'content': courier.content }, this);
});
});
$.each( data.orders, function(i, order) {
$('#map_canvas').gmap('addMarker', {
'position': new google.maps.LatLng(order.latitude, order.longitude),
'bounds': true,
'title' : order.address,
'icon' : ""
}).click(function() {
// Populating order view and forms to take / confirm delivery and send digital signature
$('#OrderViewTitle').html('<h1>'+order.orderID+order.address+'</h1>');
$('#OrderData').html('<p><b>'+order.customerID+'</b><br><b>Order:</b>'+order.salesorder+'</p>');
document.getElementById('TakeDelivery').value = order.orderID;
document.getElementById('DeliveryComplete').value = order.orderID;
$('#OrderView').popup("open");
});
});
}, "json");
$('#map_canvas').gmap('refresh');
setTimeout('syncData()', 10000);
});
}
$(document).ready(function() {
courierApp.add(function() {
$('#map_canvas').gmap().bind('init', function() {
syncData();
});
}).load();
});