How to select which layer to show on a map? - leaflet

If I had an array of layers added to my map, i.e.:
for (i = 0; i < myoptionsArray.length; i++) {
lyr = L.tileLayer.wms(url, {optionsArray[i]});
layer.push(lyr);
lyr.addTo(mymap);
}
how can I select programmatically which layer[i] to show? I can't find any available function in Leaflet docs...

Add your layer to a featureGroup when you create it. A great idea is to add a name to your layer so it will be simpler to get it after :
var group = new L.featureGroup();
for (i = 0; i < myoptionsArray.length; i++) {
lyr = L.tileLayer.wms(url, {optionsArray[i]});
layer.push(lyr);
layer.name = 'My_layer ...';
lyr.addTo(group);
}
mymap.addLayer(group);
In this example, for me, each iteration provide a layer. You add it to your group and wait the end of the loop to add it to the map.
To show or hide you will need this function :
function showHideTile(tileToShowOrHide)
{
group.eachLayer(function(layer) {
layer.eachLayer(function(yourLayer) {
//Do your test here
if (yourLayer == tileToShowOrHide) {
//To add the layer to your map
map.addLayer(yourLayer);
} else {
//To remove the layer
map.removeLayer(yourLayer);
}
//You can also send an array to this function
//With the layer name and what you want to do
//Ex : tile1 hide
})
})
}
Not the best way but it will give you something to start with.

I did this way.
1- load the layers into the group:
var group = new L.featureGroup();
for (i = 0; i < myoptionsArray.length; i++) {
lyr = L.tileLayer.wms(url, {optionsArray[i]});
layer.push(lyr);
lyr.addTo(group);
}
mymap.addLayer(group);
2 - Then I added a function to show the layer I need:
function showLayer(i) {
layer[i].bringToFront();
}

Related

marker with polyline while dragging the marker using leaflet

Hi I have connection between marker with polyline like this Image .
I am attaching a sample here.
How Can I make drag possible that when I drag the the marker with polyline.
example , If I drag the marker 3 it should also update the polyline point and where ever I put the marker 3 polyline should connect with marker 3.
I need this type of drag event that can update the polyline also when dragging the marker.
I am using leaflet for this purpose but still unable to solve the dragging logic of marker with polyline.
Here is the sample code I am using
$http.get("db/getConnectionData.php").then(function (response) {
$scope.links1 = response.data.records;
// $scope.showArrow();
angular.forEach($scope.links1, function(value, i) {
var source_panoId = $scope.links1[i].s_panoId;
var dest_panoId = $scope.links1[i].d_panoId;
var sPanoID = $scope.links1[i].sourcePano_id;
var dPpanoID = $scope.links1[i].destPano_id;
angular.forEach($scope.panoramas, function(value, index) {
if($scope.panoramas[index].panoId == source_panoId){
if($scope.links.indexOf($scope.panoramas[index])== -1){
$scope.links.push($scope.panoramas[index]);
}
var SlatLang = $scope.panoramas[index].project_latLng ;
var SLatLngArr = SlatLang.split(",");
var Slat = parseFloat(SLatLngArr[0]);
var Slang = parseFloat(SLatLngArr[1]);
var polypoint1 = [Slat, Slang];
angular.forEach($scope.panoramas, function(value, index1) {
if($scope.panoramas[index1].panoId == dest_panoId){
if($scope.links.indexOf($scope.panoramas[index1])== -1){
$scope.links.push($scope.panoramas[index1]);
}
var DlatLang = $scope.panoramas[index1].project_latLng ;
var DLatLngArr = DlatLang.split(",");
var Dlat = parseFloat(DLatLngArr[0]);
var Dlang = parseFloat(DLatLngArr[1]);
var polypoint2 = [Dlat, Dlang];
// Draw seperate polyline for each connection
polyline = L.polyline([[Slat, Slang],[Dlat, Dlang]],
{
color: 'blue',
weight: 5,
opacity: .7,
}
).addTo(map);
$scope.polycoords.push(polyline);
}
});
}
});
Here is the code that I am using to make drag of marker with polyline
angular.forEach($scope.panoramas, function(value, index4){
$scope.markers[index4].on('dragstart', function(e){
var latlngs = polyline.getLatLngs(),
latlng = $scope.markers[index4].getLatLng();
for (var i = 0; i < latlngs.length; i++) {
if (latlng.equals(latlngs[i])) {
this.polylineLatlng = i;
}
}
});//dragstart
$scope.markers[index4].on('drag', function(e){
var latlngs = polyline.getLatLngs(),
latlng = $scope.markers[index4].getLatLng();
latlngs.splice(this.polylineLatlng, 1, latlng);
polyline.setLatLngs(latlngs);
});//drag
$scope.markers[index4].on('dragend', function(e){
delete this.polylineLatlng;
});//dragEnd
});
First, when creating the marker, remember to pass the draggable option as true, like this:
var marker = L.marker(latLng, { draggable: true });
Now, check which drag event you want to attach a listener to and then call the redraw function of the polyline inside the callback, like this:
// var polyline defined somewhere
marker.on('drag', function (e) {
polyline.redraw();
});
If this doesn't work, please provide sample code so we can work around with it.
Edit
You also need to change the coordinates of the polyline, otherwise redraw will do nothing. Check out this answer on SO and see if it fits your needs.
Edit 2
You're using an array of polylines while the answer just uses one polyline which has the array of coordinates, so in your case you need to use two loops to accomplish the same task. You can make this faster and maybe use an object as a lookup table to get the right polyline for each marker, for example, like this:
var table = {};
// ...
table[marker] = polyline;
Then later you can get the polyline used for each marker. But anyway, here's what I think would work in your case the way it is in the sample (it was a little hard to understand but I hope it works for you).
I don't know where you are putting the second part of your sample (the event handlers) but I assume it's not inside the double loop that is creating the polylines, right? So this is what I came up with:
marker.on('dragstart', function (e) {
var markerLatLng = marker.getLatLng();
this.polylineLatLngs = [];
for (var i = 0; i < $scope.polycoords.length; i++) {
var polyline = $scope.polycoords[i];
var latLngs = polyline.getLatLngs()
for (var j = 0; j < latLngs.length; j++) {
if (markerLatLng.equals(latLngs[j])) {
this.polylineLatLngs.push([i, j]);
}
}
}
});
marker.on('drag', function (e) {
for (var i = 0; i < this.polylineLatLngs.length; i++) {
var polyline = $scope.polycoords[this.polylineLatLngs[i][0]];
var latLngs = polyline.getLatLngs();
var markerLatLng = marker.getLatLng();
latLngs.splice(this.polylineLatLngs[i][1], 1, markerLatLng);
polyline.setLatLngs(latLngs);
}
});
I am getting this type of behavior. Please let me know how I can solve this .
Thank you for your time.
This is the polyline created by getting data from db or by making the connection between panorama.
This Image when I start dragging the marker 2 I got the result like this
This image when I dragged the marker 3.
This type of result I am getting using the source code you provided above.

How to get selected layers in control.layers?

Is there a way to select all selected layers in the control.layers with leaflet api?
I can do it with the help of jquery like this :
$('.leaflet-control-layers-selector:checked')
But maybe there is an api?
Thanks
There is no API for that but you could easily create one yourself:
// Add method to layer control class
L.Control.Layers.include({
getActiveOverlays: function () {
// Create array for holding active layers
var active = [];
// Iterate all layers in control
this._layers.forEach(function (obj) {
// Check if it's an overlay and added to the map
if (obj.overlay && this._map.hasLayer(obj.layer)) {
// Push layer to active array
active.push(obj.layer);
}
});
// Return array
return active;
}
});
var control = new L.Control.Layers(...),
active = control.getActiveOverlays();
Based on iH8's answer
L.Control.Layers.include({
getOverlays: function() {
// create hash to hold all layers
var control, layers;
layers = {};
control = this;
// loop thru all layers in control
control._layers.forEach(function(obj) {
var layerName;
// check if layer is an overlay
if (obj.overlay) {
// get name of overlay
layerName = obj.name;
// store whether it's present on the map or not
return layers[layerName] = control._map.hasLayer(obj.layer);
}
});
return layers;
}
});
Now you can use
var control = new L.Control.Layers(...)
control.getOverlays(); // { Truck 1: true, Truck 2: false, Truck 3: false }
I find this a little more useful because
all the layers are included
the key is the name of the layer
if the layer is showing, it has a value of of true, else false

How to remove L.rectangle(boxes[i])

I few days ago I implement a routingControl = L.Routing.control({...}) which works perfect for my needs. However I need for one of my customer also the RouteBoxer which I was also able to implement it. Now following my code I wants to remove the boxes from my map in order to draw new ones. However after 2 days trying to find a solution I've given up.
wideroad is a param that comes from a dropdown list 10,20,30 km etc.
function routeBoxer(wideroad) {
this.route = [];
this.waypoints = []; //Array for drawBoxes
this.wideroad = parseInt(wideroad); //Distance in km
this.routeArray = routingControl.getWaypoints();
for (var i=0; i<routeArray.length; i++) {
waypoints.push(routeArray[i].latLng.lng + ',' + routeArray[i].latLng.lat);
}
this.route = loadRoute(waypoints, this.drawRoute);
}; //End routeBoxer()
drawroute = function (route) {
route = new L.Polyline(L.PolylineUtil.decode(route)); // OSRM polyline decoding
boxes = L.RouteBoxer.box(route, this.wideroad);
var bounds = new L.LatLngBounds([]);
for (var i = 0; i < boxes.length; i++) {
**L.rectangle(boxes[i], {color: "#ff7800", weight: 1}).addTo(this.map);**
bounds.extend(boxes[i]);
}
console.log('drawRoute:',boxes);
this.map.fitBounds(bounds);
return route;
}; //End drawRoute()
loadRoute = function (waypoints) {
var url = '//router.project-osrm.org/route/v1/driving/';
var _this = this;
url += waypoints.join(';');
var jqxhr = $.ajax({
url: url,
data: {
overview: 'full',
steps: false,
//compression: false,
alternatives: false
},
dataType: 'json'
})
.done(function(data) {
_this.drawRoute(data.routes[0].geometry);
//console.log("loadRoute.done:",data);
})
.fail(function(data) {
//console.log("loadRoute.fail:",data);
});
}; //End loadRoute()
Well, my problem is now how to remove previously drawn boxes in order to draw new ones because of changing the wideroad using a dropdown list. Most of this code I got from the leaflet-routeboxer application.
Thanks in advance for your help...
You have to keep a reference to the rectangles so you can manipulate them (remove them) later. Note that neither Leaflet nor Leaflet-routeboxer will do this for you.
e.g.:
if (this._currentlyDisplayedRectangles) {
for (var i = 0; i < this._currentlyDisplayedRectangles.length; i++) {
this._currentlyDisplayedRectangles[i].remove();
}
} else {
this._currentlyDisplayedRectangles = [];
}
for (var i = 0; i < boxes.length; i++) {
var displayedRectangle = L.rectangle(boxes[i], {color: "#ff7800", weight: 1}).addTo(this.map);
bounds.extend(boxes[i]);
this._currentlyDisplayedRectangles.push(displayedRectangle);
}
If you don't store a reference to the L.rectangle() instance, you obviously won't be able to manipulate it later. This applies to other Leaflet layers as well - not storing explicit references to Leaflet layers is a usual pattern in Leaflet examples.

Leaflet Marker Cluster add weight to marker

I have a leaflet map and I am using the Leaflet.markerCluster plugin to cluster my markers. I have some markers that represent multiple points on the same location. Unfortunately when it gets clustered it only represents one single point. Is there a way to add a weight to each marker? So that the cluster sees it as more than one point?
Basically I am hoping for a clusterWeight property like the follwing:
var newMarker = L.marker(coordinates, {
icon: myIcon,
clusterWeight: 5
});
This propety does not exist however. Anyoneknow of a work around? Thanks!
First you will need to create a marker that supports custom properties. You can do this by extending the default L.Marker like so:
var weightMarker = L.Marker.extend({
options: {
customWeight: 0
}
});
Then you can make use of Leaflet.markercluster's iconCreateFunction to create a custom cluster marker, by changing what is displayed on the marker:
var markers = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
// iterate all markers and count
var markers = cluster.getAllChildMarkers();
var weight = 0;
for (var i = 0; i < markers.length; i++) {
if(markers[i].options.hasOwnProperty("customWeight")){
weight += markers[i].options.customWeight;
}
}
var c = ' marker-cluster-';
if (weight < 10) {
c += 'small';
} else if (weight < 100) {
c += 'medium';
} else {
c += 'large';
}
// create the icon with the "weight" count, instead of marker count
return L.divIcon({
html: '<div><span>' + weight + '</span></div>',
className: 'marker-cluster' + c, iconSize: new L.Point(40, 40)
});
}
});
Demo: https://jsfiddle.net/chk1/0hq1t13t/

Dynamically Generated Telerik MVC3 Grid - Add Checkboxes

I have a grid that is dynamically generated based on search criteria. I render the grid in a partial view using Ajax. That all works fine.
I now need to add a checkbox column as the first column.
Also, how do I get filtering, sorting paging etc. to work now since it is in a partial view.
When i click on a header to sort I get a Page not found error and the filter Icon doesnt do anything.
And one more thing. When I try to add a GridCommandColumnSettings to the grid I get the error
"Invalid initializer member declarator"
Code is below for the gridcolumnsettings
public GridColumnSettings[] NewColumns(DataTable fullDT)
{
GridColumnSettings[] newColumns = new GridColumnSettings[fullDT.Columns.Count];
for (int i = 0; i < fullDT.Columns.Count; i++)
{
// set the visibility property for the DeliveryID
bool boolDeliveryID;
if (fullDT.Columns[i].ColumnName == "DeliveryID")
boolDeliveryID = false;
else
boolDeliveryID = true;
newColumns[i] = new GridColumnSettings
{
new GridCommandColumnSettings
{
Commands =
{
new GridEditActionCommand(),
new GridDeleteActionCommand()
},
Width = "200px",
Title = "Commands"
},
Member = fullDT.Columns[i].ColumnName,
Title = fullDT.Columns[i].ColumnName,
Visible = boolDeliveryID,
Filterable = true,
Sortable = true
};
}
return newColumns;
}
Any suggestions would be appreciated.
Thanks
I edited my post to add my partial for the Grid
Here is my partial for the grid
#(Html.Telerik().Grid<System.Data.DataRow>(Model.Data.Rows.Cast<System.Data.DataRow>())
.Name("Grid")
.Columns(columns =>
{
columns.LoadSettings(Model.Columns as IEnumerable<GridColumnSettings>);
})
.DataBinding(dataBinding => dataBinding.Ajax().Select("_DeliveryManagerCustomBinding", "Deliveries"))
.EnableCustomBinding(true)
.Resizable(resize => resize.Columns(true))
)
I don't add columns this way when I use the Telerik Grid control, but looking at what you're doing I would hazard a guess to say you will need to do something like the following:
increase the size of the newColumns array by 1 (because we're going to add in the checkbox column):
GridColumnSettings[] newColumns = new GridColumnSettings[fullDT.Columns.Count + 1];
if you want it at the beginning you will need to do the following before your for-loop:
GridColumnSettings s = new GridColumnSettings() {
ClientTemplate("<input type=\"checkbox\" name=\"checkeditems\" value=\"some value\" />")
Title("title goes in here")
};
Then you will add it into your array:
newColumns[0] = s;
and then increase the start index for your for-loop to 1:
for (int i = 1; i < fullDT.Columns.Count; i++)
the checkbox column will go at the beginning