Create a Seekbar like vimeo video player (HTML5) - javascript

I tried to create a HTML5 video player from scratch. But I couldn't create a seekbar that slide nicely like vimeo(or youtube).
What I did is I added a extra div/span(that highlights the total viewed time) in the seekbar. Then I added mousedown & mousemove event.
When mousedown event get called I make a var(Boolean) true. While it is true and I change the width of the div/span according to the mousemove position.
It works, but It's unresponsive. I can't slide it seamlessly. So I wanted to know how can build a responsive seekbar like vimeo(youtube is same but youtube player has a dot like a range slider, but I don't want that). I prefer pure JavaScript without any frameware or API.
My Code:
HTML
<html>
<head>
<meta charset="utf-8" />
<title>Page Title</title>
</head>
<body>
<div class="container">
<video src="http://www.treatbd.com/Assets/vid.mp4" poster=""></video>
<div class="controls">
<!-- play/pause button -->
<div class="play"></div>
<!-- the seekbar -->
<div class="line">
<div class="elapsed"></div>
</div>
<div class="screen"></div>
</div>
</div>
</body>
</html>
CSS/SASS
html, body
margin: 0
padding: 0
background-color: #272b32
.container
height: 465px
width: 808px
margin: auto
margin-top: calc(50vh - 270px)
display: flex
flex-wrap: wrap
justify-content: center
position: relative
overflow: hidden
border-radius: 1px
video
background-color: aliceblue
object-position: center
width: 100%
height: 100%
display: block
object-fit: cover
.controls
background-color: transparent
width: 100%
height: 9%
position: absolute
left: 0
right: 0
bottom: 0
display: flex
transition: visibility 750ms
.controls *
box-sizing: border-box
border-left: 1px solid deepSkyblue
.play
display: inline-block
height: 100%
width: 7%
background: rgba(16,18,20, .4)
&:hover
background: rgba(16,18,20, .6)
.screen
display: inline-block
height: 100%
width: 7%
background: rgba(16,18,20, .4)
&:hover
background: rgba(16,18,20, .6)
.volume
display: none
.line
display: inline-block
height: 100%
width: 86%
background: rgba(0, 5, 7, 0.45)
position: relative
.elapsed
position: absolute
background: rgba(78, 144, 249, 0.4)
height: 100%
width: 0%
transition: width 200ms
JavaScript
var video = document.querySelector("video");
var playButton = document.querySelector(".play");
var elapsed = document.querySelector(".elapsed");
var line = document.querySelector(".line");
var duration = video.duration;
var playing = false;
var mouseDown = false;
// the play/pause button
playButton.addEventListener("click", function() {
if (playing) video.pause();
else video.play();
playing = !playing;
});
// click on the video to play/pause
video.addEventListener("click", function() {
if (playing) video.pause();
else video.play();
playing = !playing;
});
// seekbar
line.addEventListener("mousedown", function(e) {
// set current time according to mousedown position
video.currentTime = Number(
e.layerX / (line.clientWidth / 100) * (duration / 100)
).toFixed(1);
// change the width of elapsed bar.
elapsed.style.width = video.currentTime / (duration / 100) + "%";
mouseDown = true;
});
line.addEventListener("mousemove", function(e) {
if (mouseDown) {
video.currentTime = Number(
e.layerX / (line.clientWidth / 100) * (duration / 100)
).toFixed(1);
}
});
line.addEventListener("mouseup", () => (mouseDown = false));
// to let the metadata loaded
var dt = setInterval(function() {
if (video.readyState > 0) {
duration = Number(video.duration).toFixed(2);
clearTimeout(dt);
}
}, 50);
// highgligh the amount of played time. via a elapse bar
setInterval(function() {
elapsed.style.width = video.currentTime / (duration / 100) + "%";
}, 1000);

I was changing the currentTime according to mousemove.
line.addEventListener("mousemove", function(e) {
if (mouseDown) {
video.currentTime = Number(
e.layerX / (line.clientWidth / 100) * (duration / 100)
).toFixed(1);
}
});
and leaving the width of elapse bar to the currentTime. But I'm reading currentTime in every 1s.
setInterval(function() {
elapsed.style.width = video.currentTime / (duration / 100) + "%";
}, 1000);
That's why it's not responsive. Even if I slide quickly, the width of the elapse bar will only move after another second.

set the Interval to 10 (10 milliseconds)

Related

How can I make my audio seek bar clickable and skip to where I click it?

I have a custom audio seek bar I would like to make it clickable and make the audio jump to that section.
This is my HTML code of the audio seek bar
<audio src="" preload="auto" controls id="audioPlayer" ontimeupdate="updateTrackTime(this);" style="width: 0px; visibility: hidden ;"></audio>
<div class="p-bar">
<div class="progress1" id="progress1"></div>
</div>
This is my CSS code:
.p-bar{
flex: ;
width: 25%;
height: 4px;
background: #333333;
}
.progress1 {
height:3px;
background: whitesmoke;
transition: width .1s linear;
cursor: pointer;
justify-self: left;
left: 0;
box-shadow: 1px 1px 2px white;
}
This is my JavaScript code of the seek bar:
var track = document.getElementById('audioPlayer');
var controlBtn = document.getElementById('play-pause');
var timer;
var percent = 0;
var audio = document.getElementById("audioPlayer");
audio.addEventListener("playing", function(_event) {
var duration = _event.target.duration;
advance(duration, audio);
});
audio.addEventListener("pause", function(_event) {
clearTimeout(timer);
});
var advance = function(duration, element) {
var progress = document.getElementById("progress1");
increment = 10/duration
percent = Math.min(increment * element.currentTime * 10, 100);
progress.style.width = percent+'%'
startTimer(duration, element);
}
var startTimer = function(duration, element){
if(percent < 100) {
timer = setTimeout(function (){advance(duration, element)}, 100);
}
}
You can make any HTML element clickable by using a "click" event handler. Once you're inside the click event handler, the MouseEvent passed to the handler will have about five different ways to get the x position of the mouse click, so you can determine how far left on the bar the user clicked. You may need to try a few of them to see which works for you, but I'd suggest starting with offsetX. From there you should be able to calculate the percentage to skip the media to based on the percentage along the progress item the user clicked.

make parallax mouse effect responsive using svg images HTML - SCSS

I am creating a landing page, I used svg images for the home of the site.
On the left I have a title and a button, which are in the data div, while on the left there are 3 svg images, which are in the banner-images div and have a mouse parallax effect.
Now, everything is well placed if full screen, but when I resize the page everything gets messed up.
I have problems managing the 3 images and I don't know if what I wrote is correct.
I have no preferences for the responsive layout.
document.addEventListener('mousemove', move);
function move(e) {
this.querySelectorAll('.moving-img').forEach(layer => {
const speed = layer.getAttribute('data-speed');
const x = (window.innerWidth - e.pageX * speed) / 150;
const y = (window.innerHeight - e.pageY * speed) / 150;
layer.style.transform = "translateX(" + x + "px) translateY(" + y + "px)";
})
}
/* ------------------ Imports ------------------ */
#import url("https://fonts.googleapis.com/css2?family=Rubik:wght#300;400;500;700&display=swap");
/* ------------------ Colors ------------------ */
$blackBackgroundColor: #121212;
$blackDivsColor: #0c0c0c;
$whiteText: #fff;
$whiteBackgroundColor: #fff;
$whiteDivsColor: #e9e9e9;
$blackText: #121212;
$purple: #7b49db;
/* ------------------ Fonts ------------------ */
$bodyFont: "Rubik",
sans-serif;
/* ------------------ GLOBAL ------------------ */
* {
box-sizing: border-box;
scroll-behavior: smooth;
}
body {
margin: 0;
padding: 0;
font-family: $bodyFont;
}
section {
height: 100vh;
}
h1,
p {
margin: 0;
}
a {
text-decoration: none;
}
.container {
width: 100%;
max-width: 1300px;
margin: 100% auto;
}
/* ------------------ HOME ------------------ */
#home {
width: 100%;
display: flex;
background: $whiteBackgroundColor;
.home-container {
margin: auto;
display: flex;
align-items: center;
justify-content: space-between;
.data {
color: $blackText;
.home-title {
font-size: 15vh;
margin-bottom: 20px;
}
.home-button {
display: inline-block;
background-color: $purple;
color: $whiteText;
padding: 20px 50px;
border-radius: 10px;
}
}
.banner-images {
position: relative;
width: 600px;
height: 750px;
margin-left: 20px;
img {
position: absolute;
top: 0;
left: 0;
}
#up-hand, #down-hand {
z-index: 1;
}
}
}
}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/style/main.css">
<title>Tap-it</title>
</head>
<body>
<!-- Home section -->
<section id="home">
<div class="home-container container">
<div class="data">
<h1 class="home-title">TAP-IT</h1>
Get Started
</div>
<div class="banner-images">
<img src="./assets/images/banner-up-hand.svg" alt="banner" class="moving-img" id="up-hand" data-speed="-2">
<img src="./assets/images/banner-down-hand.svg" alt="banner" class="moving-img" id="down-hand" data-speed="1">
<img src="./assets/images/banner-phone.svg" alt="banner" class="moving-img" id="phone" data-speed="-1">
</div>
</div>
</section>
</body>
</html>
I don't know how to help with the code because I used images and the snippet can't handle them, so ask me anything you need.
If you need the 3 images, I'll leave them here: https://wetransfer.com/downloads/5c47bfcc566d33497e1e1accb33e942f20210615171854/23edfa
In the pen I built of your code for testing, the only real issue I saw with smaller page widths was that a horizontal scrollbar popped in and out as the parallax changed. Let us know if there's something else not working.
To fix that, first I made the parallax distance traveled constant across different window sizes by changing the calculation from your original:
const x = (window.innerWidth - e.pageX * speed) / 150;
const y = (window.innerHeight - e.pageY * speed) / 150;
to one that takes the cursor position as a proportion of the window size:
const x = (window.innerWidth - e.pageX) / window.innerWidth * speed * 6;
const y = (window.innerHeight - e.pageY) / window.innerHeight * speed * 6;
(The factor 6 was my best effort to recreate your factor 150 as it would apply to a maximized window on a 1080p screen.)
Since the speeds are -2, 1 and -1, the furthest to the right (and thus off the page horizontally) that one of the images can be offset is now 6px. So, to ensure that the images will stay within the window, just this had to be added in CSS:
.banner-images {
/* ... */
margin-right: 6px;
}

make the video fill the screen width and and remove the frame

I have created this frame for playing the movie which resizes based on the user's screen size.
Now I want to be able to remove the frame and fill the whole width of the user screen using another function but each time I failed.
Now I'm using injectViewportSizes() function. I want a new function to do this:
remove the frame completely without affecting anything else.
stretch the width of the movie until it fills the whole width of the screen.
of course stretching the movie is much simpler for me than removing the frame ... each time I've tried to remove it the whole movie removes or a distortion occurs for the rest of the elements.
Here is the code:
const clipSource = `https://langfox.ir/movie/movieclip/My_name_is_Edward_Bloom.mp4`;
const content = document.querySelector('.content');
const box = document.getElementById("box");
let video = document.createElement('video');
content.appendChild(video);
video.id = 'clip';
let clip = document.getElementById("clip");
clip.currentTime = 0;
let source = document.createElement('source');
source.src = clipSource;
source.type = 'video/mp4';
video.appendChild(source);
video.load();
setTimeout(() => {
injectViewportSizes(); // or goFull();
clip.play();
}, 3000);
function goFull(){
// Remove the frame and make the video fill the while 'Width' of the screen
}
function injectViewportSizes(){
let screenWidth = screen.width;
let screenHeight = screen.height;
let vwPixels = screenWidth / 100;
let clipWidth = clip.videoWidth;
let clipHeight = clip.videoHeight;
screenWidth = screenWidth - (screenWidth * 0.10); // available space to put the clip inside
screenHeight = screenHeight - (screenHeight * 0.10);
let clipWidthNew;
let clipHeightNew;
if(clipWidth > clipHeight){
clipWidthNew = clipWidth;
let ratio = clipWidth / clipHeight;
while(screenWidth < clipWidthNew) {
clipWidthNew--;
}
clipHeightNew = clipWidthNew / ratio;
} else {
clipHeightNew = clipHeight;
let ratio = clipWidth / clipHeight;
while(screenHeight < clipHeightNew) {
clipHeightNew--;
}
clipWidthNew = clipHeightNew * ratio;
}
let viewPortClipWidth = clipWidthNew * (100 / document.body.clientWidth);
let viewPortClipHeight = clipHeightNew / vwPixels;
document.querySelector('.box .content').style.width = `${viewPortClipWidth}vw`;
document.querySelector('.box .content').style.height = `${viewPortClipHeight}vw`;
}
video {
position: absolute;
top: 0;
left: 0;
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
}
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #0b0e12;
}
.box {
border-radius: 0.31vh;
position: relative;
overflow: hidden;
}
.box::after {
content: '';
position: absolute;
z-index: -1;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: repeating-linear-gradient(-45deg, white 0 0.48828125vw, #f00c36 0 0.9765625vw) 0 0/1.380859375vw 1.380859375vw;
width: calc(100vw + 1.380859375vw);
height: calc(100vh + 1.380859375vw);
}
.box .content {
position: relative;
max-width: 100vw;
max-height: 100vh;
box-shadow: 0 0 0.262vh black, 0 0 0.6553vh rgba(0, 0, 0, 1), inset 0 0 0.6553vh rgba(0, 0, 0, 1);
margin: 0.45vh;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id='box' class="box">
<div class="content"></div>
</div>
</body>
</html>
Note: it seems that this code snippet can't show the original frame correctly but it works in a raw HTML file locally.

Increase and decreasing width and height of a div with set interval

I am doing this project for practice and I am achieving half the results but can't figure out how to the other half. Basically I have div1 with 0 width and 0 height inside a parent div2 with 280px width and height each with border radius of 50%. There is a sibling div3 of div1 with value inside. On clicking the div2 the div3 text converted into seconds and then set interval will run a function that increases the width and height proportionate to the seconds such that when seconds reach 0 height and width of div1 should be equal to parent div2. I am achieving this far and now I want to reassign seconds = 70 and decrease the width and height of div1 proportionally. My explanation might not be enough so please refer to the code snippet attached. Thanks for your help in advance.
var display, time, loader, width, height, reverse, seconds, running, interval;
display = document.getElementById("display");
time = document.getElementById("time");
loader = document.getElementById("loader");
width = 0;
height = 0;
reverse = false;
running = false;
seconds = parseInt(time.textContent)*60;
if ( width === 280 && height === 280 ) {
reverse = true;
time.textContent = 70;
}
display.addEventListener("click" , function(){
if ( running === false ) {
running = true;
interval = setInterval(function(){
if ( reverse === false ) {
width += (280-width)/seconds;
height += (280-height)/seconds;
}
else {
width -= (width/seconds);
height -= (height/seconds);
}
loader.style.width = Math.round(width) + "px";
loader.style.height = Math.round(height) + "px";
console.log(width + " " + height);
time.textContent = seconds;
if ( seconds > 0 ) {
seconds--;
}
},1000);
}
else {
running = false;
clearInterval(interval);
console.log("Inteval cleared");
}
});
#display {
width : 280px;
height: 280px;
border: 1px solid #5fcf80;
border-radius: 50%;
position: relative;
overflow: hidden;
font-family: sans-serif;
cursor: pointer;
}
#time {
font-size: 120px;
text-align: center;
line-height: 280px;
position: relative;
z-index: 9;
}
#loader {
z-index: 1;
width: 40px;
height: 40px;
background: #5fcf80;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="display">
<div id="time">1</div>
<div id="loader"></div>
</div>
</body>
</html>
There are some mistakes in your code:
1- The following if clause is useless because its contents never executes:
if ( width >= 280 && height >= 280 ) {
reverse = true;
time.textContent = 70;
}
It never executes because this if is outside addEventListener and setInterval. It will run one time at the beginning, when width and height are still 0.
2- The following code should be at the beginning of setInterval:
if ( seconds > 0 ) {
seconds--;
The reason is, imagine what happens when seconds reaches 0:
These lines will be executed: width += (280-width)/seconds and height += (280-height)/seconds.
seconds is 0, so a division by zero will happen!
width and height will be NaN (Not a Number).
3- The code in (2) should be:
if ( seconds > 1 ) {
seconds--;
} else if ( seconds == 1 ){
reverse = reverse ? false : true;
seconds = 70;
}
first, we check if seconds is above 1 not 0, to stop seconds from being 0, and in that case, we decrease by 1.
If seconds is 1, then we've reached the max (or min) width and height.
In this case, if we are increasing, we will reverse, and vice versa.
In addition, we will reset seconds to 70 based on your specification.
4- Based on the above changes, the initial value of seconds should be 61, not 60:
seconds = parseInt(time.textContent)*61;
That's because we will decrease seconds right away in the beginning of addEventListener.
Here is a working modified version on JSFiddle

How to simulate rays emerging from an image/div to another image/div using HTML and CSS

I want to build a page to show a blown-up version of an image.
I have the smaller image and the bigger image built out. I am not sure how to build the in between portion that looks like rays coming out of the smaller image.
HTML
<div class="flex">
<div class="exp" tabindex="0">
<img class="image" src="http://via.placeholder.com/50x50">
</div>
<div class="big-image">
<img class="image" src="http://via.placeholder.com/350x550">
</div>
</div>
CSS
.exp {
margin: 5px;
width: 100px;
height: 100px;
background-color: #ded3c0;
border-radius: 100%;
line-height: 80px;
align-items: center;
display: flex;
justify-content: center;
}
.exp .image {
width: 50px;
height: 50px;
}
.big-image {
border: 1px solid #000;
padding: 20px;
border-radius: 19px;
}
.flex {
display: flex;
align-items: center;
justify-content: space-around;
}
Any pointers on how to do this is helpful.
Here is jsfiddle https://jsfiddle.net/npkeq7ut/
If you need only lines you can achieve this with JS and skew transform:
let topLine = document.getElementById('top-line');
let bottomLine = document.getElementById('bottom-line');
function updateLines()
{
let b = document.getElementById('b').getBoundingClientRect();
let a = document.getElementById('a').getBoundingClientRect();
let left = a.right;
let width = b.left - a.right;
let tHeight = a.top - b.top;
let tTop = tHeight / 2 + b.top;
let tAngle = Math.atan(tHeight / width) * 180 / Math.PI;
let bHeight = b.bottom - a.bottom;
let bTop = bHeight / 2 + a.bottom - bottomLine.offsetHeight;
let bAngle = Math.atan(bHeight / width) * 180 / Math.PI;
topLine.style.top = tTop + "px";
topLine.style.left = left + "px";
topLine.style.width = width + "px";
topLine.style.transform = "skewY("+(-tAngle)+"deg)";
bottomLine.style.top = bTop + "px";
bottomLine.style.left = left + "px";
bottomLine.style.width = width + "px";
bottomLine.style.transform = "skewY("+(bAngle)+"deg)";
}
updateLines();
Fiddle: https://jsfiddle.net/JacobDesight/f40yeuqe/2/
#EDIT
If you want trapeze with background then here is example using canvas: https://jsfiddle.net/JacobDesight/f40yeuqe/3/
This could be a starting point for you.
Code by thecodeplayer.
http://thecodeplayer.com/walkthrough/magnifying-glass-for-images-using-jquery-and-css3
$(document).ready(function() {
var native_width = 0;
var native_height = 0;
//Now the mousemove function
$(".magnify").mousemove(function(e) {
//When the user hovers on the image, the script will first calculate
//the native dimensions if they don't exist. Only after the native dimensions
//are available, the script will show the zoomed version.
if (!native_width && !native_height) {
//This will create a new image object with the same image as that in .small
//We cannot directly get the dimensions from .small because of the
//width specified to 200px in the html. To get the actual dimensions we have
//created this image object.
var image_object = new Image();
image_object.src = $(".small").attr("src");
//This code is wrapped in the .load function which is important.
//width and height of the object would return 0 if accessed before
//the image gets loaded.
native_width = image_object.width;
native_height = image_object.height;
} else {
//x/y coordinates of the mouse
//This is the position of .magnify with respect to the document.
var magnify_offset = $(this).offset();
//We will deduct the positions of .magnify from the mouse positions with
//respect to the document to get the mouse positions with respect to the
//container(.magnify)
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
//Finally the code to fade out the glass if the mouse is outside the container
if (mx < $(this).width() && my < $(this).height() && mx > 0 && my > 0) {
$(".large").fadeIn(100);
} else {
$(".large").fadeOut(100);
}
if ($(".large").is(":visible")) {
//The background position of .large will be changed according to the position
//of the mouse over the .small image. So we will get the ratio of the pixel
//under the mouse pointer with respect to the image and use that to position the
//large image inside the magnifying glass
var rx = Math.round(mx / $(".small").width() * native_width - $(".large").width() / 2) * -1;
var ry = Math.round(my / $(".small").height() * native_height - $(".large").height() / 2) * -1;
var bgp = rx + "px " + ry + "px";
//Time to move the magnifying glass with the mouse
var px = mx - $(".large").width() / 2;
var py = my - $(".large").height() / 2;
//Now the glass moves with the mouse
//The logic is to deduct half of the glass's width and height from the
//mouse coordinates to place it with its center at the mouse coordinates
//If you hover on the image now, you should see the magnifying glass in action
$(".large").css({
left: px,
top: py,
backgroundPosition: bgp
});
}
}
})
})
/*Some CSS*/
* {
margin: 0;
padding: 0;
}
.magnify {
width: 200px;
margin: 50px auto;
position: relative;
}
/*Lets create the magnifying glass*/
.large {
width: 175px;
height: 175px;
position: absolute;
border-radius: 100%;
/*Multiple box shadows to achieve the glass effect*/
box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
/*Lets load up the large image first*/
background: url('http://thecodeplayer.com/uploads/media/iphone.jpg') no-repeat;
/*hide the glass by default*/
display: none;
}
/*To solve overlap bug at the edges during magnification*/
.small {
display: block;
}
<!-- Lets make a simple image magnifier -->
<div class="magnify">
<!-- This is the magnifying glass which will contain the original/large version -->
<div class="large"></div>
<!-- This is the small image -->
<img class="small" src="http://thecodeplayer.com/uploads/media/iphone.jpg" width="200"/>
</div>
<!-- Lets load up prefixfree to handle CSS3 vendor prefixes -->
<script src="http://thecodeplayer.com/uploads/js/prefixfree.js" type="text/javascript"></script>
<!-- You can download it from http://leaverou.github.com/prefixfree/ -->
<!-- Time for jquery action -->
<script src="http://thecodeplayer.com/uploads/js/jquery-1.7.1.min.js" type="text/javascript"></script>

Categories