I try something : I have a gMap with markers.
In my index I initialise my google map, put markers etc. Everything is working.
On the left of my page I show the info of the 5 lasts markers on the maps (name, date etc.).
So for that I call a template named _timeline.
When I click one element I do an action -> Move the map. But For now, everytime I do this action, the map is reloaded (and markers are gone). I just want to see the map moving to center the marker.
But let's see my code, this is probably more simple :
my index.html.erb
<div class="row">
<% #statuses_t.each do |status| %>
<%= render partial: "statuses/timeline", locals: { status: status } %>
<% end %>
</div>
<script type="text/javascript">
handler = Gmaps.build('Google');
handler.buildMap({
provider: {
disableDefaultUI: true
// pass in other Google Maps API options here
},
internal: {
id: 'map'
}
},
function(){
markers = handler.addMarkers((<%=raw #hash.to_json %>));
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
}
);
</script>
handler is the gMap
in statuses/timeline
... # some things
<script type="text/javascript">
$(<%="timeline_div#{status.id}"%>).on("click", function() {
var centerpoint = new google.maps.LatLng(<%=status.latitude%>, <%=status.longitude%>);
gMap = new google.maps.Map(document.getElementById('map'));
gMap.setZoom(13);
gMap.setCenter(centerpoint); // HERE
gMap.setMapTypeId(google.maps.MapTypeId.ROADMAP);
});
</script>
this create a new map when a click on the item, the probleme is : I don't want to reload a page, I just want to change re-center the map with setCenter.
So I want to use the handler variable from Index in my template.
How can I do that ?
So
My variable vas already global ( template has the variable )
Thanks to comments, I had to do handler.map.centerOn(<%=status.latitude%>, <%=status.longitude%>) and that's work
Related
I am trying to plot out multiple map markers and info windows with Google Maps. I am not able to get the map to render when I add multiple markers, but I can get it to render with a central location. I am passing data from an API request in the backend to the client with EJS.
To start off, I can get the map to load at a central location given the users lat/lng that is generated from their zipcode in the backend. Here is what that code looks like on the client side (search.ejs) file:
<script>
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: <%= userLat %>, lng: <%= userLng %> },
zoom: 10
});
}
</script>
After the post request completes and renders the search.ejs file, this block of code will render a Google Map with a central point to those coordinates. The coordinates are passed in from the backend via EJS. So I know that I can successfully use the data passed in via EJS to do stuff with Google Maps.
Now, I want to be able to render markers and info windows based on the returned API location data in the backend. I can pass the location coordinates from the backend API request to the client side with no problem. I know I am successfully passing the API location data to the client by way of a console.log() in the terminal and actually rendering the data to the HTML page with this EJS tag <%= %>.
Here is the code I have writted in my search.ejs template to render the Google Map with the markers and info windows:
<script>
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: <%= userLat %>, lng: <%= userLng %> },
zoom: 10
});
}
var infoWindow = new google.maps.InfoWindow();
var marker, i;
var venueLocations = <%= venues.venues %>;
for (i = 0; i < venueLocations.length; i++) {
marker = new google.maps.Marker({
position: new google.mapsLatLng(venueLocations[i].location.lat, venueLocations[i].location.lng),
map: map,
animation: google.maps.Animation.DROP
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(venueLocations[i].location);
infowindow.open(map, marker);
}
})(marker, i));
}
</script>
This is my footer.ejs file so you can see where I am loading the Google Maps API script:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="/public/js/frontend.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD_tYpqkFMkUc1mq2pzsBGySr6IeQkFhBA&callback=initMap" async defer>
</script>
And finally, this is the error that I am getting in the console when the map is trying to render with the markers:
Uncaught SyntaxError: Unexpected identifier (index):36
Uncaught Lb {message: "initMap is not a function", name: "InvalidValueError", stack: "Error↵ at new Lb (https://maps.googleapis.com/m…MkUc1mq2pzsBGySr6IeQkFhBA&callback=initMap:150:59"}
The Unexpected identifier (index):36 throws me off because I can only think that it is referring to index.ejs, but there is nothing at line 36 that has to do with this, so I am thinking I am wrong about what this means.
Your problem is probably because you've got a typo here causing an error:
position: new google.mapsLatLng(venueLocations[i].location.lat, venueLocations[i].location.lng),
This should be:
position: new google.maps.LatLng(venueLocations[i].location.lat, venueLocations[i].location.lng),
I'm having a bit of trouble getting a google map to initialize on a page loaded by AJAX.
Live test page (in dev): http://dma.nz/practice/
The map is near the bottom of the page.
Currently it works - the map initializes when page it loaded directly or via AJAX, however it's giving me the following error in console:
Uncaught TypeError: Cannot read property 'firstChild' of null
In my footer I have:
<script src="/js/map.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBpC5JE9ZmQduEXiGbiNxZsws8OLMiC-Bw&callback=initMap" async defer></script>
<script src="/js/init.js"></script>
map.js contains:
function initMap() {
var mapOptions = {
zoom: 17,
center: new google.maps.LatLng(-36.85855, 174.754944),
disableDefaultUI: true,
styles: [
{"featureType":"administrative",
"elementType":"labels.text.fill",
"stylers":[{"gamma":"0.00"},{"weight":"0.01"},{"visibility":"off"}]
},
{"featureType":"landscape",
"elementType":"all",
"stylers":[{"color":"#ffffff"}]
},
{"featureType":"landscape.natural",
"elementType":"geometry",
"stylers":[{"visibility":"on"}]
},
{"featureType":"landscape.natural.terrain",
"elementType":"geometry.stroke",
"stylers":[{"visibility":"on"}]
},
{"featureType":"poi",
"elementType":"all",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road",
"elementType":"all",
"stylers":[{"saturation":"-100"},{"lightness":"32"},{"visibility":"on"}]
},
{"featureType":"road",
"elementType":"labels.text",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road.highway",
"elementType":"all",
"stylers":[{"visibility":"simplified"}]
},
{"featureType":"road.highway",
"elementType":"geometry",
"stylers":[{"visibility":"on"},{"lightness":"63"}]
},
{"featureType":"road.highway",
"elementType":"labels.text",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road.highway",
"elementType":"labels.icon",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road.arterial",
"elementType":"labels.icon",
"stylers":[{"visibility":"off"}]
},
{"featureType":"transit",
"elementType":"all",
"stylers":[{"visibility":"off"}]
},
{"featureType":"transit.station",
"elementType":"all",
"stylers":[{"visibility":"off"}]
},
{"featureType":"water",
"elementType":"all",
"stylers":[{"visibility":"on"},{"color":"#eeeeee"}]
}
]
};
// Get the HTML DOM element that will contain your map
var mapElement = document.getElementById('google-map');
// Create the Google Map using our element and options defined above
var map = new google.maps.Map(mapElement, mapOptions);
// Add marker
var marker = new google.maps.Marker({
icon: '/img/icons/map-pin.svg',
position: new google.maps.LatLng(-36.858749, 174.754944),
map: map,
title: 'DMA'
});
}
And then the related part of init.js
ajaxLoad = function(html) {
init();
// init google map
initMap();
// change html title
var HTMLtitle = $(".content > section:first-of-type").attr("data-title");
$(document).prop('title', HTMLtitle);
document.title = HTMLtitle;
// Used for popState event (back/forward browser buttons)
changedPage = true; }
The callback on my google maps API script call appears to properly initialize the map if page is loaded directly. If page is loaded by AJAX that doesn't work so I added the line initMap(); there to load the map after the new content is loaded via AJAX.
This is working, but throwing an error and I'm worried that this error is causing other script on my page not to work properly.
Any ideas on how to modify this so that the map initializes regardless of whether the page is loaded directly or by AJAX, and doesn't create any JS errors? Thanks!
I reproduced the error when I switched from the http://dma.nz/practice/ page to http://dma.nz/projects/ page.
As I can see you try to initialize map instance in line 82 of your map.js. The problem here is missing element with id "google-map". You don't have any DOM element with id "google-map" when you load the projects page. So you try to pass null in map constructor.
To avoid this error add a check that DOM element with id "google-map" exists.
// Get the HTML DOM element that will contain your map
var mapElement = document.getElementById('google-map');
if (mapElement) {
// Create the Google Map using our element and options defined above
var map = new google.maps.Map(mapElement, mapOptions);
// Add marker
var marker = new google.maps.Marker({
icon: '/img/icons/map-pin.svg',
position: new google.maps.LatLng(-36.858749, 174.754944),
map: map,
title: 'DMA'
});
}
I'm using rails 5 with turbolinks 5 and trying to get google places autocomplete address form to work using the example from google's website found here
I only want to load the javascript and google maps library on this page.
What would be the correct way to get the following javascript to work with rails 5 and turbolinks 5.
<script>
// This example displays an address form, using the autocomplete feature
// of the Google Places API to help users fill in the information.
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
var placeSearch, autocomplete;
var componentForm = {
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_1: 'short_name',
country: 'long_name',
postal_code: 'short_name'
};
function initAutocomplete() {
// Create the autocomplete object, restricting the search to geographical
// location types.
autocomplete = new google.maps.places.Autocomplete(
/** #type {!HTMLInputElement} */(document.getElementById('autocomplete')),
{types: ['geocode']});
// When the user selects an address from the dropdown, populate the address
// fields in the form.
autocomplete.addListener('place_changed', fillInAddress);
}
function fillInAddress() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
for (var component in componentForm) {
document.getElementById(component).value = '';
document.getElementById(component).disabled = false;
}
// Get each component of the address from the place details
// and fill the corresponding field on the form.
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType).value = val;
}
}
}
// Bias the autocomplete object to the user's geographical location,
// as supplied by the browser's 'navigator.geolocation' object.
function geolocate() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var geolocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
var circle = new google.maps.Circle({
center: geolocation,
radius: position.coords.accuracy
});
autocomplete.setBounds(circle.getBounds());
});
}
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"
async defer></script>
I solved Turbolinks 5 and Google Maps API problem just with data-turbolinks-eval="false" attribute on my google maps script tag.
... application.html.erb
<head>
<!-- Other HTML page Head content -->
<title><%= content_for?(:title) ? yield(:title) : "Untitled" %></title>
<script async src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_MAPS_API_KEY" data-turbolinks-eval="false"></script>
<%= javascript_include_tag "application", 'data-turbolinks-track' => 'reload' %>
</head>
and in your coffee/js files use:
coffee:
$(document).on "turbolinks:load", ->
map = new google.maps.Map $('map').get(0), mapOptions
js:
$(document).on("turbolinks:load", function(){
map = new google.maps.Map($('map').get(0), mapOptions)
})
Try this too....
google.maps.event.addDomListener(window, 'turbolinks:load', initialize);
I was not happy with other answers as Google Maps throws a warning if loaded multiple times, e.g. while re-visiting a page, and disabling Turbolinks defeats its purpose. Also using Google Maps JavaScript API's callback argument forces you to pollute window name space.
Instead we can get Google Maps scripts, e.g. with jQuery, if and only if it is not loaded yet. Here is the CoffeeScript that I use with Rails 4.2.10:
initMap = ->
...
$(document).on 'turbolinks:load', ->
// if you would like to limit what views are affected
// see https://brandonhilkert.com/blog/organizing-javascript-in-rails-application-with-turbolinks/
// return unless $('.plots.map').length > 0
if typeof(google)=='undefined' or typeof(google.maps)=='undefined'
$.get
url: "https://maps.googleapis.com/maps/api/js?key=<use_your_key>&libraries=geometry"
dataType: 'script'
success: initMap
else
initMap()
As per the documentation:
Turbolinks evaluates script elements in a page’s body each time it renders the page. You can use inline body scripts to set up per-page JavaScript state or bootstrap client-side models. To install behavior, or to perform more complex operations when the page changes, avoid script elements and use the turbolinks:load event instead.
But the reason it wasn't working for me was because in layouts/application.html.erb I had:
<%= javascript_include_tag "application", 'data-turbolinks-track' => true %>
when it should be:
<%= javascript_include_tag "application", 'data-turbolinks-track': 'reload' %>
I am loading longitude and latitude from my database, I want to add an additional field for for my function and pass in other values from my database to show when I click on my pin, it works fine with just the latitude and longitude as the parameters for the function AddData(latitude,longitude) but as soon as I add another value like AddData(latitude,longitude,Zoo Name) my map no longer displays. I am unsure of what I am doing wrong and I apologise if this is a simple mistake but I am just getting use to javascript.
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null, infobox, dataLayer;
function GetMap() {
// Initialize the map
map = new Microsoft.Maps.Map(document.getElementById("myMap"),
{ credentials: "API Bing Key" });
dataLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(dataLayer);
var infoboxLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(infoboxLayer);
infobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false, offset: new Microsoft.Maps.Point(0, 20) });
infoboxLayer.push(infobox);
#foreach (var item in Model)
{
#: AddData(#item.latitude,#item.longitude,#item.ZooName);
//till here
}
}
function AddData(latitude, longitude,ZooName) {
var pin = new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(latitude, longitude));
pin.Title = latitude.toString();
pin.Description = latitude.toString();
Microsoft.Maps.Events.addHandler(pin, 'click', displayInfobox);
dataLayer.push(pin);
}
function displayInfobox(e) {
if (e.targetType == 'pushpin') {
infobox.setLocation(e.target.getLocation());
infobox.setOptions({ visible: true, title: e.target.Title, description: e.target.Description });
}
}
</script>
<body onload="GetMap();">
<div id='myMap'></div>
</body>
Adding an additional parameter to your function shouldn't cause the map to stop working. I suspect that an error is occurring when accessing the #item.ZooName value. I'm guessing that this is a string, it likely needs to be surrounded with quotes. You should see an error in the browsers console. As such, the error is likely preventing the code to load the map from firing and thus the map is never loaded.
I tried to search the answer from docs, but couldn't find..
How can I enable clustering in Gmaps4rails when I add markers on the map via AJAX. My view has this:
<%= gmaps( map_options: { zoom: 15, auto_adjust: false } ) %>
and in my javascript I add the markers like this:
$.getJSON(path, { lat: lat, lng: lng, user_lat: user_lat, user_lng: user_lng }, function(markers_json) {
Gmaps.map.replaceMarkers(markers_json);
});
I'd just like to set the do_clustering option to true, but because I don't have markers json in the map gmaps() call, I can't add the markers options either.
Tell gmaps4rails directly:
Gmaps.map.markers_conf.do_clustering = true;
And include this script:
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.9/src/markerclusterer_packed.js"></script>