#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 просто убедитесь, что ваше расстояние от центра круга меньше его радиуса. И наоборот для выхода.