Name is required.
Email address is required.
Invalid email address
Answer is required.
Exceeding max length of 5KB

Support responsive design / dynamic sizing


As per this discussion: http://www.longtailvideo.com/support/forums/jw-player/setup-issues-and-embedding/30821/responsive-player-dimensions

Support for responsive design setups and dynamic sizing that does not break various portions of the player (e.g. Captions and fullscreen) would be nice. The linked thread has a basic solution in it.

The basic solution is to allow for width and height to be specified as percentages in the setup code, as right now it is ASSUMED that these will always be integers. Allowing for the percentage based values would only require a few lines in the model initialization code.

The alternative would be to provide a "responsive" or "dynamicSizing" setup tag that would handle the following:

<ol>
<li>Wrapping the player in a container with the padding hacks for aspect ratio (See linked topic, would likely also need to specify ratio in this case)</li>
<li>Set the height and width of the player to fill container</li>
<li>Possibly attaching an event to window.resize to handle calling resize() on the player when the page changes size.</li>
</ol>

The final option is to actually make the player truly responsive, but that would require a good deal of messing about in lots of places to make getting player dimensions dynamic, but would probably be a better long term option...

I am submitting this as there is no ticket in the system related to this request.

16 Community Answers

JeroenW

JW Player Support Agent  
0 rated :

We’re looking into this at present. Do note the player is capable of supporting percentage sizes (e.g. width:“100%”), but the trick is offering a setup in which the height can be set as a percentage of the width. Various options are available:

1. Presume a responsive setup when percentages are used. For example:

jwplayer().setup({
width: “100%”
height: “50%”
});

2. Offer a new option for the aspect ratio, which overrides the height:

jwplayer().setup({
width: “100%”
ratio: “50%”
});

3. Set an option “responsive=true”, which will make the height automatically be 100% and the width be proportional according to the initial dimensions:

jwplayer().setup({
width: 320,
height: 180,
responsive: true
})

If you have preferences or other ideas, we’d love to hear them.

JW Player

User  
0 rated :

I'm sorry to disagree, but the player is not capable of supporting those percentage based sizes without breaking portions of the functionality. In the other thread, I specifically point to the two things that I _noticed_ were broken with that setup: caption placement and return from fullscreen being able to get the original player dimensions.

In both cases, the issue was related to the fact that the methods that handle that get the sizing information from the Model, AND assume that the values they get back will be numeric. A percentage based setup like above is not numeric, it is a string. Javascript will always interpret these as 0 if you try and use them as a number, or as the complete wrong number in these cases:

1. When you try and calculate a location based on their numeric value: "100%" - 10 = -10
2. When you try and concatenate it for CSS purposes: "100%" + "px" = "100%px"

JWPlayer makes these assumptions about those values in at least those two places, and I'd be surprised if there aren't others too.

This means that one of the following have to happen to support that:

1. The model has to be changed to FETCH the real height and width every time something asks for it. I didn't know your API well enough to do this without risking breaking things.
2. The model has to be changed to be smart on init, and if the passed values for height and width are percentages, it needs to calculate the height and width based on it's container.

That was my first step. It maintains the static height and width in the Model that everything assumes, but allowed me to pass in a 100% for height and width in the setup and wrap the player in my own container for sizing.

I also attach an event to window.resize to call resize on the player in order to make the player ACTUALLY responsive to browser window resizes...

JW Player

User  
0 rated :

I broke this into two messages, because the former was just explaining the issue in more detail and my hack fix on our local copy.

The more permanent fix that I would recommend is this:

Add a responsive flag to the setup that will trigger a few things:

1. height and width default to the width of the container, and the calculated height of the video aspect ratio based on that. This happens in the Model init method.
2. Add a window.resize event handler that calls resize on the player with the new calculated values when necessary.

You would also have to have a way to provide the aspect ratio for this to work. While responsive COULD trigger aspect ratio to be calculated based on the original height and width that was passed in, that may be confusing to some because it redefines the meaning of an API value... but it also allows you to avoid having to provide a new API setup method just for passing aspect ratio that doesn't have any meaning without the responsive flag... so it's a toss up on which way you go there.

Note that in the above scenario, number two is optional, and serves only to make the player truly responsive to the browser window CHANGING size, as otherwise it would only be responsive to the sizing on initialization, and would be locked after that.

That's kind of a hack, and certain things would still be kind of messy (e.g. caption placement would not change dynamically on browser window size until the next caption was displayed... but that would require some interesting placement logic based on percentage based locations in the caption placement code to get rid of).

My recommendation would be for the setup to just take three values: height, width, and responsive. Then the two changes I mention above could handle the rest.

JW Player

User  
0 rated :

For example, changing the jwplayer.html5.model.js _init method to the following:

bc.. function _init() {
utils.extend(_model, new events.eventdispatcher());

_model.config = _parseConfig(utils.extend({}, _defaults, _cookies, config));
utils.extend(_model, {
id: config.id,
state : events.state.IDLE,
duration: -1,
position: 0,
buffer: 0
}, _model.config);

// Responsive sizing
if (_model.responsive) {
var aspectRatio = _model.height / _model.width;
var parentWidth = utils.bounds(document.getElementById(_model.id).parentNode).width;

utils.extend(_model, {width: parentWidth});

if (_model.listbar) {
utils.extend(_model, {height: (parentWidth - _model.listbar.size) * aspectRatio});
} else {
utils.extend(_model, {height: parentWidth * aspectRatio});
}
}

// This gets added later
_model.playlist = [];
_model.setItem(0);

_videoTag = document.createElement("video");
_video = new html5.video(_videoTag);
_video.volume(_model.volume);
_video.mute(_model.mute);
_video.addGlobalListener(_videoEventHandler);
}



That will accomplish number one... Then you would just need to add to the config defaults a "responsive: FALSE" flag, and figure out where to do the window.resize event handler. The handler would look something like this:

bc.. jQuery(window).resize(function() {
var parentWidth = jwplayer.utils.bounds(document.getElementById("videoPlayer").parentNode).width;
var calculatedHeight = parentWidth * 0.5625;
if (jwplayer("videoPlayer").getWidth() != parentWidth) { jwplayer("videoPlayer").resize(parentWidth, calculatedHeight); }
});

JW Player

User  
0 rated :

Note also, however, that the above solution doesn't address the Flash player either...

JW Player

User  
0 rated :

Ok, now if you wanted to make this work across all implementations, you would actually have to not add that first bit to the html5 model code, but to the jwplayer.embed.config code. jwplayer.embed will also need to be modified to make sure that the id is passed in with the config to the jwplayer.embed.config init code so that it can find the element and it's parent correctly.

This way, the height and width are calculated and handed to all consumers of the config values, instead of just HTML5 stuff.

My tests show that this makes it work in Chrome, Firefox, and IE 9. I haven't tested IE8 yet.

Also, my window.resize event handler doesn't seem to have any effect on resizing the flash player automatically... a pity, but it seems the flash player doesn't respect the jwplayer.resize calls?

JeroenW

JW Player Support Agent  
0 rated :

Thanks for your feedback here too. I replied to the other thread on the bugs you were seeing and on the solution we’re seeing (indeed: width/height/responsive=true seemse the best).

As to the resize() functionality: yes, the player should continue to proportionally resize, also after the initial setup.

JW Player

User  
0 rated :

I fixed my flash resize event. I had to grab the wrapper in the case that flash was being used instead of the original ID.

In any event, my solution seems to work. Grabbing the window.resize event to handle the browser resize stuff seems a little hokey, but the only real alternative was to use 100% height / width values and adding a wrapper with the padding trick, which would require a lot more work to make it look right, and falls victim to the 0.5 rounding error in Chrome (Chrome will round pixel sizes based on percentages in a padding value up, and down in the contained 100% height div, resulting in a 1 pixel difference when the calculated height value falls on a .5 value, e.g. width = 920 and height = 56.25% of that, or 517.5).

JW Player

User  
0 rated :

I haven't seen this made into a ticket yet in your system... not sure how stringent you guys are with making sure everything gets put in there, but I just wanted to point it out in case it was an oversight.

Anyway, it turns out you can be pretty tricky with the init code to do what I'm doing without modifying any code:

bc.. jQuery(document).ready(function() {
jwplayer("videoPlayer").setup({
playlist: [
{
title: "TITLE",
captions: [
{ file: "FILE", label: "English" }
],
image: "FILE",
file: "FILE"
},
{
title: "TITLE",
image: "FILE",
file: "FILE"
}
],
listbar: {
position: "right",
size: (document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth * 0.33 : document.getElementById("videoPlayer").parentNode.offsetWidth * 0.33)
},
width: document.getElementById("videoPlayer").parentNode.offsetWidth,
height: ((document.getElementById("videoPlayer").parentNode.offsetWidth - (document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth * 0.33 : document.getElementById("videoPlayer").parentNode.offsetWidth * 0.33)) * 720 / 1280),
stretching: "exactfit"
});

// Responsive player resizing after initialization
jQuery(window).resize(function() {
var parentWidth = document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth : document.getElementById("videoPlayer").parentNode.offsetWidth;
var calculatedHeight = (parentWidth - (document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth * 0.33 : document.getElementById("videoPlayer").parentNode.offsetWidth * 0.33)) * 0.5625;
if (jwplayer("videoPlayer").getWidth() != parentWidth) {
jwplayer("videoPlayer").resize(parentWidth, calculatedHeight);
}
});
});



This is an example of the setup needed for a playlist with listbar. It does the following:

1. Sets the width to the width of the container.
2. Uses a pre-set aspect ratio (represented here by the 720/1280 part) to set the height, minus the listbar size.
3. Sets the listbar size to be 1/3 of the width of the container.
4. Adds a window.resize event handler to handle resizing the player on container resize.

A non-listbar version would be a bit simpler:

bc.. jQuery(document).ready(function() {
jwplayer("videoPlayer").setup({
playlist: [
{
title: "TITLE",
captions: [
{ file: "FILE", label: "English" }
],
image: "FILE",
file: "FILE"
}
],
width: document.getElementById("videoPlayer").parentNode.offsetWidth,
height: (document.getElementById("videoPlayer").parentNode.offsetWidth * 720 / 1280),
stretching: "exactfit"
});

// Responsive player resizing after initialization
jQuery(window).resize(function() {
var parentWidth = document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth : document.getElementById("videoPlayer").parentNode.offsetWidth;
var calculatedHeight = parentWidth * 720 / 1280;
if (jwplayer("videoPlayer").getWidth() != parentWidth) {
jwplayer("videoPlayer").resize(parentWidth, calculatedHeight);
}
});
});

JW Player

User  
0 rated :

This may be easier to understand whats actually happening there... that's just the generated code I use.

bc.. jQuery(document).ready(function() {
var parentWidth = document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth : document.getElementById("videoPlayer").parentNode.offsetWidth;
jwplayer("videoPlayer").setup({
playlist: [
{
title: "TITLE",
captions: [
{ file: "FILE", label: "English" }
],
image: "FILE",
file: "FILE"
}
],
width: parentWidth;,
height: parentWidth * 720 / 1280,
stretching: "exactfit"
});

// Responsive player resizing after initialization
jQuery(window).resize(function() {
var parentWidth = document.getElementById("videoPlayer_wrapper") != null ? document.getElementById("videoPlayer_wrapper").parentNode.offsetWidth : document.getElementById("videoPlayer").parentNode.offsetWidth;
var calculatedHeight = parentWidth * 720 / 1280;
if (jwplayer("videoPlayer").getWidth() != parentWidth) {
jwplayer("videoPlayer").resize(parentWidth, calculatedHeight);
}
});
});

JeroenW

JW Player Support Agent  
0 rated :

Thanks for the update. There’s no ticket for it indeed, but we are already working on the functionality. We’re likely going to support this setup:

jwplayer().setup({
  width: "100%"
  ratio: "16:9"
});



The "ratio" tells the A/R of the video, so the player can automatically scale the height. This happens both initially and when resizing the browser. 

The "ratio" option overrides the "height", should both of them get set.

JW Player

User  
0 rated :

Fair enough. I look forward to seeing your implementation! Will this make 6.3? Since I'm using a commercial version, I can't really modify your source code to fix the bugs I want to fix myself and still get the branding capabilities. I just put together the above solution to make it work in 6.2, but of course the caption repositioning bug is still in 6.2, whereas my custom version had fixed that...

Any idea when we might see a 6.3 release?

JeroenW

JW Player Support Agent  
0 rated :

It’ll be 6.4, since 6.3 is already “done” and out to beta testers. 6.4 will be released in April (we do ~6 weeks/release).

If you sign up for our developer mailing list, you can access 6.3 today and 6.4 probably by the end of March. See the top-right here:

http://developer.longtailvideo.com/trac/

JW Player

User  
0 rated :

Well, I actually need the commercial version... I did sign up on the developer mailing list though since I'd like to know when things get released.

Thanks for all the help! I look forward to the next release.

JeroenW

JW Player Support Agent  
0 rated :

No problem, good luck!

JW Player

User  
0 rated :

Great Tutorial Michael. Thanks ! :)

This question has received the maximum number of answers.