Welcome to the LimeSurvey Community Forum

Ask the community, share ideas, and connect with other LimeSurvey users!

Google maps and previous maps answers

  • BCorfman
  • BCorfman's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
9 years 8 months ago - 9 years 8 months ago #110337 by BCorfman
Google maps and previous maps answers was created by BCorfman
Hello,

I'm trying to implement a survey where someone picks a location on one map, and then picks a location on another map, and it calculates the distance between those two points.

To do this I'm attempting to implement a modified version of tpartner's code from this page: www.limesurvey.org/en/community-services...on?start=10&start=20


But no matter what I try, I can't get this to work. I have absolutely no experience with Javascript so I've been trying to stumble my way through it, but can't figure it out. Here is the code I modified and attached to question 2:
Code:
<script type="text/javascript" charset="utf-8">  
 
  $(document).ready(function(){
 
    // Identify the map
    var map2SGQA = '{SGQ}';
    var map1SGQA = '774328X12X32';
    var currentMap = gmaps[''+map2SGQA+'_c'];
 
 
    // Wait for the map to load
    google.maps.event.addListenerOnce(currentMap, 'idle', function(){ 
 
      // Some variable definitions
      var currentMarker = gmaps['marker__'+map2SGQA+'_c'];
      var answerInput = $('#answer'+map2SGQA+'_c');
      var defaultPosition = $(answerInput).val();
      var startLat = $('{INSERTANS:'+map1SGQA+'}').val().split(';')[0];
      var startLng = $('{INSERTANS:'+map1SGQA+'}').val().split(';')[1];
      var startLatLng = new google.maps.LatLng(startLat, startLng);
      var originIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&amp;chld=O|FFFF00|000000';
 
 
      // Listener on the map events
      google.maps.event.addListener(currentMap, 'click', function() {
        calculateDistances(startLatLng, currentMarker.getPosition());
      });
      google.maps.event.addListener(currentMarker, 'dragend', function() {
        calculateDistances(startLatLng, currentMarker.getPosition());
      });
      google.maps.event.addListener(currentMap, 'rightclick', function() {
        calculateDistances(startLatLng, currentMarker.getPosition());
      });
 
      // Insert the results element
      $(answerInput).after('<div class="distanceResults" />');
 
    });
  });
 
  function calculateDistances(origin, destination) {
    var service = new google.maps.DistanceMatrixService();
    service.getDistanceMatrix({
      origins: [origin],
      destinations: [destination],
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC,
      avoidHighways: false,
      avoidTolls: false
    }, callback);
  }
 
  function callback(response, status) {
    if (status != google.maps.DistanceMatrixStatus.OK) {
      alert('Error was: ' + status);
    } else {
      var origins = response.originAddresses;
      var destinations = response.destinationAddresses;
 
      var outputDiv = $('.questiontext');
      outputDiv.innerHTML = '';
 
      for (var i = 0; i < origins.length; i++) {
        var results = response.rows[i].elements;
        for (var j = 0; j < results.length; j++) {
          $('.distanceResults').html('Start address: '+origins[i]+'<br />\
                        End address: '+destinations[j]+'<br />\
                        Distance: '+results[j].distance.text+'<br />\
                        Time: '+results[j].duration.text+'');
        }
      }
    }
  }
</script>


I could also see doing this by setting the start point of the second map to the answer of the first map, but because of how map questions output answers I can't figure out how to get that to work either.


Edit:

When putting both maps on the same page and using the following code, I have gotten this to work somewhat. Unfortunately it won't change the starting location after it has tried calculating everything once, so if anyone has any suggestions there I'd like to fix that.
Code:
<script type="text/javascript" charset="utf-8">  
 
  $(document).ready(function(){
 
    // Identify the map
    var map2SGQA = '{SGQ}';
    var map1SGQA = '774328X12X32';
    var currentMap = gmaps[''+map2SGQA+'_c'];
    var prevMap = gmaps[''+map1SGQA+'_c'];
 
 
    // Wait for the map to load
    google.maps.event.addListenerOnce(currentMap, 'idle', function(){ 
 
      // Some variable definitions
      var currentMarker = gmaps['marker__'+map2SGQA+'_c'];
      var prevMarker = gmaps['marker__'+map1SGQA+'_c'];
      var answerInput = $('#answer'+map2SGQA+'_c');
      var defaultPosition = $(answerInput).val();
      var startLat = $('#answer'+map1SGQA+'_c').val().split(' ')[0];
      var startLng = $('#answer'+map1SGQA+'_c').val().split(' ')[1];
      var startLatLng = new google.maps.LatLng(startLat, startLng);
      var originIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&amp;chld=O|FFFF00|000000';
 
 
      // Listener on the map events
      google.maps.event.addListener(prevMap, 'click', function() {
        startLatLng = prevMarker.getPosition();
      });
      google.maps.event.addListener(prevMarker, 'dragend', function() {
        startLatLng = prevMarker.getPosition();
      });
      google.maps.event.addListener(prevMap, 'rightclick', function() {
        startLatLng = prevMarker.getPosition();
      });
 
      google.maps.event.addListener(currentMap, 'click', function() {
        calculateDistances(startLatLng, currentMarker.getPosition());
      });
      google.maps.event.addListener(currentMarker, 'dragend', function() {
        calculateDistances(startLatLng, currentMarker.getPosition());
      });
      google.maps.event.addListener(currentMap, 'rightclick', function() {
        calculateDistances(startLatLng, currentMarker.getPosition());
      });
 
      // Insert the results element
      $(answerInput).after('<div class="distanceResults" />');
 
    });
  });
 
  function calculateDistances(origin, destination) {
    var service = new google.maps.DistanceMatrixService();
    service.getDistanceMatrix({
      origins: [origin],
      destinations: [destination],
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC,
      avoidHighways: false,
      avoidTolls: false
    }, callback);
  }
 
  function callback(response, status) {
    if (status != google.maps.DistanceMatrixStatus.OK) {
      alert('Error was: ' + status);
    } else {
      var origins = response.originAddresses;
      var destinations = response.destinationAddresses;
 
      var outputDiv = $('.questiontext');
      outputDiv.innerHTML = '';
 
      for (var i = 0; i < origins.length; i++) {
        var results = response.rows[i].elements;
        for (var j = 0; j < results.length; j++) {
          $('.distanceResults').html('Start address: '+origins[i]+'<br />\
                        End address: '+destinations[j]+'<br />\
                        Distance: '+results[j].distance.text+'<br />\
                        Time: '+results[j].duration.text+'');
        }
      }
    }
  }
</script>
Last edit: 9 years 8 months ago by BCorfman.
The topic has been locked.
  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
9 years 8 months ago - 9 years 8 months ago #110377 by tpartner
Replied by tpartner on topic Google maps and previous maps answers
I would use something like the script below. This puts listeners on two maps on a page and when they are moved, calculates the addresses and distance and loads it into a long-text type question.

Code:
<script type="text/javascript" charset="utf-8">  
  $(document).ready(function() {
 
    // Identify the elements
    var map1Question = $('input.text.location:eq(0)').closest('.text-short');
    var map2Question = $('input.text.location:eq(1)').closest('.text-short');
    var map1SGQA = $('input.text.location', map1Question).attr('id').replace(/answer/, '').replace(/_c/, '');
    var map1 = gmaps[''+map1SGQA+'_c'];
    var marker1 = gmaps['marker__'+map1SGQA+'_c'];
    var map1Input = $('#answer'+map1SGQA+'_c');
    var map2SGQA = $('input.text.location', map2Question).attr('id').replace(/answer/, '').replace(/_c/, '');
    var map2 = gmaps[''+map2SGQA+'_c'];
    var marker2 = gmaps['marker__'+map2SGQA+'_c'];
    var map2Input = $('#answer'+map2SGQA+'_c');
    var resultsInput = $('.text-long:eq(0) .textarea');
 
    // Disable the results textarea
    $(resultsInput).attr('readonly', true);
 
    // Wait for the maps to load
    google.maps.event.addListenerOnce(map1, 'idle', function(){ 
      // Listeners on the map 1 events
      google.maps.event.addListener(map1, 'click', function() {
        updateDistance();
      });
      google.maps.event.addListener(marker1, 'dragend', function() {
        updateDistance();
      });
      google.maps.event.addListener(map1, 'rightclick', function() {
        updateDistance();
      });
    });
    google.maps.event.addListenerOnce(map2, 'idle', function(){ 
      // Listeners on the map 2 events
      google.maps.event.addListener(map2, 'click', function() {
        updateDistance();
      });
      google.maps.event.addListener(marker2, 'dragend', function() {
        updateDistance();
      });
      google.maps.event.addListener(map2, 'rightclick', function() {
        updateDistance();
      });
    });
 
    function updateDistance() {
      var startLat = $(map1Input).val().split(' ')[0];
      var startLng = $(map1Input).val().split(' ')[1];
      var startLatLng = new google.maps.LatLng(startLat, startLng);
      var endLat = $(map2Input).val().split(' ')[0];
      var endLng = $(map2Input).val().split(' ')[1];
      var endLatLng = new google.maps.LatLng(endLat, endLng);
 
      calculateDistances(startLatLng, endLatLng);
    }
 
    function calculateDistances(origin, destination) {
      var service = new google.maps.DistanceMatrixService();
      service.getDistanceMatrix({
        origins: [origin],
        destinations: [destination],
        travelMode: google.maps.TravelMode.DRIVING,
        unitSystem: google.maps.UnitSystem.METRIC,
        avoidHighways: false,
        avoidTolls: false
      }, callback);
    }
 
    function callback(response, status) {
      if (status != google.maps.DistanceMatrixStatus.OK) {
        alert('Error was: ' + status);
      } else {
        var origins = response.originAddresses;
        var destinations = response.destinationAddresses;
 
        for (var i = 0; i < origins.length; i++) {
          var results = response.rows[i].elements;
          for (var j = 0; j < results.length; j++) {
            $(resultsInput).val('Start address: '+origins[i]+'\n\nEnd address: '+destinations[j]+'\n\nDistance: '+results[j].distance.text+'\n\nTime: '+results[j].duration.text+'');
          }
        }
      }
    }
 
  });
</script>

Here's a working 2.05 survey with the script in the source of the first map question.

File Attachment:

File Name: limesurvey...6-25.lss
File Size:22 KB




.

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
Last edit: 9 years 8 months ago by tpartner.
The following user(s) said Thank You: dglp
The topic has been locked.
  • BCorfman
  • BCorfman's Avatar Topic Author
  • Offline
  • New Member
  • New Member
More
9 years 8 months ago - 9 years 8 months ago #110563 by BCorfman
Replied by BCorfman on topic Google maps and previous maps answers
Thanks so much, this works pretty much perfectly.

Edit: The problems below are suddenly not happening anymore; go figure. I would like to know if there's a reason why the following listener inserted into the code you provided doesn't react to the map center changing when the geocoder changes the map center:

listener:
Code:
google.maps.event.addListener(map1, 'center_changed', function() {
  updateDistance();
});

Geocoding (there is a second one of these attached to the second map with all the 1s replaced with 2s):
Code:
<script>
    var geocoder1;
    var mapgeo1;
    var markergeo1;
    function initialize1() {
        geocoder1 = new google.maps.Geocoder();
        mapgeo1 = gmaps[''+'{SGQ}_c'];
        markergeo1 = gmaps['marker__{SGQ}_c'];
    }
    function codeAddress1() {
        var address1 = document.getElementById('address1').value;
        geocoder1.geocode( { 'address': address1}, function(results1, status1) {
            if (status1 == google.maps.GeocoderStatus.OK) {
                var coords1 = String(results1[0].geometry.location)
                coords1 = coords1.replace(/\(?\)?\,?/g, '')
                document.getElementById('answer{SGQ}_c').value = coords1;
                mapgeo1.setCenter(results1[0].geometry.location);
                markergeo1.setPosition(results1[0].geometry.location);
            } else {
                alert('Geocode was not successful for the following reason: ' + status1);
            }
        });
    }
 
google.maps.event.addDomListener(window, 'load', initialize1);
 
</script>

button (again, another one on the second map):
Code:
<div id="panel">
  <input id="address1" type="textbox" value="" /> <input onclick="codeAddress1()" type="button" value="Suche" /></div>




I am trying to get it to work with a geocoder, and both sets of js work fine individually, but for some reason whenever I try searching with the search box element that calls the geocoder it makes the distance calculation js stop working. Here's the code for the geocoding:

-removed-


And then, of course, I added lines like this into the distance js (though they have nothing to do with it not working)

-removed-

Any idea why these aren't interacting well? I tried to make them not have any overlapping variables or anything in case that was the problem but it hasn't helped.

Edit: Oh, and here's the button in case it matters:
-removed-
Last edit: 9 years 8 months ago by BCorfman.
The topic has been locked.
  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
9 years 8 months ago #110619 by tpartner
Replied by tpartner on topic Google maps and previous maps answers
Can you attach a test survey with your code?

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
The topic has been locked.

Lime-years ahead

Online-surveys for every purse and purpose