/* * TerranQuest - Augmented Reality fantasy game * * Copyright 2016 Netsyms Technologies * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ////////////////////////////////////////////// // GPS and map stuff ////////////////////////////////////////////// /** * Handles GPS and map data. */ // Globals var lockGot = false; var latitude = 0.0000; var longitude = 0.0000; var gpsaccuracy = 9999; var requiredaccuracy = 40; // End Globals var fetchplacecounter = 0; var lastgpstime = 0; var map = L.map('map'); var tileurl = "http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg"; map.setZoom(17); map.dragging.disable(); //map.touchZoom.disable(); //map.doubleClickZoom.disable(); //map.scrollWheelZoom.disable(); map.keyboard.disable(); $(".leaflet-control-zoom").css("visibility", "hidden"); // Disable tap handler, if present. //if (map.tap) { // map.tap.disable(); //} // Tile layer map.addLayer(new L.tileLayer(tileurl, {minZoom: 16, maxZoom: 18})); // Places layer var placeLayer = L.geoJson( {"name": "Places", "type": "FeatureCollection", "features": [{"type": "Feature", "geometry": {"type": "Point", "coordinates": [0, 0]}, "properties": {"osm_id": -1, "name": null, 'gameinfo': {'teamid': "0"}}}]}, { onEachFeature: onPlaceTap, pointToLayer: function (feature, latlng) { var teamcolor = "#" + getTeamColorFromId(feature.properties.gameinfo.teamid); return L.circleMarker(latlng, { radius: 14, fillColor: teamcolor, color: "#000", weight: 1, opacity: 1, fillOpacity: 0.6 }); } });//.addTo(map); var placemarkers = L.markerClusterGroup({ spiderfyDistanceMultiplier: 2, spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: false, maxClusterRadius: 30 }); placemarkers.on('clusterclick', function (a) { a.layer.spiderfy(); }); placemarkers.addLayer(placeLayer); map.addLayer(placemarkers); var lc = L.control.locate({ position: 'topleft', // set the location of the control layer: undefined, // use your own layer for the location marker, creates a new layer by default drawCircle: false, // controls whether a circle is drawn that shows the uncertainty about the location setView: 'always', keepCurrentZoomLevel: true, // keep the current map zoom level when displaying the user's location. (if `false`, use maxZoom) remainActive: {inView: 'setView', outOfView: 'setView'}, markerClass: L.circleMarker, // L.circleMarker or L.marker circleStyle: {}, // change the style of the circle around the user's location markerStyle: {color: '#008000', fillColor: '#32CD32'}, followCircleStyle: {}, // set difference for the style of the circle around the user's location while following followMarkerStyle: {}, icon: 'fa fa-map-marker', // class for icon, fa-location-arrow or fa-map-marker iconLoading: 'fa fa-spinner fa-pulse', // class for loading icon iconElementTag: 'span', // tag for the icon element, span or i circlePadding: [0, 0], // padding around accuracy circle, value is passed to setBounds metric: true, // use metric or imperial units onLocationError: function (err) { }, // define an error callback function onLocationOutsideMapBounds: function (context) { // called when outside map boundaries }, showPopup: false, // display a popup when the user click on the inner marker strings: { title: ".", // title of the locate control metersUnit: "meters", // string for metric units feetUnit: "feet", // string for imperial units popup: "You are within {distance} {unit} from this point", // text to appear if user clicks on circle outsideMapBoundsMsg: "You seem located outside the boundaries of the map" // default message for onLocationOutsideMapBounds }, locateOptions: {} // define location options e.g enableHighAccuracy: true or maxZoom: 10 }).addTo(map); lc.start(); function mapPos(lat, lon) { lockGot = true; hideLoading(); // Don't update places every time if (fetchplacecounter === 0) { loadPlaces(latitude, longitude); } fetchplacecounter++; if (fetchplacecounter > 10) { fetchplacecounter = 0; } } function onPlaceTap(feature, layer) { layer.on('click', function (e) { openPlace(feature); }); } function loadPlaces(lat, long) { if (!lockGot) { return; } var url = mkApiUrl('places', 'gs') + "?lat=" + lat + "&long=" + long + "&radius=.5&names=1&lang=" + USER_LANGUAGE; try { $.getJSON( url, function (data) { if (data.type === 'FeatureCollection') { placeLayer.clearLayers(); placemarkers.clearLayers(); data.features.forEach(function (item) { item.properties.popupContent = "" + item.properties.name + ""; placeLayer.addData(item); }); placemarkers.addLayer(placeLayer); } } ); } catch (ex) { serverProblemsDialog(); } } function openPlace(feature) { $('#main-content').load("screens/place.html", null, function () { loadPlace(feature); $('#overlay-main').css('display', 'block'); }); } /** * Hide the loading overlay if everything is loaded, otherwise do nothing */ function hideLoading() { if (lockGot && gpsaccuracy < requiredaccuracy && $('#loading').css('display') !== 'none') { getWeather(); getTerrain(); $('#loading').fadeOut('slow', function () { $('#loading').css('display', 'none'); updateStatusBarColor(); }); } } var updatePosition = function (position) { latitude = position.coords.latitude; longitude = position.coords.longitude; lastgpstime = position.timestamp; gpsaccuracy = position.coords.accuracy; if (gpsaccuracy > requiredaccuracy) { $('#no-lock').css('display', 'block'); } else { $('#no-lock').css('display', 'none'); } mapPos(latitude, longitude); }; function pingServer() { if (lockGot && gpsaccuracy < requiredaccuracy) { $.getJSON(mkApiUrl('ping') + "?user=" + username + "&lat=" + latitude + "&long=" + longitude + "&lang=" + USER_LANGUAGE, function (data) { if (data.status == "ERROR") { localStorage.setItem("no_autologin", "true"); username = null; password = null; document.location.href = "index.html"; navigator.notification.alert("Your session status has changed, and you have been logged out. \n\nReason: " + data.message, null, "Sign-in Status Changed", "OK"); } }); } } var errorMsgShown = false; var fifteen_seconds = false; function onError(error) { if (!errorMsgShown) { var msg = error.message; if (msg.toLowerCase().includes("timeout") && fifteen_seconds == false) { return; } else if (msg.toLowerCase().includes("timeout")) { msg = "no lock within 15 seconds"; $('#loading-error').text("Check your device's network and location settings, and ensure a clear view of the sky (" + msg + ")."); } else { $('#loading-error').text("Check your device's network and location settings, and ensure a clear view of the sky (" + msg + ")."); } errorMsgShown = true; } } function popDiagData() { navigator.notification.alert("Latitude: " + latitude + "\nLongitude: " + longitude + "\nAccuracy: " + gpsaccuracy + "\nWeather: " + rawWeatherData.temperature + " F, " + rawWeatherData.summary + ", " + rawWeatherData.windSpeed + " mph" + "\nTerrain: " + terrainName + " (" + terrainType + ")", null, "World Info", "Close"); } // Initial GPS position and stuff navigator.geolocation.getCurrentPosition(updatePosition, onError, {timeout: 15000, enableHighAccuracy: true}); // Update position setInterval(function () { navigator.geolocation.getCurrentPosition(updatePosition, onError, {timeout: 1000, enableHighAccuracy: true}); }, 1000); setTimeout(function () { fifteen_seconds = true; }, 15 * 1000); // Update places setInterval(function () { loadPlaces(latitude, longitude); }, 1000 * 15); // Ping the server with coordinates setInterval(pingServer, 5000); // Show error if it's taking too long setTimeout(function () { onError(); }, 15 * 1000); setTimeout(function () { $('#loading-error').text("If you're outside and the settings are OK, something has gone wrong. Try restarting or reinstalling the app."); }, 45 * 1000);