Leaflet Maps: How to create an overlay with key/value pairs using the contents from an array? - javascript

In my project, when I load a page I pull a list of overlay names from the database, these are stored in a JS Array.
Using the default code below, how do I fill the overlayMaps with contents from an array rather than hard coding what the values will be:
var overlayMaps = {
"Cities": cities,
"Towns": towns
};
So as an example, instead of creating overlayMaps with the hard coded values Cities & Towns, I need to pull these values from an array that gets its data from the DB, The array in leymans terms might look like this under the hood:
[ "MyValue1": myvalue1,"MyValue2": myvalue2, "MyValue2": myvalue2,] etc
Maybe I need to create a dictionary, although I have no experience doing this in JS, only in C#
Am using guide: https://leafletjs.com/examples/layers-control/

Solution:
Reading the leaflet API instructions, you can actually add a single item to an L.control
one at a time using the command addOverlay( layer, name). Adds an overlay (checkbox entry) with the given name to the control. For demo purposes below, I'm using the same value var cities for each of the three checkboxes, but to show how we add the individual items from the array, we're looping through this array and adding the items one at a time.
var littleton = L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.'),
denver = L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.'),
aurora = L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.'),
golden = L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.');
var cities = L.layerGroup([littleton, denver, aurora, golden]);
var places = new Array()
places.push("Cities");
places.push("Towns");
places.push("MyPlaces");
var lControl = L.control.layers(null, null);
lControl.addTo(map);
places.forEach(myFunction);
function myFunction (item) {
lControl.addOverlay(cities, '' + item + '');
}

Related

How do I split/slice a leaflet L.layerGroup into mutliple L.layerGroup(s)?

I'm using leafletjs to draw a line from marker to marker. But the markers are grouped into sets, each with its own name. I get the data from MySQL with PHP and create;
var OBJMarkerList = L.layerGroup([W0DLK01,W0DLK02,W0DLK03,W0DLK04,W0DLK05,WA0TJT01,WA0TJT02,WA0TJT03,WA0TJT04,WA0TJT05,WA0TJT06,WA0TJT07,WA0TJT08,WA0TJT09,]);
Notice the name changes.
But I need to pass it into a function one part at a time in order to change the color of the line. So while I have the above OBJMarkerList what I really need is;
var W0DLKOBJMarkerList = L.layerGroup([W0DLK01,W0DLK02,W0DLK03,W0DLK04,W0DLK05,]);
And another for the other set of values, WA0TJTOBJMarkerList.
I created an array of the names;
const allnameBounds = (['W0DLKOBJMarkerList','WA0TJTOBJMarkerList']);
But its literally just the names and the function (below) will not accept it as input to convert to the x,y coordinates I need.
function connectTheDots(data){
var c = [];
for(i in data._layers) {
var x = data._layers[i]._latlng.lat;
var y = data._layers[i]._latlng.lng;
c.push([x, y]);
}
return c;
}
How can I split the L.layerGroup into two or any number of parts based on the variable names given? There will usually be more than just two, this is a simplified example.
I tried iterating over the allnameBounds array in all the usual ways and while the looping works to extract the name, the function does not process it like the leaflet object it is.
I also went back to the MySQL/PHP and tried to create a stand alone for each name, that's fine but I still need another list of the L.layerGroup names to iterate over.
Spliting or slicing the combined seemed the only answer. I just don't know how to get there.
Can someone give me a better way or show me how to split the overall list?

Is there a way to push key value pairs in google earth engine in a loop that is using the map() function?

I am doing a spatiotemporal analysis of LULC on google earth engine.
For this, I have imported Landsat 5 tier 1 TOA reflectance images and filtered them by my preference. Following this I was able to extract the id values of the features in the filtered image collection, I need to create a dictionary in order to be able to assign the unique names from ID extracted by slicing the ID's and assign a value(id itself) to each pair.
The id obtained of images in an image collection is of the type: LANDSAT/LT05/C01/T1_TOA/LT05_148045_19890509
in this,
key:19890509
value:LT05_148045_19890509
both of which can be obtained from slicing the obtained ID
I have filtered the image collection and tried to create a dictionary as follows but it creates an empty dictionary.
// Create a list of image objects.
var imageList = Collection.toList(100);
print('imageList', imageList);
// Extract the ID of each image object.
var dicty = ee.Dictionary({}); //def dict for names
var id_list = imageList.map(function(item) {
var list_nm = ee.Image(item).id();
var lst_nm_slice = ee.Image(item).id().slice(-8,-1);
dicty.lst_nm_slice = list_nm;
return dicty;
});//end of map function
I expect the output of dicty to be a dictionary of key-value pairs with each key value getting assigned dynamically in the aforementioned loop so that I can call the images by using the dictionary key value pairs.
Generally speaking, you want to provide an iterable object to .map() and you get out an iterable like object with the original length (that function applied to each item). Earth Engine processes the function provided into .map() in parallel making it difficult to push values to a single variable in memory within that function. So, a solution to this is to set the ID values that you extract within the function to each image in the collection as a property and then outside of the function get the names and ids of the image into a dictionary. Here is a working code example:
// Create an ImageCollection and filter by space and time
var Collection = ee.ImageCollection('LANDSAT/LT05/C01/T1_TOA')
.filterDate('1990-01-01','1991-01-01')
.filterBounds(ee.Geometry.Point([86.5861,34.7304]));
print('LT5 Image Collection', Collection);
// Extract the ID of each image object and set as property
// within for each image in the collection
var Collection = Collection.map(function(img) {
var img_id = img.id();
var id_slice = img_id.slice(-8);
return img.set('id',id_slice);
});//end of map function
// Get the image IDs and names as lists from the collection
var ids = ee.List(Collection.aggregate_array('id'));
var names = ee.List(Collection.aggregate_array('system:index'));
// Build dictionary from each image ID and name
var out_dict = ee.Dictionary.fromLists(ids,names);
print('Output Dictionary',out_dict);

Append Key/Value pair to L.Control.layer in Leaflet

Here is a simplified example of my "issue."
I have a list of key/value pairs like this:
var baseMaps = {"thing1": thing1,
"thing2": thing2};
var overlayMaps = {"OverLay1": link to overlay2
"Overlay2": link to overlay2};
etc...........
I can uses this code to add on to my object list:
overlayMaps["New Item"] = link to new item;
I verify on the console that it's added to the overlayMaps list.
Issue: It does not show up in the box on the side of the map like all the other ones. They are in a box with little check marks by them to turn them on and off. Am I missing some code to do this? It seems like I need a way to refresh the layer group list.
Assuming the rest of your code is as per the example in documentation.
L.control.layers(baseLayers, overlays).addTo(map);
The problem is you've lost reference to the control instance because didn't assign it to anything. Since the addTo method is chainable it will give you the control.
var layerControl = L.control.layers(baseLayers, overlays).addTo(map);
Now you can access it in your code and run its methods like layerControl.addBaseLayer

jQuery loop to put together multiple arrays - Mapbox map.setFilter()

Mapbox's new GL API is proving difficult to use. I'm wondering if I can build an array with this strange format through jQuery's each function.
I'm creating a form with checkboxes for categories that would filter the markers shown on the map. I'm using a $.each() loop to grab the checked inputs, get their ID, and throw it in the middle of each array. One checked input is one array.
Basically, I need the array to be put together as such:
map.setFilter('markers', ["any",
['in',c1,true],
['in',c2,true], // these 3 arrays
['in',c3,true]
] );
But obviously, I need this done dynamically on check. Here's the incomplete jQuery I'd like to use:
jQuery('input.checkbox-child').change(function(){
args = new Array();
jQuery('input.checkbox:checked').each(function(){
id = jQuery(this).attr('id');
filter = ['in',id,true];
// ???
});
map.setFilter('markers', ["any", args] );
});
Not sure how I would join the filter variables together to form a comma-separated list of arrays, similar to ['in',id,true],['in',id,true],['in',id,true]... for use in the setFilter function.
I think this should work for what you want
var args = [];
jQuery('input.checkbox-child').change(function(){
jQuery('input.checkbox:checked').each(function(){
var id = jQuery(this).attr('id');
var filter = ['in',id,true];
args.push(filter);
});
map.setFilter('markers', ["any"].concat(args));
});

How to dynamically update drop-down list options with values in a server-generated array

I have a web form with two drop-down boxes, and I'm looking for a way to dynamically update the options of the second box based on selections from the first.
The first box represents a data type, and the second box is a list of databases associated with the selected type.
I have the basic code running smoothly here:
var TypeA_DbSuffixList = ['Test1', 'Test2', 'Test3'];
var TypeB_DbSuffixList = ['TestA', 'TestB', 'TestC'];
function fill_dbSuffixList(){
document.getElementById("dbSuffixList").options.length = 0;
var suffixMenu = document.getElementById("dbSuffixList");
var dataFormat = document.getElementById("dataFormatType");
var suffixList = dataFormat.value + "dbSuffixList";
if (suffixList == 'TypeA_dbSuffixList') {
for(index in TypeA_dbSuffixList) {
suffixMenu.options[suffixMenu.options.length] = new Option(TypeA_dbSuffixList[index], index);
}
}
if (suffixList == 'TypeB_dbSuffixList') {
for(index in TypeB_dbSuffixList) {
suffixMenu.options[suffixMenu.options.length] = new Option(TypeB_dbSuffixList[index], index);
}
}
}
That code (activated whenever a selection is made in the dataType box) clears the existing list of options and repopulates the list based on the selected value of the "dataFormatType" box.
The problem that I face is that the actual lists of database tables are not hard coded and are instead generated with the following calls to the server to avoid repetitive editing of the page every time a new database is added:
var TypeA_dbSuffixList = ${TypeA_dbSuffixList};
var TypeB_dbSuffixList = ${TypeB_dbSuffixList};
These calls return the following code:
var TypeA_dbSuffixList = [Test1, Test2, Test3];
var TypeB_dbSuffixList = [TestA, TestB, TestC];
With the above code, the initial function treats each entry in the type arrays as an undefined variable, and nothing is ever written to the drop-down list.
If I were to add
var Test1 = "Apple";
var Test2 = "Orange";
var Test3 = "Grape";
prior to the "for" loop for TypeA, then selecting TypeA from the dataType drop-down list returns "Apple", "Orange", and "Grape" as the available databases for TypeA.
Visually, I see what needs to be changed. The [Test1, Test2, Test3] returns need to be ['Test1', 'Test2', 'Test3']. I'm just unsure exactly how to go about changing it, and have exhausted every web search I can think of.
Is there a way to either change the format of the returned arrays, or use the existing format and pass variable names as drop-down selections instead of using variable values?
Any help is greatly appreciated. I will continue to search for an answer on my own as well and will post it here should I find one.
I think the cleanest solution would be to change the code on the server-side to generate a proper JavaScript array of Strings, with the values enclosed in single or double quotes.
If that's not possible for some reason, and you want a pure-JavaScript solution, then I suggest you wrap the entire JSP/ASP/PHP variable (not sure what framework you're using) in double quotes, strip the string of brackets and spaces using a regex, and then split it into a string array using the comma as a delimiter.
So in your JavaScript, this:
var TypeA_dbSuffixList = ${TypeA_dbSuffixList};
would become this:
var TypeA_dbSuffixList = "${TypeA_dbSuffixList}".replace(/[\[\]\s]/g,"").split(",");
I think the best way to convert data in a server side language into something to be used in JavaScript is to JSON encode your objects.
I'm not sure what language your using on the server, but in PHP you can do the following
var arr = <?php echo json_encode( array ('abc', 'def', 'ghi') ); ?> ;
And your output will be
var arr = ['abc', 'def', 'ghi'] ;
This will make sure that strings with embedded new lines, tabs, quotes are properly escaped.
JSP
You said you're using JSP but the code you have looks more like velocity or free marker inside JSP. In JSP you could use the following, provided you download Gson
var TypeA_dbSuffixList = <%= new Gson().toJson(TypeA_dbSuffixList) %>;

Categories