Getting Data into the JSON - javascript

I am trying to visulize Coordinates on the map . Data is Coming form json.
I am getting and error Push is undefined. I am passing the Array but getting error
Here is the Code
var testCtrl = this;
testCtrl.allOrgUnits = response.organisationUnits;
console.log(testCtrl.allOrgUnits)
for (i = 0; i < testCtrl.allOrgUnits.length; i++) {
if(testCtrl.allOrgUnits[i].coordinates != undefined && testCtrl.allOrgUnits[i].coordinates.length < 200) {
testCtrl.geoCoords.push(new Array(testCtrl.allOrgUnits[i].name, testCtrl.allOrgUnits[i].coordinates.substring(1,testCtrl.allOrgUnits[i].coordinates.length-1).split(",")));
}
}
// Add the coordinates to the map.
addMarkers(testCtrl.geoCoords);
});
JSON Data is like
organization units [{ "name":david , "coordinates""[ 10.24 ,23.80] { "name":phil , "coordinates""[ 35.80 ,23.80]
Here is the Function addMarkers
function addMarkers(coordinates) {
var marker;
markers = [];
for (i = 0; i < coordinates.length; i++) {
// Create and add a new marker per coordinate.
marker = new google.maps.Marker({
position: new google.maps.LatLng(coordinates[i][1][1], coordinates[i][1][0]),
map: map,
title: coordinates[i][0],
icon: blueMarker,
current: false,
});
markers.push(marker);
// Add a listener to each marker, so that they will display the name of the facility when clicked.
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent("<div class='info'><h4>" + coordinates[i][0] + "</h4>Facility</div>");
infowindow.open(map, marker);
}
})(marker, i));
}

You probably need to initialize geoCords to be an array before trying to push something.
testCtrl.geoCoords = [];

You are trying to call push method on undefined
You are doing this
testCtrl.geoCoords.push()
where testCtrl has no property geoCoords, so first initialize this property like
testCtrl.geoCoords = []
Now it is an empty array , you can use push method on this

You could transform your json into Object, it might be easier after that.
private ObjectMapper mapper = new ObjectMapper();
listPersonCoordinates = mapper.readValue(query_result, new TypeReference<ArrayList<PersonCoordinate>>(){})
for (PersonCoordinate pc : listPersonCoordinate) {
pc.getName();
pc.getCoordinate();
// Do your stuff here
}
and
public Class PersonCoordinate {
String name;
ArrayList<double> coordinate;
// getters + setters + constructor
}
Hope this help :)
Edit : Your JSON looks strangely formatted. misses some "

Related

Google Maps setTimeout() not working with an AJAX call

I am building a web app that drops markers on a map based on the viewport bounds. The markers are dropping as expected when the user moves the map, but they drop simultaneously and I would like them to drop consecutively.
To solve this, I am attempting to use the window.setTimeout() (as per Google Maps API docs) but I am having trouble making it work with my data which is added to a Set by an AJAX call.
I am not too sure how to structure the window.setTimeout() function within my JS code, which is more complicated than Google's example. I have tried dozens of different variations with no success.
Here is the JavaScript:
var markers = new Set();
var marker, i;
[...]
google.maps.event.addListener(map, "bounds_changed", () => {
var lat0 = map.getBounds().getNorthEast().lat();
var lng0 = map.getBounds().getNorthEast().lng();
var lat1 = map.getBounds().getSouthWest().lat();
var lng1 = map.getBounds().getSouthWest().lng();
$.ajax({
type: 'GET',
url: '/electra/marker_info/',
data: {
'neLat': parseFloat(lat0),
'neLng': parseFloat(lng0),
'swLat': parseFloat(lat1),
'swLng': parseFloat(lng1)
},
success: function (data) {
add_markers(data, i * 200);
}
});
});
[...]
function add_markers(ajaxData, timeout) {
window.setTimeout(() => {
for (i = 0; i < ajaxData.length; i++) { //puts markers in the markers set
if(! markers.has(JSON.stringify(ajaxData[i]))) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(ajaxData[i][2], ajaxData[i][3]),
map: map,
animation: google.maps.Animation.DROP,
})
[...]
markers.add(JSON.stringify(ajaxData[i]));
}
}
}, timeout);
}
Currently you have a single timeout for all the markers.
There is an example in the documentation: Marker Animations With setTimeout() which includes a setMarkerWithTimeout function:
function addMarkerWithTimeout(position, timeout) {
window.setTimeout(() => {
markers.push(
new google.maps.Marker({
position: position,
map,
animation: google.maps.Animation.DROP,
})
);
}, timeout);
}
that can be used in your code, but you will need to change the markers array it uses, as you have a markers array that contains different data and which is used for a different purpose (you can probably remove the markers.push from that function if you don't need references to the google.maps.Marker objects).
function add_markers(ajaxData, timeout) {
for (i = 0; i < ajaxData.length; i++) { //puts markers in the markers set
if(! markers.has(JSON.stringify(ajaxData[i]))) {
addMarkerWithTimeout(new google.maps.LatLng(ajaxData[i][2], ajaxData[i][3]), timeout);
[...]
markers.add(JSON.stringify(ajaxData[i]));
}
}
}
I would change your add_markers function in this way:
function add_markers(ajaxData, timeout) {
for (let i = 0; i < ajaxData.length; i++) { //puts markers in the markers set
if(! markers.has(JSON.stringify(ajaxData[i]))) {
let marker = new google.maps.Marker({
position: new google.maps.LatLng(ajaxData[i][2], ajaxData[i][3]),
map: map,
animation: google.maps.Animation.DROP,
})
[...]
// here you increase the delay based on current number or markers
addMarker(JSON.stringify(ajaxData[i]), timeout * markers.size);
}
}
and define a new function to insert a marker at the wanted time:
function addMarker(marker, interval) {
setTimeout(function() { markers.add(marker); }, interval);
}
Basically you move setTimeout to the function responsible of actually inserting the marker from the function processing the data you get from the Ajax call.
The line below, will make sure that the first marker will be inserted immediately (marker.size being 0); the next ones will be inserted with a timeout distance from each other.
addMarker(JSON.stringify(ajaxData[i]), timeout * markers.size);

Google maps add multiple markers and info windows for each one?

I have my code like this:
function algolia_search(position) {
clearOverlays();
var APPLICATION_ID = 'PSH...VAKL';
var SEARCH_ONLY_API_KEY = '2eb...efa8';
var INDEX_NAME = 'entities';
var PARAMS = { hitsPerPage: 150 };
// Client + Helper initialization
var algolia = algoliasearch(APPLICATION_ID, SEARCH_ONLY_API_KEY);
var algoliaHelper = algoliasearchHelper(algolia, INDEX_NAME, PARAMS);
// Map initialization
algoliaHelper.on('result', function(content) {
renderHits(content);
var i;
// Add the markers to the map
for (i = 0; i < content.hits.length; ++i) {
var hit = content.hits[i];
var infowindow = new google.maps.InfoWindow({
    content: hit.name
    });
var marker = new google.maps.Marker({
position: {lat: hit._geoloc.lat, lng: hit._geoloc.lng},
map: map,
label: hit.name,
animation: google.maps.Animation.DROP,
index: i
});
    marker.addListener('click', function() {
    infowindow.open(map, marker);
    });
addListenerOnPoint(marker);
markers.push(marker);
infos.push(infowindow);
}
});
function renderHits(content) {
$('#container').html(JSON.stringify(content, null, 2));
}
algoliaHelper.setQueryParameter('aroundRadius', 200);
algoliaHelper.search();
}
Now the markers works absolutely fine, however the info windows doesn't. No matter which marker I click, it shows me an info windows from one marker, however I don't exactly know how to solve it.
Explanation of the problem
The infowindow shows you data from one markerbecause when you click on them they call:
infowindow.open(map, marker);
At the point they are clicked, waht do you think the values for infowindow,map and marker are respectively?
Your assumption is that they will hold the values that you set as the for loop is running.
What is happening is that the for loop has finished running completely by the time you click on the the marker. The values of infowindow and marker will happen to be set to the last value of the for loop.
Suggested solution(s)
The solution for this is to find a way to encapsulate the data for each iteration of the loop that will persist when the listener is called.
Two ways to do this are to use the ES6 block scoped let instead of var OR use n IIFE (Immediate Invoked Function Expression) to encapsulate the state of the infowindow and marker for each step of the loop.
Using let:
for(i = 0; i < content.hits.length; ++i) {
// rest of code above --^
let infowindow = new google.maps.InfoWindow({content: hit.name});
let marker = new google.maps.Marker({...});
marker.addListener('click', function() {
infowindow.open(map, marker);
});
// rest of code below --v
}
The above works because what effectively happens is that a new
variable is created for each infowindow and marker variable for
each iteration, almost like creating a new vairable name for each iteration(marker0, marker1, etc)
Using an IIFE:
for(i = 0; i < content.hits.length; ++i) {
// rest of code above --^
var infowindow = new google.maps.InfoWindow({content: hit.name});
var marker = new google.maps.Marker({...});
function(inf, mar){
marker.addListener('click', function() {
inf.open(map, mar);
})(infowindow, marker);
}
// rest of code below --v
}

Can't remove Google Map Markers when reloading data

I'm a having some trouble with google maps V3 API.
Here's my AngularJS Directive:
;
(function () {
"use strict";
angular.module('LoVendoApp.directives')
.directive('map', ['SimpleRETS', 'InfoWindowService', 'McOptions', 'ModalOptions', '$rootScope', '$parse', '$uibModal', '$timeout', 'SafetyFilter',
function (SimpleRETS, InfoWindowService, McOptions, ModalOptions, $rootScope, $parse, $uibModal, $timeout, SafetyFilter) {
return {
restrict: 'A',
scope: {
requestObj: '='
},
link: function (scope, el, attrs) {
//Creating map instance with GoogleMaps API
var map = new google.maps.Map(el[0], {
center: {
lat: 25.7742700,
lng: -80.1936600
},
zoom: 8
});
//Markers array
var markers = [];
console.log('on init = ', markers.length);
/**
* Creates new google maps
* marker
*
* #param {Object} param
*
*/
function _newGoogleMapsMarker(param) {
var r = new google.maps.Marker({
map: param._map,
position: new google.maps.LatLng(param._lat, param._lng),
title: param._head,
icon: param._icon
});
if (param._data) {
google.maps.event.addListener(r, 'click', function () {
// this -> the marker on which the onclick event is being attached
if (!this.getMap()._infoWindow) {
this.getMap()._infoWindow = new google.maps.InfoWindow();
}
this.getMap()._infoWindow.close();
var content = InfoWindowService.getContent(param._data);
this.getMap()._infoWindow.setContent(content);
//Creates event listener for InfoWindow insances
google.maps.event.addListener(this.getMap()._infoWindow, 'domready', function () {
$("#iw_container")
.off("click")
.on("click", modalListener);
//Opens modal when click is listened
function modalListener() {
var modalOptions = ModalOptions.getHouseDetailOptions(param._data);
var modalInstance = $uibModal.open(modalOptions);
}
});
this.getMap()._infoWindow.open(this.getMap(), this);
});
}
return r;
}
//Handling request with SimpleRETS service factory
scope.$on('loadMap', function () {
SimpleRETS.requestHandler(scope.requestObj).then(dataReceived, dataError);
function dataReceived(res) {
if (markers.length > 0) {
for (var k = 0; k > markers.length; k++) {
markers[k].setMap(null);
console.log('removing! #', k);
}
markers = [];
console.log('removed!');
}
var results = res.filter(SafetyFilter.filterData);
$rootScope.globalHousesData = results;
if (markers.length == 0)
$timeout(loadMarkers(results), 1000);
}
function dataError(error) {
console.log('mapError', error);
}
});
//Randomizes position for matching coordinates
function randomPos() {
return Math.random() * (0.0001 - 0.00005) + 0.00005;
}
function loadMarkers(results) {
// Fetching marker options from service
var options = McOptions.getOptions;
for (var i = 0; i < results.length; i++) {
var marker = _newGoogleMapsMarker({
_map: map,
_icon: 'assets/images/icon.png',
_lat: results[i].geo.lat,
_lng: results[i].geo.lng,
_head: '|' + new google.maps.LatLng(results[i].geo.lat, results[i].geo.lng),
_data: results[i]
});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers, options);
}
//Initializes event to load m
scope.$broadcast('loadMap');
}
}
}
]);
})();
As you can see I've been going nuts with console.logs to see what is wrong with my logic. It may look a bit overwhelming but I simply have 4 main components or actions. 1st I initialize the map:
var map = new google.maps.Map(el[0], {
center: {
lat: 25.7742700,
lng: -80.1936600
},
zoom: 8
});
The I instantiate a markers array: var markers = [];
Then I have 2 main functions. One that create new markers: _newGoogleMapMarkers(param)
This function takes a param object that basically contain the map object, position coordinates, an icon, title and some content that should be available in the InfoWindow. Also, I'm attatching an onClick listener to all InfoWindows to open an external modal in my app.
The other function should be triggered when the markers array is empty and it loads the new data from the external API I'm using (SimpleRETS)
This is all triggered by an event `$scope.$broadcast('loadMap') that is triggered everytime filters are changed, the user interacts with some stuff, etc.
The problem is that even though I am calling the loadMarkers() function when the markers array is empty (and after iterating and doing markers[k].setMap(null)), the old markers stay in the map, creating a massive bloab of markers when loading 500 markers with each load. I even tried setting a timeout of 1000ms after the markers array is empty before the next load, to see if it helped in any way, but it doesn't.
So what do you guys think? I'd appreciate any suggestions you might have.
For anyone that might be having the same problem. If you are using the markerclusterer jQuery Plugin you must markerCluster.clearMarkers(); before emptying the markers array after a new load of markers.
So basically it'll end up looking something like this
if (markerCluster) {
markerCluster.clearMarkers();
markers = [];
}
//Load new markers in the markers array
[...]
//Creating Cluster
markerCluster = new MarkerClusterer(map, markers, options);
Then you would do whatever you need to fetch data and replace the markers, since from this point on the map would be clear of markers and clusters.

Ace Editor: Can't get rid of Marker

I am writing a simple widget that simulates a simple 8-bit CPU. For that I am abusing the Ace Editor, as you can see at the center of the image, as my "RAM"-view.
I want to highlight the line that corresponds to the value of the program counter and I am using addMarker() to do so.
However, I can't seem to get rid of that marker once I have set it. _marker is a private member that holds the value of the last marker set. But for some reason removeMarker(_marker) has no effect:
/**
*
*/
setMarker: function(position) {
//if(_marker != null) {
window.cpuRamView.session.removeMarker(_marker);
//}
_marker = new window.Range(position, 0, position, _content[position].length);
window.cpuRamView.session.addMarker(
_marker, "programCounterLocation", "fullLine"
);
}
What am I doing wrong here? :/
add marker returns an id, and removeMarker requires that id, so you can do something like
var Range = require("ace/range").Range // not the window Range!!
var _range
setMarker = function(position) {
if(_range != null) {
window.cpuRamView.session.removeMarker(_range.id);
}
_range = new Range(position, 0, position, _content[position].length);
_range.id = window.cpuRamView.session.addMarker(
_range, "programCounterLocation", "fullLine"
);
}
if(this.marker) {
this.editor.getSession().removeMarker(this.marker);
}
this.marker = this.editor.getSession().addMarker(
new Range(prop('errorLine')(formulaError), prop('errorPosition')(formulaError), prop('errorLine')(formulaError), prop('errorPosition')(formulaError) + 5), style.errorMarker, 'text');
}
set a variable marker to receive the return value, just like this:
marker=editor.session.addMarker(range, "myMarker", "fullLine");
and then remove this marker, like this:
editor.session.removeMarker(marker);

js call function stored in 2D array

I have an array:
var markerArray = [];//global var
var markerCnt = 0;//global var
for(var x=0;x<10;x++){
markerArray[markerCnt] = new Array(agency, address, marker, onMarkerClick);
//agency and agency = string
//marker = google maps marker
//onMarkerClick = function
markerCnt++;
}
How do I call a specified onMarkerClick function?
Would I just do:
markerArray[0][3]();
As an alternative solution, you can also do this:
var markerArray = [];
var markerCnt = 0;
for(var x=0;x<10;x++){
markerArray[markerCnt] = {
'agency' : agency,
'address' : address,
'marker' : marker,
'click' : onMarkerClick
};
markerCnt++;
}
//To call the click
markerArray[0].click();
The answer to your question is yes.
You can execute any function stored in an array, no matter how many dimensions.
// perfectly valid
markerArray[0][3]()
// as is this
someArray[0][1][7][2]()
To go a little bit beyond than just answering your question, I would suggest using an array of objects so you don't have to execute an array member. This will increase readability of your code and saves you a few hours if you look at it in 6 months trying to figure out what you did.
var markerArray = [];//global var
var markerCnt = 0;//global var
for(var x=0;x<10;x++){
markerArray[markerCnt] = {
agency: agency
address: address
marker: marker
onMarkerClick: onMarkerClick
};
//agency and agency = string
//marker = google maps marker
//onMarkerClick = function
markerCnt++;
}
// then reference your function
markerArray[0].onMarkerClick();

Categories

Resources