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
Related
I have a page to display all markers on a single google map and use map.data.loadGeoJson to achieve this.
The markers link to their respective details page with the following:
map.data.addListener('click', function(event) {
var id = event.feature.getProperty('name');
window.location.href = 'submission-details.php?submission_id='+id;
});
(The property 'name' is a json file property and the ID for each submission).
I would like the details page to also show a map, but only with one marker relevant to that specific details page.
My json type is feature collection, so I think I need a way to target each feature from the collection, rather than just using map.data.loadGeoJson which displays them all.
Not sure where to go from here and struggled to find someone else asking the same question so any help appreciated!
UPDATE
Thanks Duncan.
I added:
map.data.loadGeoJson('../photo_share/upload/file.json', {},function() {
map.data.getFeatureById(53);
map.data.getFeatureById(53).getProperty('name');
console.log(map.data.getFeatureById(53));
console.log(map.data.getFeatureById(53).getProperty('name'));
});
google.maps.event.addDomListener(window, "load", initMap3);
And it does display in console log, but how do I now use this to only display the one marker, because it currently displays all of them still.
The google.maps.Data class has a getFeatureById method. Given you're passing that id into the submission-details.php page, you should be able to use that to get just the single feature.
You still need to use loadGeoJson, and wait until that's loaded before trying to access it; see Google Maps API: getFeatureById for feature collection not working
Update: And then to stop the whole collection displaying, maybe something like this (completely untested)?
map.data.loadGeoJson('../photo_share/upload/file.json', {}, function(features) {
// get the feature you want:
var feature = map.data.getFeatureById(53);
// hide the current set:
map.data.setMap(null);
// wipe out all the current features:
for (var i = 0; i < features.length; i++) {
map.data.remove(features[i]);
}
// add the feature you want back in:
map.data.add(feature);
// display it:
map.data.setMap(map);
});
I try to make a map with mapbox and omnivore plugin of Leafet in order to search a data with the tutorial. I don't know how integrate this code from omnivore plugin in my case. I use for my datas a geojson url $.getJSON, clustering markers with MarkerCluster of Leaflet.
Thank you for your response.
Best regards.
Sandrine
EDIT
I try to filter marker cluster group with Mapbox js tool.
It works very well but I would like to insert this feature to my project. But I don't know how to make with the other features : omnivore plugin, search the data, displaying the popup, marker cluster group. Could you help me ?
My js Fiddle "filtering marker cluster group" : https://jsfiddle.net/sduermael78/rgoxpxwq/4/
My project : https://jsfiddle.net/sduermael78/1uuubmwb/42/
You currently load your data through both jQuery $.getJSON and directly from your mapbox account.
Then if my understanding is correct, you would like to replace these methods by using leaflet-omnivore plugin?
Direct replacement is quite straight forward, as you could directly use:
var geojsonLayer = omnivore.geojson("filePath", null, L.mapbox.featureLayer());
geojsonLayer.addTo(map);
Now it becomes slightly more complicated when you want to cluster your markers (using Leaflet.markercluster plugin in your case). But it is similar to $.getJSON since both perform an asynchronous AJAX request, and you have to make the conversion in a callback.
With leaflet-omnivore, you use the .on("ready", callback) syntax:
var geojsonLayer = omnivore.geojson("filePath", null, L.mapbox.featureLayer())
.on("ready", function() {
var markers = L.markerClusterGroup();
markers.addLayer(geojsonLayer);
markers.addTo(mymap);
});
Updated JSFiddle: https://jsfiddle.net/1uuubmwb/39/
EDIT
OK I missed your part where you "want to search the data" as done in the tutorial from mapbox you point to.
In your case it is more complicated as you want to cluster your markers, so you do not directly have your mapbox feature layer, but a marker cluster group.
A workaround would be to replace the content of that cluster group everytime you change the filtering condition on your geojsonLayer mapbox feature layer:
// this will "hide" markers that do not match the filter.
geojsonLayer.setFilter(showCode);
// replace the content of marker cluster group.
markers.clearLayers();
markers.addLayer(geojsonLayer);
Then for your popup, you have to create it and bind it manually, as mapbox feature layer needs your GeoJSON data to use the title attribute (if so, it automatically uses that info to fill the popup / "tooltip" content):
function attachPopups() {
// Create popups.
geojsonLayer.eachLayer(function (layer) {
var props = layer.feature.properties;
layer.bindPopup(
"<b>Code unité :</b> " + props.CODE_UNITE + "<br />" +
"<b>Adresse web :</b> <a href='" + props.ADRESSE_WEB + "' target='_blank'>" + props.ADRESSE_WEB + "</a>"
);
});
}
Unfortunately, it looks like .setFilter() removes that popup, so you would need to call this attachPopups() function after every setFilter.
Demo: https://jsfiddle.net/1uuubmwb/40/
Thank you for your answer. In fact, I would like to use leaflet-omnivore plugin in order to search a data from geojson with url.
The tutorial is : https://www.mapbox.com/mapbox.js/example/v1.0.0/filtering/
"Use setFilter as a fast search to filter out markers based on a user query".
How to display the popup from geojson with url in these new case ? layer.bindPopup(feature.properties.CODE);
Can I use all this features to build my map (search on markers, clustering markers...) ?
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?
I think this means I'm missing something basic about the working of nested functions in javascript, but I'm failing to add or remove a layer from a leaflet map using a click function. Specifically, I have a leaflet map with numerous vector layers defined. One of these layers is added to the map on page load, and then subsequent layers are supposed to load on a click event in a layer selector.
Here's the function that handles the click, then updates the sidebar legend, updates classes in the layer selector, and is supposed to update the visible layer:
// ADD THE LAYER CONTROL FUNCTION
$('.layer').click(function() {
var oldLayer = $('.active').attr('id');
var newLayer = $(this).attr('id');
console.log(oldLayer + ' --> ' + newLayer);
$('#infobits').html('<h2>' + this.text + '</h2><hr>' + legendFormatter(
this.id));
map.removeLayer(oldLayer);
$('.layer').removeClass('active');
$(this).addClass('active');
map.addLayer(newLayer);
});
Every time I click on a new layer I get Uncaught TypeError: undefined is not a function, no matter where I put the function (I even had it inside the .getJSON() call for a bit). What's perplexing is that is I go to the JS console in my browser and type verbatim what the function is producing on line 49 of the above script (map.removeLayer(Percent_TC_bg)), the map removes the layer in question.
What can I do to get my map adding and removing layers without error?
I suppose TypeError is thrown inside addLayer or removeLayer. Map#addLayer and #removeLayer accepts ILayer object as parameter, but oldLayer and newLayer is obviously String, which came directly from HTML element's ID property.
So changing oldLayer and newLayer to appreciate ILayer object will fix the problem, I guess.
Edit: Igor beat me to it.
Mics is right - the HTML element's ID is a string, and doesn't reference the layer. You could do something like this after you define your layers to work around this issue:
var myLayers = {
"Percent_TC_bg": Percent_TC_bg,
"Percent_TC": Percent_TC
};
And then add the handler like so
$('.layer').click(function() {
var oldLayer = myLayers[$('.active').attr('id')];
var newLayer = myLayers[$(this).attr('id')];
// ...
});
I am trying to use the Google Maps V3 API ClusterManager from http://cm.qfox.nl/ to cluster together markers on a map, but I'm hitting the same error in my code as in the original web site - an error when the page is loaded the first time, or reloaded:
Uncaught TypeError: Cannot call method 'fromLatLngToPoint' of undefined ClusterManager_v3.js:586
ClusterManager.latlngToPoint ClusterManager_v3.js:586
ClusterManager._getMarkerBounds ClusterManager_v3.js:645
ClusterManager._cacheMarkerIcon ClusterManager_v3.js:580
ClusterManager.update ClusterManager_v3.js:345
(anonymous function) ClusterManager_v3.js:91
It works fine after the initial load, so I'm fairly sure it's because of a timing issue - e.g., the map or marker isn't initialized before it being used. Unfortunately, I can't figure out a way to wait for everything to initialize because Javascript isn't my first language. Any help or pointers would be most welcome. The source from the web site is the code I'm using almost exactly.
UPDATE:
If found that changing the line:
cm._requestUpdate(50);
to
cm._requestUpdate(250);
Prevented the error. Changing it to 150 resulted in the error occurring 3/10 times. I'm not entirely sure this is a fix, but it maybe so I'm leaving this posted just in case anyone else has a better solution or wants to know mine.
For using Projection methods , it must be initialized. Map will trigger "projection_changed" event, when Projection will be created.Only after that you can use map.getProjection(). So my suggestion is, to add "projection_changed" event's listener, and initialize ClusterManager when it is called:
google.maps.event.addListenerOnce(map, 'projection_changed', function(){
var cm = window.cm = new ClusterManager(
map,
{
objClusterIcon: new google.maps.MarkerImage('markers/cluster.png', false, false, false, new google.maps.Size(20,20)),
objClusterImageSize: new google.maps.Size(20,20)
}
);
// now json contains a list of marker positions. lets add them.
for (var i = 0; i < json.length; ++i) {
.....
}
cm._requestUpdate(50);
});