enabling infowindow on cartodb multilayer geoportal map - javascript

I've created a multilayer-geoportal based on that cartodb blog post.
I have it up and running and hosted on my GitHub site, but I'm trying to enable infowindows, and can't get it to work. Cartodb support suggested I add in the following line:
cdb.vis.Vis.addInfowindow(map, layer.getSubLayer(0), ['cartodb_id']);
after I create the layer. However, when I do that, the map doesn't load at all.
Any suggestions on code that I may be missing in my github repository to fix this problem (line 77 in the multilayer.js file is currently commented out).
To view this live, go to andrewmartini.github.io/labs-multilayer/multilayer.html?u=andrewmartini&t=multilayer_test&v=0d192f34-2a79-11e5-8e7c-0e4fddd5de28&tt=Title&d=descr
Note:
I'm new to this forum, forgive me if I've broken any posting rules. Also I would add more links but since I'm new, the system won't let me yet. I'm relatively new to using GitHub and Javascript but very familiar with GIS.
Thanks, Andrew

So, this answer from folks at Cartodb was a helpful start, and I wanted to share this for others who are experimenting - the line of code from above needed to go inside the addLayer function:
function addLayer(id, show, map) {
return function (layer) {
if (!show) {
layer.hide();
}
cdb.vis.Vis.addInfowindow(map, layer.getSubLayer(0), ['cartodb_id'])
cartodbLayers[id] = layer;
};
}
And also change this:
cartodb.createLayer(map, layerOptions)
.addTo(map)
.done(addLayer(id, layer.show, map))
.error(function (error) {
console.log("error: " + error);
});
But, this still has issues - for instance if you add other columns to the cbd.vis.Vis.addInfowindow function - only the data layers with that column value will load, and all of the others will fail to load. Can anyone tell me how to fix this so that I can add infowindow for selected columns for multiple datasets from my cartodb account/database?

Related

HERE Traffic incidents integration in Leaflet.js

Background:
I'm currently integrating HERE maps into our web-based application. I'm trying both - HERE provided Javascript API and Leaflet at the same time to find the best approach for our use-case.
While JavaScript API provided by HERE maps is OK, rendering wise Leaflet performs much better when using raster tiles.
Issue:
It would be fine by me to use raster tiles + leaflet, but our application also needs to display traffic incidents data.
Traffic incident data is provided by HERE in JSON and XML formats (Documentation link, Example JSON). They provide [Z]/[X]/[Y], quadkey, prox, bbox, or corridor filters which can be used to retrieve filtered data set.
I've tried using [Z]/[X]/[Y] addressing with custom L.TileLayer implementation which loads appropriate JSON, converts it to GeoJSON and displays GeoJSON on map. However that approach is very inefficient and significant performance drop is visible.
Question:
Maybe anyone has already solved this issue and could share any insights on how the HERE traffic incidents could be shown on Leaflet map without encountering performance issues?
I created the following script, which works without any performance issues:
var fg = L.featureGroup().addTo(map);
function loadTraffic(data) {
fg.clearLayers();
var d = data.TRAFFICITEMS.TRAFFICITEM.map((r) => {
var latlngs = [];
if (r.LOCATION.GEOLOC) {
if (r.LOCATION.GEOLOC.ORIGIN) {
latlngs.push(L.latLng(r.LOCATION.GEOLOC.ORIGIN.LATITUDE, r.LOCATION.GEOLOC.ORIGIN.LONGITUDE));
}
if (r.LOCATION.GEOLOC.TO) {
if (L.Util.isArray(r.LOCATION.GEOLOC.TO)) {
r.LOCATION.GEOLOC.TO.forEach((latlng) => {
latlngs.push(L.latLng(latlng.LATITUDE, latlng.LONGITUDE));
})
} else {
latlngs.push(L.latLng(r.LOCATION.GEOLOC.TO.LATITUDE, r.LOCATION.GEOLOC.TO.LONGITUDE));
}
}
}
var desc = r.TRAFFICITEMDESCRIPTION.find(x => x.TYPE === "short_desc").content;
return {
latlngs,
desc
}
})
console.log(d);
d.forEach((road)=>{
L.polyline(road.latlngs,{color: 'red'}).addTo(fg).bindPopup(road.desc);
});
map.fitBounds(fg.getBounds())
}
If this script is not working for you, please share your json file.
Ok, so I've found a solution for this task. Apparently I was on a good path, I only needed to optimize my implementation.
What I had to do to achieve appropriate performance is:
Create custom CircleMarker extension which would draw custom icon on canvas
Create JS worker which would fetch the data from a given URL, transform it to GeoJSON and return GeoJSON to it's listener
Create custom GridLayer implementation, which, in fetchTile function, creates worker instance, passes it a link with appropriate [Z]/[X]/[Y] coordinates already set, adds listener, which listens for worker's done event and returns empty tile
On worker's done event, custom GridLayer implementation creates GeoJSON layer, adds it to the dictionary with coordinates as a key and, if zoom level is still the same - adds that layer to the map
Add zoomend observer on a map, which removes any layers that does not match current zoom level from the map
Now the map is definitely usable and works way faster than original HERE JS API.
P.S. Sorry, but I can't share the implementation itself due to our company policies.

How Can I animate Bing map pushpins based on a live GPS feed

I have looked over the bing maps documentation trying to find an answer to my question. I would prefer to do everything using the bing maps api and not have to add a third party library if possible.
Question: How can I animate a pushpin to make a smooth transition from one set of gps coordinate(longitude/latitude) to another in order to simulate smooth movement of a Pushpin on Bing maps?
Question: can deleting an entire object out of the map.entities array waste enough resources to cause performance issues? If so how can I change the pushpin latitude and longitude properties without deleting the entire object?
Sample code of trying to change the pushpins properties without deleting the object out of the array. This code does not work… I am unsure why it is not working?
map.entities.get(theIndexOfThePushPin)._location.latitude = newLat;
map.entities.get(theIndexOfThePushPin)._location.longitude = newLon;
I create a pushpin like so - This works fine
map.entities.push(new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(lat, lon), {
text: text,
visible: true,
textOffset: new Microsoft.Maps.Point(0, 5)
}));
Pseudo code for my recursive angular $http call
function BusMoveGPSRefresh() {
$http.get(resourceURL)
.then(function (data) {
if ('if pushpins have not been created') {
//create pushpins...
}
} else {
//delete pushpins out of the array and then recreate them
//with updated lon/lat. Or just update existing objects lon/lat properties if possible?
}
}
BusMoveGPSRefresh();//after everything is done then go get more info and start again. recursion...
}, function (reason) {// if fail than do
console.log(reason);
console.log("This Is not Working!!! Dang!!");
});
}
Any insight into the problem would be greatly appreciated! Thanks!
I could not find a simple answer for adding animation. I did find a site that gave a step by step tutorial on a more in-depth answer on how to animate pushpins.
Answer: 1 -- tutorial on how to animate bing map pushpins
https://blogs.bing.com/maps/2014/08/07/bring-your-maps-to-life-creating-animations-with-bing-maps-javascript/
Answer: 2 -- this is how to update the pushpin location without deleting the pushpin object out of the entities array.
Instead of deleting the entire pushpin object find the pushpin index and then use the property "setLocation()" and then add a new location.
//check to make sure that the lat and lon have
//changed if it is still the same location do nothing. else update
if (map.entities.get(indexOfPushpin).getLocation().latitude != lat
|| map.entities.get(indexOfPushpin).getLocation().longitude != lon) {
map.entities.get(indexOfPushpin).setLocation(new Microsoft.Maps.Location(lat, lon));
}

Cannot read property '_leaflet_mousedown5' of null when attempting to enable marker dragging in Mapbox/Leaflet

I am building the functionality that allows mapbox markers to be edited from within a CMS. The functionality should open up and populate a form when a map marker is clicked, and then allow the map marker to be dragged. When the form is saved, the content is submitted via ajax and then the map is reloaded with the featureLayer.loadURL("my_geojson_endpoint").
I have added comments throughout my code below to outline how I am getting to the error.
N.B. I define a property db_id in the geojson to identify each point because when you apply a filter, _leaflet_id changes. I also have jquery included in the code.
Code:
// loop through each marker, adding a click handler
$.each(points._layers, function (item) {
var point = points._layers[item];
attachClickHandler(point);
});
function attachClickHandler(point) {
// open the edit state for the marker on click
$(point._icon).on("click", function () {
openEditState(point);
})
}
function openEditState (point) {
disableEditOthers(point);
displayContent(point);
point.dragging.enable(); // this line causes the error
$(point._icon).off("click");
}
function disableEditOthers (point) {
// hide the other markers from the map (using db_id as mentioned above)
points.setFilter(function (f) {
return f.db_id === point.feature.db_id;
})
// this functions as a callback to display the popup
// since applying the filter on click, does not show the popup
setTimeout(function () {
for (key in points._layers) {
points._layers[key].openPopup();
}
}, 0)
}
In the map creation step I have been able to call this dragging.enable() method on each of the markers and provide "draggability" to all of them, however this is undesirable from a usability point of view. I want the user to clear swap in and out of an edit state.
I discovered this issue on github, solved by the solution to this. However after swapping my mapbox.js version out to the standalone and including the latest version of leaflet (0.7.3) the same error still occured.
Am I calling the function on the wrong property of the object? dumping out the "point" variable just before the line which errors does not show that the draggable property has the enable() function defined.
Any help is much appreciated.
Ok so as a slight workaround, but still not solving the original error.
$.each(points._layers, function (item) {
points._layers[item].dragging.enable()
})
Because I have filtered out the other points, enabling dragging on all points is working around the issue.
If you can provide a fix to my original fix (avoiding the loop) I am happy to accept it.

heatmap-leaftet updating heatmap with more data

I am using the heatmap.js library from pa7 in github successfully to make some heatmap
http://www.patrick-wied.at/static/heatmapjs/example-heatmap-leaflet.html
But when I updated the heatmap with additional data or new data points, the leaflet library does not really update with the additional data points. There seems to be no method that can used for redraw. I dont know if someone has already solved this problem, thats why I am asking to see. Here is the simple portion of my additional script:
ndata=[{lat: 13.59, lon:-17.05, value: 11},{lat: 33.08, lon:-103.24, value: 19}]
testData.data.push.apply(ndata)
layer.addData(testData.data);
There is no errors in the console of Google chrome or no exceptions.
Thanks
There is a redraw method in the layer:
var heatmapLayer = L.TileLayer.heatMap();
// add layer to map
heatmapLayer.redraw()
Having said this, in the latest version, the heatmap layer automatically redraws when you set the data (see https://github.com/pa7/heatmap.js/blob/d09c4e99852b4849e2b4d4f12976a9fce0327ca5/src/heatmap-leaflet.js#L112).

Google Maps - open InfoWindow onMouseover instead onClick

I have a question regarding Google Maps and a jquery plugin that I use to display maps, etc.
All works fine, Marker Positioning, reload of page (with new db query to retrieve new data based on the new map coordinates, etc. ....)
Only thing that I did not manage to get to work is to change the behavior of the info windows (bubbles) on the map.
I would like them to open "onMouseOver" instead of "onClick" - can you help me out?
What I am using is this: http://gmap.nurtext.de/download.html
I know it's not the "most up tp date" thing, but it does what I need (and it's easy).
Sample is here: http://www.divessi.com/code/geo/divecenter.php?lat=48.14&lon=11.73&s=600
Christian
This should work. When looping throught the markers, add this:
GEvent.addListener(gmarker, 'mouseover', function() {
gmarker.openInfoWindowHtml(opts.html_prepend + marker.html + opts.html_append);
});
mouseover, or any other GMarker event http://code.google.com/apis/maps/documentation/javascript/v2/reference.html#GMarker
EDIT. I notice that you are using the deprecated Google Maps v2. I edited the code. Basically is what you had there. But be sure to add the listener before adding the marker to the overlay, just in case.
EDIT2. To avoid have the same infowindow for all your markers, wrap the code in a function so that a closure is created: (for more info read "The infamous Loop Problem" http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/ )
function listenMarker (gmarker,marker) {
GEvent.addListener(gmarker, 'mouseover', function() {
gmarker.openInfoWindowHtml(opts.html_prepend + marker.html + opts.html_append);
});
}
Put the function at the end of your file for example and call it inside the loop.
There is a js file included in the sample you linked to above
/code/js/jquery.gmap-1.1.0_CK.js
There are several lines of code in there related to the mouseover event and they are commented out:
//GEvent.addListener(gmarker,"mouseover", function() {
// this.openInfoWindowHtml(myHtml[j]);
//});
and
//GEvent.addListener(marker, "mouseover", function() {this.openInfoWindowHtml("no." + j + opts.markers[j]);});
//GEvent.addListener(gmarker,"mouseover", function() {
// this.openInfoWindowHtml("test " + j); //+ ": " + opts.html_prepend + marker.html + opts.html_append
//});
This is the reference for the Google Maps Javascript API V2 that the plugin is using:
http://code.google.com/apis/maps/documentation/javascript/v2/reference.html#GMarker
You can see definitions of the methods used by the plugin.
I'd recommend having a look at the reference then try uncommenting some of the lines above as you see fit.
Version 3 of the API is quite easy to use in case you wanted to try it without a plugin.
HTH

Categories