<!DOCTYPE html>
<html ng-app="geodesicApp">

  <head>
    <script data-require="angular.js@*" data-semver="1.2.0-rc3-nonmin" src="//code.angularjs.org/1.2.0-rc.3/angular.js"></script>
    <script src="geodesic.js"></script>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css">
    <link rel="stylesheet" href="style.css" />
  </head>

  <body ng-controller="MainCtrl" ng-init="init()">
    <!-- Inspired from: http://tympanus.net/Tutorials/Cust"omDropDownListStyling/index3.html -->
    <div id="dd" class="wrapper-dropdown-3" ng-class="{'active':dropDownEnabled}" ng-click="dropDownEnabled = !dropDownEnabled">
			<span>Select</span>
			<ul class="dropdown">
				<li ng-repeat="site in frenchSites | orderBy:'rawDistance'">
				  <a href="#"><i class="fa fa-map-marker icon-large"></i>{{ site.name }} <span><strong>{{ site.distance }}</strong></span></a>
				</li>
			</ul>
		</div>
		
    <script src="controller.js"></script>
    
    <!-- Always enjoyable to be flttred! -->
    <div style="position:absolute;bottom:0px; margin: 0px 0px 40px 10px;">
      <script id='fbketsn'>(function(i){var f,s=document.getElementById(i);f=document.createElement('iframe');f.src='//api.flattr.com/button/view/?uid=ggarcia&button=compact&url='+encodeURIComponent(document.URL);f.title='Flattr';f.height=20;f.width=110;f.style.borderWidth=0;s.parentNode.insertBefore(f,s);})('fbketsn');</script>
    </div>    
  </body>

</html>
/* Inspired from: http://tympanus.net/Tutorials/CustomDropDownListStyling/index3.html */

/* DEMO 3 */

.wrapper-dropdown-3 {
    /* Size and position */
    position: relative;
    width: 200px;
    margin: 0 auto;
    padding: 10px;

    /* Styles */
    background: #fff;
    border-radius: 7px;
    border: 1px solid rgba(0,0,0,0.15);
    box-shadow: 0 1px 1px rgba(50,50,50,0.1);
    cursor: pointer;
    outline: none;

    /* Font settings */
    font-weight: bold;
    color: #8AA8BD;
}

.wrapper-dropdown-3:after {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    right: 15px;
    top: 50%;
    margin-top: -3px;
    border-width: 6px 6px 0 6px;
    border-style: solid;
    border-color: #8aa8bd transparent;
}

.wrapper-dropdown-3 .dropdown {
  /* Size & position */
    position: absolute;
    top: 140%;
    left: -80px;
    right: 0;
    width: 300px;

    /* Styles */
    background: white;
    border-radius: inherit;
    border: 1px solid rgba(0,0,0,0.17);
    box-shadow: 0 0 5px rgba(0,0,0,0.1);
    font-weight: normal;
    -webkit-transition: all 0.5s ease-in;
    -moz-transition: all 0.5s ease-in;
    -ms-transition: all 0.5s ease-in;
    -o-transition: all 0.5s ease-in;
    transition: all 0.5s ease-in;
    list-style: none;
    
    padding: 0px 0px 0px 0px;

    /* Hiding */
    opacity: 0;
    pointer-events: none;
}

.wrapper-dropdown-3 .dropdown:after {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    bottom: 100%;
    right: 15px;
    border-width: 0 6px 6px 6px;
    border-style: solid;
    border-color: #fff transparent;    
}

.wrapper-dropdown-3 .dropdown:before {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    bottom: 100%;
    right: 13px;
    border-width: 0 8px 8px 8px;
    border-style: solid;
    border-color: rgba(0,0,0,0.1) transparent;    
}

.wrapper-dropdown-3 .dropdown li a {
    display: block;
    padding: 10px;
    text-decoration: none;
    color: #8aa8bd;
    border-bottom: 1px solid #e6e8ea;
    box-shadow: inset 0 1px 0 rgba(255,255,255,1);
    -webkit-transition: all 0.3s ease-out;
    -moz-transition: all 0.3s ease-out;
    -ms-transition: all 0.3s ease-out;
    -o-transition: all 0.3s ease-out;
    transition: all 0.3s ease-out;
}

.wrapper-dropdown-3 .dropdown li a span {
  float: right;
  color: #999;
}

  
.wrapper-dropdown-3 .dropdown li i {
    float: left;
    padding: 0px 10px 0px 5px;
    color: inherit;
}

.wrapper-dropdown-3 .dropdown li:first-of-type a {
    border-radius: 7px 7px 0 0;
}

.wrapper-dropdown-3 .dropdown li:last-of-type a {
    border: none;
    border-radius: 0 0 7px 7px;
}

/* Hover state */

.wrapper-dropdown-3 .dropdown li:hover a {
    background: #f3f8f8;
}

/* Active state */

.wrapper-dropdown-3.active .dropdown {
    opacity: 1;
    pointer-events: auto;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2012             */
/*                                                                                                */
/* from: Vincenty inverse formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the */
/*       Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975    */
/*       http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf                                             */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

function distVincentyDeg(lat1, long1, lat2, long2) {
   return( distVincenty( degToRad(lat1),
                         degToRad(long1),
                         degToRad(lat2),
                         degToRad(long2))
         );
}
  
function distVincenty(lat1, long1, lat2, long2) {
  var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;  // WGS-84 ellipsiod
  var L = long2 - long1;
  var U1 = Math.atan((1-f) * Math.tan(lat1));
  var U2 = Math.atan((1-f) * Math.tan(lat2));
  var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
  var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
  
  var lambda = L, lambdaP = 2*Math.PI;
  var iterLimit = 20;
  while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
    var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
    var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + 
      (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
    if (sinSigma==0) return 0;  // co-incident points
    var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
    var sigma = Math.atan2(sinSigma, cosSigma);
    var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
    var cosSqAlpha = 1 - sinAlpha*sinAlpha;
    var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
    if (isNaN(cos2SigmaM)) cos2SigmaM = 0;  // equatorial line: cosSqAlpha=0 (§6)
    var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
    lambdaP = lambda;
    lambda = L + (1-C) * f * sinAlpha *
      (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
  }
  if (iterLimit==0) return NaN  // formula failed to converge

  var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
  var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
  var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
  var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
    B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
  var s = b*A*(sigma-deltaSigma);
  
  s = s.toFixed(3); // round to 1mm precision
  return s;
}

/*
 * convert lat/long in degrees to radians, for handling input values
 *
 *   this is very flexible on formats, allowing signed decimal degrees (numeric or text), or
 *   deg-min-sec suffixed by compass direction (NSEW). A variety of separators are accepted 
 *   (eg 3º 37' 09"W) or fixed-width format without separators (eg 0033709W). Seconds and minutes
 *   may be omitted. Minimal validation is done.
 */
function degToRad(llDeg) {
  if (!isNaN(llDeg)) return llDeg * Math.PI / 180;  // signed decimal degrees without NSEW

  llDeg = llDeg.replace(/[\s]*$/,'');               // strip trailing whitespace
  var dir = llDeg.slice(-1).toUpperCase();          // compass dir'n
  if (!/[NSEW]/.test(dir)) return NaN;              // check for correct compass direction
  llDeg = llDeg.slice(0,-1);                        // and lose it off the end
  var dms = llDeg.split(/[\s:,°º′\'″\"]/);          // check for separators indicating d/m/s
  if (dms[dms.length-1] == '') dms.length--;        // trailing separator? (see note below)
  switch (dms.length) {                             // convert to decimal degrees...
    case 3:                                         // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; break;
    case 2:                                         // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; break;
    case 1:                                         // non-separated format dddmmss
      if (/[NS]/.test(dir)) llDeg = '0' + llDeg;    // - normalise N/S to 3-digit degrees
      var deg = llDeg.slice(0,3)/1 + llDeg.slice(3,5)/60 + llDeg.slice(5)/3600; break;
    default: return NaN;
  }
  if (/[WS]/.test(dir)) deg = -deg;                 // take west and south as -ve
  return deg * Math.PI / 180;                       // then convert to radians
}
var app = angular.module('geodesicApp', []);

app.controller('MainCtrl', function($scope, $templateCache, $timeout) {
    $scope.author           = 'Guillaume Garcia';    
    $scope.frenchSites      = [ { name: "Eiffel Tower",          coords: { latitude: 48.858087, longitude: 2.294703 },  distance: "" },
                                { name: "Notre-Dame Cathedral",  coords: { latitude: 48.853146, longitude: 2.349066 },  distance: "" },
                                { name: "Alti-TCS Villiers",     coords: { latitude: 48.893554, longitude: 2.276270 },  distance: "" },
                                { name: "Saint Michael's Mount", coords: { latitude: 48.635702, longitude: -1.511160 }, distance: "" } ];
    $scope.position         = null;
    $scope.distance         = '';
    $scope.rawDistance      = 0;
    $scope.linkToGMaps      = '';
    $scope.dropDownEnabled  = true;

    $scope.init = function() {
      if (navigator.geolocation) {
         // L’API est disponible
         navigator.geolocation.getCurrentPosition($scope.calculateDistance);
      } else {
        // Pas de support...
        return("Pas de support de géoloc...");
      }
    };

    $scope.calculateDistance = function(position) {
      $scope.$apply(function() {
        var siteIndex;
      
        $scope.position = position;
        console.log($scope.position);
        
        for (siteIndex = 0 ; siteIndex<$scope.frenchSites.length ; siteIndex++) {
          $scope.frenchSites[siteIndex].rawDistance = parseInt(distVincentyDeg( $scope.frenchSites[siteIndex].coords.latitude,
                                                                                $scope.frenchSites[siteIndex].coords.longitude,
                                                                                $scope.position.coords.latitude,
                                                                                $scope.position.coords.longitude ), 10);
          $scope.frenchSites[siteIndex].distance = $scope.frenchSites[siteIndex].rawDistance < 1000 ? Math.round($scope.frenchSites[siteIndex].rawDistance) + " m" : Math.round($scope.frenchSites[siteIndex].rawDistance / 1000 * 10) / 10 + " km";                                              
        } 
      });
    };
});