Real Time Google Map in Rails - ruby-on-rails

I have a google map that shows up on a page, with markers on each location with a different marker based on each locations status.
I want for when a location is updated: the map to be re-rendered for everyone who is viewing it. This means all the markers would update, so no user would be looking at old marker indicators.
How can I achieve this? I tried to use render_Sync, but apparently render_sync gem has to load an entire collection seperately. Meaning it tries to render the map as many times as locations there are, which sends too many requests to Google Maps and fails/breaks it.

Your google map is initialized in your view via Javascript call. You just need to write method which make repeated calls to your controller or other REST server in some time intervals. After each successfull response you will update your markers positions.
Something like that:
<script type="text/javascript">
var handler = Gmaps.build('Google');
var markers = [];
var once = true;
$(document).on('rails_admin.dom_ready', function() {
handler.buildMap({ provider: {maxZoom: 20, zoom: 15}, internal: {id: 'map'}}, function(){
getMarker();
window.setInterval(getMarker, 5000);
});
});
function getMarker() {
$.post('/api/v1/get_position',
{
uuid: '<%= #object.uuid %>'
},
function (data, status) {
handler.removeMarkers(markers);
markers = [];
markers = handler.addMarkers([
{
"lat": data.lat,
"lng": data.lng,
"infowindow": "<%= #object.name %>"
}
]);
if (once) {
handler.fitMapToBounds();
handler.bounds.extendWith(markers);
handler.map.centerOn({ lat: data.lat, lng: data.lng });
once = false;
}
console.log(data);
});
};
</script>
<div style="width: 800px;">
<div id="map" style="width: 800px; height: 600px;"></div>
</div>

You can use Action Cable to broadcast the coordinates to the UI, save them in some data attributes and poll them from your map script.
You can follow the steps below:
Create a new channel. Lets call it 'locations':
rails g channel locations
Broadcast the latest coordinates as you receive them:
ActionCable.server.broadcast 'locations_channel', { latitude: 'NEW_LATITUDE', longitude: 'NEW_LONGITUDE' }
Once you receive the latest coordinates on the UI, you can set them as data attributes for your map div like this:
$('#map').data(data);
You can find the code snippet for this part in this gist
Poll the map div's data attributes at a regular interval and update the marker's position with:
marker.setPosition(latlng)
I have written a step by step guide on Medium on how to do this. You can take a look for more.

Related

how to set the map center and zoon in gmap4rails

I am a student in china . and when use the gmap4rails gem I have one problem.I want to set the mao center and zoom like the official guide offer
https://developers.google.com/maps/documentation/javascript/tutorial?#HelloWorld
so I code like the picture shows.but it doesn't work. and google the question but didn't get the answer.what is more ,i want set the language to chinese I just like do like this but It didn't work.
var mapOptions = {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8
};
handler = Gmaps.build('Google',mapOptions);
can you help me?
You should do:
var mapOptions = {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8
};
handler = Gmaps.build('Google');
handler.buildMap( {provider: mapOptions, internal: {id: 'map'}}, function(){
//code to add overlays etc... here
});
Or:
handler = Gmaps.build('Google');
handler.buildMap( {internal: {id: 'map'}}, function(){
// handler.map is the proxy object created by the gem,
// where you can add your custom methods,
// like centerOn
handler.map.centerOn([-34.397, 150.644]);
// handler.getMap() is the google map object
// you can also access it with handler.map.getServiceObject()
handler.getMap().setZoom(8);
});
It's important to pass the id of the div where you want the map to appear.

Google Maps and ASP .NET MVC - Center the map at a marker

I'm building a page with a Google MAP that has a side bar with dynamically created divs linked to positions of markers in the map.
I'm using ASP.NET MVC with JQuery and Google Maps API v3.
Here is a look of it.
This page is loaded in a splash window and is generated dynamically.
In the background page the user types a state or city in an input field and in my controller action I search for all people that are located in that area and return a JSON.
I get the JSON and populate the map with markers and then I make the list of divs in the side bar.
I'd like to add a function to those divs that when they are clicked the map will center at the marker.
I came up with an idea for this solution which I could not finish.
I added class="clickable" and the attributes "Lat" and "Lng" with the values equal to the ones in the markers they are related to, and I tried to get their click event with JQuery and then set the map center with its Lat and Lng like this:
$(".clickable div").click(function(){
$('map_canvas').panTo($(this).attr('lat'), $(this).attr('lng'));
}
I had 2 problems with this approach.
- First, I didn't know how to get the map with JQuery.
I found 2 ways using like $('map_canvas').gMap but it didn't work. Tried a couple more things that I've found here in Stackoverflow but also didn't work.
Second - The JQuery would not catch the event click from the DIVs.
I tested on Google Chrome console the JQuery code and It worked but then my code would not trigger the click.
I tried something like $(".clickable div").click(function(){ alert("test"); } on Google Chrome and it worked, but in my script it did not.
I also tried to add listeners using addDomListener in my code but couldn't get around that either.
Could anyone please give me a light what would be a good way to do this without having to recreate the map when a div is clicked.
I also don't like the idea of adding Lat and Lng attributes to the divs, I don't know if that would work in any browser or if its good practice. I'm just out of solutions to this.
Here is the code I'm using. (I removed some of it to make it shorter and easier to read)
$(document).ready(function () {
//Google Maps API V3 - Prepares the ajaxForm options.
var options = {
beforeSubmit: showRequestPesquisaAdvogados,
success: showResponsePesquisaAdvogados,
type: 'post',
resetForm: false
};
$('#form-pesquisaAdvogado').ajaxForm(options);
//$(".clickable").click(function () { alert($(this).attr('lat')) });
});
function showRequestPesquisaAdvogados(formData, jqForm, options) {
$("#modal-processing-background").show(); //Shows processing splash window
}
function showResponsePesquisaAdvogados(responseText, statusText, xhr, $form) {
$("#modal-processing-background").hide();
//Hide processing window
loadSplashWindow();
CreateMap(responseText);
CreateSideBar(responseText);
}
}
function CreateMap(json) {
var mapOptions = {
center: new google.maps.LatLng(json[0].Endereco.Lat, json[0].Endereco.Lng),
zoom: 5,
mapTypeId: google.maps.MapTypeId.ROADMAP
// marker:true
};
var infoWindow = new google.maps.InfoWindow();
var map = new google.maps.Map(document.getElementById("map-result"), mapOptions);
for (i = 0; i < json.length; i++) {
var data = json[i]
var myLatlng = new google.maps.LatLng(data.Endereco.Lat, data.Endereco.Lng);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: data.Endereco.Logradouro
});
(function (marker, data) {
// Attaching a click event to the current marker
google.maps.event.addListener(marker, "click", function (e) {
// Prepare the infoWindows content.
var contentString = //my content;
infoWindow.setContent(contentString);
infoWindow.open(map, marker);
});
//here I tried to add the listener to the div.
google.maps.event.addDomListener($(".clickable")[i], 'click',
function () {
map.panTo(new google.maps.LatLng($(this).attr('lat'),
$(this).attr('lng')));
});
})(marker, data);
}
}
function CreateSideBar(json) {
$(".sideBarConteiner").empty();
for (i = 0; i < json.length; i++) {
var contentString =
"<div class='clickable' lat='" + data.Endereco.Lat +
"' lng='" + data.Endereco.Lng + "' >" +
//...div's content here
"</div>";
$(".sideBarConteiner").append(contentString);
}
}
If you have any suggestions to make the code better or better practices, since I have only 3 months of experience with programming I might be going in the wrong direction without knowing, so please, feel free to change something if you think it'd be a better way.
I know my post is a bit lenghty, I just wanted to make it clear.
Thank you for your support in advance.
Regards,
Cesar.
I've found a way to do this by creating a global variable in javascript and keeping the map information in order to call it again later.
To to this I just added a var "map" right at the top of the .
<script type="text/javascript">
$.ajaxSetup({ cache: false }); //Forces IE to renew the cash for ajax.
var zoom = 8;
var mapOptions, map;
And then call a method to pan to the right point.
I added the properties Lat and Lng to the div and then pass the div in the javascript function and get the attributes from it.
function CreateSideBar(json) {
$(".sideBarConteiner").empty();
for (i = 0; i < json.length; i++) {
var contentString =
"<div class='clickable' data-lat='" + data.Endereco.Lat +
"' data-lng='" + data.Endereco.Lng + "' onclick='MarkerFocus(this)'>" +
//...div's content here
"</div>";
$(".sideBarConteiner").append(contentString);
}
}
And in my function:
function MarkerFocus(obj) {
var myLatlng =
new google.maps.LatLng($(obj).attr('data-lat'), $(obj).attr('data-lng'));
map.panTo(myLatlng);
}
It worked for me. I hope it helps you too.
Thanks to all for the help and support.
Cesar

Loading Fusion Tables InfoWindow data in a div outside map

I hope someone can help with what is probably a fairly simple query. I have seen a question on here about trying to do this without a mouseclick, but I want to add an event listener to the markers on the Fusion Table map that will load the infoWindow content in a separate div below the map. So far I have suppressed the infoWindow, but I'm a bit lost on the next step of adding the click, retrieving the data relevant to that marker and loading into the div.
The marker display is limited to markers within a set radius of the user's location, in order to reduce load time.
I'm assuming I need to start with something like this:
google.maps.event.addListener(layer, 'click', function() {
I'd be grateful for any clues.
Here's the relevant bit of my code so far:
var tableid = '[ID]';
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'Location',
from: tableid,
where: 'ST_INTERSECTS(Location, CIRCLE(LATLNG'+marker.position+', 2000))'
},
options: {
suppressInfoWindows: true
}
});
var circle = new google.maps.Circle({
map: map,
radius: 2000,
fillOpacity: 0.1,
strokeOpacity: 0,
clickable: false
});
circle.bindTo('center', marker, 'position');
layer.setMap(map);
});
EDIT:
For everyone's amusement, this is what I've tried so far:
google.maps.event.addListener(layer, "click", function () {
$('#infoWindowDiv').append('new google.maps.infoWindowHtml');
});
It probably comes as a surprise ot no-one that it doesn't work. But hey, at least I'm trying! Thanks
EDIT 2:
I'm delighted to say I have found a solution that works - which I post here for anyone else who might have the same problem/goal:
google.maps.event.addListener(layer, "click", function (e) {
document.getElementById("infoWindowDiv").innerHTML = e.infoWindowHtml;
});
I'm delighted to say I have found a solution that works - which I post here for anyone else who might have the same problem/goal:
google.maps.event.addListener(layer, "click", function (e) {
document.getElementById("infoWindowDiv").innerHTML = e.infoWindowHtml;
});

Why is my Google Map in a jQuery UI tab only displaying one tile at the top left corner of the screen?

I have two Google Map API v3 Maps in jQuery tabs. They both display the first time they appear in their tabs, but the initially deselected tab only displays a tile or so at the top left-hand corner.
Calling google.maps.event.trigger(all_map, 'resize') periodically does not change this.
In my code I have:
<div id='all_map_canvas'>
</div>
<script>
function show_all_map()
{
var center = new google.maps.LatLng(%(center_latitude)s - .15, %(center_longitude)s + .2);
var myoptions = {
zoom: %(zoom)s,
center: center,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
all_map = new google.maps.Map(document.getElementById('all_map_canvas'), myoptions);
all_map.setZoom(%(zoom)s);
jQuery('#all_map_canvas').show();
google.maps.event.trigger(all_map, 'resize');
}
function show_all_map_markers()
{
%(all_map_markers)s
}
var markers = [];
jQuery('#all_map_canvas').width(jQuery(window).width() - 300);
jQuery('#all_map_canvas').height(jQuery(window).height() - 125);
How can I make both maps display in full after tab swaps?
I had the same problem: Google map in div that has style display:none;.
Solved it with this two steps:
Removing all additional styling of the div I'm placing the map except height:100%;
Initiate the map after the holding div is displayed not when the it is created. In my case in the callback function of the show method:
CSS
.main-window #map{
height:100%;
}
JS
$('.main-window').show(3000, function() {
// create the map after the div is displayed
var mapOptions = {
center: new google.maps.LatLng(42.499591, 27.474961),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
});
HTML
<div class="main-window">
<div id="map"></div>
</div>
Initiating it in events like jQuery's '$(document).ready(...' or Google's 'google.maps.event.addDomListener(window, "load", ...' is not working for some reason.
Hope it helps.
I am using gmaps.js which is a simplified api for google map. But it's simply a matter of attaching a tabsshow event in javascript and refreshing the map in the delegate's function.
Here's the code I use for gmaps.js
$('#tabs').bind('tabsshow', function(event, ui) {
event.preventDefault();
if (ui.panel.id == "tabs2") {
//gmaps.js method
map.refresh();
map.setCenter(lastLoc.lat(), lastLoc.lng());
//for native google.maps api
google.maps.event.trigger(map, 'resize');
map.panTo(new google.maps.LatLng(lastLoc.lat(), lastLoc.lng()));
}
});

add marker with Google-Maps-for-Rails

I was playing with https://github.com/apneadiving/Google-Maps-for-Rails and
i'd like to clear all the marker on a map and add a new one at the position clicked by the user on the map, I added the following code in my page
<script type="text/javascript" charset="utf-8">
function gmaps4rails_callback() {
google.maps.event.addListener(Gmaps4Rails.map, 'click', function(object){
alert(object.latLng);
});
</script>
And in this way i can see an alert with the lat and long value, now how can i delete the old markers and create a new marker and place it on the map?
If you want to clear markers created by gmaps4rails, use this js function:
Gmaps4Rails.clear_markers();
otherwise, loop through your markers and make marker.setMap(null)
Well, the following function removes all markers and add a new one where user clicks:
var marker = null;
function gmaps4rails_callback() {
Gmaps4Rails.clear_markers();
if (marker != null) { marker.setMap(null); }
google.maps.event.addListener(Gmaps4Rails.map, 'click', function(object){ marker = new google.maps.Marker({position: object.latLng, map: Gmaps4Rails.map});});
}
Notes:
You could use whatever logic you desire in the js code to create only one marker or send it's coordinates through ajax.
latitude can be retrieved with: object.latLng.lat(), longitude with: object.latLng.lng()
Another way to add markers is to use the add_marker function described here: https://github.com/apneadiving/Google-Maps-for-Rails/wiki/Dynamic-%28or-Ajax%29-map-refresh

Resources