I played a bit with the javascript function called requestAnimationFrame(), and made this stroke by stroke kanji painter. It works well... the code is clean enough, considered my newbie-ness. I followed a nice tutorial here and landed on a structure like this :
function here_a_closure() {
var some_state = 0;
var last_frame = false;
function machinery() {
// do mysterious stuff
return last_frame;
}
function frame_display() {
handle = window.requestAnimationFrame(frame_display);
if (machinery()) {
window.cancelAnimationFrame(handle);
}
// do the display
}
frame_display();
}
However, I would like to extend this, and paint some more kanjis next to the first one. Should I wait for the end of the first animation to launch the next one ? I would prefer (more modularity and re-use), but how ? Or should I make the machinery more complex to animate more than one character in the same animation ?
Use a single requestAnimationFrame to drive all your animations.
If you have multiple animations that run with different timings then you can make use of the elapsed time that's automatically fed into each call.
function animate(time){
requestAnimationFrame(animate);
}
This way you have the flexibility of running each of your animations either consecutively or serially without increasing the complexity of your 'machinery'.
if(time>doSomethingOnAnimation1whenThisTimeElapses){ ... }
if(time>doSomethingOnAnimation2whenThisTimeElapses){ ... }
if(time>doSomethingOnAnimation3whenThisTimeElapses){ ... }
Here's a more detailed code about using requestAnimationFrame's timer on a previous post:
How to control animation speed (requestAnimationFrame)?
Related
I'm trying to write a code so that when a rect() reaches a certain point, a song will start playing. I was having trouble with my actual code so I started a new test file to mess around with it and try to get it to work (my actual js file is very long & I wanted something short and simple) but I just ran into the problem again.
The code is supposed to work so if the mouse is pressed, the left square will slide over to the right square, and when it hits the right square, the song will play. If the mouse is clicked again, the song will stop.
I've gotten most of that to work, but the trouble comes in when I add in
if ( backtoblack.isPlaying() ) {
backtoblack.stop();
} else {
backtoblack.play();
}
Here's the complete code for the sketch:
var backtoblack;
var rect1X = 20;
var speed = 1;
var mouseWasPressed;
function preload(){
backtoblack = loadSound('assets/backtoblack.mp3');
}
function setup() {
createCanvas(590,630);
background("#704e34");
}
function draw(){
fill("#fff");
rect(rect1X, 20, 120, 120);
rect(450, 20, 120, 120);
if (mouseWasPressed == true ) {
if(rect1X <= 390){
rect1X += speed;
}
}
if ( backtoblack.isPlaying() ) {
backtoblack.stop();
} else {
backtoblack.play();
}
}
function mousePressed(){
mouseWasPressed = true;
}
The problem is that your if else block that toggles whether the song is playing is inside the draw() function. That means that 60 times per second, you toggle the song! It's like you're constantly hitting the play and stop buttons. Then when you switch tabs, the draw() function is paused, which is why it stops toggling.
To fix your problem, you need to not toggle the song every frame. Perhaps put it inside the mousePressed() function to test things out.
Taking a step back, I'd also encourage you to debug your code (that guide is for Processing, but here is a guide on JavaScript). It's really great that you put together a smaller example program to test things out, but you should also try to step through the code line by line, or add print statements, to figure out what's going on. Stepping through or adding print statements would have helped you realize what was going on.
Anyway, good luck!
I try to display a loading alert on Meteor with modal package during loading of data.
'change .filterPieChart': function(evt){
Modal.show('loadingModal');
/* a little bit of work */
var data = MyCollection.find().fetch(); // takes 3 or 4 seconds
/* lot of work */
Modal.hide('loadingModal');
}
Normally, the alert is displayed at the beginning of the function, and disappears at the end. But here, the alert appears only after the loading time of the MyCollection.find(), and then disappears just behind. How to display it at the beginning of the function ??
I tried to replace Modal.show with reactive variable, and the result is the same, the changing value of reactive variable is detect at the end of the function.
From what you describe, what probably happens is that the JS engine is busy doing your computation (searching through the collection), and indeed blocks the UI, whether your other reactive variable has already been detected or not.
A simple workaround would be to give some time for the UI to show your modal by delaying the collection search (or any other intensive computation), typically with a setTimeout:
Modal.show('loadingModal');
setTimeout(function () {
/* a little bit of work */
var data = MyCollection.find().fetch(); // takes 3 or 4 seconds
/* lot of work */
Modal.hide('loadingModal');
}, 500); // delay in ms
A more complex approach could be to decrease the delay to the bare minimum by using requestAnimationFrame
I think you need to use template level subscription + reactiveVar. It is more the meteor way and your code looks consistent. As i can see you do some additional work ( retrive some data ) on the change event. Make sense to actually really retrive the data on the event instead of simulation this.
Template.TemplateName.onCreated(function () {
this.subsVar = new RelativeVar();
this.autorun( () => {
let subsVar = this.subsVar.get();
this.subscribe('publicationsName', this.subsVar);
})
})
Template.TemplateName.events({
'change .filterPieChart': function(evt){
Template.instance().collectionDate.subsVar.set('value');
Modal.show('loadingModal');
MyCollection.find().fetch();
Modal.hide('loadingModal');
}
})
Please pay attention that i didn't test this code. And you need to use the es6 arrow function.
I'm working with a script that needs to delay (or have a setTimeout) before any animation loads or initializes, but can't seem to figure out where to put it.
As for delay, if I'm not mistaken, this is used mainly with jquery...So for example: $('id or class here').delay(2000); ...Correct?
As for the setTimeout, if I'm not mistaken, it would be with javascript correct? If so, wouldn't it look something similar to this: setTimeout(function () {function_name},2000); or a slightly different variation of that?
Regardless of these two approaches and trying to add it where I think it should go (using either variations mentioned above), for some reason it just doesn't work right. The console isn't really helping either to check for errors.
In a nutshell, I'm trying to set a delay of 2s (2000ms) before anything starts or initializes.
JS CODE (Where I believe the issue lies):
$(document).ready(function() {
// Additional code here...
// start
BG.init();
// Additional code here...
}
});
Where you have this:
$(document).ready(function() {
Put this:
$(document).ready(function() {
setTimeout(function() {
And then where you have this:
});
// wrapper for background animation functionality
var BG = {
Put this:
}, 2000);
});
// wrapper for background animation functionality
var BG = {
And then, if you don't want to incur the wrath of everyone in the world, indent the stuff inside that new function we just created by one more level. 'Cause indentation is the stuff of life.
There's a lot of 'useless' code for us to help you. Next time share only on a need-to-know bases :)
I've edited your $document.ready block to include the timeout, have a look-see:
$(document).ready(function() {
function initiationProcess() {
// setup logo image
BG.logo = new Image();
BG.logo.onload = function() {
BG.logo_loaded = true;
BG.showLogo();
}
// /../ more code /../
// wire ticker listener
Ticker.addListener(BG.tick);
// start
BG.init();
// /../ more code /../
}
setTimeout(initiationProcess, 2000);
});
Edit:
I'd also like to note that it's considered bad practise (not to mention that it might result in buggy code) to only partly use semicolons in your script file. There's points and counterpoints to using semicolons, but pick a standard and stick to it!
I am running Timbre.js successfully on iOS 9.2 by coupling it with AudioContextMonkeyPatch, and I am trying to use a slightly modified version of code found here: http://mohayonao.github.io/timbre.js/interval.html. The code (to save lookup) is:
var freqs = T(function(count) {
return [220, 440, 660, 880][count % 4];
});
var osc = T("sin", {freq:freqs, mul:0.5});
var env = T("perc", {a:50, r:500}, osc).bang();
var interval = T("param", {value:500}).linTo(50, "30sec");
T("interval", {interval:interval}, freqs, env).start();
env.play();
What I am trying to figure out is how to start and then stop and then re-start the sound. I'm trying to see how the developer's example 'Pause' button works, but I can't seem to locate that code example. I do basic things tike "T().stop(); env.pause();" followed by "env.play();" (in separate onClick events), and I end up with multiple signals on the second play event. Really frustrating. The documentation suggests a 'removeAll' will remove all items loaded into Timbre() (or T()?), but applying this in my stop function does not provide a satisfactory result either.
Anyone know the correct way to pause and restart this script snippet?
In order to start and stop the sequence you need to assign the last T function to a variable. You can then use .start() and .stop() as you like:
code....
var interval = T("param", {value:500}).linTo(50, "30sec");
var audioSequence = T("interval", {interval:interval}, freqs, env);
env.play();
audioSequence.start(); // Start the Sequence
interval.stop(); // Stop the interval
audioSequence.stop(); // Stop the Sequence
interval.start(); // Restart the Interval
audioSequence.start(); // Restart the Sequence
Its a little confusing at first as play()/pause() is used for oscillators or drums for example and start()/stop() is used for intervals.
I'm using MIDI.js to build a music app that allows users to play piano through their keyboard.
Everything is working, but the problem I'm having is that the notes (called with MIDI.noteOn) only last 3 seconds, then just cut off. I'm trying to find a way to:
1- Make the note last for longer.
2- Make the note fade to nothing as opposed to just cutting off.
Could anyone point me in the right direction with there? There is so little documentation & discussion on MIDI.js.
Thanks in advance!
EDIT: The instrument name is acoustic_grand_piano
In theory, you need to call noteOff at the proper time.
In practice, MIDI.Plugin.js has this:
// FIX: needs some way to fade out smoothly..
root.noteOff = function (channel, note, delay) {
// var source = sources[channel+""+note];
// if (!source) return;
// source.noteOff(delay || 0);
// return source;
};