Highlight player seekbar in HTML5 video - javascript

I have a customized seekbar for my HTML5 video player. But I need to highlight some predefined portions of the seekbar, say seconds 2-5 and 7-8. How can I do that?
Basically, I need it to be something like this:
Here is my simple code so far:
<!DOCTYPE html>
<html>
<head>
<style>
.body{
background-color:black;
}
.video-player {
position: relative;
width: 66%;
height: 66%;
}
.video-player img {
width: 100%;
height: 100%;
}
.video-player video {
position: fixed;
top: 0;
left: 0;
min-width: 66%;
min-height: 66%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
.video-player .controls {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.video-player .controls .progress-bar {
position: absolute;
margin-left: 28%;
bottom: 10%;
color: orange;
font-size: 12px;
width: 40%;
height: 8%;
border: none;
background: #434343;
border-radius: 9px;
vertical-align: middle;
cursor: pointer;
}
.video-player .controls progress::-moz-progress-bar {
color: orange;
background: #434343;
}
.video-player .controls progress[value]::-webkit-progress-bar {
background-color: #434343;
border-radius: 2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
}
.video-player .controls progress[value]::-webkit-progress-value {
background-color: orange;
}
video#backgroundvid {
position: absolute;
right: 0;
bottom: 0;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div class="video-player">
<video preload="auto" autoplay loop id="backgroundvid">
<source src="mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<img src="top2.png" style="object-fit:cover" alt="" id="backgroundvid">
<div class="controls">
<progress class="progress-bar" style="object-fit:cover; z-index=10000" min="0" max="100" value="0">0% played</progress>
</div>
</div>
<script>
const player = document.querySelector('.video-player');
const video = player.querySelector('video');
const progressBar = player.querySelector('.progress-bar');
video.addEventListener('timeupdate', updateProgressBar, false);
progressBar.addEventListener('click', seek);
function updateProgressBar() {
var percentage = Math.floor((100 / video.duration) * video.currentTime);
progressBar.value = percentage;
progressBar.innerHTML = percentage + '% played';
}
function seek(e) {
let percent = e.offsetX / this.offsetWidth;
video.currentTime = percent * video.duration;
e.target.value = Math.floor(percent / 100);
e.target.innerHTML = progressBar.value + '% played';
}
</script>
</body>
</html>

You can use a canvas that you will superimpose on top of your progress-bar,
Then you will have just to draw the markers in this canvas.
Just making slight changes in the html (adding an id to the progress-bar id="progress-bar"):
<progress id="progress-bar" class="progress-bar" style="object-fit:cover; z-index=10000" min="0" max="100" value="0">0% played</progress>
Adding the CSS to style place the canvas (same CSS property than your progress-bar)
#markers{
position: absolute;
bottom: 10%;
margin-left: 28%;
border-radius: 9px;
pointer-events: none;
}
Note the pointer-events: none; If you don't put it, you can't have access to the control of your progress-bar.
And so, the javascript to create & insert the canvas, and then place the markers on it.
// We need the metadata 'duration', so we wrap the code in an event listener to be sure we execute our code when the metadata is loaded
video.addEventListener('loadedmetadata', function () {
// Get the dimension of the progress-bar
const progressbar = document.getElementById('progress-bar');
const widthProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("width");
const heightProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("height");
// Create the canvas
const canvas = document.createElement('canvas');
const w = canvas.width = parseFloat(widthProgressBar);
const h = canvas.height = parseFloat(heightProgressBar);
canvas.id = 'markers';
const progressBar = document.getElementById("progress-bar");
// Insert the canvas in the DOM
progressBar.parentNode.insertBefore(canvas, progressBar.nextSibling)
// Define the context
const ctx = canvas.getContext('2d');
// Calcul how many px will represent 1s
const videoDuration = video.duration;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
// Define the markers
const markers = {
'marker1': [2, 5],
'marker2': [7, 8]
};
// Function to draw the markers
function setMarkers(markers, ratioPxSec, height) {
for (marker in markers) {
let x = markers[marker][0] * ratioPxSec; // Start x position of the marker
let y = 0; // Start y position of the marker
let w = (markers[marker][1] - markers[marker][0]) * ratioPxSec; // Width of the marker
let h = parseFloat(height); // Height of the marker
ctx.fillStyle = "#7f3302"; // Set the color of the marker
ctx.fillRect(x, y, w, h); // Draw a rectangle
}
}
setMarkers(markers, ratioPxBySeconds, h); // Call the function
});
const player = document.querySelector('.video-player');
const video = player.querySelector('video');
const progressBar = player.querySelector('.progress-bar');
video.addEventListener('timeupdate', updateProgressBar, false);
progressBar.addEventListener('click', seek);
function updateProgressBar() {
var percentage = Math.floor((100 / video.duration) * video.currentTime);
progressBar.value = percentage;
progressBar.innerHTML = percentage + '% played';
}
function seek(e) {
let percent = e.offsetX / this.offsetWidth;
video.currentTime = percent * video.duration;
e.target.value = Math.floor(percent / 100);
e.target.innerHTML = progressBar.value + '% played';
}
// We need the metadata 'duration', so we wrap the code in an event listener to be sure we execute our code when the metadata is loaded
video.addEventListener('loadedmetadata', function() {
// Get the dimension of the progress-bar
const progressbar = document.getElementById('progress-bar');
const widthProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("width");
const heightProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("height");
// Create the canvas
const canvas = document.createElement('canvas');
const w = canvas.width = parseFloat(widthProgressBar);
const h = canvas.height = parseFloat(heightProgressBar);
canvas.id = 'markers';
const progressBar = document.getElementById("progress-bar");
// Insert the canvas in the DOM
progressBar.parentNode.insertBefore(canvas, progressBar.nextSibling)
// Define the context
const ctx = canvas.getContext('2d');
// Calcul how many px will represent 1s
const videoDuration = video.duration;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
// Define the markers
const markers = {
'marker1': [2, 5],
'marker2': [7, 8]
};
// Function to draw the markers
function setMarkers(markers, ratioPxSec, height) {
for (marker in markers) {
let x = markers[marker][0] * ratioPxSec; // Start x position of the marker
let y = 0; // Start y position of the marker
let w = (markers[marker][1] - markers[marker][0]) * ratioPxSec; // Width of the marker
let h = parseFloat(height); // Height of the marker
ctx.fillStyle = "rgb(127, 51, 2, 0.9)"; // Set the color of the marker
ctx.fillRect(x, y, w, h); // Draw a rectangle
}
}
setMarkers(markers, ratioPxBySeconds, h); // Call the function
// Calculate the new dimensions & redraw
function resize(){
const progressBar = document.getElementById('progress-bar');
const w = canvas.width = progressBar.clientWidth;
const h = canvas.height = progressBar.clientHeight;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
setMarkers(markers, ratioPxBySeconds, h);
}
// On page resize, call the resize() function
window.addEventListener("resize", resize, false);
});
body {
background-color: black;
}
.video-player {
position: relative;
width: 66%;
height: 66%;
}
.video-player img {
width: 100%;
height: 100%;
}
.video-player video {
position: fixed;
top: 0;
left: 0;
min-width: 66%;
min-height: 66%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
.video-player .controls {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.video-player .controls .progress-bar {
position: absolute;
margin-left: 28%;
bottom: 10%;
color: orange;
font-size: 12px;
width: 40%;
height: 8%;
border: none;
background: #434343;
border-radius: 9px;
vertical-align: middle;
cursor: pointer;
}
#markers {
position: absolute;
bottom: 10%;
margin-left: 28%;
border-radius: 9px;
pointer-events: none;
}
.video-player .controls progress::-moz-progress-bar {
color: orange;
background: #434343;
}
.video-player .controls progress[value]::-webkit-progress-bar {
background-color: #434343;
border-radius: 2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
}
.video-player .controls progress[value]::-webkit-progress-value {
background-color: orange;
}
video#backgroundvid {
position: absolute;
right: 0;
bottom: 0;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
<div class="video-player">
<video preload="auto" autoplay loop id="backgroundvid">
<source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<img src="https://i.stack.imgur.com/gmK7P.png" style="object-fit:cover" alt="" id="backgroundvid">
<div class="controls">
<progress id="progress-bar" class="progress-bar" style="object-fit:cover; z-index=10000" min="0" max="100" value="0">0% played</progress>
</div>
</div>
Edit:
Added a resize() function to update the markers when the screen resize
(typically, it will happen when you put the video in full screen)
// Calculate the new dimensions & redraw
function resize(){
const progressBar = document.getElementById('progress-bar');
const w = canvas.width = progressBar.clientWidth;
const h = canvas.height = progressBar.clientHeight;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
setMarkers(markers, ratioPxBySeconds, h);
}
// On page resize, call the resize() function
window.addEventListener("resize", resize, false);

Related

Making a Javascript music app based on tutorial, hit roadblock

I am currently trying to create a music app based on the following video: https://youtu.be/OafpiyPa63I?t=13127
I am at the linked timestamp, and I have written the code exactly as shown in the video, but for some reason, when I try to seek, the input is set back to 0 and therefore so is the song. My code for this part:
let currentStart = document.getElementById('currentStart');
let currentEnd = document.getElementById('currentEnd');
let seek = document.getElementById('seek');
let bar2 = document.getElementById('bar2');
let dot = document.getElementsByClassName('dot')[0];
music.addEventListener('timeupdate', () => {
let music_curr = music.currentTime;
let music_dur = music.duration;
let min1 = Math.floor(music_dur / 60);
let sec1 = Math.floor(music_dur % 60);
if (sec1 < 10) {
sec1 = `0${sec1}`;
};
currentEnd.innerText = `${min1}:${sec1}`;
let min2 = Math.floor(music_curr / 60);
let sec2 = Math.floor(music_curr % 60);
if (sec2 < 10) {
sec2 = `0${sec2}`;
};
currentStart.innerText = `${min2}:${sec2}`;
let progressBar = parseInt((music_curr / music_dur) * 100);
seek.value = progressBar;
let seekbar = seek.value;
bar2.style.width = `${seekbar}%`;
dot.style.left = `${seekbar}%`;
});
seek.addEventListener('change', () => {
music.currentTime = seek.value * music.duration / 100;
});
<div class="bar">
<input type="range" id="seek" min="0" max="100">
<div class="bar2" id="bar2"></div>
<div class="dot"></div>
</div>
header .master_play .bar {
position: relative;
width: 43%;
height: 2px;
background: rgb(105,105,170,.1);
margin: 0px 15px 0px 10px;
}
header .master_play .bar .bar2 {
position: absolute;
background: #36e2ec;
width: 0%;
height: 100%;
top: 0;
transition: 1s linear;
}
header .master_play .bar .dot {
position: absolute;
width: 5px;
height: 5px;
background: #36e2ec;
border-radius: 50%;
left: 0%;
top: -1.5px;
transition: 1s linear;
}
header .master_play .bar .dot::before {
content: '';
position: absolute;
width: 15px;
height: 15px;
border: 1px solid #36e2ec;
border-radius: 50%;
left: -6.5px;
top: -6.5px;
box-shadow: inset 0px 0px 3px #36e2ec;
}
header .master_play .bar input {
position: absolute;
width: 100%;
top: -7px;
left: 0;
cursor: pointer;
z-index: 999999999999;
opacity: .5;
}
I'm not sure if I am in the wrong, or if the tutorial is outdated.
I figured out it was the platform I was running the code on. Somewhere it had clashed, so I was able to move it to a new host and it worked.

Add disappearing circle element to click function

I have a page where circles randomly appear in a certain place.
When you click on the circle, it disappears.
So, I have another circle-smoke, and I want that when the clicked circle disappears, this circle with the circle-smoke class appears in its place, and also dissolves in just a second.
I tried to add new element creation to my click function, but it didn't work
let div1 = document.createElement('div');
div1.classList.add("circle-smoke");
Isn’t it possible for the smoky circle to hold on a little more and steam out? The first one quickly disappeared.
In general, the whole point is to remain like this in the place of the disappearing circle, and then also disappear
How can I best implement this?
//create circle
var clickEl = document.getElementById("clicks");
var spawnRadius = document.getElementById("spawnRadius");
var spawnArea = spawnRadius.getBoundingClientRect();
const circleSize = 95; // Including borders
function createDiv(id, color) {
let div = document.createElement('div');
div.setAttribute('class', id);
if (color === undefined) {
let colors = ['#ebc6df', '#ebc6c9', '#e1c6eb', '#c6c9eb', '#c6e8eb', '#e373fb', '#f787e6', '#cb87f7', '#87a9f7', '#87f7ee'];
randomColor = colors[Math.floor(Math.random() * colors.length)];
div.style.borderColor = randomColor;
}
else {
div.style.borderColor = color;
}
// Randomly position circle within spawn area
div.style.top = `${Math.floor(Math.random() * (spawnArea.height - circleSize))}px`;
div.style.left = `${Math.floor(Math.random() * (spawnArea.width - circleSize))}px`;
div.classList.add("circle", "animation");
// Add click handler
let clicked = false;
div.addEventListener('click', (event) => {
if (clicked) { return; } // Only allow one click per circle
clicked = true;
div.style.animation = 'Animation 200ms linear forwards';
setTimeout(() => { spawnRadius.removeChild(div); }, 220);
});
spawnRadius.appendChild(div);
}
let i = 0;
const rate = 3000;
setInterval(() => {
i += 1;
createDiv(`circle${i}`);
}, rate);
html, body {
width: 100%;
height: 100%;
margin: 0;
background: #0f0f0f;
}
.circle {
width: 80px;
height: 80px;
border-radius: 80px;
background-color: #0f0f0f;
border: 3px solid #000;
position: absolute;
}
#spawnRadius {
top: 55%;
height: 250px;
width: 500px;
left: 50%;
white-space: nowrap;
position: absolute;
transform: translate(-50%, -50%);
background: #0f0f0f;
border: 2px solid #ebc6df;
}
#keyframes Animation {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(.8);
}
100% {
transform: scale(1);
opacity: 0;
}
}
.circle-smoke {
position: relative;
height: 500px;
width: 500px;
filter: url(#wave);
transform: scale(0.3);
}
.circle-smoke::before {
content: "";
position: absolute;
top: 100px;
left: 100px;
right: 100px;
bottom: 100px;
border: 10px solid #fff;
border-radius: 50%;
box-shadow: 0 0 50px #ebc6df, inset 0 0 50px #ebc6df;
filter: url(#wave) blur(10px);
}
svg {
display: none;
}
<html>
<body>
<div id="spawnRadius"></div>
</body>
</html>
My quick and dirty solution is here (the filters were disabled and the rate was increased for debugging purposes):
//create circle
var clickEl = document.getElementById("clicks");
var spawnRadius = document.getElementById("spawnRadius");
var spawnArea = spawnRadius.getBoundingClientRect();
const circleSize = 95; // Including borders
function createDiv(id, color, isSmoke) {
let div = document.createElement('div');
div.setAttribute('class', id);
if (!isSmoke) {
if (color === undefined) {
let colors = ['#ebc6df', '#ebc6c9', '#e1c6eb', '#c6c9eb', '#c6e8eb', '#e373fb', '#f787e6', '#cb87f7', '#87a9f7', '#87f7ee'];
randomColor = colors[Math.floor(Math.random() * colors.length)];
div.style.borderColor = randomColor;
} else {
div.style.borderColor = color;
}
}
// Randomly position circle within spawn area
div.style.top = `${Math.floor(Math.random() * (spawnArea.height - circleSize))}px`;
div.style.left = `${Math.floor(Math.random() * (spawnArea.width - circleSize))}px`;
div.classList.add("circle", "animation");
// Add click handler
let clicked = false;
if (!isSmoke) {
div.addEventListener('click', (event) => {
if (clicked) {
return;
} // Only allow one click per circle
clicked = true;
div.style.animation = 'Animation 200ms linear forwards';
setTimeout(() => {
spawnRadius.removeChild(div);
}, 220);
let newDiv = createDiv(id, color, true);
newDiv.style.top = div.style.top;
newDiv.style.left = div.style.left;
newDiv.classList.add("circle-smoke");
newDiv.classList.remove("circle");
newDiv.id = null;
});
} else {
div.style.animation = 'Animation 500ms linear forwards';
setTimeout(() => {
spawnRadius.removeChild(div);
}, 220);
}
spawnRadius.appendChild(div);
return div;
}
let i = 0;
const rate = 1000;
setInterval(() => {
i += 1;
createDiv(`circle${i}`);
}, rate);
html,
body {
width: 100%;
height: 100%;
margin: 0;
background: #0f0f0f;
}
.circle {
width: 80px;
height: 80px;
border-radius: 80px;
background-color: #0f0f0f;
border: 3px solid #000;
position: absolute;
}
#spawnRadius {
top: 55%;
height: 250px;
width: 500px;
left: 50%;
white-space: nowrap;
position: absolute;
transform: translate(-50%, -50%);
background: #0f0f0f;
border: 2px solid #ebc6df;
}
#keyframes Animation {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(.8);
}
100% {
transform: scale(1);
opacity: 0;
}
}
.circle-smoke {
position: absolute;
margin: -5px;
height: 80px;
width: 80px;
border: 10px solid rgba(255, 255, 255, .5);
border-radius: 50%;
box-shadow: 0 0 50px #ebc6df, inset 0 0 50px #ebc6df;
//filter: url(#wave) blur(10px);
}
svg {
display: none;
}
<html>
<body>
<div id="spawnRadius"></div>
</body>
</html>
We can animate box-shadow:
let noOfCircles = 0;
const totalCircles = 10;
const colors = ['#ebc6df', '#ebc6c9', '#e1c6eb', '#c6c9eb', '#c6e8eb', '#e373fb', '#f787e6', '#cb87f7', '#87a9f7', '#87f7ee'];
const circleSize = 95; // Including borders
let i = 0;
const rate = 1000;
const clickEl = document.getElementById("clicks");
const spawnRadius = document.getElementById("spawnRadius");
const spawnArea = spawnRadius.getBoundingClientRect();
function createDiv(id, color) {
let div = document.createElement('div');
div.classList.add("circle", id);
if (!color)
color = colors[Math.floor(Math.random() * colors.length)];
div.style.setProperty('--bStart', color);
// Randomly position circle within spawn area
div.style.top = `${(Math.floor(Math.random() * spawnArea.height + circleSize)) % (spawnArea.height - circleSize)}px`;
div.style.left = `${(Math.floor(Math.random() * spawnArea.width + circleSize)) % (spawnArea.width - circleSize)}px`;
// Add click handler
div.addEventListener('click', (event) => {
div.style.setProperty('border-color', color+'ee');
div.style.setProperty('pointer-events', 'none');
div.classList.add("circle-smoke");
setTimeout(() => {
spawnRadius.removeChild(div);
noOfCircles--;
}, 1500);
}, { once: true });
spawnRadius.appendChild(div);
noOfCircles++;
}
setInterval(() => {
if (noOfCircles >= totalCircles) return;
createDiv(`circle${++i}`);
}, rate);
*{
box-sizing:border-box;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background: #0f0f0f;
}
.circle {
--bStart: #fff;
width: 80px;
height: 80px;
border-radius: 50%;
background-color: transparent;
border: 3px solid var(--bStart);
position: absolute;
}
#spawnRadius {
height: 100vh;
width: 100vw;
background: #0f0f0f;
border: 2px solid #ebc6df;
}
#keyframes Animation {
0% {
box-shadow: 0 0 0px 0px var(--bStart), inset 0 0 0px 0px var(--bStart);
opacity: 1;
}
100% {
box-shadow: 0 0 30px 25px #0000, inset 0 0 30px 25px #0000;
border-color: #0000;
opacity: 0;
}
}
.circle-smoke {
animation: Animation 1.5s linear forwards;
}
<div id="spawnRadius"></div>
{ once: true } removes the click event handler after one click.
div.style.setProperty('pointer-events', 'none') this allows us to click on multiple circles that are on top of each other.
For the demo I am allowing only 10 circles at a time.

How to rotate a box div while dragging an element using jquery

I understand that we need to use transform: rotate(ndeg); in order to rotate a specific element in CSS. In this case, I want to do it dynamically. Using jQuery, I want to rotate the box/container div when the user drags the handle (the red background) on n degrees as the user wishes. Is it possible in jQuery?
body {
padding: 50px;
}
.box_element {
border: 1px solid black;
width: 200px;
height: 200px;
position: relative;
z-index: -1;
}
.handle {
position: absolute;
bottom: -10px;
right: -10px;
width: 10px;
height: 10px;
border: 1px solid;
background: red;
z-index: 10;
}
<body>
<div class="box_element">
THIS IS TEST
<div class="handle"></div>
</div>
</body>
Here you need to write few code to make it possible, try live code https://codepen.io/libin-prasanth/pen/xxxzbLg
var stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI;
function start(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x,
y;
center = {
x: l + w / 2,
y: t + h / 2
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return (active = true);
}
function rotate(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return (rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)");
}
function stop() {
angle += rotation;
return (active = false);
}
rot = document.getElementById("draggable");
rot.addEventListener("mousedown", start, false);
window.addEventListener("mousemove", function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
window.addEventListener("mouseup", function(event) {
event.preventDefault();
stop(event);
});
#draggable {
left: 50px;
top: 50px;
width: 100px;
height: 100px;
position: relative;
border: 1px solid #000;
}
#draggable:before{
content: "";
position: absolute;
bottom: -5px;
right: -5px;
width: 10px;
height: 10px;
background: #f00;
}
<div id="draggable">
</div>
You can make use of a css-variable and then change the value of the variable when clicked.
const box_element = document.getElementById('box_element');
const handle = document.getElementById('handle');
handle.addEventListener('click', function() {
let currentVal = getComputedStyle(box_element).getPropertyValue('--rotate_deg');
box_element.style.setProperty(
'--rotate_deg', ((parseInt(currentVal.replace('deg', '')) + 90) % 360) + 'deg');
});
:root {
--rotate_deg: 0deg;
}
.box_element {
margin: 1em;
border: 1px solid black;
width: 100px;
height: 100px;
position: relative;
z-index: -1;
transform: rotate(var(--rotate_deg))
}
.handle {
position: absolute;
bottom: -10px;
right: -10px;
width: 10px;
height: 10px;
border: 1px solid;
background: red;
z-index: 10;
cursor: pointer;
}
<div class="box_element" id="box_element">
THIS IS TEST
<div class="handle" id="handle"></div>
</div>

JavaScript Moving transition without the use of CSS

I'm using a small script to follow the cursor with a div element.
This script makes the element strictly follow the cursor.
What I'm trying to do is to add some kind of duration to the process of "following" the cursor. I tried CSS transitions but the animation always ended up breaking. Can somebody please help me with this?
Let's say mouse is somewhere, and then it changes position by around 100px. I want to specify the duration like if i was using CSS... But the thing is that I can not use any transitions but only some javascript magic instead...
document.body.addEventListener("mousemove", function(e) {
var curX = e.clientX;
var curY = e.clientY;
document.querySelector('mouse').style.left = curX - 10 + 'px';
document.querySelector('mouse').style.top = curY - 10 + 'px';
});
body {
background: #333;
height: 500px;
width: 500px;
}
mouse {
display: block;
position: fixed;
height: 20px;
width: 20px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
I was wondering how to add a transition without using the CSS but I'm not the most advanced when it comes to JavaScript.
[edit] : I don't wanna use window.setTimeout.
[edit 2] : I wanted to use transition: 0.1s; but as I said it broke the effect when user moved the mouse too quickly.
There's a whole bunch of ways to do this, as you can see in the other answers, each with its own "feel". I'm just adding one more, where the dot approaches the cursor by a percentage of the remaining distance.
let curX = 0, curY = 0, elemX = null, elemY = null;
document.body.addEventListener("mousemove", function(e) {
curX = e.clientX;
curY = e.clientY;
if (elemX === null) [ elemX, elemY ] = [ curX, curY ];
});
let amt = 0.1; // higher amount = faster tracking = quicker transition
let elem = document.querySelector('mouse');
let frame = () => {
requestAnimationFrame(frame);
elemX = (elemX * (1 - amt)) + (curX * amt);
elemY = (elemY * (1 - amt)) + (curY * amt);
elem.style.left = `${elemX}px`;
elem.style.top = `${elemY}px`;
};
frame();
body {
position: absolute;
background: #333;
left: 0; top: 0; margin: 0; padding: 0;
height: 100%;
width: 100%;
}
mouse {
display: block;
position: absolute;
height: 20px; margin-left: -10px;
width: 20px; margin-top: -10px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
You can use setTimeout() function, to introduce a delay:
document.body.addEventListener("mousemove", function(e) {
var delay=250 //Setting the delay to quarter of a second
setTimeout(()=>{
var curX = e.clientX;
var curY = e.clientY;
document.querySelector('mouse').style.left = curX - 10 + 'px';
document.querySelector('mouse').style.top = curY - 10 + 'px';
},delay)
});
body {
background: #333;
height: 500px;
width: 500px;
}
mouse {
display: block;
position: fixed;
height: 20px;
width: 20px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
Or, to avoid trailing, use an interval and move the cursor to the correct direction (change ratio to set the speed ratio):
var curX,curY
document.body.addEventListener("mousemove", function(e) {
curX = e.clientX;
curY = e.clientY;
});
setInterval(()=>{
var ratio=5
var x=document.querySelector('mouse').offsetLeft+10
var y=document.querySelector('mouse').offsetTop+10
document.querySelector('mouse').style.left=((curX-x)/ratio)+x-10+"px"
document.querySelector('mouse').style.top=((curY-y)/ratio)+y-10+"px"
},16)
body {
background: #333;
height: 500px;
width: 500px;
}
mouse {
display: block;
position: fixed;
height: 20px;
width: 20px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>

How to create (or at least, describe) horizontal progress bar with thresholds?

I'm looking to create a horizontal chart with thresholds at certain percentages- if you've ever used Battle.Net, kind of similar to their download bar:
Blizzard Download Bar
I'm sure there's a name for it, I just don't know what it is...
Thanks!
I made this just in case it helps. Have 'fun'.
You can edit the little threshold pointer so they look stylish with css. But yea that all depends on what you want to do
// Btw, I'm a big fan of the canvas element that's why I'm doing this. Otherwise, you can also use a progress bar
var c = document.getElementById('progressBar'),
dt = document.getElementById('download-text'),
btn = document.querySelector('button'),
p2 = document.querySelector('progress');
var cx = c.getContext('2d');
var counter = 0,
loop;
btn.onclick = function() {
btn.innerText = 'N';
var timeInter = setInterval(function(){
btn.innerText += 'o';
},70);
setTimeout(function(){
clearTimeout(timeInter);
btn.hidden = true;
p2.hidden = false;
progress2();
},1000);
}
var loop2 = '',
counter2 = 0;
function progress2() {
counter2++;
var percentage = (counter2 / 17).toFixed(2);
if (percentage - 0 >= 100) {
percentage = 100;
}
p2.value = percentage - 0 +'';
if (percentage - 0 > 100) {
cancelAnimationFrame(loop2);
} else {
loop2 = requestAnimationFrame(progress);
}
//This is me failing to animate the progress bar
}
function progress() {
counter++;
var percentage = (counter / 17).toFixed(2);
if (percentage >= 100) {
percentage = 100+'.00';
}
dt.innerText = "Download: " + percentage + "%";
cx.fillStyle = '#00FFFF';
cx.fillRect(0, 0, c.width * percentage / 100, c.height);
cx.strokeStyle = '#ccc';
cx.beginPath();
cx.moveTo(100, 70);
cx.lineTo(100, 0);
cx.stroke();
cx.moveTo(300, 70);
cx.lineTo(300, 0);
cx.stroke();
if (percentage - 0 > 100) {
cancelAnimationFrame(loop);
} else {
loop = requestAnimationFrame(progress);
}
}
progress();
#progressBar {
border: 1px solid grey;
z-index: -10;
}
#progressBar,
#download-text,
#playable,
#optimal,
button,
progress{
position: absolute;
top: 0px;
left: 0px;
}
button,
progress{
top:200px;
}
#download-text {
height: 70px;
padding-top: 25px;
padding-left: 7px;
font-family: sans-serif;
background-color: transparent;
}
#playable,
#optimal {
width: 100px;
height: 43px;
text-align: center;
padding-top: 20px;
font-family: sans-serif;
font-weight: bolder;
}
#playable {
background-color: yellow;
position: absolute;
top: 72px;
left: 100px;
}
#optimal {
background-color: green;
position: absolute;
top: 72px;
left: 300px;
}
<div>
<canvas id="progressBar" width="430px" height="70px"></canvas>
<div id="download-text">Hello</div>
</div>
<div id="playable">PLAYABLE</div>
<div id="optimal">OPTIMAL</div>
<button type="button">Please don't press me just stick to canvas</button>
<progress max="100" hidden="true"></progress>

Categories