Creating animated direction indicators in the "aroundMe" style with ngCordova

I am attempting to recreate a compass or arrow similar to the one featured in the AroundMe Mobile App. This arrow should accurately point towards a pin on the map based on my mobile device's position and update as I move.

I have been struggling to figure out how to achieve this functionality and have not been able to find any comprehensive guides or tutorials on the topic.

My research led me to a bearing function, which I incorporated into a directive:

app.directive('arrow', function () {

    function bearing(lat1, lng1, lat2, lng2) {
      var dLon = (lng2 - lng1);
      var y = Math.sin(dLon) * Math.cos(lat2);
      var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
      var rad = Math.atan2(y, x);
      var brng = toDeg(rad);
      return (brng + 360) % 360;
    }

    function toRad(deg) {
      return deg * Math.PI / 180;
    }

    function toDeg(rad) {
      return rad * 180 / Math.PI;
    }

    return {
    restrict: 'E',
    link: function (scope, element, attrs) {
      var arrowAngle = bearing(scope.user.position.lat, scope.user.position.lng, attrs.lat, attrs.lng);
      element.parent().css('transform', 'rotate(' + arrowAngle + 'deg)');
    }
  };

});

Although this code updates the arrow direction, it does not take into account the mobile device's magnetic heading information.

To address this, I included the ngCordova plugin for Device Orientation to retrieve the magneticHeading, but I am unsure of how to incorporate it into the existing bearing function.

  $cordovaDeviceOrientation.getCurrentHeading().then(function(result) {
    var magneticHeading = result.magneticHeading;
    var arrowAngle = bearing(scope.user.position.lat, scope.user.position.lng, attrs.lat, attrs.lng, magneticHeading);
    element.parent().css('transform', 'rotate(' + arrowAngle + 'deg)');
  });

I attempted to modify the return statement as follows:

return (brng - heading) % 360;

or:

return (heading - ((brng + 360) % 360));

Despite implementing this code with a watcher, the arrow is not pointing in the correct direction; for instance, it should be facing North but instead points East.

After extensive online searches, I have not found any resources detailing how to calculate the bearing between a lat/lng point and a magneticHeading.

I feel like I may be close to a solution, but I am unable to progress further independently.

In my attempts to resolve the issue, I have also looked into mathematical formulas, but understanding and implementing them has proven challenging.

Your assistance would be greatly appreciated.

Answer №1

Addressing this question straightforwardly is challenging due to the variety of factors that influence the graphical representation involved. For example, when utilizing rotate(0deg), the direction can vary.

I can provide an explanation of the formula you've discovered, which may assist in resolving the issue independently. The complexity lies in the following:

  var dLon = (lng2 - lng1);
  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
  var rad = Math.atan2(y, x);

This formula utilizes Haversine's theorem (https://en.wikipedia.org/wiki/Haversine_formula). With latitude and longitude coordinates, a standard angle calculation won't suffice due to Earth's spherical shape. The first three lines represent Haversine calculations, resulting in coordinates on the unit circle (https://en.wikipedia.org/wiki/Unit_circle)

The subsequent step involves determining the angle from the point on the unit circle to its center. Aiding in this process is the arctangent; JavaScript's atan2 function streamlines this computation. Essentially, it provides the angle between your current position and a reference point. The output is in radians and should be converted to degrees. (https://en.wikipedia.org/wiki/Atan2)

In a simplified scenario with flat coordinates, the process would resemble:

var deltaX = poi.x - you.x;
var deltaY = you.y - poi.y;
var rotation = toDeg(Math.atan2(deltaX, deltaY));

bearingElement.css('transform', 'rotate(' + rotation + 'deg)');

Here, poi denotes the Point of Interest, while you represents your location.

To adjust for your own rotation, subtract your current rotation angle. In the previous snippet, it would appear as follows:

var deltaX = poi.x - you.x;
var deltaY = you.y - poi.y;
var rotation = toDeg(Math.atan2(deltaX, deltaY));

rotation -= you.rotation;

bearingElement.css('transform', 'rotate(' + rotation + 'deg)');

A sample Plunckr has been created to showcase a basic flat coordinate system. By moving and rotating 'you' along with the 'point of interest,' observe how the arrow within 'you' consistently aims towards the 'poi,' despite 'you' rotating. This compensates for our rotational adjustments.

https://plnkr.co/edit/OJBGWsdcWp3nAkPk4lpC?p=preview

In the Plunckr demonstration, note that the 'zero' orientation always points north. Verify your application to determine your 'zero' alignment. Adjust accordingly to ensure script functionality.

Trust this elucidation proves beneficial :-)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Clicking activates Semantic UI's dropdown function with the onClick method

I am experiencing an issue with the dropdown functionality on my website. Everything works fine until I add onClick() to the Semantic UI component. It seems like there are some built-in functions for handling onClick() within Semantic UI, so when I impleme ...

Tips for making multiple $http requests while using AngularJS to consume RESTful APIs

When attempting to fetch data from JSONPlaceholder for display, I encountered an issue with using multiple $http.get requests in my code. The problem arises when making the second call as it does not return any data. MyAlbum1.controller('albumList& ...

Controlling user login sessions and cookies with angular.js is essential for ensuring secure and seamless

I have a login application where I need to implement session and cookies using angular.js. Below is the code for my login functionality. loginController.js: var loginAdmin=angular.module('Channabasavashwara'); loginAdmin.controller('log ...

How can I access the id_lang variable in React JS from outside its scope?

How do I access the 'id_lang' variable outside of the render function in order to pass it down for checking? const Navbar = () => { const getID = async (id) => { let id_lang = id; console.log(id_lang); } ret ...

Creating a text file while in a suspended state within the event handler on Windows 8 using HTML5

When the suspend event is triggered inside the winjs.application.oncheckpoint event handler, I am attempting to write a text file. The content of the file is my object in JSON format. Below is the code snippet: applicationData.localFolder.createFileAsync( ...

Adjust CSS classes as user scrolls using skrollr

I am currently facing an issue with the prinzhorn/skrollr plugin when trying to use removeClass/addClass on scroll function. I have attempted to find a solution but unfortunately, nothing has worked for me. <li class="tab col s3"><a data-800="@cl ...

Automatically trigger a popup box to appear following an AJAX request

I am currently working on a time counter script that triggers a code execution through ajax upon completion. The result of the code should be displayed in a popup box. Below is the code snippet I am using: var ticker = function() { counter--; var t = ...

What could be causing NestJS/TypeORM to remove the attribute passed in during save operation?

Embarking on my Nest JS journey, I set up my first project to familiarize myself with it. Despite successfully working with the Organization entity, I encountered a roadblock when trying to create a User - organizationId IS NULL and cannot be saved. Here ...

Unable to display image source in viewport

Currently, I am working on developing a basic ionic app that interacts with an API that I have created. I am encountering an issue where all data is being displayed correctly in the view except for the src attribute of an image. When I use console.log to c ...

Smart method for repositioning multiple elements on the display

Imagine we have multiple divs displayed on a screen: https://i.stack.imgur.com/jCtOj.png ...and our goal is to move them collectively, either to the left: https://i.stack.imgur.com/KBfXC.png ...or to the right: https://i.stack.imgur.com/c1cUw.png An ...

Tips for passing a function reference within a recursive directive in AngularJS

Here is a directive I am working with: app.directive('recursiveListItem', ['$http', 'RecursionHelper', function ($http, RecursionHelper) { return { restrict: 'E', scope: { parent: &ap ...

Reactivating a React hook following the execution of a function or within a function in ReactJS

A new react hooks function has been created to retrieve data from an API and display it on the page: function useJobs () { const [jobs, setJobs] = React.useState([]) const [locations, setLocations] = React.useState({}) const [departments, setDepartm ...

What's the best way to retrieve the id or index of a card within a list?

Struggling to fetch the id's of documents retrieved from a MongoDB database and displayed on React and Material-Ui cards. Tried logging id in functions and APIs, but receiving 'undefined' or metadata from the delete function. Delete functi ...

Modify x and y axes in highcharts for stacked columns

Can anyone assist me in finding charts similar to the one shown below? I am interested in utilizing the stacked column charts provided by the highcharts library. However, I need to modify the presentation of the data values as demonstrated in the image. I ...

JS Issue with Countdown functionality in Internet Explorer and Safari

I am having an issue with a JavaScript countdown not working on Internet Explorer and Safari, despite being tested on Windows 7. It works fine on Chrome and Firefox. I am unable to switch to a jQuery countdown due to certain restrictions on the website, so ...

Send a vanilla JavaScript ajaxForm submission by completing the form

I am currently in the process of integrating JavaScript from an iOS application into a web application. I have control over the code for both apps. My objective is to develop a JavaScript function that can receive input from a barcode scanner, populate a w ...

Sending search queries from a frontend built with React.js to a backend in Express.js: What is the best approach?

I have been attempting to develop a basic search bar using react.js that will communicate with my express.js backend in order to retrieve the accurate data from the database and display it on the front-end. However, I am struggling to grasp how to transmit ...

Methods for applying multiple styles within a div using the Document Object Model

Is there a way to add multiple style attributes using DOM `setAttribute` in JavaScript? I've tried doing it but it doesn't seem to work. Can someone provide guidance on how to achieve this? var modify = document.getElementById('options&apo ...

How to display JSON containing nested objects in AngularJS using the ng-repeat directive

Hey everyone, I have this JSON external file that I need help with: { "success":true, "errors":[ ], "objects":[ { "cod":"8211300", "descricao":"Serviços advocatícios" }, // more objects here... ] } In ...

Is it possible to retrieve the vertices array from a QuickHull instance in three.js?

I'm currently working on generating a geometry using QuickHull from a THREE Mesh. However, it seems that the QuickHull object only contains information pertaining to the Faces of the mesh. Does anyone know if there is a way to access the vertex infor ...