Add a video control on top of a local html video - javascript

The following is a link which shows a nice example of playing a local video in a browser:
http://jsfiddle.net/dsbonev/cCCZ2/
<h1>HTML5 local video file player example</h1>
<div id="message"></div>
<input type="file" accept="video/*"/>
<video controls autoplay></video>
However, on top of this, I would like to allow the user to create a "trailer clip" of a particular segment of their video. In this, I would like to have some sort of adjustable playhead such as the following:
Here is a site that does this exact same thing: https://www.flexclip.com/editor/app?ratio=landscape. Any insight into how I would go about building something like this that plays the local file and allows me to select a segment of it?

There's a few different things, though the particular question seems to be how to draw a preview bar of a local video.
Local Files
From the example in your question, you can see it's not too different working with a local file than with a remote file; you can create an object URL of the local file via URL.createObjectURL and then work with it as you would a normal video link.
Drawing the Preview Bar
Drawing the preview bar should consist of seeking to the appropriate time in the video, and then drawing that frame onto a canvas. You can seek to a specific point by setting the .currentTime property of the video and waiting for the seeked event. You can then use the canvasContext.drawImage method to draw an image using the video element.
I'd also recommend using a video element that isn't attached to the DOM for this, for a better user experience that doesn't have an onscreen video jumping to different times.
It could look something like this:
function goToTime(video, time) {
return new Promise ((resolve) => {
function cb () {
video.removeEventListener('seeked', cb);
resolve();
}
video.addEventListener('seeked', cb);
video.currentTime = time;
});
}
async function drawPreviewBar(video) {
const { duration, videoWidth, videoHeight } = video;
const previewBarFrameWidth = previewBarHeight * videoWidth / videoHeight;
const previewBarFrames = previewBarWidth / previewBarFrameWidth;
for (let i = 0; i < previewBarFrames; i++) {
await goToTime(video, i * duration * previewBarFrameWidth / previewBarWidth);
previewBarContext.drawImage(video, 0, 0,
videoWidth, videoHeight,
previewBarFrameWidth * i, 0,
previewBarFrameWidth, previewBarHeight
);
}
}
Resizing / Moving the Selected Clip
If you want to create a UI to resize or move around the clip, you can use standard drag handlers.
Example
Here's a basic example:
const previewBarWidth = 600;
const previewBarHeight = 40;
const videoElement = document.getElementById('video');
const inputElement = document.getElementById('file-picker');
const invisibleVideo = document.createElement('video');
const previewBarCanvas = document.getElementById('preview-bar-canvas');
previewBarCanvas.width = previewBarWidth;
previewBarCanvas.height = previewBarHeight;
const selector = document.getElementById('selector');
const previewBarContext = previewBarCanvas.getContext('2d');
const topHandle = document.getElementById('selector-top-handle');
const leftHandle = document.getElementById('selector-left-handle');
const rightHandle = document.getElementById('selector-right-handle');
const leftMask = document.getElementById('selector-left-mask');
const rightMask = document.getElementById('selector-right-mask');
var selectorLeft = 0, selectorWidth = previewBarWidth;
var minimumPreviewBarWidth = 80; // may want to dynamically change this based on video duration
var videoLoaded = false;
function goToTime(video, time) {
return new Promise ((resolve) => {
function cb () {
video.removeEventListener('seeked', cb);
resolve();
}
video.addEventListener('seeked', cb);
video.currentTime = time;
});
}
async function drawPreviewBar(video) {
const { duration, videoWidth, videoHeight } = video;
const previewBarFrameWidth = previewBarHeight * videoWidth / videoHeight;
const previewBarFrames = previewBarWidth / previewBarFrameWidth;
for (let i = 0; i < previewBarFrames; i++) {
await goToTime(video, i * duration * previewBarFrameWidth / previewBarWidth);
previewBarContext.drawImage(video, 0, 0, videoWidth, videoHeight, previewBarFrameWidth * i, 0, previewBarFrameWidth, previewBarHeight);
}
}
function loadVideo(file) {
var src = URL.createObjectURL(file);
var loaded = new Promise(function (resolve) {
invisibleVideo.addEventListener('loadedmetadata', resolve);
}).then(function () {
videoLoaded = true;
document.body.classList.add('loaded');
return drawPreviewBar(invisibleVideo);
});
videoElement.src = src;
invisibleVideo.src = src;
return loaded;
}
function updateSelectorBar() {
selector.style.width = selectorWidth + 'px';
selector.style.left = selectorLeft + 'px';
leftMask.style.width = selectorLeft + 'px';
rightMask.style.left = (selectorLeft + selectorWidth) + 'px';
rightMask.style.width = (previewBarWidth - selectorWidth - selectorLeft) + 'px';
}
function selectorUpdated() {
if (!videoLoaded) {
return;
}
var startFraction = selectorLeft / previewBarWidth;
var durationFraction = selectorWidth / previewBarWidth;
var startTime = startFraction * invisibleVideo.duration;
var duration = durationFraction * invisibleVideo.duration;
var endTime = startTime + duration;
// do something with startTime, endTime, and duration, maybe;
videoElement.currentTime = startTime;
}
function addDragHandler (event, cb, ecb) {
var startX = event.clientX;
function dragged(e) {
cb(e.clientX - startX);
}
window.addEventListener('mousemove', dragged);
window.addEventListener('mouseup', function ended() {
window.removeEventListener('mousemove', dragged);
window.removeEventListener('mouseup', ended);
ecb();
});
}
updateSelectorBar();
topHandle.addEventListener('mousedown', function (e) {
var startLeft = selectorLeft;
addDragHandler(e, function (dx) {
selectorLeft = Math.max(0, Math.min(previewBarWidth - selectorWidth, startLeft + dx));
updateSelectorBar();
}, selectorUpdated);
});
leftHandle.addEventListener('mousedown', function (e) {
var startLeft = selectorLeft;
var startWidth = selectorWidth;
addDragHandler(e, function (dx) {
selectorLeft = Math.max(0, Math.min(selectorLeft + selectorWidth - minimumPreviewBarWidth, startLeft + dx));
selectorWidth = (startWidth + startLeft - selectorLeft);
updateSelectorBar();
}, selectorUpdated);
});
rightHandle.addEventListener('mousedown', function (e) {
var startWidth = selectorWidth;
addDragHandler(e, function (dx) {
selectorWidth = Math.max(minimumPreviewBarWidth, Math.min(previewBarWidth - selectorLeft, startWidth + dx));
updateSelectorBar();
}, selectorUpdated);
});
var pendingLoad = Promise.resolve();
inputElement.addEventListener('change', function () {
let file = inputElement.files[0];
pendingLoad = pendingLoad.then(function () {
return loadVideo(file)
});
});
#video {
width: 100%;
height: auto;
}
#preview-bar {
position: relative;
margin-top: 10px;
}
.canvas-container {
position: relative;
left: 5px;
}
#preview-bar-canvas {
position: relative;
top: 2px;
}
#selector {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 100%;
border: 2px solid orange;
border-left-width: 5px;
border-right-width: 5px;
border-radius: 3px;
overflow: show;
opacity: 0;
transition: opacity 1s;
pointer-events: none;
}
.loaded #selector{
opacity: 1;
pointer-events: initial;
}
#selector-top-handle {
position: absolute;
top: 0;
height: 10px;
width: 100%;
max-width: 30px;
left: 50%;
transform: translate(-50%,-100%);
background: darkgreen;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
cursor: move;
}
.resize-handle {
position: absolute;
top: 0;
bottom: 0;
width: 5px;
cursor: ew-resize;
background: darkgreen;
opacity: 0.75;
transition: opacity 1s;
}
.resize-handle:hover {
opacity: 1;
}
.preview-mask {
position: absolute;
background: black;
opacity: 0.6;
top: 0;
bottom: 0;
}
#selector-left-mask {
left: 0;
}
#selector-left-handle {
left: -5px;
}
#selector-right-handle {
right: -5px;
}
<input type="file" id="file-picker" />
<video id="video"></video>
<div id="preview-bar">
<div class="canvas-container">
<canvas id="preview-bar-canvas"></canvas>
<div id="selector-left-mask" class="preview-mask"></div>
<div id="selector-right-mask" class="preview-mask"></div>
</div>
<div id ="selector">
<div id="selector-top-handle"></div>
<div id="selector-left-handle" class="resize-handle"></div>
<div id="selector-right-handle" class="resize-handle"></div>
</div>
</div>

Here is some infomation I found online about this question:
(all of the lines are commented fyi)
https://gist.github.com/simonhaenisch/116010ed657f6b257246464e33719613

Related

Remove the ability to hold down a keyboard key

I have a small page. Circles appear here, when you click on them they disappear.
I added here the possibility that in addition to clicking on the LMB, you can also click on a keyboard key, in my case it is "A".
But I noticed the problem that if you hold down the "A" button, then drive in circles, then the need for clicks disappears, and this is the main goal.
Can I somehow disable the ability to hold this button so that only clicking on it works?
I tried pasting this code, but all animations stopped working for me.
var down = false;
document.addEventListener('keydown', function () {
if(down) return;
down = true;
// your magic code here
}, false);
document.addEventListener('keyup', function () {
down = false;
}, false);
Get error:
"message": "Uncaught ReferenceError: mouseOverHandler is not defined"
//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('mouseover', mouseOverHandler );
div.addEventListener('mouseout', mouseOutHandler );
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 = 1000;
setInterval(() => {
i += 1;
createDiv(`circle${i}`);
}, rate);
let focusedEl = null;
const keyDownHandler = (evt) => {
if(evt.keyCode === 65 && focusedEl) focusedEl.click();
}
const mouseOutHandler = (evt) => focusedEl = null;
const mouseOverHandler = (evt) => focusedEl = evt.currentTarget;
document.addEventListener('keydown', keyDownHandler );
window.focus();
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;
}
}
<html>
<body>
<div id="spawnRadius"></div>
</body>
</html>
You can check the repeat property of the event, which
… is true if the given key is being held down such that it is automatically repeating.
(but notice the compatibility notes on auto-repeat handling)
const keyDownHandler = (evt) => {
if (!evt.repeat && evt.keyCode === 65) {
// ^^^^^^^^^^^
focusedEl?.click();
}
}
//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('mouseover', mouseOverHandler );
div.addEventListener('mouseout', mouseOutHandler );
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 = 1000;
setInterval(() => {
i += 1;
createDiv(`circle${i}`);
}, rate);
let focusedEl = null;
const mouseOutHandler = (evt) => focusedEl = null;
const mouseOverHandler = (evt) => focusedEl = evt.currentTarget;
document.addEventListener('keydown', keyDownHandler );
window.focus();
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;
}
}
<html>
<body>
<div id="spawnRadius"></div>
</body>
</html>

How to drag images in JS

I have a large background image and some much smaller images for the user to drag around on the background. I need this to be efficient in terms of performance, so i'm trying to avoid libraries. I'm fine with drag 'n' drop if it work's well, but im trying to get drag.
Im pretty much trying to do this. But after 8 years there must be a cleaner way to do this right?
I currently have a drag 'n' drop system that almost works, but when i drop the smaller images, they are just a little off and it's very annoying. Is there a way to fix my code, or do i need to take a whole different approach?
This is my code so far:
var draggedPoint;
function dragStart(event) {
draggedPoint = event.target; // my global var
}
function drop(event) {
event.preventDefault();
let xDiff = draggedPoint.x - event.pageX;
let yDiff = draggedPoint.y - event.pageY;
let left = draggedPoint.style.marginLeft; // get margins
let top = draggedPoint.style.marginTop;
let leftNum = Number(left.substring(0, left.length - 2)); // cut off px from the end
let topNum = Number(top.substring(0, top.length - 2));
let newLeft = leftNum - xDiff + "px" // count new margins and put px back to the end
let newTop = topNum - yDiff + "px"
draggedPoint.style.marginLeft = newLeft;
draggedPoint.style.marginTop = newTop;
}
function allowDrop(event) {
event.preventDefault();
}
let imgs = [
"https://upload.wikimedia.org/wikipedia/commons/6/67/Orange_juice_1_edit1.jpg",
"https://upload.wikimedia.org/wikipedia/commons/f/ff/Solid_blue.svg",
"https://upload.wikimedia.org/wikipedia/commons/b/b4/Litoria_infrafrenata_-_Julatten.jpg"
]
/* my smaller images: */
for (let i = 0; i < 6; i++) {
let sensor = document.createElement("img");
sensor.src = imgs[i % imgs.length];
sensor.alt = i;
sensor.draggable = true;
sensor.classList.add("sensor");
sensor.style.marginLeft = `${Math.floor(Math.random() * 900)}px`
sensor.style.marginTop = `${Math.floor(Math.random() * 500)}px`
sensor.onclick = function() {
sensorClick(logs[i].id)
};
sensor.addEventListener("dragstart", dragStart, null);
let parent = document.getElementsByClassName("map")[0];
parent.appendChild(sensor);
}
<!-- my html: -->
<style>
.map {
width: 900px;
height: 500px;
align-content: center;
margin: 150px auto 150px auto;
}
.map .base {
position: absolute;
width: inherit;
height: inherit;
}
.map .sensor {
position: absolute;
width: 50px;
height: 50px;
}
</style>
<div class="map" onDrop="drop(event)" ondragover="allowDrop(event)">
<img src='https://upload.wikimedia.org/wikipedia/commons/f/f7/Plan-Oum-el-Awamid.jpg' alt="pohja" class="base" draggable="false">
<div>
With the answers from here and some time i was able to get a smooth drag and click with pure js.
Here is a JSFiddle to see it in action.
let maxLeft;
let maxTop;
const minLeft = 0;
const minTop = 0;
let timeDelta;
let imgs = [
"https://upload.wikimedia.org/wikipedia/commons/6/67/Orange_juice_1_edit1.jpg",
"https://upload.wikimedia.org/wikipedia/commons/f/ff/Solid_blue.svg",
"https://upload.wikimedia.org/wikipedia/commons/b/b4/Litoria_infrafrenata_-_Julatten.jpg"
]
var originalX;
var originalY;
window.onload = function() {
document.onmousedown = startDrag;
document.onmouseup = stopDrag;
}
function sensorClick () {
if (Date.now() - timeDelta < 150) { // check that we didn't drag
createPopup(this);
}
}
// create a popup when we click
function createPopup(parent) {
let p = document.getElementById("popup");
if (p) {
p.parentNode.removeChild(p);
}
let popup = document.createElement("div");
popup.id = "popup";
popup.className = "popup";
popup.style.top = parent.y - 110 + "px";
popup.style.left = parent.x - 75 + "px";
let text = document.createElement("span");
text.textContent = parent.id;
popup.appendChild(text);
var map = document.getElementsByClassName("map")[0];
map.appendChild(popup);
}
// when our base is loaded
function baseOnLoad() {
var map = document.getElementsByClassName("map")[0];
let base = document.getElementsByClassName("base")[0];
maxLeft = base.width - 50;
maxTop = base.height - 50;
/* my smaller images: */
for (let i = 0; i < 6; i++) {
let sensor = document.createElement("img");
sensor.src = imgs[i % imgs.length];
sensor.alt = i;
sensor.id = i;
sensor.draggable = true;
sensor.classList.add("sensor");
sensor.classList.add("dragme");
sensor.style.left = `${Math.floor(Math.random() * 900)}px`
sensor.style.top = `${Math.floor(Math.random() * 500)}px`
sensor.onclick = sensorClick;
let parent = document.getElementsByClassName("map")[0];
parent.appendChild(sensor);
}
}
function startDrag(e) {
timeDelta = Date.now(); // get current millis
// determine event object
if (!e) var e = window.event;
// prevent default event
if(e.preventDefault) e.preventDefault();
// IE uses srcElement, others use target
targ = e.target ? e.target : e.srcElement;
originalX = targ.style.left;
originalY = targ.style.top;
// check that this is a draggable element
if (!targ.classList.contains('dragme')) return;
// calculate event X, Y coordinates
offsetX = e.clientX;
offsetY = e.clientY;
// calculate integer values for top and left properties
coordX = parseInt(targ.style.left);
coordY = parseInt(targ.style.top);
drag = true;
document.onmousemove = dragDiv; // move div element
return false; // prevent default event
}
function dragDiv(e) {
if (!drag) return;
if (!e) var e = window.event;
// move div element and check for borders
let newLeft = coordX + e.clientX - offsetX;
if (newLeft < maxLeft && newLeft > minLeft) targ.style.left = newLeft + 'px'
let newTop = coordY + e.clientY - offsetY;
if (newTop < maxTop && newTop > minTop) targ.style.top = newTop + 'px'
return false; // prevent default event
}
function stopDrag() {
if (typeof drag == "undefined") return;
if (drag) {
if (Date.now() - timeDelta > 150) { // we dragged
let p = document.getElementById("popup");
if (p) {
p.parentNode.removeChild(p);
}
} else {
targ.style.left = originalX;
targ.style.top = originalY;
}
}
drag = false;
}
.map {
width: 900px;
height: 500px;
margin: 50px
position: relative;
}
.map .base {
position: absolute;
width: inherit;
height: inherit;
}
.map .sensor {
display: inline-block;
position: absolute;
width: 50px;
height: 50px;
}
.dragme {
cursor: move;
left: 0px;
top: 0px;
}
.popup {
position: absolute;
display: inline-block;
width: 200px;
height: 100px;
background-color: #9FC990;
border-radius: 10%;
}
.popup::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -10px;
border-width: 10px;
border-style: solid;
border-color: #9FC990 transparent transparent transparent;
}
.popup span {
width: 90%;
margin: 10px;
display: inline-block;
text-align: center;
}
<div class="map" width="950px" height="500px">
<img src='https://upload.wikimedia.org/wikipedia/commons/f/f7/Plan-Oum-el-Awamid.jpg' alt="pohja" class="base" draggable="false" onload="baseOnLoad()">
<div>

Hide scroll bar when page preloader loads

I want to hide scroll bar while preloader is loading the scroll bar will not show until unless preloader disappears which means the user can't able to scroll the page while preloader is loading here I'm using canvas as a preloader. I tried by using body overflow: hidden and some CSS also but unable to achieve the result here I used canvas effect as a preloader. Can anyone point me in the right direction what I'm doing wrong?
/* Preloader Effect */
var noise = function(){
//const noise = () => {
var canvas, ctx;
var wWidth, wHeight;
var noiseData = [];
var frame = 0;
var loopTimeout;
// Create Noise
const createNoise = function() {
const idata = ctx.createImageData(wWidth, wHeight);
const buffer32 = new Uint32Array(idata.data.buffer);
const len = buffer32.length;
for (var i = 0; i < len; i++) {
if (Math.random() < 0.5) {
buffer32[i] = 0xff000000;
}
}
noiseData.push(idata);
};
// Play Noise
const paintNoise = function() {
if (frame === 9) {
frame = 0;
} else {
frame++;
}
ctx.putImageData(noiseData[frame], 0, 0);
};
// Loop
const loop = function() {
paintNoise(frame);
loopTimeout = window.setTimeout(function() {
window.requestAnimationFrame(loop);
}, (1000 / 25));
};
// Setup
const setup = function() {
wWidth = window.innerWidth;
wHeight = window.innerHeight;
canvas.width = wWidth;
canvas.height = wHeight;
for (var i = 0; i < 10; i++) {
createNoise();
}
loop();
};
// Reset
var resizeThrottle;
const reset = function() {
window.addEventListener('resize', function() {
window.clearTimeout(resizeThrottle);
resizeThrottle = window.setTimeout(function() {
window.clearTimeout(loopTimeout);
setup();
}, 200);
}, false);
};
// Init
const init = (function() {
canvas = document.getElementById('noise');
ctx = canvas.getContext('2d');
setup();
})();
};
noise();
$(document).ready(function(){
$('body').css({
overflow: 'hidden'
});
setTimeout(function(){
$('#preloader').fadeOut('slow', function(){
$('body').css({
overflow: 'auto'
});
});
}, 5000);
});
#preloader {
position: fixed;
height: 100vh;
width: 100%;
z-index: 5000;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
/* change if the mask should have another color then white */
z-index: 10000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="preloader">
<canvas id="noise" class="noise"></canvas>
</div>
Try these Codes, If it works for you. I found this on StackOverflow. Source: Disable scrolling when preload a web page
Js Code
$(window).load(function() {
$(".preloader").fadeOut(1000, function() {
$('body').removeClass('loading');
});
});
Css Code
.loading {
overflow: hidden;
height: 100vh;
}
.preloader {
background: #fff;
position: fixed;
text-align: center;
bottom: 0;
right: 0;
left: 0;
top: 0;
}
.preloader4 {
position: absolute;
margin: -17px 0 0 -17px;
left: 50%;
top: 50%;
width:35px;
height:35px;
padding: 0px;
border-radius:100%;
border:2px solid;
border-top-color:rgba(0,0,0, 0.65);
border-bottom-color:rgba(0,0,0, 0.15);
border-left-color:rgba(0,0,0, 0.65);
border-right-color:rgba(0,0,0, 0.15);
-webkit-animation: preloader4 0.8s linear infinite;
animation: preloader4 0.8s linear infinite;
}
#keyframes preloader4 {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
#-webkit-keyframes preloader4 {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
Code
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body class="loading">
<div class="preloader">
<div class="preloader4"></div>
</div>
//Code
</body>
You need to set overflow: hidden and height: 100vh both on the body and the html tags.
/* Preloader Effect */
var noise = function(){
//const noise = () => {
var canvas, ctx;
var wWidth, wHeight;
var noiseData = [];
var frame = 0;
var loopTimeout;
// Create Noise
const createNoise = function() {
const idata = ctx.createImageData(wWidth, wHeight);
const buffer32 = new Uint32Array(idata.data.buffer);
const len = buffer32.length;
for (var i = 0; i < len; i++) {
if (Math.random() < 0.5) {
buffer32[i] = 0xff000000;
}
}
noiseData.push(idata);
};
// Play Noise
const paintNoise = function() {
if (frame === 9) {
frame = 0;
} else {
frame++;
}
ctx.putImageData(noiseData[frame], 0, 0);
};
// Loop
const loop = function() {
paintNoise(frame);
loopTimeout = window.setTimeout(function() {
window.requestAnimationFrame(loop);
}, (1000 / 25));
};
// Setup
const setup = function() {
wWidth = window.innerWidth;
wHeight = window.innerHeight;
canvas.width = wWidth;
canvas.height = wHeight;
for (var i = 0; i < 10; i++) {
createNoise();
}
loop();
};
// Reset
var resizeThrottle;
const reset = function() {
window.addEventListener('resize', function() {
window.clearTimeout(resizeThrottle);
resizeThrottle = window.setTimeout(function() {
window.clearTimeout(loopTimeout);
setup();
}, 200);
}, false);
};
// Init
const init = (function() {
canvas = document.getElementById('noise');
ctx = canvas.getContext('2d');
setup();
})();
};
noise();
$(document).ready(function(){
$('body, html').css({
overflow: 'hidden',
height: '100vh'
});
setTimeout(function(){
$('#preloader').fadeOut('slow', function(){
$('body, html').css({
overflow: 'auto',
height: 'auto'
});
});
}, 5000);
});
#preloader {
position: fixed;
height: 100vh;
width: 100%;
z-index: 5000;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
/* change if the mask should have another color then white */
z-index: 10000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="preloader">
<canvas id="noise" class="noise"></canvas>
</div>
Set the position of body as fixed and when the page is loaded, remove that.
document.body.style.position = "fixed";
window.addEventListener("load", () => {
document.body.style.position = "";
document.querySelector(".preloader").style.display = "none";
});

How can I use requestAnimationFrame along with setInterval?

See the following snippet of code.
It creates a loader on click of a button. But the animation is not smooth.
I have recently read about requestAnimationFrame function which can do this job. But how can I use it to replace setInterval altogether since there is no way to specify time in requestAnimationFrame function.
Can it be used in conjunction with setInterval ?
let idx = 1;
const timetoEnd = 5000;
function ProgressBar(width){
this.width = width || 0;
this.id = `pBar-${idx++}`;
this.create = () => {
let pBar = document.createElement('div');
pBar.id = this.id;
pBar.className = `p-bar`;
pBar.innerHTML = `<div class="loader"></div>`;
return pBar;
};
this.animator = () => {
let element = document.querySelector(`#${(this.id)} div`);
if(this.width < 100){
this.width++;
element.style.width = `${this.width}%`;
} else {
clearInterval(this.interval);
}
};
this.animate = () => {
this.interval = setInterval(this.animator, timetoEnd/100);
}
}
function addLoader (){
let bar1 = new ProgressBar(40);
let container = document.querySelector("#container");
container.appendChild(bar1.create());
bar1.animate();
}
.p-bar{
width: 400px;
height: 20px;
background: 1px solid #ccc;
margin: 10px;
overflow:hidden;
border-radius: 4px;
}
.p-bar .loader{
width: 0;
background: #1565C0;
height: 100%;
}
<input type="button" value="Add loader" onclick="addLoader()" />
<div id="container"></div>
You are right, requestAnimationFrame is the recommended way to avoid UI jam when doing animation.
You can remember the absolute starting time at start instead of trying to do this at each frame. Then it's just a matter of computing a width based on the delta time between start and current time.
Also, document.querySelector is considered a relatively "heavy" operation so I added this.element to avoid doing it at each frame.
Here is how to new width is computed: ((100 - this.startWidth) / timetoEnd) * deltaT + this.startWidth
100 - this.startWidth is the total amount of width we have to animate
(100 - this.startWidth) / timetoEnd is how much width each second must add to (1)
((100 - this.startWidth) / timetoEnd) * deltaT is how much width we have to add to (1)
We just have to shift the whole thing this.startWidth px to have the frame's width
Also notice that some of this computation is constant and do not have to be computed on each frame, which I left as an exercise :)
Here is your slightly adapted code:
let idx = 1;
const timetoEnd = 5000;
function ProgressBar(startWidth){
this.startWidth = startWidth || 0;
this.id = `pBar-${idx++}`;
this.create = () => {
let pBar = document.createElement('div');
pBar.id = this.id;
pBar.className = `p-bar`;
pBar.innerHTML = `<div class="loader"></div>`;
return pBar;
};
this.animator = () => {
const deltaT = Math.min(new Date().getTime() - this.start, timetoEnd);
if(deltaT < timetoEnd){
const width = ((100 - this.startWidth) / timetoEnd) * deltaT + this.startWidth;
this.element.style.width = `${width}%`;
requestAnimationFrame(this.animator.bind(this))
}
};
this.animate = () => {
this.element = document.querySelector(`#${(this.id)} div`);
this.start = new Date().getTime();
this.animator();
}
}
function addLoader (){
let bar1 = new ProgressBar(40);
let container = document.querySelector("#container");
container.appendChild(bar1.create());
bar1.animate();
}
.p-bar{
width: 400px;
height: 20px;
background: 1px solid #ccc;
margin: 10px;
overflow:hidden;
border-radius: 4px;
}
.p-bar .loader{
width: 0;
background: #1565C0;
height: 100%;
}
<input type="button" value="Add loader" onclick="addLoader()" />
<div id="container"></div>

Full page view on single scroll move to next section

I have tried to create single scroll and move to next section, I have using javascript, It is not working fine, The window top distance not giving properly, I need to div fullscreen moved to next screen, Please without jquery, Please help
if (window.addEventListener) {window.addEventListener('DOMMouseScroll', wheel, false);
window.onmousewheel = document.onmousewheel = wheel;}
function wheel(event) {
var delta = 0;
if (event.wheelDelta) delta = (event.wheelDelta)/120 ;
else if (event.detail) delta = -(event.detail)/3;
handle(delta);
if (event.preventDefault) event.preventDefault();
event.returnValue = false;
}
function handle(sentido) {
var inicial = document.body.scrollTop;
var time = 500;
var distance = 900;
animate({
delay: 0,
duration: time,
delta: function(p) {return p;},
step: function(delta) {
window.scrollTo(0, inicial-distance*delta*sentido);
}
});
}
function animate(opts) {
var start = new Date();
var id = setInterval(function() {
var timePassed = new Date() - start;
var progress = (timePassed / opts.duration);
if (progress > 1) {progress = 1;}
var delta = opts.delta(progress);
opts.step(delta);
if (progress == 1) {clearInterval(id);}}, opts.delay || 10);
}
body{
width: 100%;
height: 100%;
margin:0;
padding:0;
}
.wrapper{
width: 100%;
height: 100%;
position: absolute;
}
section{
width: 100%;
height: 100%;
}
.pg1{
background: green;
}
.pg2{
background: blue;
}
.pg3{
background: yellow;
}
<div class="wrapper" id="myDiv">
<section class="pg1" id="sec1"></section>
<section class="pg2"></section>
<section class="pg3"></section>
</div>
Return the height of the element and store it in distance variable, instead of giving it a static 900.
From this:
var distance = 900;
To this:
var distance = document.getElementById('sec1').clientHeight;

Categories