使用ngCordova制作动画方向箭头"aroundMe"样式

Aye*_*azo 37 javascript google-maps angularjs ionic-framework ngcordova

我希望创建一个指南针/箭头,就像我们在AroundMe移动应用程序中看到的那样,指向地图上的一个引脚与移动位置相对应,并在我移动手机时更新箭头.

我很难理解如何做到这一点,我找不到任何解释它的指南或教程.

我在网上找到的是一个轴承功能,我围绕它创建了一个指令:

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)');
    }
  };

});
Run Code Online (Sandbox Code Playgroud)

它似乎在一个方向更新箭头但不幸的是它不是正确的方向,因为它不是使用移动magneticHeading位置计算的.

所以我添加了设备方向ngCordova插件来获取,现在我不知道如何使用它以及在函数中的位置.magneticHeadingbearing

  $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)');
  });
Run Code Online (Sandbox Code Playgroud)

我试着在return语句中添加它:

return (brng - heading) % 360;
Run Code Online (Sandbox Code Playgroud)

要么:

return (heading - ((brng + 360) % 360));
Run Code Online (Sandbox Code Playgroud)

实现这个代码与守望我看到的箭头移动,但不是在准确的位置...例如从我的位置与销的箭头应指向ñ和它指向Ë.

总是在线查找我找不到任何教程/问题来找到a lat/lng point和a 之间的方位magnetingHeading.

也许我接近解决方案,但我无法独自前进.

我也试图寻找数学公式,但即使理解和实施它也会有巨大的痛苦.

我希望你能提供帮助.

Wou*_*ink 1

很难对这个问题给出简单的答案,因为很大程度上取决于实际的图形表示。例如,您指向哪个方向rotate(0deg)

我可以解释您找到的公式,这可能会帮助您自己解决问题。困难的部分如下:

  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);
Run Code Online (Sandbox Code Playgroud)

您在这里看到的是半正弦公式(https://en.wikipedia.org/wiki/Haversine_formula)。通常,只要有两组坐标就足够了,并计算它们之间的角度。当使用纬度和经度时,这将不起作用,因为地球不是平坦的表面。前三行是半正矢,结果 (x和) 是( https://en.wikipedia.org/wiki/Unit_circle )y上的坐标unit circle

下一步是计算从该单位圆上的点到圆心的角度。arctangant我们可以为此使用。Javascript 有一个辅助函数atan2可以简化这个过程。结果很简单,就是你的点与圆心的角度。换句话说,你对你的兴趣点的立场。结果以弧度为单位,需要转换为度数。(https://en.wikipedia.org/wiki/Atan2

具有平面坐标系的简化版本如下所示:

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)');
Run Code Online (Sandbox Code Playgroud)

poi兴趣点在哪里,you你的位置在哪里。

为了补偿您自己的旋转,您需要减去您自己的旋转。在上面的示例中,结果将变为:

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)');
Run Code Online (Sandbox Code Playgroud)

我制作了一个 Plunkr,您可以在其中看到一个简单的平面坐标系。您可以移动和you旋转point of interestpoi即使您旋转“您”,“您”内部的箭头也将始终指向。这是因为我们补偿了自己的轮换。

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

请注意,在 Plunkr 中,“零”位置始终位于北方。检查您的应用程序以查看您的“零”位置。相应地调整它,您的脚本就会起作用。

希望这可以帮助 :-)