diff --git a/src/components/geolocation/GeolocationDirective.js b/src/components/geolocation/GeolocationDirective.js index e8dce9175a..23d577a783 100644 --- a/src/components/geolocation/GeolocationDirective.js +++ b/src/components/geolocation/GeolocationDirective.js @@ -7,31 +7,42 @@ 'ga_permalink' ]); - module.directive('gaGeolocation', function($parse, gaPermalink) { + module.directive('gaGeolocation', function($parse, $window, gaPermalink) { return { restrict: 'A', scope: { map: '=gaGeolocationMap' }, - template: '', - replace: true, + templateUrl: 'components/geolocation/partials/geolocation.html', link: function(scope, element, attrs) { - if (!('geolocation' in window.navigator)) { - element.addClass('error'); + var btnElt = $(element.children()[0]); + var markerElt = $(element.children()[1]); + if (!('geolocation' in $window.navigator)) { + btnElt.addClass('error'); return; } + // This boolean defines if the user has moved the map itself after the + // first change of position. + var userTakesControl = false; + // Defines if the geolocation control is zooming + var geolocationZooming = false; + var overlay = null; + var currentResolution = null; + var currentAccuracy = null; var map = scope.map; var view = map.getView().getView2D(); var geolocation = new ol.Geolocation(); geolocation.on('error', function() { - element.removeClass('tracking'); - element.addClass('error'); + btnElt.removeClass('tracking'); + btnElt.addClass('error'); }); geolocation.bindTo('projection', map.getView()); // used to having a zoom animation when we click on the button, // but not when we are tracking the position. var first = true; - var locate = function(dest) { + var locate = function() { + geolocationZooming = true; + var dest = geolocation.getPosition(); if (dest) { var source = view.getCenter(); var dist = Math.sqrt(Math.pow(source[0] - dest[0], 2), @@ -48,12 +59,11 @@ var bounce; if (first) { first = false; - var accuracy = geolocation.getAccuracy(); var extent = [ - dest[0] - accuracy, - dest[1] - accuracy, - dest[0] + accuracy, - dest[1] + accuracy + dest[0] - currentAccuracy, + dest[1] - currentAccuracy, + dest[0] + currentAccuracy, + dest[1] + currentAccuracy ]; var size = map.getSize(); var resolution = Math.max( @@ -75,7 +85,7 @@ map.beforeRender(pan, zoom, bounce); view.setCenter(dest); view.setResolution(resolution); - } else { + } else if (!userTakesControl) { bounce = ol.animation.bounce({ duration: duration, resolution: Math.max(view.getResolution(), dist / 1000), @@ -85,23 +95,61 @@ view.setCenter(dest); } } + geolocationZooming = false; }; + var markPosition = function() { + var divSize = currentAccuracy / currentResolution; + markerElt.css({ + width: divSize, + height: divSize, + 'border-radius': divSize / 2 + }); + }; + map.on('postrender', function(evt) { + var res = view.getResolution(); + if (res != currentResolution) { + currentResolution = res; + markPosition(); + } + }); + geolocation.on('change:position', function(evt) { - element.removeClass('error'); - element.addClass('tracking'); - locate(geolocation.getPosition()); + btnElt.removeClass('error'); + btnElt.addClass('tracking'); + locate(); + markPosition(); }); + geolocation.on('change:tracking', function(evt) { var tracking = geolocation.getTracking(); if (tracking) { first = true; + userTakesControl = false; + if (!overlay) { + overlay = new ol.Overlay({ + element: markerElt, + positioning: ol.OverlayPositioning.CENTER_CENTER, + stopEvent: false + }); + overlay.bindTo('position', geolocation); + } + map.addOverlay(overlay); } else { // stop tracking - element.removeClass('tracking'); + btnElt.removeClass('tracking'); + if (overlay) { + map.removeOverlay(overlay); + } + } + }); + geolocation.on('change:accuracy', function(evt) { + var accuracy = geolocation.getAccuracy(); + if (accuracy != currentAccuracy) { + currentAccuracy = accuracy; + markPosition(); } - }); - element.bind('click', function(e) { + btnElt.bind('click', function(e) { e.preventDefault(); var tracking = !geolocation.getTracking(); geolocation.setTracking(tracking); @@ -114,6 +162,14 @@ }); geolocation.setTracking(gaPermalink.getParams().geolocation == 'true'); + + var updateUserTakesControl = function() { + if (!geolocationZooming) { + userTakesControl = true; + } + }; + view.on('change:center', updateUserTakesControl); + view.on('change:resolution', updateUserTakesControl); } }; }); diff --git a/src/components/geolocation/partials/geolocation.html b/src/components/geolocation/partials/geolocation.html new file mode 100644 index 0000000000..9e62eb0fda --- /dev/null +++ b/src/components/geolocation/partials/geolocation.html @@ -0,0 +1,4 @@ + +
+
+
diff --git a/src/components/geolocation/style/geolocation.less b/src/components/geolocation/style/geolocation.less index e1d455d533..bb9e471f5e 100644 --- a/src/components/geolocation/style/geolocation.less +++ b/src/components/geolocation/style/geolocation.less @@ -17,3 +17,21 @@ top: unit(@small-header-height + @control-btns-top, px); } } +.geolocation-marker { + background-color: rgba(255, 0, 0, 0.1); + border: 2px solid rgba(255, 0, 0, 0.9); + + .user-position { + position: absolute; + width: 14px; + height: 14px; + border-radius: 50%; + left: 50%; + top: 50%; + margin-top: -7px; + margin-left: -7px; + background: red; + box-shadow: 0 0 14px rgba(0, 0, 0, 0.9); + } +} +