Titanium geolocation distanceFilter property is not working as expected - titanium

Need a help here for geolocation API - even after using Titanium.Geolocation.distanceFilter = 10; 10 in meter callback function is getting triggered randomly without moving here and there. Any idea what is wrong here ?
function Geolocate() {
var self = this;
// The callback function we should call when location is finally determined
this.locationReceivedCallback = function () {};
// Check if location event is already triggered or not
this.isLocationEventRegister = false;
// The function that unregisters the location event
this.unregisterLocationEvent = function () {
this.isLocationEventRegister = false;
Ti.Geolocation.removeEventListener('location', self.locationReceivedCallback);
};
}
Geolocate.prototype.init = function () {
// Setting up some preference values
Titanium.Geolocation.distanceFilter = 10; //The minimum change of position (in meters) before a 'location' event is fired.
if (deviceDetect.isIos()) {
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST; // Using this value on Android enables legacy mode operation, which is not recommended.
} else {
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_LOW; //Using this value on Android enables simple mode operation.
}
};
Geolocate.prototype.getCurrentPosition = function (callback) {
this.isLocationEventRegister = true;
this.locationReceivedCallback = callback;
Titanium.Geolocation.addEventListener("location", this.locationReceivedCallback);
};
Geolocate.prototype.locationServicesAreAvailable = function () {
if (Titanium.Geolocation.locationServicesEnabled) {
return true;
} else {
return false;
}
};
Geolocate.prototype.cancelLocationRequest = function () {
this.unregisterLocationEvent();
};
module.exports = Geolocate;
Actual scenario is whenever I clicked on get location its gives me current location. then i tried to drag it map or image view for nearest place. Suddenly my view go current location. This is happening because of call back ? How to get rid off this ?

It's not a problem to do with your code, it is simply GPS in-accuracy.
GPS accuracy is (almost) never better than 10 meters, meaning it can be 10 meters off. When it recalculates your position it can be 10 meters down the line, so even if you're perfectly still with perfect GPS accuracy, you still might have differences of about 10 meters.
That said, you probably don't have best GPS accuracy when sitting behind a computer in a building, you probably have closer to 30-45 meters accuracy. Meaning every recalculation can easily be 10 meters differently.
Your solution would actually be rate-limit on top of using this property. The property will make sure it will not trigger multiple times per second, and then you can, in your own code, rate limit what you do with it.

Related

How to change the current time in the progress control?

Is it possible to manualy set the current time position on the timeline? I need this because I have several separated videos which represent one video and are playing in different players.
For example, the actual current time is marked as white dot, the desired current time that I want to show as red dot.
Can I do this somehow without creating completely new custom controlbar?
Middleware could be part of the solution, which allows you to intercept and modify what's sent to / received from the playback tech (video element).
var myMiddleware = function(player) {
return {
currentTime: function(ct) {
// When the video el says the currentTime is 60s, report 160s
return ct + 100;
},
setCurrentTime: function(time) {
// When the user / progress bar wants to seek to 220s, actually seek to 120s
return time - 100;
}
};
};
videojs.use('*', myMiddleware);

Why navigator.geolocation.watchposition not work in setInterval()?

I try to get location coordinate every 1 sec. But geolocation.watchposition not work in setInterval
here is my code:
componentDidMount(){
const intervalId = BackgroundTimer.setInterval(() => {
navigator.geolocation.watchPosition((position) => {
console.log(position.coords.latitude);
var lat = parseFloat(position.coords.latitude);
var lng = parseFloat(position.coords.longitude);
console.log("lat :",lat);
console.log("lng :",lng);
});
}, 1000);
BackgroundTimer.clearInterval(intervalId);
}
if I remove BackgroundTimer.setInterval method. It gives me coordinates. But I want everysecond
The watchPosition method will automatically call the success callback as soon as the user's position has changed, so doing this won't work. If you really need to get every second (which you might not need as user's position rarely will change in 1 second and it consumes a lot of battery power) you use the setInterval using along with navigator.geolocation.getCurrentPosition method.

Game loop on redux-saga

I'm playing with redux-saga to create a version of the snake game in react native, and I'm not sure how to go about the game loop implementation. So far I have a working version, but it feels clunky.. the snake moves at different speeds and the game is not very smooth.
Here is what I've got so far:
function *tickSaga() {
while (true) {
yield call(updateGameSaga)
const game = yield select(getGame)
if (game.crashed)
break
yield delay(1000)
}
}
The updateGameSaga basically gets the state from the store, process some logic (finds out if the snake next move will be a crash, move to an empty tile or move to a food tile and grow) and dispatches the corresponding action for it.
I'm slightly aware of things like requestAnimationFrame which I know I should be using, but I'm not sure how to make it work within the saga (maybe I don't need too do it in the saga, hence this question).
Any ideas on how to improve the smoothness of the game loop would be welcome.
UPDATE
I've included redux-saga-ticker, which internally uses setInterval (code here) to periodically send updates to the channel.
function *tickSaga() {
const channel = Ticker(1000); // game tick every 1000ms
while (true) {
yield take(channel);
yield call(updateGameSaga);
const game = yield select(getGame)
if (game.crashed)
break
}
}
It works better now and I like the channel aproach, but I still feel requestAnimationFrame is the way to go, although I'm not yet sure on how to implement it.
How about this.
let lastTime = 0;
function *tickSaga() {
while (true) {
var time = +new Date();
var delayTime = Math.max(0, 1000 - (time - lastTime));
lastTime = time + delayTime;
yield call(updateGameSaga)
const game = yield select(getGame)
if (game.crashed)
break
yield delay(delayTime)
}
}
If you need 60 fps, replace 1000 to 16 (1000/60).
For each tick you have a correction of the interval (time - lastTime) so the ticker interval should be uniform.

How to debounce a signal in QML?

I have a few properties that have change handlers that request a repaint of a canvas. This works fairly well, but I would like to debounce the signal because a user can only see a limited number of refreshes and some of the data items can change quite frequently. This causes far more refreshes than the user can see and reduces how responsive the UI is.
I have looked at debouncing the signal in javascript (there are examples on the web for how to do that) and tie it in to QML, but I haven't figured out how to get QML and javascript to work together in that way yet.
I would love to see something like the following:
function rateLimitedRefresh(){
// magic to limit to 30 frames per second
canvas.requestPaint()
}
onValueChanged: {
rateLimitedRefresh();
}
With the requestPaint method only being called on the canvas a maximum of 30 times per second.
I used a modification of Mertanian's answer. This modification enforces the frame rate limit at a per frame level as opposed to a per second level.
property var limitStartTime: new Date()
function rateLimitedRefresh(){
// magic to limit to 30 frames per second
var now = new Date();
if (now - limitStartTime >= 32) {
limitStartTime = now
canvas.requestPaint()
}
}
How about something like this:
property var limitStartTime: new Date()
property int refreshesThisSecond: 0
function rateLimitedRefresh(){
// magic to limit to 30 frames per second
if ((new Date()) - limitStartTime >= 33) {
limitStartTime = new Date(limitStartTime.getTime() + 33)
canvas.requestPaint()
}
}
onValueChanged: {
rateLimitedRefresh();
}

Panning the map to certain extent javascript API

I want to limit map extent to the initial extent of the map and limit user from panning more than certain extent.
I tried following but nothing has changed:
map = new Map( "map" , {
basemap: "gray",
center: [-85.416, 49.000],
zoom : 6,
logo: false,
sliderStyle: "small"
});
dojo.connect(map, "onExtentChange", function (){
var initExtent = map.extent;
var extent = map.extent.getCenter();
if(initExtent.contains(extent)){}
else{map.setExtent(initExtent)}
});
Just to flesh out Simon's answer somewhat, and give an example. Ideally you need two variables at the same scope as map:
initExtent to store the boundary of your valid extent, and
validExtent to store the last valid extent found while panning, so that you can bounce back to it.
I've used the newer dojo.on event syntax as well for this example, it's probably a good idea to move to this as per the documentation's recommendation - I assume ESRI will discontinue the older style at some point.
var map;
var validExtent;
var initExtent;
[...]
require(['dojo/on'], function(on) {
on(map, 'pan', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
console.log('Outside bounds!');
} else {
console.log('Updated extent');
validExtent = evt.extent;
}
});
on(map, 'pan-end', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
map.setExtent(validExtent);
}
});
});
You can do the same with the zoom events, or use extent-change if you want to trap everything. Up to you.
It looks like your extent changed function is setting the initial extent variable to the maps current extent and then checking if that extent contains the current extents centre point - which of course it always will.
Instead, declare initExtent at the same scope of the map variable. Then, change the on load event to set this global scope variable rather than a local variable. In the extent changed function, don't update the value of initExtent, simply check the initExtent contains the entire of the current extent.
Alternatively you could compare each bound of the current extent to each bound of the initExtent, e.g. is initExtent.xmin < map.extent.xmin and if any are, create a new extent setting any exceeded bounds to the initExtent values.
The only problem is these techniques will allow the initExtent to be exceeded briefly, but will then snap the extent back once the extent changed function fires and catches up.
I originally posted this solution on gis.stackexchange in answer to this question: https://gis.stackexchange.com/a/199366
Here's a code sample from that post:
//This function limits the extent of the map to prevent users from scrolling
//far away from the initial extent.
function limitMapExtent(map) {
var initialExtent = map.extent;
map.on('extent-change', function(event) {
//If the map has moved to the point where it's center is
//outside the initial boundaries, then move it back to the
//edge where it moved out
var currentCenter = map.extent.getCenter();
if (!initialExtent.contains(currentCenter) &&
event.delta.x !== 0 && event.delta.y !== 0) {
var newCenter = map.extent.getCenter();
//check each side of the initial extent and if the
//current center is outside that extent,
//set the new center to be on the edge that it went out on
if (currentCenter.x < initialExtent.xmin) {
newCenter.x = initialExtent.xmin;
}
if (currentCenter.x > initialExtent.xmax) {
newCenter.x = initialExtent.xmax;
}
if (currentCenter.y < initialExtent.ymin) {
newCenter.y = initialExtent.ymin;
}
if (currentCenter.y > initialExtent.ymax) {
newCenter.y = initialExtent.ymax;
}
map.centerAt(newCenter);
}
});
}
And here's a working jsFiddle example: http://jsfiddle.net/sirhcybe/aL1p24xy/