Very slow loop in angularjs - javascript

I use this loop for create map markers (1000 points):
var markers = {};
for (var i = 0; i < items.data.data.length; i++) {
latVal = items.data.data[i].lat;
lngVal = items.data.data[i].lng;
ikona = icons.infost;
message = "<b>" + items.data.data[i].name + "</b>";
markers[i] = {'group': 'cmp', 'lat' : eval(latVal), 'lng' : eval(lngVal), 'icon' : ikona, 'message' : message};
}
$scope.Markers = markers;
how I can improve the for loop speed in angularjs (currently it takes almost 10s)?

Remove eval. It's slow and drops all browser optimizations for entire chain of functions.
Use array markers = [] instead of object.
Use + for converting string to number.
Use push to append elements to array.
Save items.data.data to a variable.

There is a few things that can improve your code speed like avoiding eval and caching loop variables and arrays as well. By caching some values, reduce a bunch of operations like member access and unecessary calculations.
var items = { data: { data: [] }};
var icons = { infost: 'infost'};
for (var i = 0; i < 1000; i++) {
items.data.data.push({ lat: ''+i, lng: ''+i, name:''+i });
}
console.time('time');
/// YOUR CODE STARTS HERE
var
data = items.data.data,
l = data.length,
markers = Array(l), // or just []
item, latVal, lngVal, ikona, message;
for (var i = 0; i < l; i++) {
item = data[i];
latVal = item.lat;
lngVal = item.lng;
ikona = icons.infost;
message = "<b>" + item.name + "</b>";
markers[i] = {
group: 'cmp',
lat: +latVal,
lng: +lngVal,
icon: ikona,
message: message
};
}
console.timeEnd('time');
//$scope.Markers = markers;

Related

Filter data from database in Leaflet [duplicate]

I want to filter my markers by name, using map.addLayer(nameOfTheMarker) and map.remvoeLayer(nameOfTheLayer) with a checkbox like this:
$('#markertoggle').change(function () {
if (!this.checked)
// ^
map.addLayer(nameOfTheMarker);
else
map.remvoeLayer(nameOfTheLayer;
});
I found a jsfiddle with an example of a filter, but I don't know how to apply it to my code:
var locations = [
['AB11 5HW','17','A',57.147701,-2.085442 ] ,
['AB11 8DG','3','B',57.129372,-2.090916 ]
];
var markersA = [];
var markersB = [];
//Loop through the initial array and add to two different arrays based on the specified variable
for(var i=0; i < locations.length; i++) {
switch (locations[i][2]) {
case 'A' :
markersA.push(L.marker([locations[i][3], locations[i][4]]));
break;
case 'B' :
markersB.push(L.marker([locations[i][3], locations[i][4]]));
break;
default :
break;
}
}
//add the groups of markers to layerGroups
var groupA = L.layerGroup(markersA);
var groupB = L.layerGroup(markersB);
//background tile set
var tileLayer = {'Gray' : L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png')
};
var map = L.map('map', {
center: new L.LatLng(57.0, -2),
zoom: 9,
layers: [tileLayer['Gray'], groupA, groupB] //change this to determine which ones start loaded on screen
});
//Control on the Top Left that handles the switching between A and B
var overlayMaps = {
"A": groupA,
"B": groupB
};
L.control.layers(tileLayer, overlayMaps, {position:'topleft'}).addTo(map);
http://jsfiddle.net/RogerHN/31v2afte/2/
The function that I use to pull the markers:
function showMarkersByName(name) {
for (var i = 0; i < markers.resources.length; i++) {
var resName = markers.resources[i].name;
if (resName == name) {
var resIcon = icons.resources[i].icon;
var resSize = icons.resources[i].size;
var resPname = icons.resources[i].pname;
var customIcon = L.icon({
iconUrl: resIcon,
iconSize: resSize, // size of the icon
iconAnchor: [resSize[0]/2, resSize[1]/2], // point of the icon which will correspond to marker's location
popupAnchor: [2, -resSize[1]/2] // point from which the popup should open relative to the iconAnchor
});
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {icon: customIcon});
marker.addTo(map).bindPopup(resPname);
$(marker._icon).addClass(name)
}
}
}
My markers structure its very similar with the one in the example, I just don't know where in my function I need to insert the filter to filter the markers by name, adding then to a layer to later toggle them use the checkbox above.
My full code here: http://plnkr.co/edit/UwAelIuUYz4OkoOG7zFn?p=preview
Using the example above and the code iH8 mentioned I was able to create a checkbox to toggle markers filtering them by its name:
function initLayerGroups() {
for (var i = 0; i < markers.resources.length; i++) {
switch (markers.resources[i].name) {
case 'GreenMarker':
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {
icon: getIcon(i)
}).bindPopup(getPopupContent(i));
markersGreen.push(marker);
}
break;
case 'BlueMarker':
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {
icon: getIcon(i)
}).bindPopup(getPopupContent(i));
markersBlue.push(marker);
}
break;
case 'RedMarker':
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {
icon: getIcon(i)
}).bindPopup(getPopupContent(i));
markersRed.push(marker);
}
break;
default:
break;
}
}
groupGreen = L.layerGroup(markersGreen);
groupBlue = L.layerGroup(markersBlue);
groupRed = L.layerGroup(markersRed);
}
The checkbox:
<input type="checkbox" id="greenmarkertoggle"/>
<label for="greenmarkertoggle">Green Marker</label>
And the javascript code to show or hide the layer:
$('#greenmarkertoggle').change(function() {
if (this.checked)
map.addLayer(groupGreen);
else
map.removeLayer(groupGreen);
});
And here's the full working example using the code above:
http://plnkr.co/edit/GuIVhtFdtMDbmZdME1bV?p=preview
Thanks to iH8 and the example above I was able to create that function and filter the markers by its name.

How to get all the pins/markers in on click of a markercluster in google maps?

I am using google maps api to create a store locator with clusters and I am referring the marker cluster api.
I wanted to get the list of stores with in a markercluster rather than returning marker cluster with pins/markers. Please find the below code -
google.maps.event.addListener(mapsCore.mapsVar.markerCluster, 'clusterclick', function(cluster) {
var content = "";
// Convert lat/long from cluster object to a usable MVCObject
var info = new google.maps.MVCObject;
info.set('position', cluster.center_);
//----
//Get markers
console.log(cluster.getSize());
var markers = cluster.getMarkers();
var x = {};
$(mapsCore.mapsVar.totalResults.Result).each(function(k, v) {
$(markers).each(function(km, vm) {
if (parseFloat(v.LAT) == parseFloat(markers[km].position.lat()) && parseFloat(v.LON) == parseFloat(markers[km].position.lng())) {
// locArr[k] = { lat: parseFloat(v.CounterLatitude), lng: parseFloat(v.CounterLongitude) };
x.Counter_ID = v.Counter_ID;
x.Counter_Name = v.Counter_Name;
x.Counter_Zip_code = v.Counter_Zip_code;
x.Address_1 = v.Address_1;
x.Address_2 = v.Address_2;
x.Province = v.Province;
x.City = v.City;
x.Area = v.Area;
x.SubArea = v.SubArea;
x.Counter_Tel = v.Counter_Tel;
x.Counter_Email = v.Counter_Email;
x.Open_Time = v.Open_Time;
x.Close_Time = v.Close_Time;
x.LAT = v.LAT;
x.LON = v.LON;
x.MR_FLG = v.MR_FLG;
mapsCore.mapsVar.clusterDetail.Results.push(x);
x = {};
}
});
});
});
As a workaround you can set a custom image to an transparent png and text size to 0, that way it'll be invisible on the map.
cluster.setStyles({
url: your_path/transparent.png,
height: 20,
width: 20,
textSize: 0
});
Alternatively you can try and see if setting the image height and width to 0 works.
All,
thanks for your help for formatting my code and comments any way I found the solution for it. I will attach the spinet of code below
google.maps.event.addListener(mapsCore.mapsVar.markerCluster, 'clusterclick', function(cluster) {
var content = '';
// Convert lat/long from cluster object to a usable MVCObject
var info = new google.maps.MVCObject;
info.set('position', cluster.center_);
//----
//Get markers
console.log(cluster.getSize());
var markers = cluster.getMarkers();
var x = {};
mapsCore.mapsVar.clusterDetail.Counters.length = 0;
$(mapsCore.mapsVar.totalResults.Counters).each(function(k, v) {
$(markers).each(function(km, vm) {
console.log(parseFloat(v.CounterLatitude) == parseFloat(vm.position.lat()) && parseFloat(v.CounterLongitude) == parseFloat(vm.position.lng()));
if (parseFloat(v.CounterLatitude) == parseFloat(vm.position.lat())) {
// locArr[k] = { lat: parseFloat(v.CounterLatitude), lng: parseFloat(v.CounterLongitude) };
x.CounterCode = v.CounterCode;
x.CounterName = v.CounterName;
x.CounterZipCode = v.CounterZipCode;
x.AddressLine1 = v.AddressLine1;
x.AddressLine2 = v.AddressLine2;
x.Province = v.Province;
x.City = v.City;
x.Area = v.Area;
x.SubArea = v.SubArea;
x.CounterPhoneNumber = v.CounterPhoneNumber;
x.CounterEmailAddress = v.CounterEmailAddress;
x.CounterOpenTime = v.CounterOpenTime;
x.CounterCloseTime = v.CounterCloseTime;
x.CounterLatitude = v.CounterLatitude;
x.CounterLongitude = v.CounterLongitude;
x.IsMagicRingAvailable = v.IsMagicRingAvailable;
mapsCore.mapsVar.clusterDetail.Counters.push(x);
x = {};
}
});
});
console.log(mapsCore.mapsVar.clusterDetail);
var template = $.templates("#mapslist");
var output = template.render(mapsCore.mapsVar.clusterDetail);
$(".store-list-section").html(output);
});
Always need to reset the array of object like -
mapsCore.mapsVar.clusterDetail.Counters.length = 0;

Multiple markers with specific infotemplate content

When I'm looping through a list of addresses, I'm able to plot the markers for all the addresses fine. But when I click on any marker, the infowindow content shows data of only the last marker. How do I solve this?
Javscript
var map ={};
map.markers = [];
map.addresses = [
{
'line': '2101 K St',
'ref_no': '160621-000005'
},
{
'line': '2131 K St',
'ref_no': '170708-000015'
},
{
'line': '2321 K St',
'ref_no': '170707-000028'
}
];
.
.
.
map.map_object = new Map("esri_map", {
basemap: "topo",
center: [<lat>, <lng>],
zoom: 12
});
var locator = new Locator("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
for(var i = 0; i < map.addresses.length; i++)
{
var addr = map.addresses[i];
var params = {
countryCode: "US",
maxLocations: 1,
address: {"SingleLine": addr.line}
};
locator.addressToLocations(params, function(candidates){
locatorDone(candidates, addr);
});
}
function locatorDone(candidates, addr)
{
.
.
.
var html = "<h5>"+addr.line+"</h5>";
html += "<p>Ref#: "+addr.ref_no+"</p>";
var infoTemplate = new esri.InfoTemplate(addr.ref_no, html); // <--- Problem lies here
var graphic = new esri.Graphic(pt, symbol,'',infoTemplate);
map.map_object.graphics.add(graphic);
map.markers.push(graphic);
}
P.S: I've solved similar problems (in case of Google Maps API) by using closures. But I'm not sure how to use that in this case.
You can wrap the inside of the for loop in a self invoking function which will provide the closure. Something like this:
for(var i = 0; i < map.addresses.length; i++)
(function (i) {
var addr = map.addresses[i];
var params = {
countryCode: "US",
maxLocations: 1,
address: {"SingleLine": addr.line}
};
locator.addressToLocations(params, function(candidates){
locatorDone(candidates, addr);
});
})(i)
This will make i local to this code block. As it is now in your code all addr are referencing the last address because the for loop has finished running when you call locatorDone asynchronously. Alternatively you can use let like so: for (let i = 0; ... if you don't need this code to run on Internet Explorer below version 11.

Why does my for loop skip some markers coordinates?

I have this for loop that loops through an array (4 levels deep) to retrieve the lat and long coordinates of my marker positions. It seems to work fine however it skips the 5th, 8th and 9th coordinate. I would really appreciate any help or advice. Thank you.
var bounds = new google.maps.LatLngBounds();
for (i=0; i < categories.length; i++){
for (j=0; j < categories[i].length; j++){
for (var k = 0; k < categories[i][j].length; k++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(parseFloat(categories[i][1][j][k]),
parseFloat(categories[i][2][j][k])),
index:k,
icon : categories[i][5][j][0]
});
//create marker categories
marker.category = categories[i][6][j][0];//category[6][j][0]
marker.setVisible(true);
markers.push(marker);
bounds.extend(marker.getPosition());
marker.setMap(map);
}
}
}
//the arrays
var categories = [category];
var category = [
names,
lat_locations,
long_locations,
links,
icons,
icon_image,
real_names,
];
var lat_locations = [
container_yards_locations_lats,
truck_yards_locations_lats,
terminals_locations_lats,
new_developments_locations_lats,
manufacturing_companies_locations_lats,
warehouses_locations_lats,
transport_companies_locations_lats,
jettys_locations_lats,
free_land_locations_lats
];
var container_yards_locations_lats = [
6.445638,
6.447416
];
var truck_yards_locations_lats = [
6.452937
];
var terminals_locations_lats = [
6.4356407,
6.432294,
6.4433638,
6.442223,
6.4371918,
6.4331848,
6.433211,
6.440850
];
var new_developments_locations_lats = [
6.450393
];
var manufacturing_companies_locations_lats = [
6.447272
];
var warehouses_locations_lats = [
6.446857,
6.450077
];
var transport_companies_locations_lats = [
6.450675
];
var jettys_locations_lats = [
6.443349
];
var free_land_locations_lats = [
6.451843
];
var lat_locations = [
container_yards_locations_lats,
truck_yards_locations_lats,
terminals_locations_lats,
new_developments_locations_lats,
manufacturing_companies_locations_lats,
warehouses_locations_lats,
transport_companies_locations_lats,
jettys_locations_lats,
free_land_locations_lats
];
var container_yards_locations_lngs = [
3.3111681,
3.3113029
];
var truck_yards_locations_lngs = [
3.3062503
];
var terminals_locations_lngs = [
3.3330524,
3.3555287
];
var new_developments_locations_lngs = [
3.3031123
];
var manufacturing_companies_locations_lngs = [
3.3099291
];
var warehouses_locations_lngs = [
3.3082508,
3.3089833
];
var transport_companies_locations_lngs = [
3.3090743
];
var jettys_locations_lngs = [
3.3159546
];
var free_land_locations_lngs = [
3.3017833
];
var long_locations = [
container_yards_locations_lngs,
truck_yards_locations_lngs,
terminals_locations_lngs,
new_developments_locations_lngs,
manufacturing_companies_locations_lngs,
warehouses_locations_lngs,
transport_companies_locations_lngs,
jettys_locations_lngs,
free_land_locations_lngs
];
I feel it will be too much putting all the arrays here and those arrays are obviously not complete but this is the explanation:
var categories = [category];
var category = [//contains 9 different categories];
var "sub_category" = [//contains arrays that have multiple variables in
each];
Each category has an array that contains various variables. So to access the
deepest variable you would need to reference it like so:
categories[0][2][8][0]
The reference in the for loop is all wrong:
var bounds = new google.maps.LatLngBounds();
for (i=0; i < categories.length; i++){
for (j=0; j < categories[0][i].length; j++){
for (var k = 0; k < categories[0][i][j].length; k++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(parseFloat(categories[i][1][j][k]),
parseFloat(categories[i][2][j][k])),
index:k,
icon : categories[i][5][j][0]
});
//create marker categories
marker.category = categories[i][6][j][0];//category[6][j][0]
marker.setVisible(true);
markers.push(marker);
bounds.extend(marker.getPosition());
marker.setMap(map);
}
}
}
Code works fine now.

How would I go about iterating over this JSON data

I'm pulling in the below json data from a database using ajax.
{"route":[{"latitude":-27.38851,"longitude":153.11606},{"latitude":-27.47577,"longitude":153.01693}]}
How would I got about iterating over it to get lat/long pairs to plot on a map?
Assign the JSON data to a variable, and loop through the route object like below:
var j = {"route":[{"latitude":-27.38851,"longitude":153.11606},{"latitude":-27.47577,"longitude":153.01693}]}
for(i=0; i<=j.route.length; i++){
var thisRoute = j.route[i];
}
Give it a try:
var j = {"route":[{"latitude":-27.38851,"longitude":153.11606},{"latitude":-27.47577,"longitude":153.01693}]};
for(var i= 0,len=j.route.length; i<len; i++){
var lat = j.route[i].latitude;
var long = j.route[i].longitude;
console.log(lat+' '+long);
}
var o = {"route":[{"latitude":-27.38851,"longitude":153.11606},{"latitude":-27.47577,"longitude":153.01693}]};
var i = 0;
var lat, long;
var len=o.route.length;
for(i,i<len; i++){
lat = o.route[i].latitude;
long = o.route[i].longitude;
console.log(lat+' '+long);
}
Here's a full implementation of what you're trying to achieve:
JSFIddle with a map
function createMarker(options) {
var marker = new google.maps.Marker(options);
return marker;
}
for (i = 0; i < data.route.length; i++) {
createMarker({
position: new google.maps.LatLng(data.route[i].latitude, data.route[i].longitude),
map: map
});

Categories

Resources