Weird Issue with Javascript object properties - javascript

Apologies in advance if this is an obvious issue. I have done as much searching as I could putting this issue into search terms.
I have the below block of code which is supposed to create a Google maps marker for each 'transponder' if there has not been one added previously. However every time this block of code runs it doesn't detect the previously created marker stored in the transponder object and recreates it.
This is despite seeing the marker within the transponder object in the DOM view of Firebug.
function addOrUpdateTransponderPostionRpt(transponderPositionRpt) {
var t = getTransponderById(transponderPositionRpt.TransponderId);
if (t) {
console.log("Found Transponder: " + t.Id);
if (t.gMapMarker) {
console.log("Transponder has existing marker, updating: " + t.Id);
moveMarker(t.gMapMarker, new google.maps.LatLng(transponderPositionRpt.Latitude, transponderPositionRpt.Longitude));
} else {
console.log("Transponder has no existing marker, creating: " + t.Id);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(transponderPositionRpt.Latitude, transponderPositionRpt.Longitude),
map: map,
title: t.DefaultNickname
});
t.gMapMarker = marker;
}
}
}
debug output from the javascript (the same every time)
Found Transponder: 4
Transponder has no existing marker, creating: 4
Found Transponder: 6
Transponder has no existing marker, creating: 6
Can anyone help ? :)
EDIT: Additional methods referenced in this code block:
function getTransponderById(id) {
var ret;
$.each(transponders, function (i, item) {
if (transponders[i].Id == id) {
ret = transponders[i];
return;
}
});
return ret;
}
function moveMarker(marker, newPosition) {
marker.setPosition(newPosition);
}

Related

GoogleMaps Marker setVisible is not a function

I cannot set a marker in a marker cluster invisible by looping my array of markers. I always get the message Uncaught TypeError: Property 't' of object [object Object] is not a function Which translates to setVisible is not a function in my case. (Found out after debugging in chrom)
The following code is used (simplified):
var markers = [];
function placeMarker() {
marker = new google.maps.Marker({
position: position,
map: map,
icon: pinImage,
});
markers.push(marker);
}
function deleteMarkers() {
if (markers) {
for (var i = 0; i < markers.length; i++) {
markers[i].setVisible(false);
}
markers = [];
}
}
The error is thrown in deleteMarkers on the line with markers[i].setVisible(false); What causes this error to be thrown? It seems like the marker is placed inside the array as Object instead of google.maps.Marker
Solved the problem myself in a way that works, but which is not the best way imho.
I had this script embedded in my source
<script src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/src/markerclusterer_compiled.js" type="text/javascript"></script>
The error wasnt thrown by google maps but instead by the call to removeMarker on the clusterer:
google.maps.event.addListener(marker, 'visible_changed', function () {
if (marker.getVisible()) {
markerCluster.addMarker(marker, true);
} else {
markerCluster.removeMarker(marker, true);
}
});
All I did was removing _compiled from the script (As I wanted to know what goes wrong in this code). But instead of finding the source of this error, the code began to work.
I think there's something interfering with our scripts in the compiled version, as we have many js scripts on our site.
So the problem is fixed for me, as we embed the script as uncompiled version.

Google Maps v3 -> Database/mysql -> AJAX -> LOOP -> AJAX -> Loop

a) the real joke first:
Finally buying Microsoft stuff over the years paid off..
Trying to debug using Chrome, my map was showing just one marker. It was on the correct latlng for the period of the setTimeout, blinks for a small fraction of second, back to same position.
At a certain time, shot code to Explorer by mistake....... voila... code iterates through the database, but does not use the setTimeout for each marker. At Explorer, setTime out (Ex, 5 seconds), means all the markers will show up, with the right infowindow, but it's 5 seconds for all markers. The longer the time, the longer it will stay in one of them (alwyas the same one), going really fast on the other markers. At chrome, the iteration was so fast I could not see the iteration thru the other latlng's. It was just a blink.
b) I guess the problem is that the getJson (or Ajax), using either for loop or $.each (I used all sorts of combinations.....) is combined with the other loop inside the function changeMarker. So there are two loops going on at the same time. However, I don't know how to fix it. If I close the Ajax (or getJson) right after the $.each or for loop, the rest of the code doesn't get the values. Nothing happens (just my alert, which is for debugging purposes).
No, I don't fully understand closures. Yes, I read a bunch of stuff, the main one here, but also here and here and there. but still didn't figure it out to :/
c) Not easy being a newbie, trying to solve a problem for days... and not getting it solved.
Any help will be greatly appreciated!
Here is the code - omitted a long section where map gets personal options.
var BERLIN = new google.maps.LatLng(-32.517683, -46.394393);
var map = null;
var marker = null;
var index = 0;
var infoWindow = null;
var latlng ;
var MY_MAPTYPE_ID = 'custom_style';
function initialize() {
//personal options not included here.
var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);
map.mapTypes.set(MY_MAPTYPE_ID, customMapType);
$.getJSON('php/locationsJson.php',function(json){
$.each( json, function(i, item) {
var lat = this.lat;
var lng = this.lng;
var location = new google.maps.LatLng(json[i].lat,json[i].lng);
alert( json[i].lat +','+json[i].lng );
function dropMarker (map, pos){
return new google.maps.Marker({
map: map,
position: location,
draggable: false,
}); // return
}
function changeMarker() {
if (marker) {
infoWindow.close();
marker.setMap(null);
}
var pos = location[index];
marker = dropMarker(map,pos);
var contentString = ('lat: ' + location.lat() + '<br />' + 'lng: ' + location.lng())
infoWindow.setContent(contentString);
setTimeout(function () {
infoWindow.open(map, marker);
}, 100);
index = (index + 1) % json.length;
setTimeout(function () {
changeMarker();
}, 4000);
}
var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);
infoWindow = new google.maps.InfoWindow()
changeMarker();
}); //$.each
}); //end of getjson
} //end of initialized
Here is fiddle (thanks for the help to get to that point) for the code BEFORE the AJAX. I tried to add the json file in the fiddle, but it's too complex to add json inside the fiddle.
Thank you again for your time.
As your approach in the fiddle works fine, you don't need much modifications to
achieve it via ajax.
Instead of starting the timeouts inside the loop use the loop only to populate the NEIGBORHOODS-array, and after the loop call changeMarker()
The success-callback for $.getJSON:
function(json){
NEIGBORHOODS=[];
$.each(json,
function(){
NEIGBORHOODS.push(new google.maps.LatLng(this.lat,this.lng));
});
changeMarker();
}
The rest of the code may stay as it is in the fiddle.
Working fiddle with ajax-request: http://jsfiddle.net/doktormolle/CVECG/
(Note: In the fiddle I've used $.post() because jsfiddle requires post-requests for JSON, you can use $.getJSON in your application)

Android Webview using Leaflet - JNI Error

I'm developing an Android application containing a Webview. The HTML corresponding to the webview contains mainly JavaScript code ; it retrieves a map of a building from a Geoserver. I use Leaflet to display the different layers. Each base layer is a floor.
I'm adding 2 overlays to the base layers from Android ; one is a heatmap, the other is a set of markers representing the locations of some sensors. Thanks to a JavaScript interface in Android, the JavaScript code can get datasets created from Android.
It works when I display only ONE of the overlays. As soon as I want to display both overlays, or after I displayed an overlay, hid it, and display the other, the application crashes. I have different errors according to the overlay added first.
Something really strange : it only happens with my tablet (which is very cheap), not with the AVD.
Here is my JavaScript code :
<script type="text/javascript" charset="utf-8">
var map, baseLayers, heatmapLayer, sensorsLayer;
var ground_floor = new L.tileLayer.wms('http://192.168.1.16/geoserver/wms',
{
layers: 'ground_floor',
format: 'image/png'
});
var first_floor = new L.tileLayer.wms('http://192.168.1.16/geoserver/wms',
{
layers: 'first_floor',
format: 'image/png'
});
var second_floor = new L.tileLayer.wms('http://192.168.1.16/geoserver/wms',
{
layers: 'second_floor',
format: 'image/png'
});
var current_floor = ground_floor;
baseLayers = {
"Ground floor": ground_floor,
"First floor": first_floor,
"Second floor": second_floor
};
map = new L.Map('map', {
center: new L.LatLng(-45, 170),
zoom: 30,
layers: [ground_floor],
crs: L.CRS.EPSG900913
}).setView([-45.8668664, 170.5185323], 31);
var control = L.control.layers(baseLayers).addTo(map);
map.on('baselayerchange', onBaseLayerChanged);
// Called when the base layer (meaning the floor) is changed
function onBaseLayerChanged(event) {
// Update the current floor
if (event.layer == ground_floor)
current_floor = ground_floor;
else if (event.layer == first_floor)
current_floor = first_floor;
else if (event.layer == second_floor)
current_floor = second_floor;
else
Android.debug("Wrong base layer");
Android.debug("yo1");
// Update the heatmap and sensors' location
// if they are displayed
if (map.hasLayer(heatmapLayer)) {
removeHeatmap();
addHeatmap();
}
Android.debug("yo2");
if (map.hasLayer(sensorsLayer)) {
Android.debug("yo3");
removeSensors();
addSensors();
Android.debug("yo4");
}
}
function addHeatmap() {
heatmapLayer = L.TileLayer.heatMap({
// radius could be absolute or relative
// absolute: radius in meters, relative: radius in pixels
radius: { value: 5, absolute: true },
opacity: 0.8,
gradient: {
0.45: "rgb(0,0,255)",
0.55: "rgb(0,255,255)",
0.65: "rgb(0,255,0)",
0.95: "yellow",
1.0: "rgb(255,0,0)"
}
});
var dataSet;
if (current_floor == ground_floor)
dataSet = JSON.parse(Android.getDataSetGroundFloor());
else if (current_floor == first_floor)
dataSet = JSON.parse(Android.getDataSetFirstFloor());
else if (current_floor == second_floor)
dataSet = JSON.parse(Android.getDataSetSecondFloor());
else
Android.debug("Error getDataSet : wrong floor");
heatmapLayer.setData(dataSet.data);
control.addOverlay(heatmapLayer, "Heatmap");
heatmapLayer.addTo(map);
}
function removeHeatmap() {
control.removeLayer(heatmapLayer);
map.removeLayer(heatmapLayer);
}
function addSensors() {
var sLat, sLon;
var markers = new Array();
if (current_floor == ground_floor) {
sLat = JSON.parse(Android.getLatitudesGroundFloor());
sLon = JSON.parse(Android.getLongitudesGroundFloor());
}
else if (current_floor == first_floor) {
sLat = JSON.parse(Android.getLatitudesFirstFloor());
sLon = JSON.parse(Android.getLongitudesFirstFloor());
}
else if (current_floor == second_floor) {
sLat = JSON.parse(Android.getLatitudesSecondFloor());
sLon = JSON.parse(Android.getLongitudesSecondFloor());
}
else
Android.debug("Error getCoordinates : wrong floor");
for (i=0; i<sLat.length && i<sLon.length; i++) {
var marker = L.marker([sLat[i],sLon[i]]);
markers.push(marker);
}
sensorsLayer = L.layerGroup(markers);
control.addOverlay(sensorsLayer, "Sensors");
sensorsLayer.addTo(map);
}
function removeSensors() {
control.removeLayer(sensorsLayer);
map.removeLayer(sensorsLayer);
}
</script>
If I add the heatmap first, and then the sensors I have a NullPointerException on "sensorsLatFloor" of the following code :
public JSONArray getLatitudesGroundFloor() {
if (!isSensorsQueryDone())
new SelectSensorsLocationATask(SensorsFragment.this).execute();
// Wait for the end of the query
while (!querySuccessful) {}
JSONArray latJSON = null;
latJSON = new JSONArray(sensorsLatGroundFloor);
return latJSON;
}
This is for the ground floor but it does the same for every floor. "sensorsLatGroundFloor" is an ArrayList filled by the AsyncTask SelectSensorsLocationATask after a query in the local database. The code works, since it works when I only want to display sensors.
When I display the sensors first, and then the heatmap, the app crashes and I have the following error in the LogCat :
JNI ERROR (app bug): accessed staled weak global reference 0xffffffff (index 65535 in a table of size 8)
VM aborting
Fatal signal 11 (SIGSEV) at 0xdeadd00d
This is very odd, because I don't manipulate JNI code at all...
Besides, I have another error, which must be very stupid but I don't figure out why it doesn't work. Have a look at this part of my JavaScript code :
// Called when the base layer (meaning the floor) is changed
function onBaseLayerChanged(event) {
// Update the current floor
if (event.layer == ground_floor)
current_floor = ground_floor;
else if (event.layer == first_floor)
current_floor = first_floor;
else if (event.layer == second_floor)
current_floor = second_floor;
else
Android.debug("Wrong base layer");
Android.debug("yo1");
// Update the heatmap and sensors' location
// if they are displayed
if (map.hasLayer(heatmapLayer)) {
removeHeatmap();
addHeatmap();
}
Android.debug("yo2");
if (map.hasLayer(sensorsLayer)) {
Android.debug("yo3");
removeSensors();
addSensors();
Android.debug("yo4");
}
}
This function is supposed to update the overlay(s) displayed when I switch the base layer (meaning the floor). It works with the heatmap, but not with the sensors... If the heatmap is not on the map, the function is finished, it doesn't even look at my second if. You can see my "Android.debug", it displays in the LogCat the message I put as parameter. Here, the LogCat only displays "yo1".
EDIT : I figured something out about this last error. The problem seems to be the Leaflet function "hasLayer". If the map has the layer indicated, it returns true. So in my mind, if it doesn't, it's supposed to return false... It makes sense. But instead of it, it makes the code bug, so the code after the function is ignored. Either I'm making a mistake that I don't see when I call it, or Leaflet made a useless function... So I must have done a silly mistake but I don't find it !
I hope I've been clear enough to let you understand my problems... Let me know if you need more Android code, although I don't think it would be helpful.
Thanking you in advance.
* PROBLEM FIXED *
The errors were caused by a problem of task synchronisation in the Android code. You can see that I wait for the end of the query with the variable "querySuccessful". Actually I was manipulating this variable from the AsyncTask only : I set it to false at the beginning and true at the end. Now I set it to true before I start the AsyncTask, and the application works, I have no more errors.
I still have some problems with the Leaflet function hasLayer ; it works when I switch the base layer once, sometimes twice, but then it stops working. But apparently it might be an error from Leaflet, which will be fixed in the next release.

Storing javascript data in global array not working as expected [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
change global variable inside javascript closure
I am having a problem storing data in a javascript global array . I can't figure out why the array is empty even though I have assigned it some elements.
Basically I have two functions: loadMarkers is called whenever a user clicks a button and gets some information from a url in JSON, parses that data and stores it in the global array. The other function is showMarkers that just iterates over the array and show all the markers, but that array is empty!
Thansks in advance.
var markers = [];
function loadMarkers(url) {
markers = [];
$.get(url, function(data) {
var json = jQuery.parseJSON(data);
for (var i = 0; i < json.length; i++) {
// parsing json
var lat = json[i].Latitude;
var lng = json[i].Longitude;
var id = json[i].ID;
console.log(id); // this prints with no problems!
// create new marker
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
title: id,
html: "<p>" + "Info for container " + id + "</p>"
});
// add marker to markers array
markers.push(markers[i]);
// add info window to marker
google.maps.event.addListener(marker, "click", function() {
infoWindow.setContent(this.html);
infoWindow.open(map, this);
});
}
});
}
function showMarkers() {
for (i = 0; i < markers.length; i++)
console.log(markers); // here I get an empty array!
markers[i].setMap(map);
}
It seems like this line:
markers.push(markers[i]);
should instead be:
markers.push(marker);
Maybe its the following code
// add marker to markers array
markers.push(marker); // was markers[i]
Regarding your second question in the comments the $.get() method returns a jQuery deferred object which allows you to execute functions after method has finished.
$.get().done( function( ) {
// your code
});
There's a typo in the code:
markers.push(markers[i]);
should be:
markers.push(marker);
It can be surprisingly hard to spot this kind of typos by just looking at the code (it's like our brains are trained to let us read what we expect to read)... In this case the best approach to find quickly these kind of errors is to add a debugger; instruction in the code, and follow along the execution of the program through the devtools of your choice.

What is causing this Google Maps marker click error in Chrome?

I wonder whether someone may be able to help me please.
This page allows users to filter (via checkboxes), markers which are placed on the map. Clicking on any marker performs a 'reverse geocode' action and in conjunction with selecting the 'Search Locations' button, the user can then see POI's within a given radius of the clicked marker.
For demo purposes, if you select the 'Coin' checkbox, click the green marker, then select the 'Search Locations' button, the marker will bounce and the right hand sidebar will be populated with POI's.
The problem I'm having is that in Internet Explorer everything works fine, but when I try to run this in Chrome, the marker looses the 'bounce' functionality, the 'reverse geocode' doesn't run and in the error console I receive the following error:
Uncaught ReferenceError: reversegeocode is not defined at line 55 of my code which is:
reversegeocode(); I've done some reading on this and other sites and from reading the guidance I've tried changing this part of my code to this:
function geocodePosition(pos) {
var clickListener =
document.getElementById('findosgb36lat').value = this.mylat;
document.getElementById('findosgb36lon').value = this.mylon;
document.getElementById('address').value = this.myaddress;
if(bouncingMarker)
bouncingMarker.setAnimation(null);
if(bouncingMarker != this) {
this.setAnimation(google.maps.Animation.BOUNCE);
bouncingMarker = this;
}
else bouncingMarker = null;
}
geocoder.geocode({latLng: pos }, function(responses) {
if (responses && responses.length > 0) {
updateMarkerAddress(responses[0].formatted_address);
} else {
updateMarkerAddress('Cannot determine address at this location.');
}
});
}
function updateMarkerAddress(str) {
document.getElementById('address').value = str;
}
function getAddress(latlng) {
if (!geocoder) {
geocoder = new google.maps.Geocoder();
}
geocoder.geocode({ 'latLng': latlng }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// Looping through the result
for (var i = 0; i < results.length; i++) {
if (results[0].formatted_address) {
document.getElementById('address').value =
results[0].formatted_address;
}
}
}
}
)
}
But unfortunately, this doesn't work and actually creates more problems with syntax errors.
I'm relatively new to Javascript, so perhaps I've totally misunderstood,. But I just wondered whether someone could possibly take a look at this please and let me know where I'm going wrong?
Many thanks and kind regards
Code feedback:
What is the second line in your code: var clickListener = meant to do (something is missing)?
Both of your calls to geocoder.geocode pass an object with a property named: latLng; the object passed should match the structure of google.maps.GeocoderRequestapi-doc, which has properties named: address, bounds, location, and region. I suggest you change the name of these properties from: latLng to location.
I'm not sure of the context of the code shown, but the usage of this in this code section looks suspicious:
if(bouncingMarker != this) {
this.setAnimation(google.maps.Animation.BOUNCE);
bouncingMarker = this;
}
It looks like you are within a global function, so it looks like the use of this may not make sense here?
That's all I see after a first pass; hope this helps you -

Categories

Resources