No loadedmetadata callback when setting video source - javascript

I need the video dimensions of a video that is uploaded via an input tag. But when I set the uploaded video as source of a video tag, the loadedmetadata event doesn't get called.
In this method I set the video and the listener:
function getVideoDimensionsOf(objUrl){
return new Promise(function(resolve){
let video = document.createElement('video');
//THIS GETS CALLED AS EXPECTED
video.addEventListener( "loadedmetadata", function () {
//THIS GETS NEVER CALLED
let height = this.videoHeight;
let width = this.videoWidth;
console.log(height,width)
}, false );
video.src = objUrl;
});
}
In this method, I set up the callback for the video upload:
function localFileVideoPlayer() {
var URL = window.URL || window.webkitURL
var uploadSelectedFile = function (event) {
var file = this.files[0]
var type = file.type
var fileURL = URL.createObjectURL(file)
var fileReader = new FileReader();
fileReader.onload = function() {
var videofile = this.result;
//do something here with video data
};
fileReader.readAsArrayBuffer(file);
getVideoDimensionsOf(window.URL.createObjectURL(file))//-->>HERE I CALL THE FUNCTION THAT SHOULD SET THE VIDEO SOURCE
}
var inputNode = document.getElementById("videofile")
inputNode.addEventListener('change', uploadSelectedFile, false)
}
And this is the html upload field:
<div>
Upload Video:
<input id="videofile" type="file" accept="video/*"/>
</div>
I checked that the getVideoDimensionsOf method gets called, but why is the loadedmetadata listener not getting the callback?

Because nothing forces the browser to preload your video element.
For all it knows, you will never play this video, so it makes sense it won't preload its content.
You could try to force this preloading by calling its play() method.
function getVideoDimensionsOf(objUrl) {
return new Promise(function(resolve) {
let video = document.createElement('video');
video.muted = true; // bypass Chrome autoplay policies
video.addEventListener("loadedmetadata", function() {
let height = this.videoHeight;
let width = this.videoWidth;
video.pause();
resolve( { width, height } );
}, false);
video.src = objUrl;
video.play();
});
}
inp.onchange = e => {
const url = URL.createObjectURL(inp.files[0]);
getVideoDimensionsOf(url)
.then(obj => {
URL.revokeObjectURL(url);
console.log(obj);
});
}
<input type="file" id="inp" accept="video/*,.mp4">

localFileVideoPlayer();
function getVideoDimensionsOf(objUrl) {
return new Promise(function(resolve) {
let video = document.createElement("video");
{
// if you need to append the video to the document
video.controls = true;
document.body.appendChild(video);
}
//THIS GETS CALLED AS EXPECTED
video.addEventListener(
"loadedmetadata",
function() {
//THIS GETS NEVER CALLED
let height = this.videoHeight;
let width = this.videoWidth;
console.log(height, width);
},
false
);
video.src = objUrl;
});
}
function localFileVideoPlayer() {
var URL = window.URL || window.webkitURL;
var uploadSelectedFile = function(event) {
var file = this.files[0];
var type = file.type;
var fileURL = URL.createObjectURL(file);
var fileReader = new FileReader();
fileReader.onload = function() {
var videofile = this.result;
//do something here with video data
};
fileReader.readAsArrayBuffer(file);
getVideoDimensionsOf(window.URL.createObjectURL(file)); //-->>HERE I CALL THE FUNCTION THAT SHOULD SET THE VIDEO SOURCE
};
var inputNode = document.getElementById("videofile");
inputNode.addEventListener("change", uploadSelectedFile, false);
}
<div>
Upload Video:
<input id="videofile" type="file" accept="video/*" />
</div>
In your code, you need to initialize the input change event using the localFileVideoPlayer method, so I first executed this method. Then if you need to display this video in the document, you need to append a video element to the document, so there is appendChild method in getVideoDimensionsOf

Related

HTMLImageElement onclick

I am trying to add an onclick event that calls a function selectMain(name). When I run my project it doesn't seem to generate the onclick attribute from the image.
function previewFiles() {
var preview = document.querySelector('#preview');
var files = document.querySelector('input[type=file]').files;
function readAndPreview(file) {
if (/\.(jpe?g|png)$/i.test(file.name)) {
var reader = new FileReader();
reader.addEventListener("load", function() {
var image = new Image();
image.height = 100;
image.title = file.name;
image.src = this.result;
image.onclick = selectMain(file.name);
preview.appendChild(image);
}, false);
reader.readAsDataURL(file);
}
}
if (files) {
[].forEach.call(files, readAndPreview);
}
}
function selectMain(name) {
var files = document.querySelector('input[type=file]').files;
Array.from(files).forEach(file => {
if (file.name == name) {
document.getElementById("primaryPhoto").value = file;
}
});
}
Try thisimage.onclick = function(){ selectMain(file.name); };
In addition to what Gagik answered (the early selectMain call is definitiely an issue even if it doesn't fix the whole thing), what is
document.getElementById("primaryPhoto").value = file;
supposed to do? If primaryPhoto is a input[type=file] element, then that won't work due to security limitations
You cannot set the value of a file picker from a script
Source.
(/\.(jpeg?g|png)$/i.test(file.name))
In the existing code, function get invoked on the time of render on dom.
here is the correct way to bind event.
var image = new Image();
image.height = 100;
image.title = file.name;
image.src = this.result;
image.onclick =()=>{selectMain(file.name)};

Cannot get file size after uploading using JavaScript

I need to validate one file field with required width,height and if file has not uploaded using JavaScript but its not happening like this. Here is my code:
<input type="file" name="copImage" id="copImage" class="form-control" value="" onchange="setBackgroundImage(event);">
function setBackgroundImage(e){
var url = URL.createObjectURL(e.target.files[0]);
bg = new Image();
bg.src = url;
bg.onload = function () {
bgLoaded = true;
backImageHeight=this.height;
backImageWidth=this.width;
};
console.log('size bg',backImageHeight,backImageWidth);
}
Here I could not get the file height and width. I also to check the if file has not uploaded.
Pu the log statement inside the onload function. This is because you are trying to access the variable outside its scope, else define those variables outside onload function
bg.onload = function() {
var bgLoaded = true,
backImageHeight = this.height,
backImageWidth = this.width;
console.log('size bg',backImageHeight,backImageWidth);
};
DEMO
suppose i have one button and without selecting file if I am clicking
on the file alert should say to select the file.
Seems you cannot do that with onchange event handler because if file is not loaded. nothing has changed and so function wont fire. In that case you can create a variable & update its state on file upload. On clicking of the button check the variable state
var isFileLoaded = false;
function setBackgroundImage(fileValue) {
var url = URL.createObjectURL(fileValue.files[0]);
bg = new Image();
if (fileValue.value !== '') {
bg.src = url;
bg.onload = function() {
bgLoaded = true;
isFileLoaded = true;
backImageHeight = this.height;
backImageWidth = this.width;
console.log('size bg', backImageHeight, backImageWidth);
};
}
}
function buttonClick() {
if (isFileLoaded) {
} else {
alert('No file selected')
}
}
DEMO 2
Hello You just need to log your height and width inside bg.onload function.these are outside of the scope of variables.thats why you not getting the height and width like this
function setBackgroundImage(e){
var url = URL.createObjectURL(e.target.files[0]);
bg = new Image();
bg.src = url;
bg.onload = function () {
bgLoaded = true;
backImageHeight=this.height;
backImageWidth=this.width;
console.log('size bg',backImageHeight,backImageWidth);
};
}
Everything is fine in your code, you need to include console.log() within bg.onload block only like this .
function setBackgroundImage(e)
{
var url = URL.createObjectURL(e.target.files[0]);
bg = new Image();
bg.src = url;
bg.onload = function () {
bgLoaded = true;
backImageHeight=this.height;
backImageWidth=this.width;
console.log('size bg',backImageHeight,backImageWidth);
};
}
function isFileSelected()
{
return document.getElementById('copImage').files.length > 0;
}
You can use isFileSelected() function to know whether file is selected or not .

Assign the value of MediaDevices.enumerateDevices() into global variable in JavaScript

I have a question about the sequence of JavaScript. Let me show you my code first:
Here is my HTML:
<video id="video" width="320" height="320" autoplay></video><br>
<button id="snap">Snap Photo</button><br>
<canvas id="canvas" width="320" height="320"></canvas>
<p id="pngHolder"></p>
And here is my JavaScript:
<script>
var Id;
//List cameras and microphones.
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
console.log("enumerateDevices() not supported.");
}
navigator.mediaDevices.enumerateDevices()
.then(function (devices) {
devices.forEach(function (device) {
if (device.kind == "videoinput" && device.label.indexOf('back') >= 0) {
Id = device.deviceId;
alert("ID 1 : " + Id);
}
});
})
.catch(function (err) {
console.log(err.name + ": " + err.message);
});
// Put event listeners into place
window.addEventListener("DOMContentLoaded", function () {
// Grab elements, create settings, etc.
alert("ID 2 : "+ Id);
var canvas = document.getElementById("canvas"),
videoObj = {
video: {
optional: [{ deviceId: Id }]
}
},
context = canvas.getContext("2d"),
video = document.getElementById("video"),
errBack = function (error) {
console.log("Video capture error: ", error.code);
};
// Trigger photo take
document.getElementById("snap").addEventListener("click", function () {
context.drawImage(video, 0, 0, 640, 480);
// Get the image
var image = convertCanvasToImage(canvas);
// Actions
document.getElementById("pngHolder").appendChild(image);
// Converts canvas to an image
function convertCanvasToImage(canvas) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
return image;
}
});
//alert("ID 2 : " + Id);
// Put video listeners into place
if (navigator.getUserMedia) { // Standard
navigator.getUserMedia(videoObj, function (stream) {
video.src = stream;
video.play();
}, errBack);
} else if (navigator.webkitGetUserMedia) { // WebKit-prefixed
navigator.webkitGetUserMedia(videoObj, function (stream) {
video.src = window.webkitURL.createObjectURL(stream);
video.play();
}, errBack);
} else if (navigator.mozGetUserMedia) { // Firefox-prefixed
navigator.mozGetUserMedia(videoObj, function (stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
}, errBack);
}
}, false);
I want to insert the value of device.deviceId into variable Id that I define on the first of my JavaScript row. It is still a success (it is shown by the alert("ID 1 : " + Id);). But when I try to put it into optional: [{ deviceId: Id }], the Id doesn't have any value.
And also, when I try to run it with browser, I have found that the alert("ID 2 : " + Id); is shown first instead of alert("ID 1 : " + Id);. In fact, I have already put the alert("ID 1 : " + Id); first. I think that's why the variable is still empty.
My question is how can I insert the device.deviceId value to optional: [{ deviceId: Id }] ?
navigator.mediaDevices.enumerateDevices and DOMContentLoaded are racing, and the latter is winning, so you're using Id before it's set.
To solve this use a temporary haveId promise:
var haveId = navigator.mediaDevices.enumerateDevices()
.then(devices => devices.find(d => d.kind == "videoinput" &&
d.label.indexOf("back") >= 0));
// Put event listeners into place
window.addEventListener("DOMContentLoaded", function () {
haveId.then(id => {
// Grab elements, create settings, etc.
alert("ID 2 : "+ id);
var canvas = document.getElementById("canvas"),
videoObj = { video: { deviceId: id } }, // <-- adapter.js constraints
Promise-chains create dependencies, and this way the getUserMedia code wont proceed until both things have happened.
The second problem is you're mixing new and outdated Chrome-specific constraints. Either use adapter.js until Chrome catches up, or in a pinch, use the Chrome-only sourceId (but that wont work in any other browser).
navigator.mediaDevices.enumerateDevices() is asynchronous. It returns a promise (think callback, but fancier).
You should trigger your call to getUserMedia from there or wait for both DOMContentLoaded and enumerateDevices and then execute getUserMedia.

Onload() handler not responding in IE

I'm creating a canvas and using drawImage() to draw an inline svg. Everything works okay but I'm stuck because of the below problem...
My problem is that the onload handler not responding in IE?? Rhis works in FF and chhrome. How do I fix it to work in IE 9 upwards?
img2.onload = function() {
console.log("load");
}
jsFiddle
function createme() {
var test = $('<canvas />', { id : 'mycanvs' })
$('#album').append(test);
var svg2 = document.getElementById('sSource').innerHTML,
vms = test[0], //canvas
ctx2 = vms.getContext('2d');
svgToImage(svg2);
function svgToImage(svg2) {
var nurl = "data:image/svg+xml;utf8," + encodeURIComponent(svg2),
img2 = new Image;
alert("just before onload")
img2.onload = function() {
console.log("load"); // does not show
}
img2.src = nurl;
}
}
I don't have an IE VM running at the moment, but according to their docs the handler has to be defined before the object itself:
To ensure that an event handler receives the onload event for these
objects, place the script object that defines the event handler before
the object and use the onload attribute in the object to set the
handler.
I don't see why your code wouldn't work in IE, but this fiddle tweaks it slightly so your handler is defined before you create the image object... give this a try:
function createme() {
var test = $('<canvas />', { id : 'mycanvs' });
var onloadHandler = function() {
console.log("load");
};
$('#album').append(test);
var svg2 = document.getElementById('sSource').innerHTML,
vms = test[0], //canvas
ctx2 = vms.getContext('2d');
function svgToImage(svg2) {
var nurl = "data:image/svg+xml;utf8," + encodeURIComponent(svg2),
img2 = new Image;
img2.onload = onloadHandler
img2.src = nurl;
}
svgToImage(svg2);
}
createme();
https://jsfiddle.net/z769z7af/10/

Display a spinner as img src attribute is set using FileReader()

I'm using the following code to read a image file and set the result as the src for an image attribute,
document.getElementsByClassName("upload-image"),
function(fileElement) {
var previewElement = document.createElement("img");
previewElement.style.display = "block";
fileElement.parentNode.insertBefore(previewElement, fileElement);
var fileReader = new FileReader();
fileReader.onload = function(event) {
previewElement.src = event.target.result;
};
fileElement.addEventListener("change", updateImagePreview, false);
updateImagePreview();
function updateImagePreview() {
var file = fileElement.files[0];
if (file) {
fileReader.readAsDataURL(file);
} else {
var placeholderSrc = fileElement.getAttribute("data-placeholder");
if (placeholderSrc) {
previewElement.src = placeholderSrc;
} else {
previewElement.removeAttribute("src");
}
}
}
}
This works well, however I know that it takes some time for the actual image src to be set and for the image to be displayed.
Is there anyway for me to detect when the image src is set, and loaded, and ready to be displayed?

Categories

Resources