Multiple markers with specific infotemplate content - javascript

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.

Related

google map not loading 2nd time in java script

In SAP UI5, google map is not loading for the second time. I am loading the map on attachPatternMatched() function. So, how can I resolve this issue?
onInit: function() {
var that = this;
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("master").attachPatternMatched(this.setMapData, this);
},
setMapData: function() {
var that = this;
this.getView().getModel("BookMyRideModel").read("/Stops", {
success: function(response) {
var arry = [];
for (var k = 0; k < response.results.length; k++) {
var lat = response.results[k].Latitude;
var long = response.results[k].Longitude;
var address = response.results[k].Stop_Name;
var pincode = response.results[k].Pincode;
var id = response.results[k].Stop_Id;
arry.push({
"lat": lat,
"long": long,
"addr": address,
"pin": pincode,
"key": id
});
}
that.setMarkerForMap(arry);
},
error: function(response) {
}
});
},
setMarkerForMap: function(array) {
var that = this;
var markersarry = [];
var map = new google.maps.Map(document.getElementById('googleMap'), {
center: new google.maps.LatLng(parseFloat(12.9715),
parseFloat(77.5945626)),
zoom: 2,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
There in setMapForMarkers() I'm loading multiple markers on Map which are coming from oData service.
[After clicking other tabs in master page, and later on clicking Bokk my ride tab , that time facing the issue][1]
Thanks & Regards,
Raheen
snap of application
The onInit function is executed when your component is initialized. This method is only called once so that explains why your map is not loaded the second time. You might want to try and add your function in the onAfterRendering() function.

iterate arrays with forEach Loop

in this project there are 3 files, index.html, helper.js and resumeBuilder.js. The last one is the file I work with all the time.
My problem in this project is that I can't figure how to make images array,which is inside the projects array to display in my Resume, and the same for the onLineCourses array which is inside the schools array. This online school needs to make all arrays with
forEach loop. please if someone can help to write the code I have to write to make it display, I am searching for a week and can't figure it out!
resumeBuilder.js
var projects = {
"projects" : [
{
"title":"",
"location":"",
"dates":"",
"description":"",
},
{
"title":"",
"location":"",
"dates":"",
"description":"",
>
> "images":["", ""]
}
],
};
//projects function
projects.display = function(){
$.each(projects.projects, function(i){
$("#projects").append(HTMLprojectStart);
var myProjects = projects.projects[i];
var formattedTitle = HTMLprojectTitle.replace("%data%", myProjects.title);
$(".project-entry:last").append(formattedTitle);
var formattedDates = HTMLprojectDates.replace("%data%", myProjects.dates);
$(".project-entry:last").append(formattedDates);
var formattedDescription = HTMLprojectDescription.replace("%data%", myProjects.description);
$(".project-entry:last").append(formattedDescription);
> //image array here!
> var formattedImage = HTMLprojectImage.replace("%data%",projects.images);
> $("#projects").append(HTMLprojectStart);
> $(".project-entry:last").append(formattedImage);
});
};
projects.display();
> var education = {
"schools": [
{
"name" : "",
"location" : "",
"degree":",
"majors":["","",""],
"dates" : "2",
"url" : ""
},
{
"name" : "",
"location" :"",
"degree":"",
"majors":[""],
"dates" : "",
"url" : ""
}
],
//create onLine Courses
> "onlineCourses" : [
> {
> "title" : "",
> "school" : "",
> "dates" : "",
> "url" : ""
> } ] };
//education function
education.display = function(){
$.each(education.schools, function(i) {
var mySchools = education.schools[i];
$("#education").append(HTMLschoolStart);
var formattedName = HTMLschoolName.replace("%data%",mySchools.name);
var formattedDegree = HTMLschoolDegree.replace("%data%",mySchools.degree);
var formattedNameDegree = formattedName + formattedDegree;
$(".education-entry:last").append(formattedNameDegree);
var formattedDates = HTMLschoolDates.replace("%data%",mySchools.dates);
$(".education-entry:last").append(formattedDates);
var formattedLocation = HTMLschoolLocation.replace("%data%",mySchools.location);
$(".education-entry:last").append(formattedLocation);
var formattedMajor = HTMLschoolMajor.replace("%data%",mySchools.majors);
$(".education-entry:last").append(formattedMajor);
});
//onLine courses here
> $("#education").append(HTMLonlineClasses);
> $("#education").append(HTMLschoolStart); var courses =
> education.onlineCourses; var formattedTitle =
> HTMLonlineTitle.replace("%data%", courses.title); var
> formattedSchool = HTMLonlineSchool.replace("%data%",courses.name);
> var formattedDates = HTMLonlineDates.replace("%data%", courses.dates);
> var formattedOnline = formattedTitle + formattedSchool +
> formattedDates;
> $(".education-entry:last").append(formattedOnline);
>
> };
>
> education.display();
helper.js
> /*
This file contains all of the code running in the background that makes resumeBuilder.js possible. We call these helper functions because they support your code in this course.
Don't worry, you'll learn what's going on in this file throughout the course. You won't need to make any changes to it until you start experimenting with inserting a Google Map in Problem Set 3.
/*
These are HTML strings. As part of the course, you'll be using JavaScript functions
replace the %data% placeholder text you see in them.
*/
var HTMLheaderName = '<h1 id="name">%data%</h1>';
var HTMLheaderRole = '<span>%data%</span><hr>';
var HTMLcontactGeneric = '<li class="flex-item"><span class="orange-text">%contact%</span><span class="white-text">%data%</span></li>';
var HTMLmobile = '<li class="flex-item"><span class="orange-text">mobile</span><span class="white-text">%data%</span></li>';
var HTMLemail = '<li class="flex-item"><span class="orange-text">email</span><span class="white-text">%data%</span></li>';
var HTMLtwitter = '<li class="flex-item"><span class="orange-text">twitter</span><span class="white-text">%data%</span></li>';
var HTMLgithub = '<li class="flex-item"><span class="orange-text">github</span><span class="white-text">%data%</span></li>';
var HTMLblog = '<li class="flex-item"><span class="orange-text">blog</span><span class="white-text">%data%</span></li>';
var HTMLlocation = '<li class="flex-item"><span class="orange-text">location</span><span class="white-text">%data%</span></li>';
var HTMLbioPic = '<img src="%data%" class="biopic">';
var HTMLwelcomeMsg = '<span class="welcome-message">%data%</span>';
var HTMLskillsStart = '<h3 id="skills-h3">Skills at a Glance:</h3><ul id="skills" class="flex-column"></ul>';
var HTMLskills = '<li class="flex-item"><span class="white-text">%data%</span></li>';
var HTMLworkStart = '<div class="work-entry"></div>';
var HTMLworkEmployer = '<a href="#">%data%';
var HTMLworkTitle = ' - %data%</a>';
var HTMLworkDates = '<div class="date-text">%data%</div>';
var HTMLworkLocation = '<div class="location-text">%data%</div>';
var HTMLworkDescription = '<p><br>%data%</p>';
var HTMLprojectStart = '<div class="project-entry"></div>';
var HTMLprojectTitle = '%data%';
var HTMLprojectDates = '<div class="date-text">%data%</div>';
var HTMLprojectDescription = '<p><br>%data%</p>';
var HTMLprojectImage = '<img src="%data%">';
var HTMLschoolStart = '<div class="education-entry"></div>';
var HTMLschoolName = '<a href="#">%data%';
var HTMLschoolDegree = ' -- %data%</a>';
var HTMLschoolDates = '<div class="date-text">%data%</div>';
var HTMLschoolLocation = '<div class="location-text">%data%</div>';
var HTMLschoolMajor = '<em><br>Major: %data%</em>';
var HTMLonlineClasses = '<h3>Online Classes</h3>';
var HTMLonlineTitle = '<a href="#">%data%';
var HTMLonlineSchool = ' - %data%</a>';
var HTMLonlineDates = '<div class="date-text">%data%</div>';
var HTMLonlineURL = '<br>%data%';
var internationalizeButton = '<button>Internationalize</button>';
var googleMap = '<div id="map"></div>';
$(document).ready(function() {
$('button').click(function() {
var $name = $('#name');
var iName = inName($name.text()) || function(){};
$name.html(iName);
});
});
/*
The next few lines about clicks are for the Collecting Click Locations quiz in the lesson Flow Control from JavaScript Basics.
*/
var clickLocations = [];
function logClicks(x,y) {
clickLocations.push(
{
x: x,
y: y
}
);
console.log('x location: ' + x + '; y location: ' + y);
}
$(document).click(function(loc) {
// your code goes here!
});
var map; // declares a global map variable
/*
Start here! initializeMap() is called when page is loaded.
*/
function initializeMap() {
var locations;
var mapOptions = {
disableDefaultUI: true
};
/*
For the map to be displayed, the googleMap var must be
appended to #mapDiv in resumeBuilder.js.
*/
map = new google.maps.Map(document.querySelector('#map'), mapOptions);
/*
locationFinder() returns an array of every location string from the JSONs
written for bio, education, and work.
*/
function locationFinder() {
// initializes an empty array
var locations = [];
// adds the single location property from bio to the locations array
locations.push(bio.contacts.location);
// iterates through school locations and appends each location to
// the locations array. Note that forEach is used for array iteration
// as described in the Udacity FEND Style Guide:
// https://udacity.github.io/frontend-nanodegree-styleguide/javascript.html#for-in-loop
education.schools.forEach(function(school){
locations.push(school.location);
});
// iterates through work locations and appends each location to
// the locations array. Note that forEach is used for array iteration
// as described in the Udacity FEND Style Guide:
// https://udacity.github.io/frontend-nanodegree-styleguide/javascript.html#for-in-loop
work.jobs.forEach(function(job){
locations.push(job.location);
});
return locations;
}
/*
createMapMarker(placeData) reads Google Places search results to create map pins.
placeData is the object returned from search results containing information
about a single location.
*/
function createMapMarker(placeData) {
// The next lines save location data from the search result object to local variables
var lat = placeData.geometry.location.lat(); // latitude from the place service
var lon = placeData.geometry.location.lng(); // longitude from the place service
var name = placeData.formatted_address; // name of the place from the place service
var bounds = window.mapBounds; // current boundaries of the map window
// marker is an object with additional data about the pin for a single location
var marker = new google.maps.Marker({
map: map,
position: placeData.geometry.location,
title: name
});
// infoWindows are the little helper windows that open when you click
// or hover over a pin on a map. They usually contain more information
// about a location.
var infoWindow = new google.maps.InfoWindow({
content: name
});
// hmmmm, I wonder what this is about...
google.maps.event.addListener(marker, 'click', function() {
// your code goes here!
//quiz 4 lesson 6
infowindow.open(map, marker);
});
// this is where the pin actually gets added to the map.
// bounds.extend() takes in a map location object
bounds.extend(new google.maps.LatLng(lat, lon));
// fit the map to the new marker
map.fitBounds(bounds);
// center the map
map.setCenter(bounds.getCenter());
}
/*
callback(results, status) makes sure the search returned results for a location.
If so, it creates a new map marker for that location.
*/
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
createMapMarker(results[0]);
}
}
/*
pinPoster(locations) takes in the array of locations created by locationFinder()
and fires off Google place searches for each location
*/
function pinPoster(locations) {
// creates a Google place search service object. PlacesService does the work of
// actually searching for location data.
var service = new google.maps.places.PlacesService(map);
// Iterates through the array of locations, creates a search object for each location
locations.forEach(function(place){
// the search request object
var request = {
query: place
};
// Actually searches the Google Maps API for location data and runs the callback
// function with the search results after each search.
service.textSearch(request, callback);
});
}
// Sets the boundaries of the map based on pin locations
window.mapBounds = new google.maps.LatLngBounds();
// locations is an array of location strings returned from locationFinder()
locations = locationFinder();
// pinPoster(locations) creates pins on the map for each location in
// the locations array
pinPoster(locations);
}
/*
Uncomment the code below when you're ready to implement a Google Map!
*/
// Calls the initializeMap() function when the page loads
window.addEventListener('load', initializeMap);
// Vanilla JS way to listen for resizing of the window
// and adjust map bounds
window.addEventListener('resize', function(e) {
//Make sure the map bounds get updated on page resize
map.fitBounds(mapBounds);
});

Very slow loop in angularjs

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;

Changing z-order of layer in Leaflet

I created an example of layers using as base this code:
http://bl.ocks.org/ragnarheidar/a711faa1a94be4dae48f
The piece of code responsible to creating the layers is the following:
function getColor(d)
{
return marker_colors[d];
}
function marker_style(i)
{
return {
fillColor: getColor(i),
radius: 5,
weight: 1,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
//data URL variables
var start_date = '2013-08-01'; //YYYY-MM-DD
var end_date = '2013-08-08'; //YYYY-MM-DD
var c_type = 'Noise'; // Complaint Type
// Build the data URL
var URL = "http://data.cityofnewyork.us/resource/erm2-nwe9.json";
URL += "?";
URL += "$where=";
URL += "(latitude IS NOT NULL)";
URL += " AND ";
URL += "(complaint_type='" + c_type + "')";
URL += " AND ";
URL += "(created_date>='" + start_date + "') AND (created_date<='" + end_date + "')";
URL += "&$group=complaint_type,descriptor,latitude,longitude";
URL += "&$select=descriptor,latitude,longitude,complaint_type";
URL = encodeURI(URL);
console.log(URL);
var noise_description = ["Air Condition/Ventilation Equipment",
"Alarms",
"Banging/Pounding",
"Barking Dog",
"Car/Truck Horn",
"Car/Truck Music",
"Construction Equipment",
"Construction Before/After Hours",
"Engine Idling",
"Ice Cream Truck",
"Jack Hammering",
"Lawn Care Equipment",
"Loud Music/Party",
"Loud Talking",
"Loud Television",
"Manufacturing Noise",
"Private Carting Noise",
"Others"];
var marker_colors = ['#7f3b08',
'#a50026',
'#d73027',
'#f46d43',
'#fdae61',
'#fee090',
'#ffffbf',
'#ffffff',
'#e0f3f8',
'#abd9e9',
'#74add1',
'#4575b4',
'#313695',
'#d8daeb',
'#b2abd2',
'#8073ac',
'#542788',
'#2d004b'];
// Load GeoJSON from an external file
$.getJSON(URL, function(data)
{
var markers = []
var layers = []
for (var i = 0; i < noise_description.length; i++)
{
markers[i] = [];
}
var all_markers = [];
$.each(data, function(index, rec)
{
var marker;
for (var i = 0; i < noise_description.length; i++)
{
if (rec.descriptor.indexOf(noise_description[i]) > -1)
{
marker = L.circleMarker([rec.latitude, rec.longitude], marker_style(i));
markers[i].push(marker);
all_markers.push(marker);
break;
}
}
});
// Create layer of all markers but do not add to map
var all_layers = L.featureGroup(all_markers);
// Create specific layers of markers and add to map
for (var i = 0; i < markers.length; i++)
{
layers[i] = L.featureGroup(markers[i]).addTo(map);;
}
map.fitBounds(all_layers.getBounds());
// Create object containing all marker layers
var overlays = {};
for (var i = 0; i < noise_description.length; i++)
{
overlays[noise_description[i]] = layers[i];
}
//add layer control using above object
L.control.layers(null,overlays).addTo(map);
});
That's the last part of my code, but it's being showed behind another layer (this behavior changes with some refreshment of the page):
I'm wondering how to control this.
All vectors in Leaflet 0.x (I guess you are using Leaflet v0.7.7 from your previous question) are added to a single SVG container in the overlayPane.
This includes your first areas (I think you did not include that code in the current question?) as well as your Circle Markers.
Their stack order depend on their insertion order. So because you load them asynchronously, depending on the time it takes for the server to send the data, your Circle Markers may be below or above your areas.
You could either chain your 2 asynchronous requests to predefine in which order they execute. You would simply start the next query once the first one has completed. But you would delay the data display.
Or you could force some vectors to be brought on top / bottom using bringToFront / bringToBack methods. You would have to loop through your feature group and apply it on each individual layer, like:
all_layers.eachLayer(function (layer) {
layer.bringToFront();
});
The situation is different in Leaflet 1.0, where you can create your own panes and specify their z-index (possibly through CSS). Then you can insert your layers (including vectors) in any desired pane.

FOR loop to iterate through array

I have an array that I would like to iterate through with a for loop to avoid excessive code. I would like to take the following:
var mySchool = document.getElementById(varID[0]);
google.maps.event.addDomListener(mySchool,'click', function() {
filterMap(layer, tableId, map);
});
and have it be more like:
for(var i=0; i < varID.length; i++){
var mySchool = document.getElementById(varID[i]);
google.maps.event.addDomListener(mySchool,'click', function() {
filterMap(layer, tableId, map);
});
}
I've been doing some reading and i suspect it has something to do with Javascript closures but can't for the life of me get it to work with the various code examples i have found. I'm hoping the experienced eye can spot something i'm missing from this Javascript newbie.
My complete code looks like this:
//There are more items in my array but i wanted to keep it short here
var varID = [
"adamRobertson",
"blewett",
"brentKennedy"
];
var tableId = '1yc4wo1kBGNJwpDm6e-eJY_KL1YhQWfftjhA38w8';
function initialize() {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(49.491052,-117.304484),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var layer = new google.maps.FusionTablesLayer();
filterMap(layer, tableId, map);
//Trying to get this to work
for(var i=0; i < varID.length; i++){
var mySchool = document.getElementById(varID[i]);
google.maps.event.addDomListener(mySchool,'click', function() {
filterMap(layer, tableId, map);
});
}
//Trying to avoid this 25 times
/*
google.maps.event.addDomListener(document.getElementById(varID[0]),
'click', function() {
filterMap(layer, tableId, map);
});
*/
}
// Filter the map based on checkbox selection.
function filterMap(layer, tableId, map) {
var where = generateWhere();
if (where) {
if (!layer.getMap()) {
layer.setMap(map);
}
layer.setOptions({
query: {
select: 'Location',
from: tableId,
where: where
}
});
} else {
layer.setMap(null);
}
}
// Generate a where clause from the checkboxes. If no boxes
// are checked, return an empty string.
function generateWhere() {
var filter = [];
var schools = document.getElementsByName('school');
for (var i = 0, school; school = schools[i]; i++) {
if (school.checked) {
var schoolName = school.value.replace(/'/g, '\\\'');
filter.push("'" + schoolName + "'");
}
}
var where = '';
if (filter.length) {
where = "School IN (" + filter.join(',') + ')';
}
return where;
}
google.maps.event.addDomListener(window, 'load', initialize);
The HTML basically contains input for checkboxes to turn my polygons on and off.
Thanks in advance for any help.
I think it will help if you change the code to this:
var mySchool; var limit = varID.length;
for(var i=0; i < limit; i++){
mySchool = document.getElementById(varID[i]);
(function(){
google.maps.event.addDomListener(mySchool,'click', function() {
filterMap(layer, tableId, map);
});
}());
}
I took the for limit calculation out of the loop so that will save some speed too.
I haven't used the maps api so you may have to add some arguments to the closure.
var mySchool; var limit = varID.length;
for(var i=0; i < limit; i++){
mySchool = document.getElementById(varID[i]);
(function(s, l, t, m){
google.maps.event.addDomListener(s,'click', function() {
filterMap(l, t, m);
});
}(mySchool, layer, tableId, map));
}
I'm not sure which args are needed, but you'll probably figure it out.

Categories

Resources