index.html
· 5.8 KiB · HTML
Raw
<video controls style="width: 100%; margin-bottom: 24px;" src="./vid.mp4"></video>
<div class="full-seekbar">
<div class="video-timestamp">
<span id="text-live">--:--</span>
<span id="text-full">--:--</span>
</div>
<div class="seekbar">
<span class="seekbar-current-progress"></span>
<span class="seekbar-tooltip"></span>
<input id="seek" name="seekbar" type="range"/>
</div>
</div>
<style>
body {
font-family: arial,sans-serif;
}
.full-seekbar {
display: flex;
flex-direction: row-reverse;
align-items: center;
gap: 6px;
}
.video-timestamp {
background: gray;
border-radius: 3rem;
color: white;
display: flex;
flex-direction: row;
align-items: center;
width: min-content;
padding: 4px 12px 4px 4px;
font-size: 14px;
gap: 6px;
}
#text-live {
width: max-content;
background: #414141;
border-radius: 3rem;
padding: 4px 12px;
}
.seekbar {
width: 100%;
position: relative;
background: gray;
border-radius: 3rem;
height: 6px;
display: flex;
align-items: center;
}
.seekbar input {
position: absolute;
left: 0;
width: 100%;
accent-color: red;
opacity: 0;
}
.seekbar-tooltip {
position: absolute;
background: #d3d3d3;
color: black;
border-radius: 3rem;
transform: translate(-24px, 0px);
padding: 4px 8px;
font-size: 12px;
border: 6px white solid;
transition: 0.3s font-size;
}
.seekbar-current-progress {
background: red;
border-radius: 3rem;
height: 6px;
display: flex;
align-items: center;
}
</style>
<script>
// Set variables
const VideoElement = document.querySelector('video')
const SeekbarTooltip = document.querySelector('.seekbar-tooltip')
const SeekbarElementInput = document.querySelector('#seek')
const SeekbarProgressbarElement = document.querySelector('.seekbar .seekbar-current-progress')
////////////////////////////////
// Video Seekbar and Tooltip //
////////////////////////////////
// Set max attribute to the range input
VideoElement.addEventListener('loadedmetadata', () => {
const VideoMaxLength = Math.round(VideoElement.duration).toString()
SeekbarElementInput.setAttribute("max", VideoMaxLength)
})
// Update progress bar and live timestamp
function UpdateSeekbar() {
SeekbarElementInput.value = Math.floor(VideoElement.currentTime)
SeekbarProgressbarElement.style.width = VideoElement.currentTime / VideoElement.duration * 100 + '%'
SeekbarTooltip.style.left = VideoElement.currentTime / VideoElement.duration * 100 + '%'
}
// Format timestamp for Seekbar Tooltip
function TooltipFormat(Second) {
const result = new Date(Second * 1e3).toISOString().slice(11, 19)
return {
hours: result.slice(0, 2),
minutes: result.slice(3, 5),
seconds: result.slice(6, 8),
}
}
// Tooltip
function updateSeekTooltip(event) {
const skipTo = Math.round(
(event.offsetX / event.target.clientWidth) *
parseInt(event.target.getAttribute("max"), 10),
)
SeekbarElementInput.setAttribute("data-seek", skipTo.toString())
const t = TooltipFormat(skipTo)
if (t.hours === "00") {SeekbarTooltip.textContent = `${t.minutes}:${t.seconds}`}
else {SeekbarTooltip.textContent = `${t.hours}:${t.minutes}:${t.seconds}`}
const rect = SeekbarProgressbarElement.getBoundingClientRect()
SeekbarTooltip.style.left = `${event.pageX - rect.left}px`
SeekbarTooltip.style.fontSize = '12'
SeekbarElementInput.addEventListener('mouseleave', () => {
SeekbarTooltip.style.fontSize = '0'
SeekbarTooltip.style.left = VideoElement.currentTime / VideoElement.duration * 100 + '%'
})
}
// If end-users clicks anywhere on the seekbar, skip video current time to the point
SeekbarElementInput.addEventListener("mousemove", updateSeekTooltip)
function skipAhead(event) {
const skipTo = event.target.dataset.seek ? event.target.dataset.seek : event.target.value
VideoElement.currentTime = skipTo
SeekbarProgressbarElement.value = skipTo
SeekbarElementInput.value = skipTo
}
SeekbarElementInput.addEventListener("input", skipAhead)
///////////////////////////////////
// Video Duration and Timestamp //
///////////////////////////////////
// Convert the video duration to a readable format
Number.prototype.VideoReadableFormat = function () {
let seconds = Math.floor(this), hours = Math.floor(seconds / 3600)
seconds -= hours*3600
let minutes = Math.floor(seconds / 60)
seconds -= minutes*60
if (hours < 10) {hours = "0"+hours}
if (minutes < 10) {minutes = "0"+minutes}
if (seconds < 10) {seconds = "0"+seconds}
if (hours === '00') {
// Hide 'hour' if the video not over an hour long
return minutes+':'+seconds
} else {
return hours+':'+minutes+':'+seconds
}
}
// When the video is playing, automatically update the 'Current Time' text
VideoElement.addEventListener('timeupdate', Live)
VideoElement.addEventListener('timeupdate', UpdateSeekbar)
function Live() {document.getElementById('text-live').innerText = `${VideoElement.currentTime.VideoReadableFormat()}`}
// Post the video's full duration
VideoElement.onloadedmetadata = function() {document.getElementById('text-full').innerText = `${VideoElement.duration.VideoReadableFormat()}`}
</script>
1 | <video controls style="width: 100%; margin-bottom: 24px;" src="./vid.mp4"></video> |
2 | <div class="full-seekbar"> |
3 | <div class="video-timestamp"> |
4 | <span id="text-live">--:--</span> |
5 | <span id="text-full">--:--</span> |
6 | </div> |
7 | <div class="seekbar"> |
8 | <span class="seekbar-current-progress"></span> |
9 | <span class="seekbar-tooltip"></span> |
10 | <input id="seek" name="seekbar" type="range"/> |
11 | </div> |
12 | </div> |
13 | |
14 | <style> |
15 | body { |
16 | font-family: arial,sans-serif; |
17 | } |
18 | .full-seekbar { |
19 | display: flex; |
20 | flex-direction: row-reverse; |
21 | align-items: center; |
22 | gap: 6px; |
23 | } |
24 | .video-timestamp { |
25 | background: gray; |
26 | border-radius: 3rem; |
27 | color: white; |
28 | display: flex; |
29 | flex-direction: row; |
30 | align-items: center; |
31 | width: min-content; |
32 | padding: 4px 12px 4px 4px; |
33 | font-size: 14px; |
34 | gap: 6px; |
35 | } |
36 | #text-live { |
37 | width: max-content; |
38 | background: #414141; |
39 | border-radius: 3rem; |
40 | padding: 4px 12px; |
41 | } |
42 | .seekbar { |
43 | width: 100%; |
44 | position: relative; |
45 | background: gray; |
46 | border-radius: 3rem; |
47 | height: 6px; |
48 | display: flex; |
49 | align-items: center; |
50 | } |
51 | .seekbar input { |
52 | position: absolute; |
53 | left: 0; |
54 | width: 100%; |
55 | accent-color: red; |
56 | opacity: 0; |
57 | } |
58 | .seekbar-tooltip { |
59 | position: absolute; |
60 | background: #d3d3d3; |
61 | color: black; |
62 | border-radius: 3rem; |
63 | transform: translate(-24px, 0px); |
64 | padding: 4px 8px; |
65 | font-size: 12px; |
66 | border: 6px white solid; |
67 | transition: 0.3s font-size; |
68 | } |
69 | .seekbar-current-progress { |
70 | background: red; |
71 | border-radius: 3rem; |
72 | height: 6px; |
73 | display: flex; |
74 | align-items: center; |
75 | } |
76 | </style> |
77 | |
78 | <script> |
79 | // Set variables |
80 | const VideoElement = document.querySelector('video') |
81 | const SeekbarTooltip = document.querySelector('.seekbar-tooltip') |
82 | const SeekbarElementInput = document.querySelector('#seek') |
83 | const SeekbarProgressbarElement = document.querySelector('.seekbar .seekbar-current-progress') |
84 | |
85 | |
86 | //////////////////////////////// |
87 | // Video Seekbar and Tooltip // |
88 | //////////////////////////////// |
89 | // Set max attribute to the range input |
90 | VideoElement.addEventListener('loadedmetadata', () => { |
91 | const VideoMaxLength = Math.round(VideoElement.duration).toString() |
92 | SeekbarElementInput.setAttribute("max", VideoMaxLength) |
93 | }) |
94 | |
95 | // Update progress bar and live timestamp |
96 | function UpdateSeekbar() { |
97 | SeekbarElementInput.value = Math.floor(VideoElement.currentTime) |
98 | SeekbarProgressbarElement.style.width = VideoElement.currentTime / VideoElement.duration * 100 + '%' |
99 | SeekbarTooltip.style.left = VideoElement.currentTime / VideoElement.duration * 100 + '%' |
100 | } |
101 | |
102 | // Format timestamp for Seekbar Tooltip |
103 | function TooltipFormat(Second) { |
104 | const result = new Date(Second * 1e3).toISOString().slice(11, 19) |
105 | return { |
106 | hours: result.slice(0, 2), |
107 | minutes: result.slice(3, 5), |
108 | seconds: result.slice(6, 8), |
109 | } |
110 | } |
111 | |
112 | // Tooltip |
113 | function updateSeekTooltip(event) { |
114 | const skipTo = Math.round( |
115 | (event.offsetX / event.target.clientWidth) * |
116 | parseInt(event.target.getAttribute("max"), 10), |
117 | ) |
118 | SeekbarElementInput.setAttribute("data-seek", skipTo.toString()) |
119 | |
120 | const t = TooltipFormat(skipTo) |
121 | if (t.hours === "00") {SeekbarTooltip.textContent = `${t.minutes}:${t.seconds}`} |
122 | else {SeekbarTooltip.textContent = `${t.hours}:${t.minutes}:${t.seconds}`} |
123 | |
124 | const rect = SeekbarProgressbarElement.getBoundingClientRect() |
125 | SeekbarTooltip.style.left = `${event.pageX - rect.left}px` |
126 | SeekbarTooltip.style.fontSize = '12' |
127 | SeekbarElementInput.addEventListener('mouseleave', () => { |
128 | SeekbarTooltip.style.fontSize = '0' |
129 | SeekbarTooltip.style.left = VideoElement.currentTime / VideoElement.duration * 100 + '%' |
130 | }) |
131 | } |
132 | |
133 | // If end-users clicks anywhere on the seekbar, skip video current time to the point |
134 | SeekbarElementInput.addEventListener("mousemove", updateSeekTooltip) |
135 | function skipAhead(event) { |
136 | const skipTo = event.target.dataset.seek ? event.target.dataset.seek : event.target.value |
137 | VideoElement.currentTime = skipTo |
138 | SeekbarProgressbarElement.value = skipTo |
139 | SeekbarElementInput.value = skipTo |
140 | } |
141 | SeekbarElementInput.addEventListener("input", skipAhead) |
142 | |
143 | /////////////////////////////////// |
144 | // Video Duration and Timestamp // |
145 | /////////////////////////////////// |
146 | // Convert the video duration to a readable format |
147 | Number.prototype.VideoReadableFormat = function () { |
148 | let seconds = Math.floor(this), hours = Math.floor(seconds / 3600) |
149 | seconds -= hours*3600 |
150 | let minutes = Math.floor(seconds / 60) |
151 | seconds -= minutes*60 |
152 | if (hours < 10) {hours = "0"+hours} |
153 | if (minutes < 10) {minutes = "0"+minutes} |
154 | if (seconds < 10) {seconds = "0"+seconds} |
155 | if (hours === '00') { |
156 | // Hide 'hour' if the video not over an hour long |
157 | return minutes+':'+seconds |
158 | } else { |
159 | return hours+':'+minutes+':'+seconds |
160 | } |
161 | } |
162 | // When the video is playing, automatically update the 'Current Time' text |
163 | VideoElement.addEventListener('timeupdate', Live) |
164 | VideoElement.addEventListener('timeupdate', UpdateSeekbar) |
165 | function Live() {document.getElementById('text-live').innerText = `${VideoElement.currentTime.VideoReadableFormat()}`} |
166 | // Post the video's full duration |
167 | VideoElement.onloadedmetadata = function() {document.getElementById('text-full').innerText = `${VideoElement.duration.VideoReadableFormat()}`} |
168 | </script> |