- Posts: 8
- Thank you received: 0
Welcome to the LimeSurvey Community Forum
Ask the community, share ideas, and connect with other LimeSurvey users!
Can survey participants directly mark specific locations on the map?
- Hyeran
- Topic Author
- Offline
- New Member
Less
More
6 months 1 week ago #251290
by Hyeran
Can survey participants directly mark specific locations on the map? was created by Hyeran
Hello. I am planning to integrate OpenStreetMap into a survey, allowing participants to directly indicate areas of discomfort within City A (Example).
I am reaching out to inquire if this functionality is possible in LimeSurvey.
I am reaching out to inquire if this functionality is possible in LimeSurvey.
- Is it feasible to implement the mentioned feature in LimeSurvey? It would be sufficient if we could obtain latitude and longitude for specific locations.
- If the first question is achievable in LimeSurvey, is there a method to enable multiple selections for several locations within a single question?
Please Log in to join the conversation.
- tpartner
- Offline
- LimeSurvey Community Team
Less
More
- Posts: 10109
- Thank you received: 3595
6 months 1 week ago - 6 months 1 week ago #251297
by tpartner
Cheers,
Tony Partner
Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
Replied by tpartner on topic Can survey participants directly mark specific locations on the map?
There is no core LimeSurvey facility to record multiple locations from a map but I have been working on this for a new custom question theme, using
ArcGIS Esri Leaflet
.
Add the following three blocks of code to the source of a multiple-short-text question. It will insert a Leaflet map and allow dropping of multiple location markers. When a marker is dropped, its coordinates and Geolocation data are recorded in the question text inputs.
In lines 20-30 of the JavaScript, you will need to replace "yourAPIKey" with an ArcGIS API key and adjust the map parameters to your requirements.
1) Links to the various Leaflet files:
2) Some styles:
3) The required JavaScript:
Sample survey attached:
Add the following three blocks of code to the source of a multiple-short-text question. It will insert a Leaflet map and allow dropping of multiple location markers. When a marker is dropped, its coordinates and Geolocation data are recorded in the question text inputs.
In lines 20-30 of the JavaScript, you will need to replace "yourAPIKey" with an ArcGIS API key and adjust the map parameters to your requirements.
1) Links to the various Leaflet files:
Code:
<!-- Load Leaflet from CDN --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" crossorigin="" /> <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" crossorigin=""></script> <!-- Load Esri Leaflet from CDN --> <script src="https://unpkg.com/esri-leaflet@3.0.10/dist/esri-leaflet.js"></script> <script src="https://unpkg.com/esri-leaflet-vector@4.0.1/dist/esri-leaflet-vector.js"></script> <!-- Load Esri Leaflet Geocoder from CDN --> <link rel="stylesheet" href="https://unpkg.com/esri-leaflet-geocoder@^3.1.3/dist/esri-leaflet-geocoder.css"> <script src="https://unpkg.com/esri-leaflet-geocoder@^3.1.3/dist/esri-leaflet-geocoder.js"></script>
2) Some styles:
Code:
<style type="text/css" data-author="Tony Partner"> .custom-map-outer-container .custom-map { max-width: 100%; } .custom-map-outer-container .leaflet-popup-content { line-height: 1.3; font-size: 13px; } .custom-map-outer-container .leaflet-popup-content p { margin: 0 0 10px 0; } .custom-map-outer-container .leaflet-popup-content p:last-child { margin: 0 0 0 0; } @media only screen and (max-width: 400px) { .custom-map-outer-container .leaflet-popup-content { max-width: 200px; } } </style>
3) The required JavaScript:
Code:
<script type="text/javascript" data-author="Tony Partner"> $(document).on('ready pjax:scriptcomplete',function(){ // Your Your Esri Leaflet (ArcGIS) API key var apiKey = 'yourAPIKey'; // Initial map parameters var position = '51.5072 -0.1279'; // Lat/Long coordinates, separated by a space var zoom = 12; var mapWidth = '800px'; var mapHeight = '400px'; // Some text definitions var removeText = 'Remove marker'; var warningText = 'Only 6 markers are allowed. You must remove a marker before adding another.'; //// NO EDITING REQUIRED BELOW HERE //// var qID = {QID}; var thisQuestion = $('#question'+qID); thisQuestion.addClass('custom-map-question'); // Disable the text inputs $(':text.form-control', thisQuestion).prop('readonly', true); // Insert a map wrapper $('.answer-container', thisQuestion).prepend('<div class="custom-map-outer-container">\ <div class="custom-map" id="custom-map-'+qID+'" style="width:'+mapWidth+'; height:'+mapHeight+';"> </div>\ </div>'); // Initiate the map const basemapEnum = "ArcGIS:Navigation"; const map = L.map('custom-map-'+qID+'', { minZoom: 2 }); var coordsArr = $.trim(position).split(' '); var latAtt = Number($.trim(coordsArr[0])); var lngAtt = Number($.trim(coordsArr[1])); mapLat = latAtt; mapLng = lngAtt; map.setView([mapLat, mapLng], zoom); L.esri.Vector.vectorBasemapLayer(basemapEnum, { apiKey: apiKey }).addTo(map); // Add a LayerGroup to the map to contain the markers and geocoding results. const markerLayer = L.layerGroup().addTo(map); // An array to hold the markers (so we can loop through them later) var markers = []; // A function to insert markers and pop-ups function createMarker(coords, latLngString, addressString, newMarker) { var id; if (markers.length < 1) { //id = Number(qID)+0; id = qID+'_'+0; } else { const lastIDNum = Number(markers[markers.length - 1]._markerID.split('_')[1]); const newIDNum = lastIDNum + 1; //id = (markers[markers.length - 1]._markerID + 1); id = qID+'_'+newIDNum; } // The marker pop-up content var popupContent = '<p>'+latLngString+', '+addressString+'</p>\ <p><button type="button" class="remove-marker btn btn-sm btn-primary" data-marker-id="'+id+'">Remove</button></p>'; // Define and insert a marker and associated pop-up myMarker = L.marker(coords, { draggable: false }); myMarker._markerID = id; myMarker._address_string = addressString; var myPopup = myMarker.bindPopup(popupContent, { //closeButton: false }); map.addLayer(myMarker); // Add the marker to the array markers.push(myMarker); // This is a new user-created marker if(newMarker == true) { myMarker.openPopup(); loadMapData(); } } // A function to remove markers function clearMarker(id) { var new_markers = []; // Loop through the markers markers.forEach(function(marker) { // Remove it if the ID matches if (marker._markerID == id) { map.removeLayer(marker) } // Otherwise add it to the new array else { new_markers.push(marker) } }) // Update the original markers array markers = new_markers; // Load the LS data loadMapData(); } // Listener on "Remove" buttons $('body').on('click', 'button.remove-marker', function (e) { clearMarker($(this).attr('data-marker-id')); }); // Listener on map for reverse geocoding map.on('click', function (e) { if(markers.length < $(':text.form-control', thisQuestion).length) { L.esri.Geocoding .reverseGeocode({ apikey: apiKey }) .latlng(e.latlng) .run(function (error, result) { if (error) { return; } const latLngString = Math.round(result.latlng.lat * 100000) / 100000+', '+Math.round(result.latlng.lng * 100000) / 100000; createMarker(result.latlng, latLngString, result.address.LongLabel, true); }); } else { // To-do - this could be a modal alert(warningText); } }); // A function to load the results into LimeSurvey function loadMapData() { // Clear everything $(':text.form-control', thisQuestion).val('').trigger('keyup'); // Loop through the markers $.each(markers, function(i, marker) { const latLngString = this._latlng.lat+', '+this._latlng.lng; const addressString = this._address_string; // Insert the LS data $(':text.form-control:eq('+i+')', thisQuestion).val(latLngString+' || '+addressString).trigger('keyup'); }) } // Returning to the page $(':text.form-control', thisQuestion).each(function(i) { if($.trim($(this).val()) != '') { var dataCoords = $.trim($(':text.form-control:eq('+i+')', thisQuestion).val().split('||')[0]).split(','); var dataAddress = $.trim($(':text.form-control:eq('+i+')', thisQuestion).val().split('||')[1]); var dataLatLngString = Math.round($.trim(dataCoords[0]) * 100000) / 100000+', '+Math.round($.trim(dataCoords[1]) * 100000) / 100000; var dataMarkerCoords = { 'lat': $.trim(dataCoords[0]), 'lng': $.trim(dataCoords[1]) }; createMarker(dataMarkerCoords, dataLatLngString, dataAddress, false); } }); if(markers.length > 0) { // Zoom to fit all markers var markerBoundsGroup = new L.featureGroup(markers); map.fitBounds(markerBoundsGroup.getBounds()); } }); </script>
Sample survey attached:
Cheers,
Tony Partner
Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
Last edit: 6 months 1 week ago by tpartner.
The following user(s) said Thank You: DenisChenu, Hyeran
Please Log in to join the conversation.
- Hyeran
- Topic Author
- Offline
- New Member
Less
More
- Posts: 8
- Thank you received: 0
6 months 1 week ago #251298
by Hyeran
Replied by Hyeran on topic Can survey participants directly mark specific locations on the map?
wow, thank you so much for the detailed explanation!
Please Log in to join the conversation.
- DenisChenu
- Offline
- LimeSurvey Community Team
Less
More
- Posts: 13648
- Thank you received: 2491
6 months 1 week ago #251309
by DenisChenu
Assistance on LimeSurvey forum and LimeSurvey core development are on my free time.
I'm not a LimeSurvey GmbH member, professional service on demand , plugin development .
I don't answer to private message.
Replied by DenisChenu on topic Can survey participants directly mark specific locations on the map?
@tpartner always rock !
I'm an admirer
I'm an admirer
Assistance on LimeSurvey forum and LimeSurvey core development are on my free time.
I'm not a LimeSurvey GmbH member, professional service on demand , plugin development .
I don't answer to private message.
Please Log in to join the conversation.
- Hyeran
- Topic Author
- Offline
- New Member
Less
More
- Posts: 8
- Thank you received: 0
6 months 1 week ago #251339
by Hyeran
Replied by Hyeran on topic Can survey participants directly mark specific locations on the map?
Tony, thanks to your explanation I was able to put the map inside the survey.
Is it possible to have a specific city (e.g. Bamberg, Germany) appear instead of London when the map first appears?
Is it possible to have a specific city (e.g. Bamberg, Germany) appear instead of London when the map first appears?
Please Log in to join the conversation.
- Hyeran
- Topic Author
- Offline
- New Member
Less
More
- Posts: 8
- Thank you received: 0
6 months 1 week ago #251343
by Hyeran
Replied by Hyeran on topic Can survey participants directly mark specific locations on the map?
Sorry. I can't erase the answer I wrote before, so I'm leaving this comment. I solved the problem!
Please Log in to join the conversation.
- tpartner
- Offline
- LimeSurvey Community Team
Less
More
- Posts: 10109
- Thank you received: 3595
6 months 1 week ago - 6 months 1 week ago #251344
by tpartner
Cheers,
Tony Partner
Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
Replied by tpartner on topic Can survey participants directly mark specific locations on the map?
The "position" variable (line 9 of the JavaScript) determines the initial location of the map.
Change that to something like "49.9032 10.8952".
Change that to something like "49.9032 10.8952".
Cheers,
Tony Partner
Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.
Last edit: 6 months 1 week ago by tpartner.
Please Log in to join the conversation.