The Media Element API
The media element API is a simple API that allows you to manipulate videos with simple Javascript commands. For example, normally when using the HTML5 video tags we type something like this:
1
2
3
4
|
<
video
id
=
"our-video"
width
=
"600"
height
=
"400"
controls>
<
source
src
=
"movie.mp4"
type
=
"video/mp4"
>
<
source
src
=
"movie-hd.mp4"
type
=
"video/mp4"
>
</
video
>
|
We have set controls in the video tag so this particular video will have controls (play, pause, etc). This is all well and good but sometimes we want to control the video with another (custom) player, or maybe we just want a link that makes the video play. To do this we use the Media Elements API. For example, lets say we have something like this:
1
|
<
a
href
=
"#"
class
=
"play"
>Click me to play the video!</
a
>
|
Using the Media Elements API with jQuery we can write something as simple as this to make the video play:
1
|
$(
'#our-video'
)[0].play();
|
Easy, huh? Well it’s also possible to control a variety of video aspects with the media elements API, and you can create some pretty interesting things.
Functions
There are a bunch of features as part of the media elements API which can be used to control a video or how it is displayed. Here’s a bunch of things which become useful when creating a custom player:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$(
'#our-video'
)[0].play();
// Play the video
$(
'#our-video'
)[0].pause();
// Pause the video
$(
'#our-video'
)[0].volume = 1;
// Sets volume, volume ranges from 0 to 1
$(
'#our-video'
)[0].currentTime;
// Current video time
$(
'#our-video'
)[0].duration;
// Duration of video
$(
'#our-video'
)[0].buffered;
// Amount of video buffered in seconds
if
($(
'#our-video'
)[0].canPlayType(
'video/mp4'
)) { ..
// If the video can play this type of format
$(
'#our-video'
)[0].requestFullscreen;
// (experimental) makes the video fullscreen
|
Using these simple functions and a few other tricks we’re going to combine all this to make a custom video player which you can change with just CSS.
Lets Get Started
First of all lets accustom ourselves with the HTML5 video tag. To create a new video element we just use the video tag. It’s best to use multiple video types since not all videos are supported by all browsers. Using just .webm and .mp4 will cover mostly every video type though. Miroprovides a simple method to convert files to .webm.
1
2
3
4
|
<
video
width
=
"600"
height
=
"340"
>
<
source
src
=
"big-video.mp4"
type
=
"video/mp4"
>
<
source
src
=
"movie.webm"
type
=
"video/webm"
>
</
video
>
|
The CSS
CSS is what we’re going to use to style the video. This opens up a lot of possibilities since CSS is very easy to use, and changing the style of your video, therefore, becomes very easy. For this particular video style this is the CSS I’m going to be using, so go ahead and put it in your CSS file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
|
body {
font-size
:
62.5%
;
}
.player {
background
:
#2a2a2a
;
box-sizing: border-box;
border-radius:
5px
;
height
:
70px
;
-moz-box-sizing: border-box;
float
:
left
;
font-family
:
Arial
,
sans-serif
;
position
:
absolute
;
padding
:
0
;
bottom
:
20px
;
z-index
:
2
;
opacity:
1
;
box-shadow:
0
0
10px
rgba(
0
,
0
,
0
,
0.3
);
-webkit-transition: opacity
0.3
s ease-in;
transition: opacity
0.3
s ease-in;
-moz-user-select:
none
;
-webkit-user-select:
none
;
user-select:
none
;
}
.video {
position
:
relative
;
}
.video:hover .player {
opacity:
1
;
}
.player .progress {
width
:
60%
;
height
:
20px
;
border-radius:
5px
;
background
:
#676767
;
box-shadow:
inset
0
-5px
10px
rgba(
0
,
0
,
0
,
0.1
);
float
:
left
;
cursor
:
pointer
;
margin
:
24px
0
0
0
;
padding
:
0
;
position
:
relative
;
}
.player .progress-bar {
background
:
#33b5d5
;
box-shadow:
inset
-30px
0px
69px
-20px
#89f6f5
;
border-radius:
5px
;
height
:
100%
;
position
:
relative
;
z-index
:
999
;
width
:
0
;
}
.player .button-holder {
position
:
relative
;
left
:
10px
;
}
.player .progress-button {
background
:
#fff
;
box-shadow:
0
0
20px
rgba(
0
,
0
,
0
,
0.3
);
border-radius:
30px
;
width
:
20px
;
height
:
20px
;
position
:
absolute
;
left
:
-20px
;
text-decoration
:
overline
;
}
.player [class^=
"buffered"
] {
background
: rgba(
255
,
255
,
255
,
0.1
);
position
:
absolute
;
top
:
0
;
left
:
30px
;
height
:
100%
;
border-radius:
5px
;
z-index
:
1
;
}
.player .play-pause {
display
: inline-
block
;
font-size
:
3em
;
float
:
left
;
text-shadow
:
0
0
0
#fff
;
color
: rgba(
255
,
255
,
255
,
0.8
);
width
:
10%
;
padding
:
17px
0
0
3%
;
cursor
:
pointer
;
font-variant
:
small-caps
;
}
.player .play, .player .pause-button {
-webkit-transition:
all
0.2
s ease-out;
}
.player .play .pause-button, .player .pause .play-button {
display
:
none
;
}
.player .pause-button {
padding
:
5px
2px
;
box-sizing: border-box;
-moz-box-sizing: border-box;
height
:
34px
;
}
.player .pause-button span {
background
:
#fff
;
width
:
8px
;
height
:
24px
;
float
:
left
;
display
:
block
;
}
.player .pause-button span:first-of-type {
margin
:
0
4px
0
0
;
}
.player .time {
color
:
#fff
;
font-weight
:
bold
;
font-size
:
1.2em
;
position
:
absolute
;
right
:
0
;
top
:
24px
;
}
.player .stime, .ttime {
color
:
#444
;
}
.player .play:hover {
text-shadow
:
0
0
5px
#fff
;
}
.player .play:active, .pause-button:active span {
text-shadow
:
0
0
7px
#fff
;
}
.player .pause-button:hover span {
box-shadow:
0
0
5px
#fff
;
} .player .pause-button:active span {
box-shadow:
0
0
7px
#fff
;
}
.player .volume {
position
:
relative
;
float
:
left
;
width
:
8%
;
margin
:
0
0
0
4%
;
height
:
100%
;
}
.player .volume-
icon
{
padding
:
1.5%
;
height
:
100%
;
cursor
:
pointer
;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-transition:
all
0.15
s linear;
}
.player .volume-icon-hover {
background-color
:
#4f4f4f
;
}
.player .volume-holder {
height
:
100px
;
width
:
100%
;
background
:
black
;
position
:
absolute
;
display
:
none
;
background
:
#4f4f4f
;
left
:
0
;
border-radius:
5px
5px
0
0
;
top
:
-100px
;
}
.player .volume-bar-holder {
background
:
#333
;
width
:
20px
;
box-shadow:
inset
0px
0px
5px
rgba(
0
,
0
,
0
,
0.3
);
margin
:
15px
auto
;
height
:
80px
;
border-radius:
5px
;
position
:
relative
;
cursor
:
pointer
;
}
.player .volume-button {
background
:
#fff
;
box-shadow:
0
0
20px
rgba(
0
,
0
,
0
,
0.3
);
border-radius:
30px
;
width
:
20px
;
height
:
20px
;
}
.player .volume-button-holder {
position
:
relative
;
top
:
-10px
;
}
.player .volume-bar {
background
:
#33b5d5
;
box-shadow:
inset
-30px
0px
69px
-20px
#89f6f5
;
border-radius:
5px
;
width
:
100%
;
height
:
100%
;
position
:
absolute
;
bottom
:
0
;
}
.player .fullscreen {
width
:
12%
;
cursor
:
pointer
;
float
:
left
;
height
:
100%
;
}
.player .fullscreen a {
width
:
25px
;
height
:
20px
;
border-radius:
3px
;
background
:
#fff
;
display
:
block
;
position
:
relative
;
top
:
23px
;
margin
:
0px
auto
;
}
.player .volume-
icon
span {
width
:
20%
;
height
:
13%
;
background-color
:
#fff
;
display
:
block
;
position
:
relative
;
z-index
:
1
;
font-weight
:
bold
;
top
:
40%
;
color
:
#fff
;
left
:
22%
;
}
.player .volume-
icon
span:before,
.player .volume-
icon
span:after {
content
:
''
;
position
:
absolute
;
}
.player .volume-
icon
span:before {
width
:
0
;
height
:
0
;
border
:
1em
solid
transparent
;
border-left
:
none
;
border-right-color
:
#fff
;
z-index
:
2
;
top
:
-2px
;
left
:
10%
;
margin-top
:
-40%
;
}
.player .volume-
icon
span:after {
width
:
2%
;
height
:
2%
;
border
:
1px
solid
#fff
;
left
:
190%
;
border-width
:
0px
0px
0
0
;
top
:
5px
;
border-radius:
0
50px
0
0
;
-webkit-transform: rotate(
45
deg);
-moz-transform: rotate(
45
deg);
-ms-transform: rotate(
45
deg);
-o-transform: rotate(
45
deg);
transform: rotate(
45
deg);
font-variant
:
small-caps
;
}
.player .v-change
-11
span:after {
border-width
:
10px
10px
0
0
;
top
:
0
; }
.player .v-change
-10
span:after {
border-width
:
9px
9px
0
0
;
top
:
1px
; }
.player .v-change
-9
span:after {
border-width
:
8px
8px
0
0
;
top
:
1px
; }
.player .v-change
-8
span:after {
border-width
:
7px
7px
0
0
;
top
:
2px
; }
.player .v-change
-7
span:after {
border-width
:
6px
6px
0
0
;
top
:
2px
; }
.player .v-change
-6
span:after {
border-width
:
5px
5px
0
0
;
top
:
3px
; }
.player .v-change
-5
span:after {
border-width
:
4px
4px
0
0
;
top
:
3px
; }
.player .v-change
-4
span:after {
border-width
:
3px
3px
0
0
;
top
:
4px
; }
.player .v-change
-3
span:after {
border-width
:
2px
2px
0
0
;
top
:
4px
; }
.player .v-change
-2
span:after {
border-width
:
1px
1px
0
0
;
top
:
5px
; }
.player .v-change
-1
span:after {
border-width
:
0px
0px
0
0
;
top
:
5px
; }
.player .v-change
-1
span:after {
content
:
'+'
;
-webkit-transform: rotate(
45
deg);
font-size
:
20px
;
top
:
-6px
;
left
:
25px
;
}
|
jQuery
The easiest and most succinct way to go about doing this is to use jQuery and design our code as a plugin. Don’t forget to include the jQuery file! As with all jQuery plugins, make a new Javascript file and paste in the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
(function($) {
$.fn.videoPlayer = function(options) { // videoPlayer is the name of our plugin
var settings = {
playerWidth : '0.95', // Default is 95%
videoClass : 'video' // Video Class
}
// Extend the options so they work with the plugin
if(options) {
$.extend(settings, options);
}
// For each so that we keep chainability.
return this.each(function() {
// Code goes here
});
}
})(jQuery);
|
I’ve added a few customizable options (when you run this plugin you’ll be able to change the options to whatever you want). These include the width of the player for styling purposes (by default 0.95 or95%) and the video class (in case you need to change it because of clashes). All of our code is going to go inside the return this.each(function() { });
brackets.
Now the first thing we want to do is check that the video meta data is ready to run. In some cases this will take a moment to load, so if we don’t check this we’ll end up loading the video player without any data (that wouldn’t work!). We’re also going to set some basic variables, the purpose of which will become more apparent later on.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
$(
this
)[0].addEventListener(
'loadedmetadata'
,
function
() {
// Basic Variables
var
$
this
= $(
this
);
var
$settings = settings;
// Wrap the video in a div with the class of your choosing
$
this
.wrap(
'<div class="'
+$settings.videoClass+
'"></div>'
);
// Select the div we just wrapped our video in for easy selection.
var
$that = $
this
.parent(
'.'
+$settings.videoClass);
// Some other misc variables to check when things are happening
var
$mclicking =
false
,
$vclicking =
false
,
$vidhover =
false
,
$volhover =
false
,
$playing =
false
,
$drop =
false
,
$begin =
false
,
$draggingProgess =
false
,
$storevol,
x = 0,
y = 0,
vtime = 0,
updProgWidth = 0,
volume = 0;
|
Next you want to create the structure of the player. This can be altered if you wish. We’ll also define some more variables and change the width of the player.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
// The Structure of our video player
{
$(
'<div class="player">'
+
'<div class="play-pause play">'
+
'<span class="play-button">►</span>'
+
'<div class="pause-button">'
+
'<span> </span>'
+
'<span> </span>'
+
'</div>'
+
'</div>'
+
'<div class="progress">'
+
'<div class="progress-bar">'
+
'<div class="button-holder">'
+
'<div class="progress-button"> </div>'
+
'</div>'
+
'</div>'
+
'<div class="time">'
+
'<span class="ctime">00:00</span>'
+
'<span class="stime"> / </span>'
+
'<span class="ttime">00:00</span>'
+
'</div>'
+
'</div>'
+
'<div class="volume">'
+
'<div class="volume-holder">'
+
'<div class="volume-bar-holder">'
+
'<div class="volume-bar">'
+
'<div class="volume-button-holder">'
+
'<div class="volume-button"> </div>'
+
'</div>'
+
'</div>'
+
'</div>'
+
'</div>'
+
'<div class="volume-icon v-change-0">'
+
'<span> </span>'
+
'</div>'
+
'</div>'
+
'<div class="fullscreen"> '
+
'<a href="#"> </a>'
+
'</div>'
+
'</div>'
).appendTo($that);
}
// Set the width of the video
$videoWidth = $
this
.width();
$that.width($videoWidth+
'px'
);
// Set width of the player based on previously noted settings
$that.find(
'.player'
).css({
'width'
: ($settings.playerWidth*100)+
'%'
,
'left'
: ((100-$settings.playerWidth*100)/2)+
'%'
});
// Video information
var
$spc = $(
this
)[0],
// Specific video
$duration = $spc.duration,
// Video Duration
$volume = $spc.volume,
// Video volume
currentTime;
// The width of the progress bar
var
progWidth = $that.find(
'.progress'
).width();
|
Next lets start defining some functions. The first function we’re going to define is for buffering, so the user can see what sections of the video is buffered. The second is for time setting, so the time will increase correctly. The timing function is going to be run every time the current time is updated. I’ve commented in the code so you can see exactly what is happening.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
var
bufferLength =
function
() {
// The buffered regions of the video
var
buffered = $spc.buffered;
// Rest all buffered regions everytime this function is run
$that.find(
'[class^=buffered]'
).remove();
// If buffered regions exist
if
(buffered.length > 0) {
// The length of the buffered regions is i
var
i = buffered.length;
while
(i--) {
// Max and min buffers
$maxBuffer = buffered.end(i);
$minBuffer = buffered.start(i);
// The offset and width of buffered area
var
bufferOffset = ($minBuffer / $duration) * 100;
var
bufferWidth = (($maxBuffer - $minBuffer) / $duration) * 100;
// Append the buffered regions to the video
$(
'<div class="buffered"></div>'
).css({
"left"
: bufferOffset+
'%'
,
'width'
: bufferWidth+
'%'
}).appendTo($that.find(
'.progress'
));
}
}
}
// Run the buffer function
bufferLength();
// The timing function, updates the time.
var
timeUpdate =
function
($ignore) {
// The current time of the video based on progress bar position
var
time = Math.round(($(
'.progress-bar'
).width() / progWidth) * $duration);
// The 'real' time of the video
var
curTime = $spc.currentTime;
// Seconds are set to 0 by default, minutes are the time divided by 60
// tminutes and tseconds are the total mins and seconds.
var
seconds = 0,
minutes = Math.floor(time / 60),
tminutes = Math.round($duration / 60),
tseconds = Math.round(($duration) - (tminutes*60));
// If time exists (well, video time)
if
(time) {
// seconds are equal to the time minus the minutes
seconds = Math.round(time) - (60*minutes);
// So if seconds go above 59
if
(seconds > 59) {
// Increase minutes, reset seconds
seconds = Math.round(time) - (60*minutes);
if
(seconds == 60) {
minutes = Math.round(time / 60);
seconds = 0;
}
}
}
// Updated progress width
updProgWidth = (curTime / $duration) * progWidth
// Set a zero before the number if its less than 10.
if
(seconds < 10) { seconds =
'0'
+seconds; }
if
(tseconds < 10) { tseconds =
'0'
+tseconds; }
// A variable set which we'll use later on
if
($ignore !=
true
) {
$that.find('.progress-bar
').css({'
width
' : updProgWidth+'
px
'});
$that.find('
.progress-button
').css({'
left
' : (updProgWidth-$that.find('
.progress-button
').width())+'
px
'});
}
// Update times
$that.find('
.ctime
').html(minutes+'
:
'+seconds)
$that.find('
.ttime
').html(tminutes+'
:
'+tseconds);
// If playing update buffer value
if($spc.currentTime > 0 && $spc.paused == false && $spc.ended == false) {
bufferLength();
}
}
// Run the timing function twice, once on init and again when the time updates.
timeUpdate();
$spc.addEventListener('
timeupdate', timeUpdate);
|
Next the play button! We’re going to add and remove CSS classes to make the play change to a pause button when clicked. We’ll also set a variable to check if the video is playing, which we will use later in the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// When the user clicks play, bind a click event
$that.find(
'.play-pause'
).bind(
'click'
,
function
() {
// Set up a playing variable
if
($spc.currentTime > 0 && $spc.paused ==
false
&& $spc.ended ==
false
) {
$playing =
false
;
}
else
{ $playing =
true
; }
// If playing, etc, change classes to show pause or play button
if
($playing ==
false
) {
$spc.pause();
$(
this
).addClass(
'play'
).removeClass(
'pause'
);
bufferLength();
}
else
{
$begin =
true
;
$spc.play();
$(
this
).addClass(
'pause'
).removeClass(
'play'
);
}
});
|
One of the most complicated parts of this code is the progress slider. First off we need to check when the user clicks on the progress bar and then set a variable telling us that’s what’s happening. Then when the user moves the mouse we’ll be able to adjust it so it slides appropriately. We’re going to use the same process for the volume slider, so I’ve included it here too, as well as an animation function for the volume icon, as well as a way to check if the user is hovering over the volume icon using the jQuery hover()
function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
// Bind a function to the progress bar so the user can select a point in the video
$that.find(
'.progress'
).bind(
'mousedown'
,
function
(e) {
// Progress bar is being clicked
$mclicking =
true
;
// If video is playing then pause while we change time of the video
if
($playing ==
true
) {
$spc.pause();
}
// The x position of the mouse in the progress bar
x = e.pageX - $that.find(
'.progress'
).offset().left;
// Update current time
currentTime = (x / progWidth) * $duration;
$spc.currentTime = currentTime;
});
// When the user clicks on the volume bar holder, initiate the volume change event
$that.find(
'.volume-bar-holder'
).bind(
'mousedown'
,
function
(e) {
// Clicking of volume is true
$vclicking =
true
;
// Y position of mouse in volume slider
y = $that.find(
'.volume-bar-holder'
).height() - (e.pageY - $that.find(
'.volume-bar-holder'
).offset().top);
// Return false if user tries to click outside volume area
if
(y < 0 || y > $(
this
).height()) {
$vclicking =
false
;
return
false
;
}
// Update CSS to reflect what's happened
$that.find('.volume-bar
').css({'
height
' : y+'
px
'});
$that.find('
.volume-button
').css({'
top
' : (y-($that.find('
.volume-button
').height()/2))+'
px
'});
// Update some variables
$spc.volume = $that.find('
.volume-bar
').height() / $(this).height();
$storevol = $that.find('
.volume-bar
').height() / $(this).height();
$volume = $that.find('
.volume-bar
').height() / $(this).height();
// Run a little animation for the volume icon.
volanim();
});
// A quick function for binding the animation of the volume icon
var volanim = function() {
// Check where volume is and update class depending on that.
for(var i = 0; i < 1; i += 0.1) {
var fi = parseInt(Math.floor(i*10)) / 10;
var volid = (fi * 10)+1;
if($volume == 1) {
if($volhover == true) {
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon volume-icon-hover v-change-11
');
} else {
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon v-change-11
');
}
}
else if($volume == 0) {
if($volhover == true) {
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon volume-icon-hover v-change-1
');
} else {
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon v-change-1
');
}
}
else if($volume > (fi-0.1) && volume < fi && !$that.find('
.volume-icon
').hasClass('
v-change-
'+volid)) {
if($volhover == true) {
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon volume-icon-hover v-change-
'+volid);
} else {
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon v-change-
'+volid);
}
}
}
}
// Run the volanim function
volanim();
// Check if the user is hovering over the volume button
$that.find('
.volume').hover(
function
() {
$volhover =
true
;
},
function
() {
$volhover =
false
;
});
|
Next we have to do the actual mouse moving event. There are a bunch of things that depend on mouse move so the function is quite long. For instance, if the user is dragging the mouse while holding the progress bar, the progress bar should slide. Similarly, so should the volume bar. On top of that, if the user is moving the mouse and the video is already playing, the player should disappear so it isn’t a distraction to the actual video. I’ve included the entire function below, commented so you can see what’s going on. I’ve also included a function that fixes a few problems with the play and pause button, so the correct icon is always displaying.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
// For usability purposes then bind a function to the body assuming that the user has clicked mouse
// down on the progress bar or volume bar
$(
'body, html'
).bind(
'mousemove'
,
function
(e) {
// Hide the player if video has been played and user hovers away from video
if
($begin ==
true
) {
$that.hover(
function
() {
$that.find(
'.player'
).stop(
true
,
false
).animate({
'opacity'
:
'1'
}, 0.5);
},
function
() {
$that.find(
'.player'
).stop(
true
,
false
).animate({
'opacity'
:
'0'
}, 0.5);
});
}
// For the progress bar controls
if
($mclicking ==
true
) {
// Dragging is happening
$draggingProgress =
true
;
// The thing we're going to apply to the CSS (changes based on conditional statements);
var
progMove = 0;
// Width of the progress button (a little button at the end of the progress bar)
var
buttonWidth = $that.find('.progress-button
').width();
// Updated x posititon the user is at
x = e.pageX - $that.find('
.progress
').offset().left;
// If video is playing
if($playing == true) {
// And the current time is less than the duration
if(currentTime < $duration) {
// Then the play-pause icon should definitely be a pause button
$that.find('
.play-pause
').addClass('
pause
').removeClass('
play
');
}
}
if(x < 0) { // If x is less than 0 then move the progress bar 0px
progMove = 0;
$spc.currentTime = 0;
}
else if(x > progWidth) { // If x is more than the progress bar width then set progMove to progWidth
$spc.currentTime = $duration;
progMove = progWidth;
}
else { // Otherwise progMove is equal to the mouse x coordinate
progMove = x;
currentTime = (x / progWidth) * $duration;
$spc.currentTime = currentTime;
}
// Change CSS based on previous conditional statement
$that.find('
.progress-bar
').css({'
width
' : $progMove+'
px
'});
$that.find('
.progress-button
').css({'
left
' : ($progMove-buttonWidth)+'
px
'});
}
// For the volume controls
if($vclicking == true) {
// The position of the mouse on the volume slider
y = $that.find('
.volume-bar-holder
').height() - (e.pageY - $that.find('
.volume-bar-holder
').offset().top);
// The position the user is moving to on the slider.
var volMove = 0;
// If the volume holder box is hidden then just return false
if($that.find('
.volume-holder
').css('
display
') == '
none
') {
$vclicking = false;
return false;
}
// Add the hover class to the volume icon
if(!$that.find('
.volume-icon
').hasClass('
volume-icon-hover
')) {
$that.find('
.volume-icon
').addClass('
volume-icon-hover
');
}
if(y < 0 || y == 0) { // If y is less than 0 or equal to 0 then volMove is 0.
$volume = 0;
volMove = 0;
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon volume-icon-hover v-change-11
');
} else if(y > $(this).find('
.volume-bar-holder
').height() || (y / $that.find('
.volume-bar-holder
').height()) == 1) { // If y is more than the height then volMove is equal to the height
$volume = 1;
volMove = $that.find('
.volume-bar-holder
').height();
$that.find('
.volume-icon
').removeClass().addClass('
volume-icon volume-icon-hover v-change-1
');
} else { // Otherwise volMove is just y
$volume = $that.find('
.volume-bar
').height() / $that.find('
.volume-bar-holder
').height();
volMove = y;
}
// Adjust the CSS based on the previous conditional statmeent
$that.find('
.volume-bar
').css({'
height
' : volMove+'
px
'});
$that.find('
.volume-button
').css({'
top
' : (volMove+$that.find('
.volume-button
').height())+'
px
'});
// Run the animation function
volanim();
// Change the volume and store volume
// Store volume is the volume the user last had in place
// in case they want to mute the video, unmuting will then
// return the user to their previous volume.
$spc.volume = $volume;
$storevol = $volume;
}
// If the user hovers over the volume controls, then fade in or out the volume
// icon hover class
if($volhover == false) {
$that.find('
.volume-holder
').stop(true, false).fadeOut(100);
$that.find('
.volume-icon
').removeClass('
volume-icon-hover
');
}
else {
$that.find('
.volume-icon
').addClass('
volume-icon-hover
');
$that.find('
.volume-holder
').fadeIn(100);
}
});
// When the video ends the play button becomes a pause button
$spc.addEventListener('
ended
', function() {
$playing = false;
// If the user is not dragging
if($draggingProgress == false) {
$that.find('
.play-pause
').addClass('
play
').removeClass('
pause');
}
});
|
Next is a little function that checks if the user is clicking their mouse down onto the volume icon, and if so, whether to mute the video or not. We use our stored volume so we can set the volume to the previous volume should the user unmute the video.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// If the user clicks on the volume icon, mute the video, store previous volume, and then
// show previous volume should they click on it again.
$that.find(
'.volume-icon'
).bind(
'mousedown'
,
function
() {
$volume = $spc.volume;
// Update volume
// If volume is undefined then the store volume is the current volume
if
(
typeof
$storevol ==
'undefined'
) {
$storevol = $spc.volume;
}
// If volume is more than 0
if
($volume > 0) {
// then the user wants to mute the video, so volume will become 0
$spc.volume = 0;
$volume = 0;
$that.find(
'.volume-bar'
).css({
'height'
:
'0'
});
volanim();
}
else
{
// Otherwise user is unmuting video, so volume is now store volume.
$spc.volume = $storevol;
$volume = $storevol;
$that.find(
'.volume-bar'
).css({
'height'
: ($storevol*100)+
'%'
});
volanim();
}
});
|
Next, a quick little function that resets everything when the user lets go of the mouse button:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// If the user lets go of the mouse, clicking is false for both volume and progress.
// Also the video will begin playing if it was playing before the drag process began.
// We're also running the bufferLength function
$('body, html
').bind('
mouseup',
function
(e) {
$mclicking =
false
;
$vclicking =
false
;
$draggingProgress =
false
;
if
($playing ==
true
) {
$spc.play();
}
bufferLength();
});
|
Finally we’re going to add a button that allows us to enable fullscreen mode. If the browser doesn’t support fullscreen the button will not be displayed, otherwise we just request it for every browser until one works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
// Check if fullscreen supported. If it's not just don't show the fullscreen icon.
if
(!$spc.requestFullscreen && !$spc.mozRequestFullScreen && !$spc.webkitRequestFullScreen) {
$(
'.fullscreen'
).hide();
}
// Requests fullscreen based on browser.
$(
'.fullscreen'
).click(
function
() {
if
($spc.requestFullscreen) {
$spc.requestFullscreen();
}
else
if
($spc.mozRequestFullScreen) {
$spc.mozRequestFullScreen();
}
else
if
($spc.webkitRequestFullScreen) {
$spc.webkitRequestFullScreen();
}
});
});
});
}
})(jQuery);
|
文章出处:https://www.inserthtml.com/2013/03/custom-html5-video-player/