Is setInterval cleared on scene change Phaser 3? - javascript

Are all setIntervals cleared on scene change in Phaser 3? For example, if I have this code:
class ExampleScene extends Phaser.Scene {
constructor () {
super();
}
preload () {
}
create () {
setInterval(() => console.log(true), 1000);
}
update () {
}
}
and I change scenes, will it continue to log true to the console? Is there an alternative in Phaser that doesn't require that I remove all intervals manually?

The short answer is, No. Since setInterval is a javascript function.
For details on the function: here in the documentation on mdn
What you can do is "save" the setInvertal calls/id's in a list and clear them on a specific scene event like, shutdown, pause, destroy ... . When that event fires you can then stop all saved intervals, or so (details to possible Scene events).
This is also considered good practice, since you always should cleanup resources, when leaving a phaser scene.
Example (here with the shutdown event):
...
// setup list for the intervals, that should be cleared later
constructor () {
super();
this.intervals = [];
}
create () {
...
// example of adding an interval, so that I can be cleanup later
this.intervals.push(setInterval(() => console.log(true), 1000));
...
// example listening to the shutdown Event
this.events.on('shutdown', this.stopAllIntervals, this);
}
...
// example "cleanup"-function, that is execute on the 'shutdown' Event
stopAllIntervals(){
for(let interval of this.intervals){
clearInterval(interval);
}
}
...
And now you just hat to call the stopAllIntervalsin the desired event function, when you want to stop them all.
From the offical documenation, on the shutdown Event: ... You should free-up any resources that may be in use by your Scene in this event handler, on the understanding that the Scene may, at any time, become active again. A shutdown Scene is not 'destroyed', it's simply not currently active. Use the DESTROY event to completely clear resources. ...

Related

Fabricjs object moving fire on finish

I want to call a function if the object move Event is finished.
Currently it Looks like this:
canvas.on('object:moving', function (event) {
recCanvas(canvas) // fire this if finished
});
The issue is that it fires the function everytime an object is moved how can I prevent this and fire the function once the moving finished.
What event happened when move event is finished?
Mouse up will finish event object moving. So you need a boolean variable to check when object is moving, then on mouse up if object has been moved call you function:
var isObjectMoving = false;
canvas.on('object:moving', function (event) {
isObjectMoving = true;
});
canvas.on('mouse:up', function (event) {
if (isObjectMoving){
isObjectMoving = false;
recCanvas(canvas) // fire this if finished
}
});
There is an object event when the object is finished moving
canvas.on('object:moved', function(event){
recCanvas(canvas) // fire this if finished
});
Yeah i know this is like pretty late and you probably found a suitable answer, but in the current version of Fabric js, if you try to use the above marked answer or try to use the object:modified event, you are likely going to encounter some bugs, not immediately but here is what I found;
when you use the mouse:up or object:modified to know if object position is changed, when you try to drag the object to change the position a couple of more times to be sure if it's working great, the browser page might stop responding, and sometimes it will take time before the canvas responds and the value to get updated.
So here is what I do, although i am using react js with fabric js so I am not fully sure if you who are using just vanilla javascript encounter this problem but in case someone also using react search for this problem here is a solution.
use a useEffect hook or onComponentDidMount, and inside it create a setInterval that get the currently active object after every 0.5 seconds or whatever time you think will suit you, and then try to update the variable and also don't forget to clear the interval.
//import your fabric js and react
const GetActivePosition = () => {
const [pos, setPos] = useState({left: 0, top: 0})
useEffect(() => {
const active = canvas.getActiveObject()
let interval = undefined
if (active){
interval = setInterval(() => {
setPos({left: active.left, top: active.top})
}, 500)
}
return () => clearInterval(interval)
}, [])
return (
<>
<p>Left: {pos.left}</>
<p>Top: {pos.top}</>
</>
)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

ES6: callback functions between objects

I'm building a page that will have various 'sections' that the user will pass through, each with their own logic. For instance:
Loading section: loading blinker. When finished, continue to:
Splash section: an introduction with some UI elements that need to be interacted with to continue. (let's just say there's a 'slide to unlock')
Video premiere: a custom player using the Youtube embed Javascript API.
Since some of these sections have a lot of specific logic, I'm separating these out into components. Almost all of this logic is internal to the component, but occasionally, I'd like to call a function within component A from component B. See the latter lines of main.js and Splash.js
main.js
import $ from 'jquery';
import Loading from './components/Loading.js';
import Splash from './components/Splash.js';
import Premiere from './components/Premiere.js';
$(() => {
Loading.init();
Splash.init();
Premiere.init();
Splash.onUnlock = Premiere.playVideo;
});
Loading.js:
const Loading = {
init() {
// watches for events, controls loading UI, etc.
},
// ... other functions for this section
}
export default Loading;
Splash.js
const Splash = {
init() {
// watches for events, controls unlocking UX, etc.
},
// ... other functions for this section
unlock() {
// called when UX is completed
this.onUnlock();
}
}
export default Splash;
Premiere.js
const Premiere = {
init() {
this.video = $('#premiereVideo');
// watches for events, binds API & player controls, etc.
},
// ... other functions for this section
playVideo() {
this.video.play()
},
}
export default Premiere;
Now, I'd expect that when this.onUnlock() is called within Splash, Premiere.playVideo() would be triggered. But, I get an error: video is not defined - because it's looking for Splash.video, not Premiere.video.
From what I understand, assigning an object or its property to a variable creates a reference to that property, not a duplicate instance. It seems I'm not understanding this correctly.
Changing this.video.play() to Premiere.video.play() works, but I feel like I'm still missing the point.
What's up?
(Possibly related sub-question: would I benefit from defining these components as classes, even if they're only going to be used once?)
So to answer your question why do you get video is not defined is because you are trying to access this which has changed contexts.
Premiere.playVideo.bind(Premiere)
Where the bind will make sure that when playVideo is called, it is called in the context of premiere rather than the context of splash. This means the context of premiere has this.video.
The code I used to verify:
const Splash = {
init() {
// watches for events, controls unlocking UX, etc.
},
// ... other functions for this section
unlock() {
// called when UX is completed
this.onUnlock();
}
}
const Premiere = {
init() {
this.video = {
play() {
console.log("playing");
}
};
// watches for events, binds API & player controls, etc.
},
// ... other functions for this section
playVideo() {
console.log(this);
this.video.play()
},
}
Premiere.init();
Splash.onUnlock = Premiere.playVideo.bind(Premiere);
console.log(Splash);
Splash.unlock();
However, this particular "architecture" is a bit smelly to me. You could use the chain of responsibility pattern. This is where the current object knows what to call next after it has done it's work.
class DoWork {
constructor(nextWorkItem) {
this.nextWorkItem = nextWorkItem;
}
doWork() {
}
}
class LoadingComponentHandler extends DoWork {
constructor(nextWorkItem) {
super(nextWorkItem);
}
doWork() {
// do what you need here
console.log("Doing loading work")
// at the end call
this.nextWorkItem.doWork();
}
}
class SplashComponentHandler extends DoWork {
constructor(nextWorkItem) {
super(nextWorkItem);
}
doWork() {
// do what you need here
console.log("Doing Splash Work")
// at the end call
this.nextWorkItem.doWork();
}
}
class PremiereComponentHandler extends DoWork {
constructor(nextWorkItem) {
super(nextWorkItem);
}
doWork() {
// do what you need here
console.log("Doing Premiere Work")
// at the end call
this.nextWorkItem.doWork();
}
}
class FinishComponentHandler extends DoWork {
constructor() {
super(null);
}
doWork() {
console.log("End of the line now");
}
}
var finish = new FinishComponentHandler();
var premiere = new PremiereComponentHandler(finish);
var splash = new SplashComponentHandler(premiere);
var loading = new LoadingComponentHandler(splash);
loading.doWork();
The FinishComponent is part of the Null Object Pattern, where its implementation does a noop (no operation). This effectively ends the line of responsibility. Of course you don't need a FinishComponent, you can just not call the this.nextWorkItem.doWork() and the chain will end there. I have it there because it is easier to see where the chain stops.
You can see from the last four lines that the chain of responsibility is easy to see:
var finish = new FinishComponentHandler();
var premiere = new PremiereComponentHandler(finish);
var splash = new SplashComponentHandler(premiere);
var loading = new LoadingComponentHandler(splash);
The loading component will call doWork on the splash object which will in turn call doWork on the premiere object, so on, so fourth.
This pattern relies on the inheritence of DoWork which is the kind of interface for the handler.
This probably isn't the best implementation, but you can see how you don't have to worry about the last thing that was called, or how to specially call the next. You just pass in the object you wish to come next into the constructor and make sure you call at the end of your operations.
I noticed you had
// watches for events, controls unlocking UX, etc.
The doWork() functions can execute the bindings, delegating them to the proper components that deal with this. So like SplashComponentHandler can delegate off to SplashComponent. It's good practise to keep these separations of concerns.
How this addresses your issue
Splash.onUnlock = Premiere.playVideo.bind(Premiere);
Firstly, Splash.onUnlock has no implementation until you give it one. Secondly, the fact you're having to bind a context to your function because it is getting executed under a different context doesn't sound good.
So you can imagine in SplashComponentHandler.doWork():
doWork() {
var component = new SplashComponent();
component.initialise(); // when this is finished we want to execute the premiere
this.nextWorkItem.doWork();
}
And in PremiereComponentHandler.doWork():
doWork() {
var component = new PremiereComponent();
component.bind(); // makes sure there is a this.video.
component.playVideo();
}
See now that SplashComponentHandler now has no knowledge of the next handler, it just knows that when it has finished its job, it needs to call the next handler.
There is no this binding, because doWork() has been executed in the context of PremiereComponentHandler or what ever handler was passed to SplashComponentHandler.
Furthermore
Technically speaking, you're not limited to executing one handler after another. You can create a handler that executes many other handlers. Each handler that gets executed will have knowledge of the next one until you stop calling into.
Another question is, what happens if once premiere is done doing its work, how can splash do something else afterwards?. Simple, so working from the previous scenario of decoupling, this is SplashComponentHandler.doWork():
doWork() {
var component = new SplashComponent();
component.initialise(); // when this is finished we want to execute the premiere
this.nextWorkItem.doWork();
// so when we get to this execution step
// the next work item (PremiereComponentHandler)
// has finished executing. So now you can do something after that.
component.destroy(); // cleanup after the component
fetch('api/profile') // i don't know, what ever you want.
.then(profileContent => {
component.splashProfile = profileContent.toJson();;
});
}
On that last note of using a Promise you can make the whole doWork() async using promises. Just return the this.nextWorkItem.doWork() and then the initialisation steps look like this:
var finish = new FinishComponentHandler();
var premiere = new PremiereComponentHandler(finish);
var splash = new SplashComponentHandler(premiere);
var loading = new LoadingComponentHandler(splash);
loading
.doWork()
.then(() => {
// here we have finished do work asynchronously.
})
.catch(() => {
// there was an error executing a handler.
});
The trick to making it all use Promises is to make sure that you always return a promise from doWork().

How setInterval and setTimeout behave on Phonegap/Cordova when app resumes from background? [duplicate]

I have a jQuery Mobile web app which targets iOS and Android devices. A component of the application is a background task, which periodically checks for a.) changes to local data and b.) connectivity to the server. If both are true, the task pushes the changes.
I'm using a simple setTimeout()-based function to execute this task. Each failure or success condition calls setTimeout() on the background task, ensuring that it runs on 30 second intervals. I update a status div with the timestamp of the last task runtime for debugging purposes.
In any desktop browser, this works just fine; however, on iOS or Android, after some period of time, the task stops executing. I'm wondering if this is related to the power conservation settings of the devices--when iOS enters stand-by, does it terminate JavaScript execution? That is what appears to happen.
If so, what is the best way to resume? Is there an on-wake event which I can hook into? If not, what other options are there which don't involve hooking into events dependent on user interaction (I don't want to bind the entire page to a click event just to restart the background task).
Looks like Javascript execution is paused on MobileSafari when the browser page isn't focused. It also seems if setInterval() events are late, they are simply fired as soon as the browser is focused. This means we should be able to keep a setInterval() running, and assume the browser lost/regained focus if the setInterval function took much longer than usual.
This code alerts after switching back from a browser tab, after switching back from another app, and after resuming from sleep. If you set your threshold a bit longer than your setTimeout(), you can assume your timeout wouldn't finish if this fires.
If you wanted to stay on the safe side: you could save your timeout ID (returned by setTimeout) and set this to a shorter threshold than your timeout, then run clearTimeout() and setTimeout() again if this fires.
<script type="text/javascript">
var lastCheck = 0;
function sleepCheck() {
var now = new Date().getTime();
var diff = now - lastCheck;
if (diff > 3000) {
alert('took ' + diff + 'ms');
}
lastCheck = now;
}
window.onload = function() {
lastCheck = new Date().getTime();
setInterval(sleepCheck, 1000);
}
</script>
Edit: It appears this can sometimes trigger more than once in a row on resume, so you'd need to handle that somehow. (After letting my android browser sleep all night, it woke up to two alert()s. I bet Javascript got resumed at some arbitrary time before fully sleeping.)
I tested on Android 2.2 and the latest iOS - they both alert as soon as you resume from sleep.
When the user switches to another app or the screen sleeps, timers seem to pause until the user switches back to the app (or when the screen awakens).
Phonegap has a resume event you can listen to instead of polling for state (as well as a pause event if you want to do things before it is out of focus). You start listening to it after deviceReady fires.
document.addEventListener("deviceready", function () {
// do something when the app awakens
document.addEventListener('resume', function () {
// re-create a timer.
// ...
}, false);
}, false);
I use angular with phonegap and I have a service implemented that manages a certain timeout for me but basically you could create an object that sets the timer, cancels the timer and most importantly, updates the timer (update is what is called during the 'resume' event).
In angular I have a scopes and root scope that I can attach data to, my timeout is global so I attach it to root scope but for the purpose of this example, I'll simply attach it to the document object. I don't condone that because you need should apply it to some sort of scope or namespace.
var timeoutManager = function () {
return {
setTimer: function (expiresMsecs) {
document.timerData = {
timerId: setTimeout(function () {
timeoutCallback();
},
expiresMsecs),
totalDurationMsecs: expiresMsecs,
expirationDate: new Date(Date.now() += expiresMsecs)
};
},
updateTimer: function () {
if (document.timerData) {
//
// Calculate the msecs remaining so it can be used to set a new timer.
//
var timerMsecs = document.timerData.expirationDate - new Date();
//
// Kill the previous timer because a new one needs to be set or the callback
// needs to be fired.
//
this.cancelTimer();
if (timerMsecs > 0) {
this.setTimer(timerMsecs);
} else {
timeoutCallback();
}
}
},
cancelTimer: function () {
if (document.timerData && document.timerData.timerId) {
clearTimeout(document.timerData.timerId);
document.timerData = null;
}
}
};
};
You could have the manager function take a millisecond parameter instead of passing it into set, but again this is modeled somewhat after the angular service I wrote. The operations should be clear and concise enough to do something with them and add them to your own app.
var timeoutCallback = function () { console.log('timer fired!'); };
var manager = timeoutManager();
manager.setTimer(20000);
You will want to update the timer once you get the resume event in your event listener, like so:
// do something when the app awakens
document.addEventListener('resume', function () {
var manager = timeoutManager();
manager.updateTimer();
}, false);
The timeout manager also has cancelTimer() which can be used to kill the timer at any time.
You can use this class github.com/mustafah/background-timer based on #jlafay answer , where you can use as follow:
coffeescript
timer = new BackgroundTimer 10 * 1000, ->
# This callback will be called after 10 seconds
console.log 'finished'
timer.enableTicking 1000, (remaining) ->
# This callback will get called every second (1000 millisecond) till the timer ends
console.log remaining
timer.start()
javascript
timer = new BackgroundTimer(10 * 1000, function() {
// This callback will be called after 10 seconds
console.log("finished");
});
timer.enableTicking(1000, function(remaining) {
// This callback will get called every second (1000 millisecond) till the timer ends
console.log(remaining);
});
timer.start();
Hope it helps, Thank you ...
You should use the Page Visibility API (MDN) which is supported just about everywhere. It can detect if a page or tab has become visible again and you can then resume your timeouts or carry out some actions.

requestAnimationFrame and knowing when the browser is re-painting?

Is there a way to know when the browser is actively running requestAnimationFrame?
For example when I switch tabs from one that was running requestAnimationFrame, the function stops getting executed, when I switch back it continues, what is the best way to deal with this?
To detect if requestAnimationFrame is running 100% you can check:
window.addEventListener('blur', function() {
//not running full
}, false);
and
window.addEventListener('focus', function() {
//running optimal (if used)
}, false);
this can be used as we know requestAnimationFrame reduces trigger rate (in most browsers) when window (tab) is not the active one (IF being used - it depends on the code actually using the requestAnimationFrame).
If you want it to run constantly you can insert a mechanism such as this:
var isActiveTab = true; //update with the events above
function myLoop() {
//my cool stuff here
if (isActiveTab) {
requestAnimationFrame(myLoop);
} else {
setTimeout(myLoop, 16); //force a rate (vblank sync not necessary
//when display isn't updated
}
}
Note that the reduction in rate for requestAnimationFrame is not part of the standard and is a browser specific implementation.
When you again come back to the tab with animation,It must be working fine(If thats the case--following is your answer!!!)
This is what RAF made for.To optimize performance.
SetInterval and Settimeout can be used instead for creating animations, But they cannot interact with the browser and eventually end up hogging up the cpu and the performance is also quite slow.
But your question is really not a question.This is actually a trick used by RAF to better your overall animation experience.
There are several articles which explains RAF.
http://creativejs.com/resources/requestanimationframe/
Just An Optimization TRICK--No need to worry about it
A solution I used in a project for canvas repainting. It's not 100% accurate but it works for out of focus users
// This will run when user is inactive
let = handleVisibilityChange = () => {
if (document.hidden) {
setTimeout(() => {
updateYourStuff();
handleVisibilityChange();
}, 1000);
}
};
// Listen if user is active or inactive
document.addEventListener("visibilitychange", handleVisibilityChange, false);
// Your loop when user is active
function myLoop() {
updateYourStuff();
requestAnimationFrame(myLoop);
}
If you need to know at what time a frame was painted, you can call requestPostAnimationFrame (google canary) or use a polyfill for it.

dojo mouseover with delay

I wish to do something like as follows:
When the mouse goes over to some element, record it
If the mouse stays there for 3 seconds, then execute some action f() for that element
If the mouse leaves that element before 3 seconds, then the action should not be executed.
How can I implement this delayed execution with possible cancellation? An answer using DOJO library would be nicer since I am using DOJO toolkit in my project.
Try the following:
var delay = 3000;
dojo.forEach(dojo.query(".some-element-set"), function(element) {
dojo.connect(element, "onmouseover", function() {
// dojo.partial(f, this.id) will apply `this.id` to `f`, but it
// will not execute it and will only a new function
this._timer = setTimeout(dojo.partial(f, this.id), delay);
});
dojo.connect(element, "onmouseout", function() {
// this._timer was set as an element attribute in the above event
// handler so we don't have to keep track of them separately in
// some silly array/object
clearTimeout(this._timer);
});
});
See the query, forEach, connect and partial documentation for more information.
Edit: I've update my answer per the OP's comment

Categories