html5 canvas drawImage not loading in Chrome - html

I am using the following code to wait for all images to load before drawing them onto the canvas. This works great in Firefox and works great when I enter the url of the page directly into the address bar of Chrome. However, when I attempt to use the refresh button in Chrome the images fail to load.
var need_to_load = 2;
var items = 0;
function item_loaded() {
items +=1;
if (items >= need_to_load) {
context.drawImage(router_pic,router_x,router_y,80,80);
context.drawImage(switch_pic,router_x,switch_y,60,60);
}
} // end item_loaded
var router_pic = new Image();
router_pic.src = "images/router.png";
router_pic.onload = item_loaded();
var switch_pic = new Image();
switch_pic.src = "images/switch.png";
switch_pic.onload = item_loaded();
Can someone point me in the right direction as to why and how to make this work with Chrome?
I realize in this case I can get rid of the item_loaded() function, but I have another more complicated canvas drawing where it makes the most sense to wait for all images to load before drawing them to the canvas.
Chrome version is 33.0.1750.152 if that makes any difference.

You're currently using the onload handler wrong. It need to have only a reference to the handlers - here the result of those functions are returned to it instead.
Simply change these lines:
router_pic.onload = item_loaded; //no parenthesis
switch_pic.onload = item_loaded;
I would also recommend switching the onload line with src line so src comes last.
Hope this helps!

Related

How to reset canvas context state entirely

I have a simple canvas animation, as follows:
function animate(){
var canvas = document.getElementById("canvas");
canvas.width = $(window).width();
canvas.addEventListener("click", replay, false);
var context = canvas.getContext("2d");
//animation code
function replay(e){
animate();
}
}
So my expectation is when the user clicks the canvas the animation will replay because I am reassigning the width:
canvas.width = $(window).width();
which will reset the entire context state ( read it here http://diveintohtml5.info/canvas.html)
It works the first time you click the canvas but after that it remembers the context transformation state and shows some weird animation.
I tried adding this:
context.setTransform( 1, 0, 0, 1, 0, 0 );
to explicitly reset the transformation matrix to identity matrix before re-drawing but has no effect.
It is different from this How to clear the canvas for redrawing
because it is about how to clear the display of context but I want to clear everything the display plus the context state.
I tried logging the state of each variable during the animation I get something weird with the ff code.
function moveHorizontal(x){
if(x < 100 ){
context.translate(1, 0);
console.log("x:"+x);
drawImage();
x += 1;
setTimeout(moveHorizontal,10,x);
}
}
I am calling this function initially as moveHorizontal(0).
so the log is as expected the first time:
x:0
x:1
x:2
.
.
x:99
when I click "replay" I get same thing as above:
x:0
x:1
x:2
.
.
x:99
which is correct but when I click "replay" the second time
I am getting this:
x:0
x:0
x:1
x:1
.
.
.
x:99
x:99
which triples the translation leading to unexpected effect.
any explanation?
Update
With the new information this may be the cause of the problem (there is not enough code to be 100% sure but it should give a good pointer as to where the problem is):
As the code is asynchronous and seem to share a global/parent variable x, what happens is that when, at some point, the replay is invoked before one earlier has stopped, the x is reset to 0 causing both (or n number of loops) to continue.
To prevent this you either need to isolate the x variable for each run, or using a simpler approach blocking the loop from running if it's already running using x from a previous invocation. You can use a flag to do this:
var x = 0,
isBusy = false;
function animation(x) {
if (isBusy) return;
if (x < 100) {
isBusy = true;
// ...
setTimeout(...); // etc.
}
else {
isBusy = false;
}
}
optionally, store the timeout ID from setTimeout (reqID = setTimeout(...)) and use clearTimeout(reqID) when you invoke a new loop.
Old answer
The only way to reset the context state entirely is to:
Set a new dimension
Replace it with a new canvas (which technically isn't resetting)
The latter should be unnecessary though.
According to the standard:
When the user agent is to set bitmap dimensions to width and height,
it must run the following steps:
Reset the rendering context to its default state.
...
In the example code in your post you are using a mix of jQuery and vanilla JavaScript. When working with canvas (or video element) I always recommend using vanilla JavaScript only.
Since you are not showing more of the code it is not possible for us to pinpoint to any specific error. But as neither setting an identity matrix nor setting a size for canvas seem to work, it indicates that the problem is in a different part of the code. Perhaps you have persistent offsets involved for your objects that are not reset.
Try to eliminate any possible errors coming from using jQuery to set width as well:
canvas.width = window.innerWidth; // and the same for height
Two other things I notice is that you set the size of canvas inside a function that appears to be part of a loop - if this is the case it should be avoided. The browser will have to, in essence, build a new canvas every time this happens. Second, this line:
canvas.addEventListener("click", replay, false);
can simply be replaced with (based on the code as shown):
canvas.addEventListener("click", animate, false);
You will need to post more code to get a deeper going answer though. But as a conclusion in regards to context: setting a new size will reset it. The problem is likely somewhere else in the code.

Unable to free my webcam in Actionscript 3.0

To free my webcam I'm using
onScrenVideo.attachCamera(null)
where onScreenVideo is a Video object.
However, this just doesn't seem to work. Even after this line executes, the webcam light remains ON.
I have scoured the Internet for a solution to this problem and everyone seems to be unanimous that this is the only way to turn the webcam off (for example : Close webcam usage via actionscript), however, this just doesn't seem to be working for me.
Can anyone help?
Thanks
Edit: Adding relevant code.
All the variables are declared previously. Here's the code to set up the Camera and attach it to the video.
testCurrCam = Camera.getCamera();
onScreenVideo = new Video(240, 180);
onScreenVideo.smoothing = true;
onScreenVideo.x = 0;
onScreenVideo.y = 0;
addChild(onScreenVideo);
testCurrCam.setQuality(0, 70);
testCurrCam.setMode(640, 480, 10);
onScreenVideo.attachCamera(testCurrCam);
And here's a function which is called by Javascript using ExternalInterface. The call works perfectly fine, because I've checked using an alert box after the if condition.
private function stopCam(): void {
if (contains(onScreenVideo)) {
onScreenVideo.attachCamera(null);
this.removeChild(onScreenVideo);
onScreenVideo = null;
testCurrCam = null;
} else
return;
}

HTML5 Audio stop function

I am playing a small audio clip on click of each link in my navigation
HTML Code:
<audio tabindex="0" id="beep-one" controls preload="auto" >
<source src="audio/Output 1-2.mp3">
<source src="audio/Output 1-2.ogg">
</audio>
JS code:
$('#links a').click(function(e) {
e.preventDefault();
var beepOne = $("#beep-one")[0];
beepOne.play();
});
It's working fine so far.
Issue is when a sound clip is already running and i click on any link nothing happens.
I tried to stop the already playing sound on click of link, but there is no direct event for that in HTML5's Audio API
I tried following code but it's not working
$.each($('audio'), function () {
$(this).stop();
});
Any suggestions please?
Instead of stop() you could try with:
sound.pause();
sound.currentTime = 0;
This should have the desired effect.
first you have to set an id for your audio element
in your js :
var ply = document.getElementById('player');
var oldSrc = ply.src;// just to remember the old source
ply.src = "";// to stop the player you have to replace the source with nothing
I was having same issue. A stop should stop the stream and onplay go to live if it is a radio. All solutions I saw had a disadvantage:
player.currentTime = 0 keeps downloading the stream.
player.src = '' raise error event
My solution:
var player = document.getElementById('radio');
player.pause();
player.src = player.src;
And the HTML
<audio src="http://radio-stream" id="radio" class="hidden" preload="none"></audio>
Here is my way of doing stop() method:
Somewhere in code:
audioCh1: document.createElement("audio");
and then in stop():
this.audioCh1.pause()
this.audioCh1.src = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAVFYAAFRWAAABAAgAZGF0YQAAAAA=';
In this way we don`t produce additional request, the old one is cancelled and our audio element is in clean state (tested in Chrome and FF) :>
This method works:
audio.pause();
audio.currentTime = 0;
But if you don't want to have to write these two lines of code every time you stop an audio you could do one of two things. The second I think is the more appropriate one and I'm not sure why the "gods of javascript standards" have not made this standard.
First method: create a function and pass the audio
function stopAudio(audio) {
audio.pause();
audio.currentTime = 0;
}
//then using it:
stopAudio(audio);
Second method (favoured): extend the Audio class:
Audio.prototype.stop = function() {
this.pause();
this.currentTime = 0;
};
I have this in a javascript file I called "AudioPlus.js" which I include in my html before any script that will be dealing with audio.
Then you can call the stop function on audio objects:
audio.stop();
FINALLY CHROME ISSUE WITH "canplaythrough":
I have not tested this in all browsers but this is a problem I came across in Chrome. If you try to set currentTime on an audio that has a "canplaythrough" event listener attached to it then you will trigger that event again which can lead to undesirable results.
So the solution, similar to all cases when you have attached an event listener that you really want to make sure it is not triggered again, is to remove the event listener after the first call. Something like this:
//note using jquery to attach the event. You can use plain javascript as well of course.
$(audio).on("canplaythrough", function() {
$(this).off("canplaythrough");
// rest of the code ...
});
BONUS:
Note that you can add even more custom methods to the Audio class (or any native javascript class for that matter).
For example if you wanted a "restart" method that restarted the audio it could look something like:
Audio.prototype.restart= function() {
this.pause();
this.currentTime = 0;
this.play();
};
It doesn't work sometimes in chrome,
sound.pause();
sound.currentTime = 0;
just change like that,
sound.currentTime = 0;
sound.pause();
From my own javascript function to toggle Play/Pause - since I'm handling a radio stream, I wanted it to clear the buffer so that the listener does not end up coming out of sync with the radio station.
function playStream() {
var player = document.getElementById('player');
(player.paused == true) ? toggle(0) : toggle(1);
}
function toggle(state) {
var player = document.getElementById('player');
var link = document.getElementById('radio-link');
var src = "http://192.81.248.91:8159/;";
switch(state) {
case 0:
player.src = src;
player.load();
player.play();
link.innerHTML = 'Pause';
player_state = 1;
break;
case 1:
player.pause();
player.currentTime = 0;
player.src = '';
link.innerHTML = 'Play';
player_state = 0;
break;
}
}
Turns out, just clearing the currentTime doesn't cut it under Chrome, needed to clear the source too and load it back in. Hope this helps.
As a side note and because I was recently using the stop method provided in the accepted answer, according to this link:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element. In the link it mentions Firefox, but I encountered this event firing after setting currentTime manually on Chrome. So if you have behavior attached to this event you might end up in an audio loop.
shamangeorge wrote:
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element.
This is indeed what will happen, and pausing will also trigger the pause event, both of which make this technique unsuitable for use as a "stop" method. Moreover, setting the src as suggested by zaki will make the player try to load the current page's URL as a media file (and fail) if autoplay is enabled - setting src to null is not allowed; it will always be treated as a URL. Short of destroying the player object there seems to be no good way of providing a "stop" method, so I would suggest just dropping the dedicated stop button and providing pause and skip back buttons instead - a stop button wouldn't really add any functionality.
This approach is "brute force", but it works assuming using jQuery is "allowed". Surround your "player" <audio></audio> tags with a div (here with an id of "plHolder").
<div id="plHolder">
<audio controls id="player">
...
</audio>
<div>
Then this javascript should work:
function stopAudio() {
var savePlayer = $('#plHolder').html(); // Save player code
$('#player').remove(); // Remove player from DOM
$('#FlHolder').html(savePlayer); // Restore it
}
I was looking for something similar due to making an application that could be used to layer sounds with each other for focus. What I ended up doing was - when selecting a sound, create the audio element with Javascript:
const audio = document.createElement('audio') as HTMLAudioElement;
audio.src = getSoundURL(clickedTrackId);
audio.id = `${clickedTrackId}-audio`;
console.log(audio.id);
audio.volume = 20/100;
audio.load();
audio.play();
Then, append child to document to actually surface the audio element
document.body.appendChild(audio);
Finally, when unselecting audio, you can stop and remove the audio element altogether - this will also stop streaming.
const audio = document.getElementById(`${clickedTrackId}-audio`) as HTMLAudioElement;
audio.pause();
audio.remove();
If you have several audio players on your site and you like to pause all of them:
$('audio').each( function() {
$(this)[0].pause();
});
I believe it would be good to check if the audio is playing state and reset the currentTime property.
if (sound.currentTime !== 0 && (sound.currentTime > 0 && sound.currentTime < sound.duration) {
sound.currentTime = 0;
}
sound.play();
for me that code working fine. (IE10+)
var Wmp = document.getElementById("MediaPlayer");
Wmp.controls.stop();
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"
standby="Loading áudio..." style="width: 100%; height: 170px" id="MediaPlayer">...
Hope this help.
What I like to do is completely remove the control using Angular2 then it's reloaded when the next song has an audio path:
<audio id="audioplayer" *ngIf="song?.audio_path">
Then when I want to unload it in code I do this:
this.song = Object.assign({},this.song,{audio_path: null});
When the next song is assigned, the control gets completely recreated from scratch:
this.song = this.songOnDeck;
The simple way to get around this error is to catch the error.
audioElement.play() returns a promise, so the following code with a .catch() should suffice manage this issue:
function playSound(sound) {
sfx.pause();
sfx.currentTime = 0;
sfx.src = sound;
sfx.play().catch(e => e);
}
Note: You may want to replace the arrow function with an anonymous function for backward compatibility.
In IE 11 I used combined variant:
player.currentTime = 0;
player.pause();
player.currentTime = 0;
Only 2 times repeat prevents IE from continuing loading media stream after pause() and flooding a disk by that.
What's wrong with simply this?
audio.load()
As stated by the spec and on MDN, respectively:
Playback of any previously playing media resource for this element stops.
Calling load() aborts all ongoing operations involving this media element

HTML5 webpage animation

Does anybody know how to achieve something like that?
http://teamviget.com/#!lift-off
I want to do something similar but I'm something new in html5 and all this stuff
Thanks!
Of course you can do. First of all the you gotta draw the background image. And provide two buttons on either side. Onclick of these buttons you call a function... which inturn calls an setInterval() function that animates(here in your case the image has to fade and a new image has to be formed) . For providing fading effect we have a popular parameter. ctx.globalAlpha(). In each animation step change the value of it. Lemme provide a sample code so that you can understand it properly.
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var ms = new Image();
ms.src = "images/asdf.jpg"
ctx.drawImage(ms,0,0); // Will draw the initial image (assume)
ctx1 = canvas.getContext("2d");
Now let me define the onclick function.
onclick="caller()";
The caller function should be made to call the animate function
function caller()
{
i=1;
inter=setInterval(animate(),500); // Calls the animate function every 500 msec
}
And the animate function would look as shown below
function animate()
{
i=i-0.1;
ctx1.globalAlpha=i;
if(i=0)
{
clearInterval(inter);
ctx1.drawImage(ms2,0,0); // This will draw the next image defined in ms2.
}
}
So the image will be faded out and a new image appears in 5 secs. Use an array if you have several images and definitely javascipts would help you to implement them all the way you want. Let me know if you need any more clarifications to a SPECIFIC problem that you are facing.

flex: Create a screenshot of UI element

I want to make a screenshot of custom as3 ui element (which was extended from Canvas), and then upload the image on the server.
Could you help me with a small example of this?
I am trying to do the following:
// This is UI component extended from Canvas
var chessBoard:ChessBoard = new ChessBoard();
// I displayed pieces on the board, but didn't add it to the stage (I just need a
// a screenshot, not need them on the canvas)
chessBoard.displayPosition(DataStorage.getInstance().getStoredPosition(0));
var img:ImageSnapshot = ImageSnapshot.captureImage(chessBoard, 300, new PNGEncoder());
var obj:Object = new Object();
obj.complexity = complexity.value;
obj.img = img;
httpService.send(obj);
and getting this error:
ArgumentError: Error #2015: Invalid
BitmapData. at
flash.display::BitmapData() at
mx.graphics::ImageSnapshot$/captureBitmapData()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\graphics\ImageSnapshot.as:186]
at
mx.graphics::ImageSnapshot$/captureImage()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\graphics\ImageSnapshot.as:282]
at
ui::SendForm/send()[/Users/oleg/Documents/chess_problems/problemme/src/ui/SendForm.mxml:53]
at
> ui::SendForm/___SendForm_Button1_click()[/Users/oleg/Documents/chess_problems/problemme/src/ui/SendForm.mxml:16]
This error was caused by missing width and height of the Canvas. I set them and it helped to create bitmap data this way:
var bitmapData:BitmapData = new BitmapData(chessBoard.width,chessBoard.height);
var encoder:PNGEncoder = new PNGEncoder();
var data:ByteArray = encoder.encode(bitmapData);
I wonder how do I send the image to the server via httpService? Is there a way. Also is data = image file?
Here is a post on someone who has done this exact thing in AS3:
Dynamically Create an Image in Flash and Save it to the Desktop or Server
It is possible, and although I have never done it, this may be useful to you: http://www.flash-db.com/Tutorials/snapshot/