add fullscreen mode to video player

This commit is contained in:
rolux 2011-05-15 09:26:00 +02:00
parent 4255470e29
commit 609ffdd4d7
2 changed files with 265 additions and 144 deletions

View file

@ -9,7 +9,7 @@ Ox.load('UI', {
videoSize = getVideoSize(),
$videos = [
Ox.VideoPlayer({
controls: ['play', 'mute', 'scale', 'timeline', 'position'],
controls: ['play', 'mute', 'fullscreen', 'scale', 'timeline', 'position'],
enableKeyboard: true,
focus: 'mouseenter',
height: 192,
@ -27,9 +27,11 @@ Ox.load('UI', {
width: 360
})
.css({
margin: '16px'
}),
left: '16px',
top: '16px'
}),
Ox.VideoPlayer({
enableKeyboard: true,
height: 192,
'in': 3128.725,
//keepIconVisible: true,
@ -38,13 +40,13 @@ Ox.load('UI', {
playInToOut: true,
//preload: 'none',
showIcon: true,
showIconOnLoad: true,
timeline: timeline,
video: url + '?' + + Ox.random(1000000),
width: 360
})
.css({
margin: '16px'
left: '16px',
top: '16px'
}),
Ox.VideoPlayer({
controls: ['play', 'playInToOut', 'mute', 'size', 'space', 'position'],
@ -60,7 +62,13 @@ Ox.load('UI', {
width: videoSize.width
})
.css({
margin: '16px'
left: '16px',
top: '16px'
})
.bindEvent({
size: function() {
}
})
];
window.$videos = $videos

View file

@ -18,6 +18,7 @@ Ox.VideoPlayer <f> Generic Video Player
externalControls <b|false> If true, controls are outside the video
focus <s|'click'> focus on 'click', 'load' or 'mouseover'
fps <n|25> Frames per second
fullscreen <b|false> If true, video is in fullscreen
height <n|144> Height in px (excluding external controls)
in <n> In point (sec)
keepIconVisible <b|false> If true, play icon stays visible after mouseleave
@ -69,6 +70,7 @@ Ox.VideoPlayer = function(options, self) {
externalControls: false,
focus: 'click',
fps: 25,
fullscreen: false,
height: 144,
'in': 0,
keepIconVisible: false,
@ -108,6 +110,12 @@ Ox.VideoPlayer = function(options, self) {
position: 'absolute'
});
Ox.UI.$window.bind({
resize: function() {
self.options.fullscreen && setSizes();
}
});
self['in'] = self.options.playInToOut ? self.options['in'] : 0,
self.out = self.options.playInToOut ? self.options.out : self.options.duration;
self.options.duration = self.out - self['in'];
@ -117,14 +125,18 @@ Ox.VideoPlayer = function(options, self) {
self.millisecondsPerFrame = 1000 / self.options.fps;
self.secondsPerFrame = 1 / self.options.fps;
self.barHeight = 16;
self.width = self.options.fullscreen ? window.innerWidth : self.options.width;
self.height = self.options.fullscreen ? window.innerHeight : self.options.height;
if (self.options.enableKeyboard) {
that.bindEvent({
key_left: function() {
setPosition(self.options.position + self.secondsPerFrame);
setPosition(self.options.position - self.secondsPerFrame);
self.video.currentTime = self.options.position;
},
key_right: function() {
setPosition(self.options.position - self.secondsPerFrame);
setPosition(self.options.position + self.secondsPerFrame);
self.video.currentTime = self.options.position;
},
key_space: function() {
self.$playButton && self.$playButton.toggleTitle();
@ -260,6 +272,9 @@ Ox.VideoPlayer = function(options, self) {
opacity: 0
})
.appendTo(self.$videoContainer);
if (self.options.showIcon) {
self.$playIcon.addClass('OxInterface');
}
if (self.options.showIconOnLoad) {
self.iconIsVisible = true;
}
@ -284,7 +299,6 @@ Ox.VideoPlayer = function(options, self) {
.addClass('OxInterface')
.css({
position: 'absolute',
width: self.options.width + 'px',
height: (self.barHeight - 1) + 'px',
paddingTop: '1px',
textAlign: 'center',
@ -372,21 +386,6 @@ Ox.VideoPlayer = function(options, self) {
} else if (control == 'volume') {
} else if (control == 'size') {
self.$sizeButton = Ox.Button({
style: 'symbol',
title: [
{id: 'grow', title: 'grow', selected: !self.options.sizeIsLarge},
{id: 'shrink', title: 'shrink', selected: self.options.sizeIsLarge}
],
tooltip: ['Larger', 'Smaller'],
type: 'image'
})
.css({float: 'left'})
.bindEvent('click', toggleSize)
.appendTo(self.$controls);
} else if (control == 'scale') {
self.$scaleButton = Ox.Button({
@ -402,7 +401,37 @@ Ox.VideoPlayer = function(options, self) {
.bindEvent('click', toggleScale)
.appendTo(self.$controls);
} else if (control == 'timeline') {
} else if (control == 'fullscreen') {
self.$fullscreenButton = Ox.Button({
style: 'symbol',
title: [
{id: 'grow', title: 'grow', selected: !self.options.fullscreen},
{id: 'shrink', title: 'shrink', selected: self.options.fullscreen}
],
tooltip: ['Enter Fullscreen', 'Exit Fullscreen'],
type: 'image'
})
.css({float: 'left'})
.bindEvent('click', toggleFullscreen)
.appendTo(self.$controls);
} else if (control == 'size') {
self.$sizeButton = Ox.Button({
style: 'symbol',
title: [
{id: 'grow', title: 'grow', selected: !self.options.sizeIsLarge},
{id: 'shrink', title: 'shrink', selected: self.options.sizeIsLarge}
],
tooltip: ['Larger', 'Smaller'],
type: 'image'
})
.css({float: 'left'})
.bindEvent('click', toggleSize)
.appendTo(self.$controls);
}else if (control == 'timeline') {
self.$timeline = Ox.Element()
.addClass('timeline')
@ -543,14 +572,18 @@ Ox.VideoPlayer = function(options, self) {
})
.bind({
blur: function() {
self.inputHasFocus = false;
},
focus: function() {
self.inputHasFocus = true;
}
})
.bindEvent({
blur: submitPositionInput
focus: function() {
self.inputHasFocus = true;
},
blur: function() {
self.inputHasFocus = false;
submitPositionInput();
}
})
.hide()
.appendTo(self.$controls.$element);
@ -623,15 +656,6 @@ Ox.VideoPlayer = function(options, self) {
}
}
function getPositionMarkerCSS() {
var position = self.options.duration ?
(self.options.position - self['in']) / self.options.duration : 0;
return {
marginLeft: position * self.timelineImageWidth -
self.timelineImageWidth - 8 + 'px',
};
}
function getProgressImageURL() {
Ox.print('---', self.timelineImageWidth)
if (!self.timelineImageWidth) return;
@ -676,32 +700,6 @@ Ox.VideoPlayer = function(options, self) {
return subtitle;
}
function getVideoCSS() {
var playerWidth = self.options.width,
playerHeight = self.options.height,
playerRatio = playerWidth / playerHeight,
videoWidth = self.video.videoWidth,
videoHeight = self.video.videoHeight,
videoRatio = videoWidth / videoHeight,
videoIsWider = videoRatio > playerRatio,
width, height;
if (self.options.scaleToFill) {
width = videoIsWider ? playerHeight * videoRatio : playerWidth;
height = videoIsWider ? playerHeight : playerWidth / videoRatio;
} else {
width = videoIsWider ? playerWidth : playerHeight * videoRatio;
height = videoIsWider ? playerWidth / videoRatio : playerHeight;
}
width = Math.round(width);
height = Math.round(height);
return {
width: width + 'px',
height: height + 'px',
marginLeft: parseInt((playerWidth - width) / 2),
marginTop: parseInt((playerHeight - height) / 2)
};
}
function hideInterface() {
if (!self.inputHasFocus) {
self.controlsTimeout = setTimeout(function() {
@ -738,7 +736,7 @@ Ox.VideoPlayer = function(options, self) {
self.options.out : self.video.duration;
self.options.duration = self.out - self['in'];
self.video.currentTime = self.options.position;
self.$video.css(getVideoCSS());
self.$video.css(getCSS('video'));
hideLoadingIcon();
if (self.options.showIcon || self.options.showIconOnLoad) {
@ -848,11 +846,16 @@ Ox.VideoPlayer = function(options, self) {
}
function seeked() {
clearTimeout(self.seekTimeout);
hideLoadingIcon();
self.$playIcon && self.$playIcon.show();
}
function seeking() {
showLoadingIcon();
self.seekTimeout = setTimeout(function() {
self.$playIcon && self.$playIcon.hide();
showLoadingIcon();
}, 250);
}
function setPosition(position) {
@ -875,101 +878,176 @@ Ox.VideoPlayer = function(options, self) {
self.posterIsVisible = false;
}
self.$subtitle && setSubtitle();
self.$timeline && self.$positionMarker.css(getPositionMarkerCSS());
self.$timeline && self.$positionMarker.css(getCSS('positionMarker'));
self.$position && self.$position.html(formatPosition());
}
function setSizes() {
var iconSize = Math.max(Math.round(self.options.height / 10), 16),
iconLeft = parseInt((self.options.width - iconSize) / 2),
iconTop = parseInt((self.options.height - iconSize) / 2),
logoHeight,
playIconPadding, playIconSize,
playerHeight = self.options.height + (
self.options.externalControls
? (!!self.options.controls.length + !!self.options.title) * self.barHeight
: 0
),
timelineWidth;
that.css({
position: 'absolute',
width: self.options.width + 'px',
height: playerHeight + 'px'
});
self.$videoContainer.css({
width: self.options.width + 'px',
height: self.options.height + 'px'
});
self.loaded && self.$video.css(getVideoCSS());
self.$poster && self.$poster.css({
width: self.options.width + 'px',
height: self.options.height + 'px'
});
if (self.$logo) {
logoHeight = Math.round(self.options.height / 10);
self.logoMargin = Math.round(self.options.height / 20);
self.$logo.css({
function getCSS(element) {
var css;
if (element == 'controls') {
css = {
width: self.width + 'px'
};
} else if (element == 'loadingIcon') {
css = {
left: self.iconLeft + 'px',
top: self.iconTop + 'px',
width: self.iconSize + 'px',
height: self.iconSize + 'px'
};
} else if (element == 'logo') {
var logoHeight = Math.round(self.height / 10);
self.logoMargin = Math.round(self.height / 20);
css = {
left: self.logoMargin + 'px',
top: self.logoMargin + 'px',
height: logoHeight + 'px',
});
}
self.$loadingIcon.css({
left: iconLeft + 'px',
top: iconTop + 'px',
width: iconSize + 'px',
height: iconSize + 'px'
});
if (self.$playIcon) {
playIconPadding = Math.round(iconSize * 1/8);
playIconSize = iconSize - 2 * playIconPadding - 4;
self.$playIcon.css({
left: iconLeft + 'px',
top: iconTop + 'px',
};
} else if (element == 'player') {
if (!self.offset) {
self.offset = that.offset();
}
css = {
left: self.options.fullscreen ? 0 : self.offset.left + 'px',
top: self.options.fullscreen ? 0 : self.offset.top + 'px',
width: self.width + 'px',
height: (self.options.fullscreen
? window.innerHeight
: self.height + (
self.options.externalControls
? (!!self.options.controls.length + !!self.options.title) * self.barHeight
: 0)) + 'px'
}
} else if (element == 'playIcon') {
var playIconPadding = Math.round(self.iconSize * 1/8),
playIconSize = self.iconSize - 2 * playIconPadding - 4;
css = {
left: self.iconLeft + 'px',
top: self.iconTop + 'px',
width: playIconSize + 'px',
height: playIconSize + 'px',
padding: playIconPadding + 'px',
borderRadius: Math.round(iconSize / 2) + 'px'
});
borderRadius: Math.round(self.iconSize / 2) + 'px'
};
} else if (element == 'positionMarker') {
var position = self.options.duration ?
(self.options.position - self['in']) / self.options.duration : 0;
css = {
marginLeft: position * self.timelineImageWidth -
self.timelineImageWidth - 8 + 'px',
};
} else if (element == 'poster') {
css = {
width: self.width + 'px',
height: self.height + 'px'
};
} else if (element == 'progress') {
css = {
width: self.timelineImageWidth + 'px',
marginLeft: -self.timelineImageWidth + 'px'
};
} else if (element == 'subtitle') {
css = {
bottom: parseInt(self.height / 16) + 'px',
width: self.width + 'px',
fontSize: parseInt(self.height / 20) + 'px',
WebkitTextStroke: (self.height / 1000) + 'px rgb(0, 0, 0)'
};
} else if (element == 'space') {
css = {
width: self.timelineWidth + 'px'
};
} else if (element == 'timeline') {
css = {
width: self.timelineWidth + 'px'
};
} else if (element == 'timelineImage') {
css = {
width: self.timelineImageWidth + 'px'
};
} else if (element == 'timelineImages') {
css = {
width: self.timelineImageWidth + 'px'
};
} else if (element == 'timelineInterface') {
css = {
width: self.timelineWidth + 'px',
marginLeft: -self.timelineWidth + 'px'
};
} else if (element == 'titlebar') {
css = {
width: self.width + 'px'
};
} else if (element == 'video') {
var playerWidth = self.width,
playerHeight = self.height,
playerRatio = playerWidth / playerHeight,
videoWidth = self.video.videoWidth,
videoHeight = self.video.videoHeight,
videoRatio = videoWidth / videoHeight,
videoIsWider = videoRatio > playerRatio,
width, height;
if (self.options.scaleToFill) {
width = videoIsWider ? playerHeight * videoRatio : playerWidth;
height = videoIsWider ? playerHeight : playerWidth / videoRatio;
} else {
width = videoIsWider ? playerWidth : playerHeight * videoRatio;
height = videoIsWider ? playerWidth / videoRatio : playerHeight;
}
width = Math.round(width);
height = Math.round(height);
css = {
width: width + 'px',
height: height + 'px',
marginLeft: parseInt((playerWidth - width) / 2),
marginTop: parseInt((playerHeight - height) / 2)
};
} else if (element == 'videoContainer') {
css = {
width: self.width + 'px',
height: self.height + 'px'
};
}
self.$subtitle && self.$subtitle.css({
bottom: parseInt(self.options.height / 16) + 'px',
width: self.options.width + 'px',
fontSize: parseInt(self.options.height / 20) + 'px',
WebkitTextStroke: (self.options.height / 1000) + 'px rgb(0, 0, 0)'
});
self.$titlebar && self.$titlebar.css({
width: self.options.width + 'px'
});
self.$controls && self.$controls.css({
width: self.options.width + 'px'
});
return css;
}
function setSizes(callback) {
var ms = callback ? 250 : 0;
self.width = self.options.fullscreen ? window.innerWidth : self.options.width;
self.height = self.options.fullscreen ? window.innerHeight : self.options.height;
self.iconSize = Math.max(Math.round(self.height / 10), 16),
self.iconLeft = parseInt((self.width - self.iconSize) / 2),
self.iconTop = parseInt((self.height - self.iconSize) / 2);
if (self.$timeline || self.$space) {
timelineWidth = self.options.width - self.options.controls.reduce(function(prev, curr) {
self.timelineWidth = self.width - self.options.controls.reduce(function(prev, curr) {
return prev + (
curr == 'timeline' || curr == 'space' ? 0 :
curr == 'position' ? self.positionWidth : 16
);
}, 0);
if (self.$timeline) {
self.timelineImageWidth = timelineWidth - self.barHeight;
self.$timeline.css({width: timelineWidth + 'px'});
self.$timelineImages.css({width: self.timelineImageWidth + 'px'});
self.$timelineImage.css({width: self.timelineImageWidth + 'px'});
self.$progress && self.$progress.css({
width: self.timelineImageWidth + 'px',
marginLeft: -self.timelineImageWidth + 'px'
});
self.$positionMarker.css(getPositionMarkerCSS());
self.$timelineInterface.css({
width: timelineWidth + 'px',
marginLeft: -timelineWidth + 'px'
});
} else {
self.$space.css({width: timelineWidth + 'px'});
self.timelineImageWidth = self.timelineWidth - self.barHeight;
}
}
that.animate(getCSS('player'), ms, callback);
self.$videoContainer.animate(getCSS('videoContainer'), ms);
self.loaded && self.$video.animate(getCSS('video'), ms);
self.$poster && self.$poster.animate(getCSS('poster'), ms);
self.$logo && self.$logo.animate(getCSS('logo'), ms);
self.$loadingIcon.animate(getCSS('loadingIcon'), ms);
self.$playIcon && self.$playIcon.animate(getCSS('playIcon'), ms);
self.$subtitle && self.$subtitle.animate(getCSS('subtitle'), ms);
self.$titlebar && self.$titlebar.animate(getCSS('titlebar'), ms);
self.$controls && self.$controls.animate(getCSS('controls'), ms);
if (self.$timeline) {
self.$timeline.animate(getCSS('timeline'), ms);
self.$timelineImages.animate(getCSS('timelineImages'), ms);
self.$timelineImage.animate(getCSS('timelineImage'), ms);
self.$progress && self.$progress.animate(getCSS('progress'), ms);
self.$positionMarker.animate(getCSS('positionMarker'), ms);
self.$timelineInterface.animate(getCSS('timelineInterface'), ms);
}
self.$space && self.$space.animate(getCSS('space'), ms);
}
function setSubtitle() {
@ -1033,6 +1111,39 @@ Ox.VideoPlayer = function(options, self) {
}
}
function toggleFullscreen() {
var wasPlaying;
self.options.fullscreen = !self.options.fullscreen;
if (!self.options.paused) {
self.video.pause();
wasPlaying = true;
}
if (self.options.fullscreen) {
self.$parent = that.parent();
self.offset = that.offset();
that.detach()
.css({
left: self.offset.left + 'px',
top: self.offset.top + 'px',
zIndex: 1000
})
.appendTo(Ox.UI.$body);
setSizes(function() {
wasPlaying && self.video.play();
});
} else {
setSizes(function() {
that.detach()
.css({
left: self.offset.left + 'px',
top: self.offset.top + 'px'
})
.appendTo(self.$parent);
wasPlaying && self.video.play();
});
}
}
function toggleMuted() {
self.options.muted = !self.options.muted;
self.video.muted = self.options.muted;
@ -1062,7 +1173,7 @@ Ox.VideoPlayer = function(options, self) {
if (self.options.showIcon) {
self.options.showIcon && self.$playIcon.animate({
opacity: 0
}, 250/*, togglePlayIcon()*/);
}, 250, togglePlayIcon);
}
}
}
@ -1077,7 +1188,7 @@ Ox.VideoPlayer = function(options, self) {
function toggleScale() {
self.options.scaleToFill = !self.options.scaleToFill;
self.$video.animate(getVideoCSS(), 250);
self.$video.animate(getCSS('video'), 250);
}
function toggleSize() {
@ -1088,7 +1199,9 @@ Ox.VideoPlayer = function(options, self) {
}
self.setOption = function(key, value) {
if (key == 'height' || key == 'width') {
if (key == 'fullscreen') {
toggleFullscreen();
} else if (key == 'height' || key == 'width') {
setSizes();
} else if (key == 'muted') {
toggleMuted();