How to automatically play a short video clip on HTML5 canvas? - javascript

I have made a simple game using canvas, but I can't seem to figure out how to get a quick 3 second intro to play just once within my canvas (before canvas is drawn).
This is what I've got for my html:
<video id="intro" src="https://www.youtube.com/watch?v=tqErAlg-QJU" controls="false" autoplay></video>
<canvas id="myCanvas" width="800" height="400"
style="border:1px solid #000000;">
</canvas>

Here you have an example, just handle the play event so when the video autoplay run, the canvas draw a copy of that video.
document.addEventListener('DOMContentLoaded', function(){
var v = document.getElementById('intro');
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
v.addEventListener('play', function(){
draw(this,context,canvas.width,canvas.height);
},false);
},false);
function draw(v,c,w,h) {
if(v.paused || v.ended) return false;
c.drawImage(v,0,0,w,h);
setTimeout(draw,20,v,c,w,h);
}
#intro{
position:absolute;
visibility:hidden
}
<video id="intro" height="200" src="http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4" controls="false" autoplay></video>
<canvas id="myCanvas"
style="border:1px solid #000000;">
</canvas>

My proposal, using your youtube video is:
use youtube api
refer only to your videoId
toggle visibility
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '400',
width: '800',
videoId: 'tqErAlg-QJU',
events: {
'onReady': function (e) {
e.target.playVideo();
// pause video after 3 seconds
setTimeout(function() {
player.pauseVideo();
}, 3 * 1000);
},
'onStateChange': function (e) {
// if video ended (0) or paused (2)....
if (e.data == 0 || e.data == 2) {
// remove the player
player.destroy();
// toggle the visibility
$('#myCanvas, #player').toggle();
}
}
}
});
}
$(function () {
$('#myCanvas').hide();
});
<script src="https://code.jquery.com/jquery-1.12.1.min.js"></script>
<script src="https://www.youtube.com/iframe_api"></script>
<div id="player"></div>
<canvas id="myCanvas" width="800" height="400" style="border:1px solid #000000;"></canvas>

Related

How to load image To HTML Canvas

I am working on the below demo. Why am I not able to load the image into HTML canvas?
I am getting this error:
{
"message": "Uncaught TypeError: c.getContext is not a function",
"filename": "https://stacksnippets.net/js",
"lineno": 24,
"colno": 17
}
$(document).ready(function() {
var expose = function() {
var c = $("#myCanvas");
var ctx = c.getContext("2d");
var img = $("#scream");
ctx.drawImage(img, 10, 10);
};
setTimeout(expose, 2000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Image to use:</p>
<img id="scream" width="220" height="277" src="https://www.w3schools.com/tags/img_the_scream.jpg" alt="The Scream">
<p>Canvas:</p>
<canvas id="myCanvas" width="240" height="297" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
Well because JQuery returns an object that contains the DOM elements, and using #myCanvas doesn't actually select the DOM element
$(document).ready(function() {
var expose = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("scream");
ctx.drawImage(img, 10, 10);
};
setTimeout(expose, 2000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Image to use:</p>
<img id="scream" width="220" height="277" src="https://www.w3schools.com/tags/img_the_scream.jpg" alt="The Scream">
<p>Canvas:</p>
<canvas id="myCanvas" width="240" height="297" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
You need to make two changes:
var ctx = c[0].getContext("2d");
var img = document.getElementById('scream');
For the first:
jQuery equivalent of getting the context of a Canvas
And for the second, is expected you to pass an CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas, jQuery returns a jQuery object not a DOM element.
It should be like this
$(document).ready(function() {
var expose = function() {
var c = $("#myCanvas");
var ctx = c[0].getContext("2d");
var img = $("#scream");
ctx.drawImage(img, 10, 10);
};
setTimeout(expose, 2000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Image to use:</p>
<img id="scream" width="220" height="277" src="https://www.w3schools.com/tags/img_the_scream.jpg" alt="The Scream">
<p>Canvas:</p>
<canvas id="myCanvas" width="240" height="297" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

Multiple canvases - trying to send parameters to function via EventListener

This program already works with onclick, but I know that using onclick on a html code is bad practice, and I'd be better off using Event listeners.
I'm facing issues with sending parameters to my function though. I understand it's much easier to do that when it's just one canvas, with something like
document.getElementById("canvas1").addEventListener("click", func, false);
and then using this in the function, but what if there are more than one?
This is what I did before:
<canvas id="canvas1" width="100" height="100" onclick="boxClick(1)">
</canvas>
<canvas id="canvas2" width="100" height="100" onclick="boxClick(2)">
</canvas>
<canvas id="canvas3" width="100" height="100" onclick="boxClick(3)">
</canvas>
There are 9 canvases like this (it's a tic tac toe game).
Then,
function boxClick(num) {
numId = "canvas" + num;
box = document.getElementById(numId);
ctx = box.getContext("2d");
}
Then I used that ctx to draw my shapes on the clicked canvas.
How do I achieve the same with an event Listener.
Thanks!!
In pure js you can implement is like this, getting the elements by class and then binding listener to all all on click event.currentTarget gives you the clicked element
function boxClick(event) {
console.log(event.currentTarget)
ctx = event.currentTarget.getContext("2d");
console.log(ctx);
}
var classname = document.getElementsByClassName("box");
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('click', boxClick, false);
}
.box{
border:1px solid #ff0000;
}
<canvas id="canvas1" width="100" height="100" class="box">
</canvas>
<canvas id="canvas2" width="100" height="100" class="box">
</canvas>
<canvas id="canvas3" width="100" height="100" class="box">
</canvas>
You need to pass 'this' and then you can refer that element
function boxClick(element){
alert(element.id)
}
canvas{
width: 100px;
height: 100px;
background-color:red;
}
<canvas id="canvas1" onClick="boxClick(this)"></canvas>
<canvas id="canvas2" onClick="boxClick(this)"></canvas>
<canvas id="canvas3" onClick="boxClick(this)"></canvas>
Or you can bind event listener to all the canvas like this.
var canvas = document.getElementsByTagName('canvas')
for (var i = 0; i < canvas.length; i++) {
canvas[i].addEventListener("click",box);
}
function box(){
alert(this.id)
}
canvas{
width: 100px;
height: 100px;
background-color:red;
}
<canvas id="canvas1" ></canvas>
<canvas id="canvas2" ></canvas>
<canvas id="canvas3" ></canvas>

Is there a way to use the Youtube API using less code?

I did some tests to find a way to play an embed video from youtube and it stops others videos of the page that is playing in the moment.
I reached the following code:
<!DOCTYPE html>
<html>
<head>
<title>Youtube players test</title>
<style type="text/css" >
li {
list-style: none;
margin-bottom: 10px;
}
</style>
<script type="text/javascript" src="jquery-2.1.3.min.js"></script>
</head>
<body>
<ul id="videos">
<li>Video1</li>
<iframe id="player1" class="video" type="text/html" width="400" height="225" src="http://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1"
frameborder="0" allowfullscreen></iframe>
<li>Video2</li>
<iframe id="player2" class="video" width="400" height="225" src="https://www.youtube.com/embed/3TAUnYZpMbA?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
<li>Video3</li>
<iframe id="player3" class="video" width="400" height="225" src="https://www.youtube.com/embed/9U38GB2qVWA?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
</div>
<script type="text/javascript">
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var primteste = document.getElementsByTagName('script')[0];
primteste.parentNode.insertBefore(tag, primteste);
var players = new Array();
function onYouTubeIframeAPIReady() {
players[0] = new YT.Player('player1', {
events: {
'onStateChange': onPlayer1StateChange
}
});
players[1] = new YT.Player('player2', {
events: {
'onStateChange': onPlayer2StateChange
}
});
players[2] = new YT.Player('player3', {
events: {
'onStateChange': onPlayer3StateChange
}
});
}
function onPlayer1StateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
var x = 0;
for (i=0;i<3;i++) {
if (i == x) {
i++;
}
players[i].stopVideo();
}
}
}
function onPlayer2StateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
var x = 1;
for (i=0;i<3;i++) {
if (i == x) {
i++;
}
players[i].stopVideo();
}
}
}
function onPlayer3StateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
var x = 2;
for (i=0;i<3;i++) {
if (i == x) {
i++;
}
players[i].stopVideo();
}
}
}
</script>
</body>
</html>
The code above satisfies my initial intention of play/stop videos and here goes my question. I did with only three videos and It's not too great for three, but I have a page that has more than 20 embed videos and with the way I coded I will have to code the same for each one of the videos what it will take lines and lines. Because I thought a lot and I couldn't figure out a simpler way to do it.
Could someone gives me a light about this situation? Is there someone that sees a better way to do the same?
Thanks
Call the same onPlayerStateChange callback for all your players and stop all but the current player. To check if this is the current player, use event.target != players[i].
Here's your example with a few tweaks.
<!DOCTYPE html>
<html>
<head>
<title>Youtube players test</title>
<style type="text/css">
li {
list-style: none;
margin-bottom: 10px;
}
</style>
<script type="text/javascript" src="jquery-2.1.3.min.js"></script>
</head>
<body>
<ul id="videos">
<li>
<h4>Video 1</h4>
<iframe id="player1" class="video" width="400" height="225" src="http://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
</li>
<li>
<h4>Video 2</h4>
<iframe id="player2" class="video" width="400" height="225" src="https://www.youtube.com/embed/3TAUnYZpMbA?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
</li>
<li>
<h4>Video 3</h4>
<iframe id="player3" class="video" width="400" height="225" src="https://www.youtube.com/embed/9U38GB2qVWA?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
</li>
</ul>
<script type="text/javascript">
// Insert youtube API
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var primteste = document.getElementsByTagName('script')[0];
primteste.parentNode.insertBefore(tag, primteste);
var players = [];
function onYouTubeIframeAPIReady() {
// Populate 'players' with all the youtube iframes
var videoIframes = document.getElementsByClassName('video');
for(var i=0; i<videoIframes.length; i++){
players.push(
new YT.Player(videoIframes[i], { // here we can pass an iframe element or an id
events: {
'onStateChange': onPlayerStateChange
}
})
);
}
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
for (i=0; i<players.length; i++) {
// Stop all but the current player (the one that triggered the event)
if(players[i] != event.target){
players[i].stopVideo();
}
}
}
}
</script>
</body>
</html>
This code will automatically add new players to the players array as long as the iframe holding the player has the class .video.
You don't need to have an id for each iframe but I left them there just in case you're using them somewhere else.
function _getOnPlayerChangeHandler(playerIndex) {
return function (event) {
if (event.data === YT.PlayerState.PLAYING) {
var i;
for (i = 0; i < players.length; i++) {
if (i !== playerIndex) {
players[i].stopVideo();
}
}
}
};
}
function _createPlayer (selector, playerIndex) {
return new YT.Player(selector, {
onStateChange: _getOnPlayerChangeHandler(playerIndex)
});
}
players[0] = _createPlayer('player1', 0);
players[1] = _createPlayer('player2', 1);
players[2] = _createPlayer('player3', 2);
If you have more information about the player in the event object, you may not even have to create the handler from a factory like the one I've made.

How to increase size of canvas image in html

I have taken 2 canvas one is the source and another is ther target. When I mouse over the image in canvas it should get enlarged in canvas2
How can I increase the height of image in canvas2 i want magnify effect .Below is the code.
Thanks
Husein
<html>
<body>
<input type="button" onclick="h()">
<p>Image to use:</p>
<p>Canvas:</p>
<canvas id="myCanvas" onmousemove="h()" width="250" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<p>Canvas2:</p>
<canvas id="myCanvas2" width="100" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var image = new Image();
image.crossOrigin="anonymous";
image.src="img_the_scream.jpg"
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=image ;
ctx.drawImage(img,0,0);
var d=document.getElementById("myCanvas2");
var ctx1=d.getContext("2d");
function h()
{
var img=ctx.getImageData(event.clientX-80,event.clientY-100,100,100);
ctx1.clearRect ( 0 , 0 , d.width , d.height );
ctx1.putImageData(img,0,0);
//d.width="200";
//d.height="200";
}
</script>
</body>
</html>
All you have to do is use toDataUrl and drawImage instead of getImageData and putImageData. Example:
function h() {
var img=new Image();
img.src = ctx.toDataUrl();
img.onload = function() {
ctx1.drawImage(img,0,0,c.width*horizontalMagnification,c.height*verticalMagnification);
};
}
Alternatively, you could just call ctx1.scale(horizontalMagnification,verticalMagnification); before you use putImageData.

How do I get a video to be play on the canvas under my canvas animation?

How do I get a video to be play on the canvas under my canvas animation?
For instance this clip.
So this animation moves along the bottom of the video.
Code:
<html>
<head>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.3.js'></script>
<script type="text/javascript">
var context;
var text = "";
var textDirection ="";
$(function()
{
context = document.getElementById("cvs").getContext("2d");
setInterval("animate()", 360);
textDirection ="right";
textXpos = 5;
text = "This is my video..";
});
function animate() {
// Clear screen
context.clearRect(0, 0, 500, 500);
context.globalAlpha = 1;
context.fillStyle = '#fff';
context.fillRect(0, 0, 500, 500);
var metrics = context.measureText(text);
var textWidth = metrics.width;
if (textDirection == "right") {
textXpos += 10;
if (textXpos > 500 - textWidth) {
textDirection = "left";
}
}
else {
textXpos -= 10;
if (textXpos < 10) {
textDirection = "right";
}
}
context.font = '20px _sans';
context.fillStyle = 'black';
context.textBaseline = 'top';
context.fillText ( text, textXpos, 180);
}
</script>
</head>
<body>
<div id="page">
<canvas id="cvs" width="500" height="500">
Your browser does not support the HTML 5 Canvas.
</canvas>
</div>
</body>
</html>
I don't think you need to play the video in the canvas. Just create a video element in your HTML and use CSS to place your canvas element over it.
HTML:
<div id="page">
<video id="video" autoplay loop>
<source id='mp4'
src="http://media.w3.org/2010/05/sintel/trailer.mp4"
type='video/mp4'>
<source id='webm'
src="http://media.w3.org/2010/05/sintel/trailer.webm"
type='video/webm'>
<source id='ogv'
src="http://media.w3.org/2010/05/sintel/trailer.ogv"
type='video/ogg'>
<p>Your user agent does not support the HTML5 Video element.</p>
</video>
<canvas id="cvs" width="500" height="500">
Your browser does not support the HTML 5 Canvas.
</canvas>
</div>
CSS:
#cvs {
position: absolute;
top: 0px;
left: 0px;
}
Fiddle.

Categories