Video width & height is not refreshing in ES6 class - ecmascript-6

I'm trying to set dimensions for canvas, based on my video dimensions. For some reason my video height and width is always 0. I assume it is something to do with my class which is not updating the details.
Webcam.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Get User Media Code Along!</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="photobooth">
<canvas class="photo"></canvas>
<video class="player"></video>
</div>
<script src="./webcam.js"></script>
</body>
</html>
webcam.js
class Webcam {
constructor(){
this.video = document.querySelector('.player');
this.canvas = document.querySelector('.photo');
this.canvasContext = this.canvas.getContext("2d");
this.strip = document.querySelector('.strip');
this.snap = document.querySelector('.snap');
}
captureVideo(){
navigator.mediaDevices.getUserMedia({video: true, audio: false})
.then(browserVideoStream => {
console.log(browserVideoStream);
this.video.src = window.URL.createObjectURL(browserVideoStream);
this.video.play();
}).then(video => {
this.videoToCanvas();
})
.catch(err => alert(err));
}
videoToCanvas(){
let videoWidth = this.video.videoWidth;
let videoheight = this.video.videoHeight;
console.log(`${videoWidth} - ${videoheight}`); // THIS IS ALWAYS 0,0
}
}
video = new Webcam();
video.captureVideo();
video.videoToCanvas();

.play() can take time, so you'll need to change
this.video.play();
to
return this.video.play();
so that the following .then handler waits for the video starts playing before calling .videoToCanvas().

Related

Clear canvas drawpad jquery

I'm using the drawing pad (pen tool) plugin of Jquery to draw with different colors and having an image in the canvas as background. My purpose is to have a button to clear the drawing over the canvas. The way I try to do it remove the background image along with the drawing. How can I keep the background and remove the drawing on clicking the clear button ?
My fiddle : https://jsfiddle.net/ub3s9go7/
<script>
$(document).ready(function() {
// set background
var urlBackground = 'https://picsum.photos/id/100/500/400';
var imageBackground = new Image();
imageBackground.src = urlBackground;
imageBackground.setAttribute('crossorigin', 'anonymous');
$("#target").drawpad();
var contextCanvas = $("#target canvas").get(0).getContext('2d');
imageBackground.onload = function(){
contextCanvas.drawImage(imageBackground, 0, 0);
}
// Need to clear only the drawing not the background image
$("#clearDrawing").click(function() {
contextCanvas.clearRect(0, 0, 750, 423);
});
});
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.css" />
<style>
body {background-color:rgb(248, 255, 227)}
#target {
width:500px;
height:400px;
}
</style>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.js"></script>
</head>
<body>
<button id="clearDrawing">Clear Drawing</button>
<div id="target" class="drawpad-dashed"></div>
</body>
</html>
This answer is an improvisation on my previous answer at https://stackoverflow.com/a/67155647/3706717
So we have new requirement: delete/clear previous drawings
There are some possible approach here:
#sinisake in comment suggested to reload the background so that we have fresh canvas with only the background intact (but for some reason, white doodle make the background gone)
the library must have "delete" or "erase" doodle feature (which it didn't have)
save each changes of the drawing when user click "save", so that user can "undo" to previous version of the drawing (like git's git commit and git reset command), I'll be using this approach in my answer
Ideally, you should use server-side language and persistent storage (e.g.: database) to store user's doodling history. But in this case, to simulate such thing I'll be using javascript's localStorage API https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
So every time I'm calling localStorage API, just assume that I'm calling some ajax to some endpoint.
Fiddle: https://jsfiddle.net/0da572jy/3/
Here is stack fiddle (modified because browser didn't allow stack fiddle to use localStorage)
// polyfill for localStorage API
var localStorage1 = {
items: {},
removeItem: function(key) {
window.localStorage1.items[key] = null;
},
getItem: function(key) {
return window.localStorage1.items[key];
},
setItem: function(key, val) {
return window.localStorage1.items[key] = val;
},
}
//window.localStorage = localStorage1;
window.localStorage1 = localStorage1;
$(document).ready(function() {
$("#save").click(function() {
// I already explained the #save logic in https://stackoverflow.com/a/67155647/3706717
//console.log("save");
var base64Image = $("#target canvas").get(0).toDataURL();
//console.log(base64Image);
$("#outputBase64FormInput").val(base64Image);
$("#outputBase64").html(base64Image);
// load/read saved states/histories
var savedImageJson = window.localStorage1.getItem("savedImage");
//console.log(savedImageJson);
// if the history is undefined, create empty array
if(savedImageJson == null || typeof savedImageJson == "undefined") savedImageJson = "[]";
// parse the history
var savedImageArr = JSON.parse(savedImageJson);
// add current state as a new item to history
savedImageArr.push(base64Image);
// save the modified (added history)
window.localStorage1.setItem("savedImage", JSON.stringify(savedImageArr));
$("#numOfSavedHistory").html( savedImageArr.length );
});
// clear button just clears the localStorage (or any kind of API you use for persistent storage
$("#clear").click(function() {
//console.log("save");
window.localStorage1.removeItem("savedImage");
$("#numOfSavedHistory").html( 0 );
});
// undo last change (rollback to last state when you clicked save)
$("#undo").click(function() {
// clear canvas (to prevent white ink bug that also clears the background)
canvas.width = canvas.width;
//console.log("undo");
// load/read saved states/histories
var savedImageJson = window.localStorage1.getItem("savedImage");
//console.log(savedImageJson);
// if the history is undefined, create empty array
if(savedImageJson == null || typeof savedImageJson == "undefined") savedImageJson = "[]";
// parse the history
var savedImageArr = JSON.parse(savedImageJson);
// delete last item in history
savedImageArr.pop();
// save the modified (pop'ed history)
window.localStorage1.setItem("savedImage", JSON.stringify(savedImageArr));
// draw old picture on canvas
var imageOld = new Image();
imageOld.src = savedImageArr[savedImageArr.length-1];
imageOld.onload = function() {
contextCanvas.drawImage(imageOld, 0, 0);
};
$("#numOfSavedHistory").html( savedImageArr.length );
});
// set background
var urlBackground = 'https://picsum.photos/id/100/500/400';
var imageBackground = new Image();
imageBackground.src = urlBackground;
//imageBackground.crossorigin = "anonymous";
imageBackground.setAttribute('crossorigin', 'anonymous');
$("#target").drawpad();
var canvas = $("#target canvas").get(0);
var contextCanvas = canvas.getContext('2d');
imageBackground.onload = function(){
contextCanvas.drawImage(imageBackground, 0, 0);
$("#clear").trigger("click"); // clear previous drawings when page refreshed
$("#save").trigger("click"); // save the first image (background only)
}
});
body {background-color:rgb(248, 255, 227)}
#target {
width:500px;
height:400px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.css" />
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.js"></script>
</head>
<body>
<button id="undo">Undo</button>
<button id="save">Save</button>
<button id="clear">Clear Saved Picture</button>
<span id="numOfSavedHistory">0</span>
<div id="target" class="drawpad-dashed"></div>
<div id="outputBase64"></div>
</body>
</html>

Play array of videos in html5

I've looked at web sources to find out how to play an array of videos in html5. Using the sources, I have only managed to get the first video to show up (no autoplay) and even when I clicked "play" button manually, the second video does not auto-play/show up after the first one ended. Any idea?
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Video.aspx.cs" Inherits="Web.Video.VideoDashboard" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>HELLO WORLD</title>
</head>
<body>
<video controls="controls" id="myVideo">
</video>
<script>
var videoSource = new Array();
videoSource[0] = "/MP4Files/Video1.mp4";
videoSource[1] = "/MP4Files/Video2.mp4";
var i = 0; // define i
var videoCount = videoSource.length;
function videoPlay(videoNum) {
document.getElementById("myVideo").setAttribute("src", videoSource[videoNum]);
document.getElementById("myVideo").load();
document.getElementById("myVideo").play();
}
document.getElementById('myVideo').addEventListener('ended', myHandler, false);
videoPlay(i); // play the video
function myHandler() {
i++;
if (i == (videoCount - 1)) {
i = 0;
videoPlay(i);
} else {
videoPlay(i);
}
}
</script>
</body>
</html>

How to pass attributes to help implement a custom element?

When we use web component techniques to create a custom element, sometimes the implementation of a custom element involves the use of attributes present on the resulting element in the main document. As in the following example:
main doc:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="import" href="web-components/my-portrait.html">
</head>
<body>
<my-portrait src="images/pic1.jpg" />
</body>
</html>
my-portrait.html:
<template id="my-portrait">
<img src="" alt="portait">
</template>
<script>
(function() {
var importDoc = document.currentScript.ownerDocument;
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = importDoc.querySelector("#my-portrait");
var clone = document.importNode(t.content, true);
var img = clone.querySelector("img");
img.src = this.getAttribute("src");
this.createShadowRoot().appendChild(clone);
}
}
});
document.registerElement("my-portrait", {prototype: proto});
})();
</script>
In the createdCallback, we use this.getAttribute("src") to get the src attribute defined on the portrait element.
However, this way of obtaining the attribute can be only used when the element is instantiated by element tag declaration. But what if the element is created using JavaScript: document.createElement("my-portrait")? When this statement is done being executed, the createdCallback has already been called and this.getAttribute("src") will return null since the element has no src attribute instantly when it is created.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="import" href="web-components/my-portrait.html">
</head>
<body>
<!--<my-portrait src="images/pic1.jpg" />-->
<script>
var myPortrait = document.createElement("my-portrait");
myPortrait.src = "images/pic2.jpg"; // too late
document.getElementsByTagName("body")[0].appendChild(myPortrait);
</script>
</body>
</html>
So how do we pass attribute to createdCallback when we instantiate a custom element using JavaScript? If there were a beforeAttach callback, we can set attributes there, but there are no such callback.
You may implement the lifecycle callback called attributeChangedCallback:
my-portrait.html:
proto.attributeChangedCallback = function ( name, old, value )
{
if ( name == "src" )
this.querySelector( "img" ).src = value
//...
}
name is the name of the modified (or added) attribute,
old is the old value of the attribute, or undefined if it was just created,
value is the new value of the attribute (of type string).
For the callback to be called, use the setAttribute method against your custom element.
main doc:
<script>
var myPortrait = document.createElement( "my-portrait" )
myPortrait.setAttribute( "src", "images/pic2.jpg" ) // OK
document.body.appendChild( myPortrait )
</script>
example:
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
this.innerHTML = document.querySelector("template").innerHTML
var path = this.getAttribute("src")
if (path)
this.load(path)
}
},
attributeChangedCallback: {
value: function(name, old, value) {
if (name == "src")
this.load(value)
}
},
load: {
value: function(path) {
this.querySelector("img").src = path
}
}
})
document.registerElement("image-test", { prototype: proto })
function add() {
var el = document.createElement("image-test")
el.setAttribute("src", "https://placehold.it/100x50")
document.body.appendChild(el)
}
<image-test src="https://placehold.it/100x100">
</image-test>
<template>
<img title="portrait" />
</template>
<button onclick="add()">
add
</button>

HTML5 getUserMedia() media sources

I have created a streaming webcam with html5. At the moment I can take a picture through my web cam, but I would like to know if it is possible to choose media stream device from the list, e.g. I have two web cams I want to choose the webcam to activate. How can I do that with html5 getUserMedia() call?
Thanks!
You can get the list of web camera
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Video Camera List</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js" ></script>
<style type="text/css" media="screen">
video {
border:1px solid gray;
}
</style>
</head>
<body>
<script>
if (!MediaStreamTrack) document.body.innerHTML = '<h1>Incompatible Browser Detected. Try <strong style="color:red;">Chrome Canary</strong> instead.</h1>';
var videoSources = [];
MediaStreamTrack.getSources(function(media_sources) {
console.log(media_sources);
// alert('media_sources : '+media_sources);
media_sources.forEach(function(media_source){
if (media_source.kind === 'video') {
videoSources.push(media_source);
}
});
getMediaSource(videoSources);
});
var get_and_show_media = function(id) {
var constraints = {};
constraints.video = {
optional: [{ sourceId: id}]
};
navigator.webkitGetUserMedia(constraints, function(stream) {
console.log('webkitGetUserMedia');
console.log(constraints);
console.log(stream);
var mediaElement = document.createElement('video');
mediaElement.src = window.URL.createObjectURL(stream);
document.body.appendChild(mediaElement);
mediaElement.controls = true;
mediaElement.play();
}, function (e)
{
// alert('Hii');
document.body.appendChild(document.createElement('hr'));
var strong = document.createElement('strong');
strong.innerHTML = JSON.stringify(e);
alert('strong.innerHTML : '+strong.innerHTML);
document.body.appendChild(strong);
});
};
var getMediaSource = function(media) {
console.log(media);
media.forEach(function(media_source) {
if (!media_source) return;
if (media_source.kind === 'video')
{
// add buttons for each media item
var button = $('<input/>', {id: media_source.id, value:media_source.id, type:'submit'});
$("body").append(button);
// show video on click
$(document).on("click", "#"+media_source.id, function(e){
console.log(e);
console.log(media_source.id);
get_and_show_media(media_source.id);
});
}
});
}
</script>
</body>
</html>
In the latest Chrome Canary (30.0.1587.2) it looks like you can enable device enumeration in chrome://flags (looks like it might already be enabled) and use the MediaStreamTrack.getSources API to select the camera.
See this WebRTC bug and mailing list post for more details.

I am trying to embed JW player in my website. I get the error 'Video not found or access denied' when I try to play the video

Here is my code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>SWFObject dynamic embed - step 1</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="swfobject/swfobject.js"></script>
<script type="text/javascript" src="jwplayer/jwplayer.js"></script>
</head>
<body>
<div id="flashContent">
<p>Alternative content</p>
</div>
<script type="text/javascript">
var flashvars = { file:'/video.flv'};
var params = { allowfullscreen:'true', allowscriptaccess:'always' };
var attributes = { id:'player1', name:'player1' };
swfobject.embedSWF('player1.swf','flashContent','480','270','9.0.115','false', flashvars, params, attributes, flashLoaded);
function flashLoaded(e) {
// e.ref is a reference to the Flash object. We'll pass it to jwplayer() so the API knows where the player is.
// Add event listeners
jwplayer(e.ref).onReady(function() { alert('Player is ready'); e.ref.play();e.ref.seek(10); });
jwplayer(e.ref).onPlay(function() { e.ref.play();});
jwplayer(e.ref).onStop(function() { e.ref.stop();});
jwplayer(e.ref).onVolume(function() { e.ref.seek(100);});
// Interact with the player
}
</script>
</body>
</html>
'video.flv' is in the same directory as the html file
try to put full path
for example:
var flashvars = { file:'http://yourwebsite.com/video.flv'};