Не удается отобразить геозону на карте Google

#javascript #google-maps #cordova #phonegap #geofencing

#javascript #google-карты #кордова #phonegap #геозона

Вопрос:

Я пытаюсь отобразить геозону Google Maps на моей карте.

Весь остальной код работает, за исключением раздела геозоны, который не отображается на карте.

Вот код, который я использую в своем мобильном:

 <!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
        <title>Blank App</title>
        <script src="http://maps.google.com/maps/api/js" type="text/javascript"></script>
    </head>
    <body>
    <div id="map" style="width: 100%; height: 100vh;"></div>

    <div id="geolocation"></div>

<script type="text/javascript" src="cordova.js"></script>

<script>

class CircularGeofenceRegion {
  constructor(opts) {
    Object.assign(this, opts)
  }

  inside(lat2, lon2) {
    const lat1 = this.latitude
    const lon1 = this.longitude
        const R = 63710; // Earth's radius in m

    return Math.acos(Math.sin(lat1)*Math.sin(lat2)  
    Math.cos(lat1)*Math.cos(lat2) *
    Math.cos(lon2-lon1)) * R < this.radius;
  }
}

</script>


<script type="text/javascript">

    document.addEventListener("deviceready", onDeviceReady, false);
    function onDeviceReady() {
        console.log("navigator.geolocation works well");
        getMapLocation();
        watchMapPosition();
    }

    var Latitude = undefined;
    var Longitude = undefined;

    // Get geo coordinates

    function getMapLocation() {

        navigator.geolocation.getCurrentPosition
        (onMapSuccess, onMapError, { enableHighAccuracy: true });
    }

    // Success callback for get geo coordinates

    var onMapSuccess = function (position) {

        Latitude = position.coords.latitude;
        Longitude = position.coords.longitude;

        getMap(Latitude, Longitude);

    }

    // Get map by using coordinates

    function getMap(latitude, longitude) {

        var mapOptions = {
            center: new google.maps.LatLng(0, 0),
            zoom: 1,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        map = new google.maps.Map
        (document.getElementById("map"), mapOptions);


        var latLong = new google.maps.LatLng(latitude, longitude);

        var marker = new google.maps.Marker({
            position: latLong
        });

        marker.setMap(map);
        map.setZoom(15);
        map.setCenter(marker.getPosition());

        //////////////////////////////////////////////////////////////////////////////////////

        var locations = [
            ['Location1', -25.363, 131.044, 1]
        ];

        var infowindow =  new google.maps.InfoWindow({});
        var marker, count;
        for (count = 0; count < locations.length; count  ) {
            marker = new google.maps.Marker({
              position: new google.maps.LatLng(locations[count][1], locations[count][2]),
              map: map,
              title: locations[count][0]
            });
        google.maps.event.addListener(marker, 'click', (function (marker, count) {
              return function () {
                infowindow.setContent(locations[count][0]);
                infowindow.open(map, marker);
              }
            })(marker, count));
          }


        //////////////////////////////////////////////////////////////////////////////////////
      // FENCING SECTION:

      const fenceA = new CircularGeofenceRegion({
        name: 'myfence',
        latitude: 85.363,
        longitude: 31.044,
        radius: 100 // meters
      });

      const fences = [fenceA]
      const fenceOptions = {}


      navigator.geolocation.watchPosition(({coords}) => {
        for (const fence of fences) {
          const lat = coords.latitude
          const lon = coords.longitude

          if (fence.inside(lat, lon)) {
            // do some logic
          }
        }
      }, console.error, fenceOptions);


      // END OF FENCING SECTION
      ///////////////////////////////////////////////////////////////////////////////////////


    }

    // Success callback for watching your changing position

    var onMapWatchSuccess = function (position) {

        var updatedLatitude = position.coords.latitude;
        var updatedLongitude = position.coords.longitude;

        if (updatedLatitude != Latitude amp;amp; updatedLongitude != Longitude) {

            Latitude = updatedLatitude;
            Longitude = updatedLongitude;

            getMap(updatedLatitude, updatedLongitude);
        }
    }

    // Error callback

    function onMapError(error) {
        console.log('code: '   error.code   'n'  
            'message: '   error.message   'n');
    }

    // Watch your changing position

    function watchMapPosition() {
        return navigator.geolocation.watchPosition
        (onMapWatchSuccess, onMapError, { enableHighAccuracy: true, maximumAge: 3600000 });
    }


</script>

    </body>
</html>
  

Я отметил начало и конец раздела ограждения, прокомментированного в коде.

Также используется класс CircularGeofenceRegion, который является началом кода.

Кто-нибудь может помочь заставить ограждение работать / появляться?

Ответ №1:

Не отвечая на ваш вопрос напрямую, но, к вашему сведению, вы можете просто поместить круг на карту и получить периметр / окружность самостоятельно. Я использую Web Worker, чтобы освободить поток пользовательского интерфейса во время фильтрации.

 importScripts("Tier3Toolbox.js");

var currVintage = 0;
var inBounds = false;
var facFilter = [];
var imageProlog = "<div style='height:5em; width:5em; display:inline-block;vertical-align:middle;'>"  
                  "<img style='height:100%; width: 100%; max-height:100%; max-width:100%' src='";
var imageEpilog = "' ></div>";
var facilityTable, lineBreak;

self.addEventListener('message', function(e) 
{
  var data = e.data;
  switch (data.cmd) {
    case 'init':
      initThread(data.load);
      break;
    case 'initFilter':
      for (var i=0; i<data.filterTable.length; i  ) {
        facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
      }
      break;
    case 'filter':
      facFilter = [];
      for (var i=0; i<data.filterTable.length; i  ) {
        if (data.filterTable[i].facSelected)
          facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
      }
      break;
    case 'search':
      var searchVintage =   currVintage;
      var tableSearch = new searcher(searchVintage, data);
      break;
    case 'reset':
      reset();
      self.postMessage({'reset': true});
      break;
    case 'stop':
      self.postMessage({'success' : true});
      self.close(); 
      break;
    default:
      self.postMessage({'success' : false, 'msg' : data.msg});
  };
}, false);

function initThread(msg) 
{
    facilityTable = JSON.parse(msg);
    reset();

    self.postMessage({'success' : true, 
                      'cnt'     : facilityTable.length
                    });     
}   

function reset() 
{
    for (var i=0; i<facilityTable.length; i  ) {
        facilityTable[i].visible=false
    }
    currVintage = 0;
}   

function searcher(searchVintage, msg)
{
    var myVintage = searchVintage;
    var facIndex  = -1;
    var msg       = msg;

    var checkLoop = function()
    {
        if (myVintage != currVintage)
            return;

        if (  facIndex == facilityTable.length)
            return;

        inBounds = geoFencer.call(this, msg);

        if (inBounds) {
            var facMatch = 0;
            var bubbleHTML = "";
            for (var i=0; i<facilityTable[facIndex].facilities.length; i  ){
                var currFac = facilityTable[facIndex].facilities[i];
                if (facFilter[currFac.locTypeId] != undefined) {
                    if (facMatch != 0) {
                        lineBreak = (facMatch / 3);
                        if (lineBreak == lineBreak.toFixed(0)) {
                            bubbleHTML  = "<br />";
                        }
                    }
                    facMatch  ;
                    bubbleHTML  = imageProlog   facFilter[currFac.locTypeId].icon   imageEpilog;

                }
            }
            if (facMatch == 0) {
                inBounds = false;
            }
        }

        if (inBounds != facilityTable[facIndex].visible) {
            self.postMessage({'match'       : inBounds,
                              'facIndex'    : facIndex,
                              'scopeVintage': msg.scopeVintage,
                              'bubbleHTML'  : bubbleHTML,
                              'success'     : true
                            }); 
            facilityTable[facIndex].visible = inBounds;
        }

        setTimeout(checkLoop,0);
    }

    var circleCheck = function(msg) 
    {
        var diff = Tier3Toolbox.calculateDistance(
                        msg.centerLat,
                        msg.centerLng,
                        facilityTable[facIndex].searchLat,
                        facilityTable[facIndex].searchLng);

        if (msg.radius > diff)
            return true;        

        return false;
    }

    var rectangleCheck = function(msg) 
    {
        if (facilityTable[facIndex].searchLat > msg.SWLat amp;amp;
            facilityTable[facIndex].searchLat < msg.NELat amp;amp;
            facilityTable[facIndex].searchLng > msg.SWLng amp;amp;
            facilityTable[facIndex].searchLng < msg.NELng)
            return true;        

        return false;
    }

    var GEOFENCER = [circleCheck,rectangleCheck];
    var geoFencer = GEOFENCER[msg.checker];

    setTimeout(checkLoop,0);
    return this;

}
  

Вызовите ее из основной строки, например: —

 function createFacilityMarkers(xmlhttp){
    facFinder = new Worker("facfinder.js");
    facFinder.addEventListener('message', workerInit, false);

    facFinder.postMessage({'cmd' : 'init', 'load' : xmlhttp.responseText});
  

И функция вычисления расстояния: —

 Tier3Toolbox.calculateDistance =
function(lat1, lon1, lat2, lon2){
    var dLat = this.toRad(lat2 - lat1);
    var dLon = this.toRad(lon2 - lon1);
    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2)   Math.cos(this.toRad(lat1)) * 
            Math.cos(this.toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
    var distance = this.EARTH_RADIUS * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return distance;
}
  

Эта настройка очень полезна, если пользователь будет перемещать круг по карте пальцем / мышью. (Хорошая новость в том, что Карты Google наконец исправили ошибку, останавливающую прокрутку карты при перетаскивании круга к границе!)

PS. На случай, если вы не знаете, как сделать бит круга: —

     var circleOptions = {
      clickable: true,
      draggable: true,
      editable: true,
      visible: false,
      strokeColor: 'gray',
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: 'gray',
      fillOpacity: 0.35,
      center: marker.getPosition()
    };

    radarCircle = new radarView(new google.maps.Circle(circleOptions));

    google.maps.event.addDomListener(radarCircle,    'center_changed', reScope);
    google.maps.event.addDomListener(radarCircle,    'radius_changed', reScope);

function radarView(superBase)
{
    this.__proto__ = superBase;

    if (this instanceof google.maps.Circle) {
        augmentCircle.apply(this);
    } else if (this instanceof google.maps.Rectangle) {
        augmentRectangle.apply(this);
    } else {
        Tier3Toolbox.reportError({header:"Internal error", 
                message:"Inheriting from unknown object"});
    }

    this.doX = function(x){return "x is>"   x;};

    return this;
}

function augmentCircle()
{
    this.moveBorder = function()
    {
        google.maps.event.trigger(radarCircle,"center_changed");
    }
}

function augmentRectangle()
{
    this.moveBorder = function()
    {
        google.maps.event.trigger(radarRectangle,"bounds_changed");
    }
}


function reScope() {

    var searchReq = {'cmd':'search', 'scopeVintage':scopeVintage};
    if (radarShape.getCenter) {
        searchReq.checker = 0;
        var currCenter = radarCircle.getCenter();
        searchReq.centerLat = currCenter.lat();
        searchReq.centerLng = currCenter.lng();         
        searchReq.radius = radarCircle.getRadius();
    } else {
        searchReq.checker = 1;
        searchReq.SWLat = radarShape.getBounds().getSouthWest().lat();
        searchReq.SWLng = radarShape.getBounds().getSouthWest().lng();
        searchReq.NELat = radarShape.getBounds().getNorthEast().lat();
        searchReq.NELng = radarShape.getBounds().getNorthEast().lng();
    }

    facFinder.postMessage(searchReq);
}
  

Комментарии:

1. Будет ли это работать как геозона, где она определяет, когда моя геолокация входит в нее или выходит из нее? Это действительно то, что мне нужно

2. В случае успешного выполнения вашего watchPosition просто убедитесь, что ваше расстояние от центра круга меньше его радиуса. И наоборот для выхода.