Page 1 of 1

SOLVED: Open the nearest panorama of given coordinates / Geolocation API

Posted: Sat Feb 16, 2019 7:16 pm
by nikolakakis.manolis
Does somebody know or indicate a way to open a virtual tour panorama that is closest to a given point? The idea is to pass the coordinates as variables and the virtual tour will display the nearest panorama of the given point. The coordinates might come either as url params or from geolocation api from the client's location.
Any hint or advice will be greatly appreciated.

Re: Open the nearest panorama of given coordinates / Geolocation API

Posted: Sat Feb 16, 2019 9:28 pm
by Hopki
If you know the location of all the nodes then just arrange them in order in the tour browser.
The Open Next Panorama, Next Node action will then open in that order.
If you add the nodes to the tour map you can choose to link using closest node.

Re: Open the nearest panorama of given coordinates / Geolocation API

Posted: Sun Feb 17, 2019 10:37 am
by nikolakakis.manolis
Thank you for your fast reply but I failed to explain the functionality that I am looking for. I wish my english was better! I will try to elaborate a bit more (sorry for that!) :lol: As a side note I will add that I am now starting with Pano2VR, I was using Kolor PT pro.
In a HTML5 output of a virtual tour, I want to be able to pass one pair of coordinates (input point) on loading the virtual tour and instead of opening with the start panorama I want it to open with the nearest panorama to the input point I passed.
It is roughly like direct node access but instead of passing a node id after # you might be able to pass a coordinates set or a lon and lat variables.
This has in my mind many uses when embedding the HTML5 output of the virtual tour as an iframe.
In one case at the moment, I have a website built in Drupal 8 with geolocated points of interest (POIs) of an area. I want to embed in the details page of each POI the virtual tour (VT) of the area (the HTML5 output of Pano2VR 6 with over 200 panoramas of 100 POIs). This VT includes all the POIs and can be viewed as a standalone website as well and it will be updated with more panoramas in the future.
To pair these two I could embed the VT and open with the starting panorama (which is not very useful), or pass the node id (having a field in Drupal and manually update the node id), so when a user loads the POI detail page of the Drupal 8 the embedded iframe will serve the node id that was passed from Drupal.
The idea is instead of passing the node id to be able to pass the coordinates, since all POIs have one and be able to open the nearest panorama.
One side use of this implementation will be the following. From a page that acquires the client location from the Geolocation API ( ... -location/) an embedded iframe HTML5 of the VT can display the nearest panorama.
If you have any advice on how to approach that I might avoid having the node id field and keep it always updated while the Drupal 8 and the VT are updated.

Re: Open the nearest panorama of given coordinates / Geolocation API

Posted: Fri Aug 02, 2019 11:05 am
by nikolakakis.manolis
Just posting this as an answer in case it is useful for someone else, or even better if someone with better background and understanding of coding than me, decide to polish this.
I managed to check all the panoramas from the pano.xml and compare the distances to the user position (acquired from geolocation, geolocation only works in https websites) in order to pick the one that is closest to the user coordinates. Since the closest panorama id from the pano.xml file as a string is known (e.g var closestpanoid = "node2"; ) I execute
pano.openNext("{" + closestpanoid + "}";
In order to get this to work I added a button with the an action on click to goto url javascript:checkdistance()
In this way the function that is in a separate custom.js file is executed every time you click on the button. This js file was added in the ggt template of the virtual tour.

Code: Select all

<script src="js/custom.js"></script>
I paste the custom.js content below

Code: Select all

function checkdistance() {    
	// On success execute readXML function
    navigator.geolocation.getCurrentPosition(readXML, errorPosition);

function readXML(position) {
	var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
	   if (this.readyState == 4 && this.status == 200) {
		   initXML(this, position);
	};"GET", "pano.xml", true);

function initXML(xml, position) {
    var panorama, panoramaid, i, xmlDoc, panolongitude, panolatitude, userlongitude, userlatitude, panodistance=[];
    xmlDoc = xml.responseXML;
    panolongitude	 = "";
	panolatitude	 = "";

	userlongitude = position.coords.longitude;
	userlatitude =  position.coords.latitude;
    panorama = xmlDoc.getElementsByTagName('panorama');
    for (i = 0; i < panorama.length; i++) { 
		userdata = xmlDoc.getElementsByTagName('userdata');
		panoramaid = panorama[i].getAttribute('id');
		panolongitude = parseFloat(userdata[i].getAttribute('longitude'));
		panolatitude = parseFloat(userdata[i].getAttribute('latitude'));
		panodistance.push([panoramaid, distance(panolongitude, panolatitude, userlongitude, userlatitude)]);
	var sortedpanos = panodistance.sort(compareDistances);
	var closestpanoid = sortedpanos[0][0];
	var closestpanodistance = sortedpanos[0][1];
	pano.openNext("{" + closestpanoid + "}")
	alert("This panorama is " + Math.round(closestpanodistance * 100) / 100 + " kilometers away from you."); 

function compareDistances(a, b) {
    if (a[1] === b[1]) {
        return 0;
    else {
        return (a[1] < b[1]) ? -1 : 1;

if (navigator.geolocation) {    
    // Browser supports it, we're good to go!     
    } else {    
    alert('Sorry your browser doesn\'t support the Geolocation API');    

function errorPosition() {                  
    alert('Sorry couldn\'t find your location');            ;         

function distance(lon1, lat1, lon2, lat2) {
  var R = 6371; // Radius of the earth in km
  var dLat = (lat2-lat1).toRad();  // Javascript functions in radians
  var dLon = (lon2-lon1).toRad(); 
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * Math.sin(dLon/2) * Math.sin(dLon/2); 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; // Distance in km
  return d;

/** Converts numeric degrees to radians */
if (typeof(Number.prototype.toRad) === "undefined") {
  Number.prototype.toRad = function() {
    return this * Math.PI / 180;