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

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?

Related

Google Apps Script Better Way to Get Unique Values

I have working code that takes data from two non-adjacent columns in a Google Spreadsheet, looks for unique values in the first column, and if unique creates a new array with the unique value from the first column and corresponding value in the second column. The problem is, the data I am using is already somewhat long (413 rows) and will only get longer over time. It takes about 1-2 minutes for the code to run through it. I've been looking for a shorter way to do this and I've come across the filter() and map() array functions which are supposedly faster than a for loop but I can't get them implemented correctly. Any help with these or a faster method would be greatly appreciated. The code I have right now is below.
function getkhanassignments(rows) {
var assignmentsraw = [];
var temparray = [];
var previousassignment = datasheet.getRange(50,1).getValue();
for(i=0, j=0;i<rows-1;i++) {
if(datasheet.getRange(50+i,1).getValue() != previousassignment) {
previousassignment = datasheet.getRange(50+i,1).getValue();
assignmentsraw[j] = new Array(2);
assignmentsraw[j][0] = datasheet.getRange(50+i,1).getValue();
assignmentsraw[j][1] = datasheet.getRange(50+i,8).getValue();
j++;
}
}
Logger.log(assignmentsraw);
return assignmentsraw;
}
The answers I've found elsewhere involve just getting unique values from a 1d array whereas I need unique values from a 1d combine with corresponding values from another 1d array. The output should be a 2d array with unique values from the first column and their corresponding values in the second column.
Solution:
The best practice of looping through ranges in Google Apps Script is to dump the range values into a 2D array, loop through that array, and then return the output array back to Google Sheets.
This way, there would be no calls to Sheets API inside loops.
Sample Code:
function getkhanassignments(rows) {
var assignmentsraw = [];
var table1 = datasheet.getRange(50,1,rows).getValues();
var table2 = datasheet.getRange(50,8,rows).getValues();
var previousassignment = table1[0][0];
assignmentsraw.push([table1[0][0],table2[0][0]]);
for(i=0; i<rows; i++) {
if (table1[i][0] != previousassignment) {
assignmentsraw.push([table1[i][0],table2[i][0]]);
previousassignment = table1[i][0];
}
}
Logger.log(assignmentsraw);
return assignmentsraw;
}
References:
Class Range
push()

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

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 + '');
}

Checking for existing array in array before pushing

I missing something when trying to push to an array while preventing duplicates.
I keep figuring out code that will push every occurence of an employee to the new employees array but I cannot figure out how to only push an unique list.
My final array is a 2d array so that can be setValues() back into a column in the Google sheet.
function queryEmployees(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var lRow = sh.getLastRow();
var data = sh.getRange(1,1,lRow,2).getValues();
var employees = [];
for(i=0;i<data.length;i++){
if(data[i][0]==='Team member evaluated'){
if(employees.indexOf([data[i][1]])===-1){
employees.push([data[i][1]]);
}
}
}
Logger.log(employees);
Logger.log(employees.length);
SpreadsheetApp.getActiveSpreadsheet().getSheets()[1]
.getRange(1,1,employees.length,1).setValues(employees);
}
IndexOf does not work with objects in arrays without your rewriting the function or writing your own. It works fine with strings, though. So a simple fix is to create a parallel array of strings, which allows us to keep your code almost intact. Thus, add,
var employeesIndex=[];
after your
var employees=[]
change the condition on your inner "if" clause to
(employeesIndex.indexOf(data[i][1])===-1)
and within that if block add a line to update the index
employeesIndex.push(data[i][1]);
That way the index tracks duplicates for you while your employees array contains arrays like you need.

Javascript equivalent of VBS redim preserve

I'm trying to rewrite some old VBScript as Javascript for an ASP.NET application and there is one line I'm not sure how to translate, and I'm not even entirely positive what it's doing.
The application essentially allows the user to enter in a new employee number to add to the database and then assign it user permissions. Don't ask me why the code is such a mess, I didn't write it originally, I'm just trying to make it work in Chrome
here's the relevant code that i've managed to translate so far:
if(form1.txtEmpno.value != ""){
var oOption;
oOption = document.createElement("OPTION");
oOption.text=form1.txtEmpno.value;
oOption.value=form1.txtEmpno.value;
form1.lstActive.add (oOption);
oOption = document.createElement("OPTION");
oOption.text="";
oOption.value="";
form1.lstPerms.add (oOption);
redim preserve arrUsers(1,ubound(arrUsers,2)+1);
arrUsers(0,ubound(arrUsers,2)) = form1.txtEmpno.value;
arrUsers(1,ubound(arrUsers,2)) = "";
form1.txtEmpno.value = "";
oOption = null;
}
here's the line in question:
redim preserve arrUsers(1,ubound(arrUsers,2)+1);
MSDN defines ReDim [Preserve] varname(subscripts) as:
The ReDim statement is used to size or resize a dynamic array that has already been formally declared using a Private, Public, or Dim statement with empty parentheses (without dimension subscripts). You can use the ReDim statement repeatedly to change the number of elements and dimensions in an array.
If you use the Preserve keyword, you can resize only the last array dimension, and you can't change the number of dimensions at all. For example, if your array has only one dimension, you can resize that dimension because it is the last and only dimension. However, if your array has two or more dimensions, you can change the size of only the last dimension and still preserve the contents of the array.
Arrays in JavaScript have different semantics to VBScript's arrays, especially in that they're actually closer to a vector than a true array, furthermore JavaScript does not provide for true N-dimensional arrays: instead you use staggered-arrays (arrays-within-arrays). Which means your VBScript cannot be syntactically converted to JavaScript.
Here's your relevant code in VBScript:
ReDim Preserve arrUsers(1,ubound(arrUsers,2)+1)
arrUsers(0,ubound(arrUsers,2)) = form1.txtEmpno.value
arrUsers(1,ubound(arrUsers,2)) = ""
We see that arrUsers is a 2-dimensional array. This will need to be converted into a staggered array, but you haven't posted the code that defines and initializes arrUsers, nor how it is used later on, so I can only work from making assumptions.
It looks to be adding 1 element to the last dimension, but the code only seems to use the extra space in the [1] subscript (i.e. it only wants the extra dimensional space for certain values of the 0th dimension instead of all values), which makes this simpler as you don't need to iterate over every 0th-dimension subscript.
JavaScript arrays have numerous function-properties that we'll use, in particular push: which appends an element to the end of an array (internally growing the buffer if necessary), and pop which removes the last (highest-indexed) element from an array (if an array is empty, it's a NOOP):
var arrUsers = [ [], [] ]; // empty, staggered 2-dimensional array
...
arrUsers[0].push( form1.txtEmpno.value );
arrUsers[1].pop();
Much simpler.
However, if this array is just part of some internal model to store and represent data then you should take advantage of JavaScript object-prototypes instead of using array indexes, as that makes the code self-describing, for example:
var User = function(empNo, name) {
this.employeeNumber = empNo;
this.name = name;
};
var users = [];
users.push( new User(1, "user 1") );
users.push( new User(23, "user 23") );
...
for(var i = 0; i < users.length; i++ ) {
alert( users[i].name );
}

Parsing a JSON object of arrays gives different results in IE9

Intro
I am working on creating a HighCharts graph from a DataTable table.
What I do is iterate over the the rows and columns of the table, convert the strings (we use different thousand separators from the US) to numbers and save them into an object called item. the object has two values item["name"] which is the name of the series and item["data"] which is the data for the series. I then use the .push method to add these objects to an array to send to a Highcharts options object to create the plot. In the case below, I only have three series, but the problem always occurs. The LineOptions is an options-object for the HighCharts Graph.
Code
function plotLineOrBar(type){
var jsonData = [];
var xaxis = $('#masters_table table').find('thead th:not(:first-child)').map(function(){
return $(this).html();
}).get();
$('#masters_table table tbody tr').each(function(){
item = {};
item["name"] = $(this).find('td:first-child').html();
item["data"] = $(this).find('td:not(:first-child)').map(function(){
return parseInt($(this).html().replace(/\./g, "").replace('',0),10);
}).get();
jsonData.push(item);
});
console.log(jsonData[0]["name"]); // send the 0th name to console
console.log(jsonData[1]["name"]); // send the 1st name to console
console.log(jsonData[2]["name"]); // send the 2nd name to console
LineOptions.series = (jsonData);
LineOptions.xAxis.categories = xaxis;
LineOptions.chart.type=type;
var chart = new Highcharts.Chart(LineOptions);
}
Problem
(The name of the series should be 2320,2321,2336)
In Chrome, the resulting console.log is:
2320
2321
2336
and the corresponding data to each series prints out correctly and everything works flawlessly.
In IE9, the resulting console.log is:
LOG: 2336
LOG: 2336
LOG: 2336
i.e., only the last series gets printed into the array. The result is three series with perfectly overlapping curves, since they have the same data.
I have searched and searched for answers, wrapped by brain around but I can still not figure out what I am doing wrong. I assume though, that my error is a simple one (I hope).
As previously wrote in the comment (for future reference), just define the item variable inside of the loop function, instead of using a "global" one (var item = {} instead of item = {}). This is because in IE9 it seems to be passed by reference, and thus you're pushing the very same object, updated three times (changing its values from iteration to iteration).
P.S.
by the way it seems that the other browser you're using, it is creating a new variable every time you use .push and I'm not sure that's the "standard" behavior. One point to IE9!

Categories