Multiple responsive video.js players - javascript

I'm using this solution, http://daverupert.com/2012/05/making-video-js-fluid-for-rwd/, to make the videojs player fluid. My problem is when I have multiple videos (each with a unique id), I'm not sure how to make this work.
Here is my dev site I have 3 videos on, http://tweedee.e-mediaresources.info/
Here is the code I have for the player (from Dave Rupert's solution above):
<script type="text/javascript">
// Once the video is ready
_V_('#my_video_1').ready(function(){
var myPlayer = this; // Store the video object
var aspectRatio = 9/16; // Make up an aspect ratio
function resizeVideoJS(){
// Get the parent element's actual width
var width = document.getElementById(myPlayer.id).parentElement.offsetWidth;
// Set width to fill parent element, Set height
myPlayer.width(width).height( width * aspectRatio );
}
resizeVideoJS(); // Initialize the function
window.onresize = resizeVideoJS; // Call the function on resize
});
</script>
This code works fine for one video, but how do I do multiple ids??? As you can see in my dev site, I just replicated the script above three times (each with a different id) and that only causes the last video to be fluid.

you overwrite window.onresize() each time, so only the last one is used.
replace
window.onresize = resizeVideoJS
with :
window.addEventListener("resize", resizeVideoJS, false); // all browsers except IE before version 9

The following works. It does involve a bit of repetition, which I think you might be able to avoid if you used something like jQuery's deferred object to wait until the ready event is fired for all of the video players, but it's a lot neater than duplicating the resize method as you're currently doing:
<script type="text/javascript">
var players = ['my_video_1', 'my_video_2', 'my_video_3'];
var aspectRatio = 9/16;
// Catch each of the player's ready events and resize them individually
// jQuery deferred might be a neater way to wait for ready on all components to load and avoid a bit of repetition
for (var i = 0; i < players.length; i ++) {
_V_('#' + players[i]).ready(function() {
resizeVideoJS(this);
});
}
// Loop through all the players and resize them
function resizeVideos() {
for (var i = 0; i < players.length; i ++) {
var player = _V_('#' + players[i]);
resizeVideoJS(player);
}
}
// Resize a single player
function resizeVideoJS(player){
// Get the parent element's actual width
var width = document.getElementById(player.id).parentElement.offsetWidth;
// Set width to fill parent element, Set height
player.width(width).height( width * aspectRatio );
}
window.onresize = resizeVideos;
</script>

// jQuery deferred might be a neater way to wait for ready
// on all components to load and avoid a bit of repetition
for (var i = 0; i < players.length; i ++) {
_V_('#' + players[i]).ready(function() {
resizeVideoJS(this);
});
}
// Loop through all the players and resize them
function resizeVideos() {
for (var i = 0; i < players.length; i ++) {
var player = _V_('#' + players[i]);
resizeVideoJS(player);
}
}
// Resize a single player
function resizeVideoJS(player){
// Get the parent element's actual width
var width = document.getElementById(player.id).parentElement.offsetWidth;
// Set width to fill parent element, Set height
player.width(width).height( width * aspectRatio );
}
window.onresize = resizeVideos;

I have slightly modified net.uk.sweet's very helpful answer above into a working script which deals with multiple video players using video js - which are also responsive. You can find my article (which also shows an example) here = http://www.andy-howard.com/videojsmultipleresponsivevideos/index.html
This also includes a provided callback function if you require it.

you can use css rather than javascript :
.wrapper {
width: 100%;
}
.video-js {
padding-top: 55.25%;
}
<div class="wrapper">
<video id="video-player" width="auto" height="auto" class="video-js vjs-default-skin vjs-big-play-centered" data-setup="{}">
</video>
</div>

Related

Force constant dimensions of a HTML video element regardless of dimensions and ratio of source

I am trying to do a not so simple task. I would like to have in a HTML5 page a video element with constant width and height (those of the window), that can manages the dimensions and aspect ratio of the source video to display at best that is to say with the window fully covered with the video and with no scroll bars.
I wrote this javascript code:
$("video").bind("loadedmetadata", function () {
var screenSize = {}, videoSize = {};
videoSize["width"] = this.videoWidth;
videoSize["height"] = this.videoHeight;
screenSize["height"] = $( window ).height();
screenSize["width"] = $( window ).width();
var ratio_screen = screenSize["width"]/screenSize["height"];
var ratio_video = videoSize["width"]/videoSize["height"];
if (ratio_video > ratio_screen) {
$("video").height(screenSize["height"]);
$("video").width(screenSize["height"]*ratio_screen);
}
else
{
$("video").width(screenSize["width"]);
$("video").height(screenSize["width"]/ratio_screen);
}
});
At the moment, I have a video element, almost fitting the window (I still have a border or margin that inspector says to be part of html element). But the source video is fitting inside the video element! As an example for my test video which is wider than the screen, I have a black strip over and under the video.
How can I manage this to "zoom" the video. Do I have to apply a scaling factor to the video element or somenthing can be done at source video level.
Thanks
Finally this piece of code worked:
$("video").on('canplay',function() {
$("video").bind("loadedmetadata", function () {
var screenSize = {}, videoSize = {};
videoSize["width"] = this.videoWidth;
videoSize["height"] = this.videoHeight;
screenSize["height"] = $( window ).height();
screenSize["width"] = $( window ).width();
var ratio_screen = screenSize["width"]/screenSize["height"];
var ratio_video = videoSize["width"]/videoSize["height"];
if (ratio_video > ratio_screen) {
$("video").css("-webkit-transform", "scale("+ratio_video/ratio_screen+")");
$("video").height(screenSize["height"]);
$("video").width(screenSize["height"]*ratio_screen);
} else {
$("video").css("-webkit-transform", "scale("+ratio_video/ratio_screen+")");
$("video").width(screenSize["width"]);
$("video").height(screenSize["width"]/ratio_screen);
}
});
});
This results in displaying a video, filling the whole screen, without stretching the video if the aspect ratio is not fitting the one of the screen.
Note that my video element plays several sources in a loop. The first video played does not apply this resizing function (I have to work on that to ensure the at start up this works).

Spine multiple animations

So I have 2, or more skeletons for an animation (so, 2 or more json files). I want them to play at the same time and 10 seconds after, to play another animation.
Problem is that there is only one animation playing, and the second isn't displayed.
The way I'm doing it is the following:
<canvas id="animationCanvas" width="240" height="240"></canvas>
<script>
var first = true,
rendererFirst = new spine.SkeletonRenderer('http://someurl.com/images/'),
spineAFirst = /* My JSON Code */,
parsedFirst = JSON.parse(spineAFirst);
rendererFirst.scale = 0.2;
rendererFirst.load(spineAFirst);
rendererFirst.state.data.defaultMix = 1.0;
for (var i in parsedFirst.animations) {
if (first) {
first = false;
rendererFirst.state.setAnimationByName(0, i, true);
} else {
rendererFirst.state.addAnimationByName(0, i, true, 10);
}
}
rendererFirst.skeleton.x = 120;
rendererFirst.skeleton.y = 120;
rendererFirst.animate('animationCanvas');
</script>
And, of course, I'm doing it twice (or more). I tried as well with a single SkeletonRenderer, just loading (and setting or adding) animations as many times as I need, and it didn't worked.
It seems that the renderer is cleaning the canvas each time it is called, the better way to achieve this seems to create a canvas for each animation, and bind a renderer to each one.

jQuery or Javascript check if image loaded

I know there is a lot of these on Stackoverflow but I haven't found one that works for me in a recent version of jquery (1.10.2).
I did try:
$(".lazy").load(function (){}
But I believe after some research using .load to detect image load is deprecated in jQuery 1.8. What I need to do is fire an image resize function once the images are loaded. I don't have control over the
HTML and at the moment I am having to add the image dimensions via jQuery by attaching an attribute (via .attr()) once page loads so that I can use lazyload js.
The problem is that I need an accurate way to hold off all my various scripts until the image has loaded properly else the functions sometimes fire before every image had loaded. I have tried using $(window).load(function (){}); however it sometimes still fires before every image had loaded.
I usually do this:
var image = new Image();
image.onload = function () {
console.info("Image loaded !");
//do something...
}
image.onerror = function () {
console.error("Cannot load image");
//do something else...
}
image.src = "/images/blah/foo.jpg";
Remember that the loading is asynchronous so you have to continue the script inside the onload and onerror events.
There's also a useful .complete property of an image object, you can use it if you have already set the .src of your <img> before attaching to it any event listeners:
var img=document.getElementById('myimg');
var func=function(){
// do your code here
// `this` refers to the img object
};
if(img.complete){
func.call(img);
}
else{
img.onload=func;
}
Reference: http://www.w3schools.com/jsref/prop_img_complete.asp
I would give the images that require this constraint a class like mustLoad where:
<img class="mustLoad" src="..." alt="" />
and then create a generic image load handler function, such as:
$('img.mustLoad').on('load',function(){
/* Fire your image resize code here */
});
Edit:
In response to your comments about deprecating .load() above, .load() was deprecated, in favor of .on('load') to reduce ambiguity between the onLoad event and Ajax loading.
In the case of waiting of loading multiple images:
var images = $("#div-with-images img");
var unloaded = images.length;
images.on('load', function(){
-- unloaded;
if (!unloaded) {
// here all images loaded, do your stuff
}
});
What I need to do is fire an image resize function once the images are loaded.
Are you sure that you need the image to be loaded? Waiting for an image to load before resizing it can cause a large jump in the page layout, especially if the images have large file sizes, such as animated GIFs.
Usually, for an image resize, you only need to know the intrinsic dimensions of the image. While there is no event to tell you this, it's easy enough to poll the images for the data. Something like this could be particularly effective:
<img src="..." data-resizeme="123" />
(function() {
var images, l, i, tmp;
if( document.querySelectorAll) {
images = [].slice.call(document.querySelectorAll("img[data-resizeme]"),0);
}
else {
tmp = document.getElementsByTagName("img");
images = [];
// browser compatibility is fun!
for( i=tmp.length-1; i>=0; i--) {
if( tmp[i].getAttribute("data-resizeme")) images.unshift(tmp[i]);
}
}
for( i=images.length-1; i>=0; i--) {
images[i].onload = resizeImage;
images[i].onerror = cancelImageResize;
}
var timer = setInterval(function() {
for( i=images.length-1; i>=0; i--) {
if( images[i].width) {
resizeImage.call(images[i]);
images[i].onload = null;
cancelImageResize.call(images[i]);
}
}
if( images.length == 0) clearInterval(timer);
},100); // adjust granularity as needed - lower number is more responsive.
function cancelImageResize() {
var i;
for( i=images.length-1; i>=0; i--) {
if( images[i] == this) {
images.splice(i,1);
break;
}
}
}
function resizeImage() {
console.log("Image "+this.src+" is "+this.width+"x"+this.height);
}
})();
Hope this helps!

JavaScript waiting until an image is fully loaded before continuing script

I've been looking around a lot of JavaScript answers but I haven't found one that really answers my problem yet. What I'm trying to do is load an image, grab the pixel data, perform an analysis, and then load another image to repeat the process.
My problem is that I can't preload all of the images because this script has to be able to work on large amounts of images and preloading could be too resource heavy. So I'm stuck trying to load a new image each time through a loop, but I'm stuck with a race condition between the image loading and the script drawing it to the canvas's context. At least I'm pretty sure that's what is happening because the script will work fine with the images precached (for example if I refresh after loading the page previously).
As you'll see there are several lines of code commented out because I'm incredibly new to JavaScript and they weren't working the way I thought they would, but I didn't want to forget about them if I needed the functionality later.
This is the snippet of code that I believe is giving rise to the problem:
EDIT: So I got my function to work after following a suggestion
function myFunction(imageURLarray) {
var canvas = document.getElementById('imagecanvas');
console.log("Canvas Grabbed");
if (!canvas || !canvas.getContext) {
return;
}
var context = canvas.getContext('2d');
if (!context || !context.putImageData) {
return;
}
window.loadedImageCount = 0;
loadImages(context, canvas.width, canvas.height, imageURLarray, 0);
}
function loadImages(context, width, height, imageURLarray, currentIndex) {
if (imageURLarray.length == 0 || imageURLarray.length == currentIndex) {
return false;
}
if (typeof currentIndex == 'undefined') {
currentIndex = 0;
}
var currentimage = new Image();
currentimage.src = imageURLarray[currentIndex];
var tempindex = currentIndex;
currentimage.onload = function(e) {
// Function code here
window.loadedImageCount++;
if (loadedImageCount == imageURLarray.length) {
// Function that happens after all images are loaded here
}
}
currentIndex++;
loadImages(context, width, height, imageURLarray, currentIndex);
return;
}
Maybe this will help:
currentimage.onload = function(e){
// code, run after image load
}
If it is necessary to wait for the image to load, the following code will load the next image (currentIndex is your "img" variable):
var loadImages = function(imageURLarray, currentIndex){
if (imageURLarray.length == 0 || imageURLarray.length == currentIndex) return false;
if (typeof currentIndex == 'undefined'){
currentIndex = 0;
}
// your top code
currentimage.onload = function(e){
// code, run after image load
loadImages(imageURLArray, currentIndex++);
}
}
Instead of a "for" loop, use for example this function:
loadImages(imageURLarray);
Maybe try this:
http://jsfiddle.net/jnt9f/
Setting onload handler before setting img src will make sure the onload event be fired even the image is cached
var $imgs = $(),i=0;
for (var img = 0; img < imageURLarray.length; img++) {
$imgs = $imgs.add('<img/>');
}
var fctn = (function fctn(i){
$imgs.eq(i).on('load',function(){
//do some stuff
//...
fctn(++i);
}).attr('src',imageURLarray[i]);
})(0);
Actually...a lot of developers are pointing here to detect when images are done loading after a jQuery event..
https://github.com/desandro/imagesloaded
If you can determine when the event triggers your images to load (for example, adding an Id or class onto the page right before your images begin to load), then you should be able to blend that in with this plug-in on github.
Good Luck!

HTML5 Video Dimensions

I'm trying to get the dimensions of a video of which I'm overlaying onto a page with JavaScript, however it is returning the dimensions of the poster image instead of the actual video as it seems it's being calculated before the video is loaded.
It should be noted that the currently accepted solution above by Sime Vidas doesn't actually work in modern browsers since the videoWidth and videoHeight properties aren't set until after the "loadedmetadata" event has fired.
If you happen to query for those properties far enough after the VIDEO element is rendered it may sometimes work, but in most cases this will return values of 0 for both properties.
To guarantee that you're getting the correct property values you need to do something along the lines of:
var v = document.getElementById("myVideo");
v.addEventListener( "loadedmetadata", function (e) {
var width = this.videoWidth,
height = this.videoHeight;
}, false );
NOTE: I didn't bother accounting for pre-9 versions of Internet Explorer which use attachEvent instead of addEventListener since pre-9 versions of that browser don't support HTML5 video, anyway.
<video id="foo" src="foo.mp4"></video>
var vid = document.getElementById("foo");
vid.videoHeight; // returns the intrinsic height of the video
vid.videoWidth; // returns the intrinsic width of the video
Spec: https://html.spec.whatwg.org/multipage/embedded-content.html#the-video-element
Ready-to-use function
Here's a ready to use function which returns the dimensions of a video asynchrously, without changing anything in the document.
// ---- Definitions ----- //
/**
Returns the dimensions of a video asynchrounsly.
#param {String} url Url of the video to get dimensions from.
#return {Promise<{width: number, height: number}>} Promise which returns the dimensions of the video in 'width' and 'height' properties.
*/
function getVideoDimensionsOf(url){
return new Promise(resolve => {
// create the video element
const video = document.createElement('video');
// place a listener on it
video.addEventListener( "loadedmetadata", function () {
// retrieve dimensions
const height = this.videoHeight;
const width = this.videoWidth;
// send back result
resolve({height, width});
}, false);
// start download meta-datas
video.src = url;
});
}
// ---- Use ---- //
getVideoDimensionsOf("https://www.w3schools.com/html/mov_bbb.mp4")
.then(console.log);
Here's the video used for the snippet if you wish to see it : Big Buck Bunny
Listen for the loadedmetadata event which is dispatched when the user agent has just determined the duration and dimensions of the media resource
Section 4.7.10.16 Event summary
https://www.w3.org/TR/html5/semantics-embedded-content.html#eventdef-media-loadedmetadata
videoTagRef.addEventListener('loadedmetadata', function(e){
console.log(videoTagRef.videoWidth, videoTagRef.videoHeight);
});
This is how it can be done in Vue:
<template>
<div>
<video src="video.mp4" #loadedmetadata="getVideoDimensions"></video>
</div>
</template>
<script>
export default {
methods: {
getVideoDimensions (e) {
console.log(e.target.videoHeight)
console.log(e.target.videoWidth)
}
}
}
</script>
This should also be noted that in some cases such as HLS streams
the "onmetadataloaded" does not work either. in those cases, this solution works perfect.
var video = document.getElementById("video")
video.onplaying = function () {
var width = video.videoWidth
var height = video.videoHeight
console.log("video dimens loaded w="+width+" h="+height)
}
In Vuejs I use following code in mounted tag.
var app = new Vue({
el: '#id_homepage',
mounted: function () {
var v = document.getElementById("id_video");
var width = v.offsetWidth;
v.height = Math.floor(width*(9/16)); // dynamically setting video height to maintain aspect ratio
},
});

Categories

Resources