i am running several JavaScript functions in parallel. some of them download images from and add them to the canvas. other functions draw rectangles on the same canvas.
now, what i dont know is when each function has completed adding their "stuff" to the canvas.
so my question is that is there a way to know if the canvas is "busy" or all operations are done and it's idle.
knowing so will help me code loader windows more efficiently.
any help appreciated.
Nothing find showing that canvas is busy in adding/updating/moving but i have an idea here
you can use
canvas.requestRenderAll()
all over instead
canvas.renderAll();
that will keep queued render request if already there is request in progress.
now there are two events
after:render at the end of the render process,event: receives the context in the callback
before:render at start the render process,event: receives the context in the callback
ref http://fabricjs.com/docs/fabric.Canvas.html
using before:render show loader and in after:render with settimeout 100mili sec you can stop loader.
Hope this idea works.
If not please message will try myself
Fabric.js uses callbacks to execute code after performing asynchronous operations. An example would be loading an image which shouldn't be added to a canvas until after the image has loaded.
fabric.Image.fromURL(imageURL, function(image) {
//this is the callback that is executed after the image has loaded.
//include any actions here that you want performed after loading the image
image.set({ left: 50, top: 50, width:50, height:50 });
canvas.add(image);
});
If you have a list of images you want to load, you can use a recursive function that executes the callback only when the list is complete. Something like this should work:
var images = [src1, src2, src3];
var x = -1;
loopImages(function() {
//include any actions here that you want performed after loading all images
alert('All done!');
});
function loopImages(callback) {
x++; //iterates current index on each loop
if (x < images.length) {
fabric.Image.fromURL(images[x], function(image) {
image.set({
left: 50,
top: 50,
width: 50,
height: 50
});
canvas.add(image);
loopImages(callback);
});
} else {
callback();
}
}
Related
I have a YouTube video link which I am trying to supply parameters to:
https://www.youtube.com/embed/wU4DgHHwVCc?autoplay=1&start=20&end=25&loop=1
Everything else works perfectly except for the loop parameter. The video doesn't loop. According to Google Developer's page:
This parameter has limited support in the AS3 player and in IFrame embeds, which could load either the AS3 or HTML5 player. Currently, the loop parameter only works in the AS3 player when used in conjunction with the playlist parameter.
So even though my Chrome browser is not using AS3, as I've disabled flash, I added the playlist parameter to the URL just to see what would happen.
https://www.youtube.com/embed/wU4DgHHwVCc?autoplay=1&start=20&end=25&loop=1&playlist=wU4DgHHwVCc
Now the video does loop but both start and end parameters are ignored and the video starts at 00:00 instead of 00:20 as specified in the URL.
Why do I need to specify the playlist parameter when I am not using AS3 player?
Why does it ignore the start and end parameters on loop?
OS: Ubuntu 16.04 LTS
Chrome version: 60.0.3112.90 (64-bit)
Looking at Youtube documentation... You can modify their shown i-frame API example code like below to get a looping effect.
The trick is :
Set Start Time of video at 20 seconds
Listen for playback begin event and handle with onPlayerStateChange() function, which itself starts a timer of a 5 seconds countdown (ie: 5000 millisecs).
When timer reaches zero it triggers function handleVideo() which itself starts a new timer of 5 seconds. Then auto-seeks back to 20 second (start time) in video's timeline. The timer now creates a feedback loop.
Try my example code below in a new html page. Can also test it here.
Code was tested on Windows/Chrome.
<!DOCTYPE html>
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady()
{
player = new YT.Player('player',
{
width: '100%',
height: '800',
videoId: 'wU4DgHHwVCc',
startSeconds:20,
//endSeconds:25,
events:
{
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event)
{
event.target.seekTo(20);
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(handleVideo, 5000);
done = true;
}
}
// Custom function to LOOP
// Moves playhead back to 20 seconds
function handleVideo()
{
setTimeout(handleVideo, 5000);
player.seekTo(20);
}
</script>
</body>
</html>
It is simple. For single video to loop, you need to have it twice.
Try this out.
https://www.youtube.com/embed/wU4DgHHwVCc?playlist=wU4DgHHwVCc&autoplay=1&rel=0&loop=1
Note that "rel" must be set to "0" for any videos that might have them linked as they break the loop.
I made a page for testing HERE if you like to test.
I have a sprite and I set its y velocity to 200 so that it moves down.
The sprite moves perfectly fine except that sometimes it stutters a lot. The other times it is silky smooth. Its like the fps drops to 20.
How do I stop this stuttering?
Below is my code and you can try it live here
var SimpleGame = (function () {
function SimpleGame() {
this.game = new Phaser.Game(800, 400, Phaser.AUTO, 'content', { preload: this.preload, create: this.create, update: this.update });
}
SimpleGame.prototype.preload = function () {
this.game.load.image('logo', 'Sprites/icon.png');
};
SimpleGame.prototype.create = function () {
//Create Sprite
this.speed = 133;
this.game.stage.backgroundColor = 0xffffff;
this.logo = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, 'logo');
this.logo.position.set(200, 50);
this.game.physics.arcade.enable(this.logo);
//Set velocity
this.logo.body.velocity.y = this.speed;
};
return SimpleGame;
})();
window.onload = function () {
var game = new SimpleGame();
};
I am not getting the stuttering myself. So, try loading it with other computers, find friends with different levels of computers, to make sure that it isn't a local client-side problem. If it is, then check your computers firewall settings any antivirus that may be stopping a process which will slow down your game.
If it is a server-side problem- firstly, try to condense your code and the memory used. Use local variables instead of global ones, don't pass too many function arguments (If you are using a lot of function arguments then you are filling up the Stack and that may be causing the lag).
Also check your server. I don't know what web server you are using so I don't really know your specs on this, but I may be able to help. Does Phaser use too much memory for your webserver? Small Webservers are designed purely for small websites so by using a lot of JS (which Phaser does ,look in Phaser.min!) you may be using too much memory on your server. Maybe a bigger subscription?
I hope I've helped.
Disclaimer: I'm a Node.js newbie and the following description may be lengthy...
I'm currently trying to teach myself Node.js for a little project I'm after. The project idea is the following: a RaspberryPI runs a Node.js application which allows me to control the colors of an RGB LED strip. The application should be able to set both a static color and also run color wheels that smoothly change colors.
My idea is now to create several Node.js scripts:
A "controller" that does the client communication, sets static colors or is able to start a color wheel
"client scripts" that each run a color wheel. At most one of them would be "alive", started/stopped by the "controller"
I've been able to create a little script that forks another script and is able to stop that script using child.send as follows:
controller.js
var fork = require('child_process').fork,
test2 = fork(__dirname + '/test2.js');
setTimeout(function() { test2.send({func: 'quit'}); }, 5000);
This forks the test2.js script and after 5 seconds sends a quit message that quits test2.js.
test2.js
function runLoop()
{
console.log("Hello");
setTimeout(runLoop, 1000);
}
process.on('message', function(m) {
if (m.func === 'quit')
{
process.exit(0);
}
});
setTimeout(runLoop, 1000);
This "client script" prints "Hello" every second until the controller sends the quit message.
This works pretty well - after 5 seconds the scripts finish gracefully.
My question is now: If I implement a color wheel, I'll need a possibly endless loop that changes the colors of the LED strip. Would the above (with shorter timer values of course - I need something like 10ms here) be a feasible way of implementing an interruptible loop or is there some neater mechanism I don't know of yet?
If you're using setTimeout, you shouldn't even need to fork a new process. Here's how I would write your example:
var ntrvl = setInterval(function() { console.log('Hello'); }, 1000);
setTimeout(function() { clearInterval(ntrvl); }, 5000);
... very simple. With setTimeout and setInterval, you're using asynchronous functions, so you will not block the event loop. When the timer is up, it runs your code, then waits for the next event. You should be able to control all of your "clients", you'll have bandwidth for far more than you'll actually need, all in the same process in this way, concurrently.
All you need to be wary of is that you're not blocking the script. If you attempt to perform any action synchronously (which means that the script will wait for the action to complete before performing the next command), then you need to make sure it runs quickly. If you have to run processor/time intensive tasks synchronously, that's when you'll need to fork a new process.
You're making the life complicated. Your global architecture is as follows:
external trigger --> listener ----------> code that changes color
(ie. web client) (ie. web server)
With that in mind you don't need to fork any process, you can control the LED strip within a single process. Somewhere in your code you'll have an object similar to this:
//"led" is the module that allows you to change the color of a led (suppose 4 leds)
var led = require ("led-controller");
var ColorChanger = module.exports = function (){
this._intervalId = null;
};
ColorChanger.prototype.setColor = function (hex){
//Color in hexadecimal
//Cancel any current interval
cancelInterval (this._intervalId);
led.color (0, hex);
led.color (1, hex);
led.color (2, hex);
led.color (3, hex);
};
ColorChanger.prototype.wheel = function (hex, ms){
//Color in hexadecimal
//"ms" is the time interval between leds going on and off
//Cancel any current interval
cancelInterval (this._intervalId);
//Shutdown all the leds
led.off (0);
led.off (1);
led.off (2);
led.off (3);
//Activate the first led
led.color (0, hex);
//Current active led
var curr = 0;
this._intervalId = setInterval (function (){
//Each "ms" the current led will go off and the next will go on
led.off (curr);
//Next led to activate
curr = ++curr%4;
led.color (curr, hex);
}, ms);
};
Then the listener module uses the ColorChanger.
var ColorChanger = require ("./color-changer");
var changer = new ColorChanger ();
//Set all the leds to red
changer.setColor ("#FF0000");
//Each 10ms one led goes green and the previous is turned off, in an endless loop
changer.wheel ("#00FF00", 10);
I'm using D3.js to render a graph with nodes containing raster images.
var mainscreenURL = s3_base_url + viewController + "/screenshot.jpeg";
svg.select(".mainScreen").transition().attr("height",0).remove();
svg.append("image").attr("xlink:href", mainscreenURL)
.attr("width", mainScreenW)
.attr("height", mainScreenH)
.attr("x", (w / 2) - (mainScreenW / 2))
.attr("y", (h / 2) - (mainScreenH / 2))
.attr("class", "mainScreen")
.attr("id", viewController)
});
Some of these images are pretty large, so the HTTP requests (made implicitly by the browser) can take a substantial amount of time. I can't cache the images, since they're dynamically generated.
If this were regular HTML, I'd show a placeholder image, and then swap it out for the real thing upon successful completion of the HTTP get request. But since this is SVG, there is no explicit request, and I end up with a nasty broken image which is then replaced with the real thing.
Are there any events I can hook to know when the image is fully loaded?
See related: Is it possible to listen image load event in SVG?
I couldn't get the native addEventListener approach to work, but it looks like you can just set the onload attribute (works in Chrome, at least):
svg.append("image")
.attr('onload', function() {
alert('loaded');
})
.attr("xlink:href", mainscreenURL);
See fiddle: http://jsfiddle.net/dKxH9/
#nrabinowitz, your code doesn't work as it was planned.
Using .attr('onload', function() {}) calls function during assigning 'onload' attribute, not during onload event.
Proper implementation should be as follows (see http://jsfiddle.net/L83nag59/)
svg.append("image")
.on('load', function() {
alert('loaded');
})
.attr("xlink:href", mainscreenURL)
Unfortunately, it doesn't work in IE11.
So, I've got this:
$('header').fadeIn(1000, function() {
// Animation complete
});
$('#intro').fadeIn(3000, function() {
// Animation complete
});
And now I want the second one to come in later, so with a delay. But where in the code do I put this?
EDIT: Got it, thanks!
If you want to start the second animation after the first one, you should do this
$('header').fadeIn(1000, function() {
$('#intro').fadeIn(3000, function() {
// Animation complete
});
});
jQuery maintains a queue of effects per element. You are animating 2 elements so they will fire simultaneously.
More info: http://api.jquery.com/queue/
You can nest the functions but that's going to get difficult if you want 10 effects.
Here's a good solution:
https://stackoverflow.com/a/11354378/907253