I want to make two progress bars working on load. But the code which I write makes only one loading. Also those two progress bars has to be different in length when loaded. I don't want to repeat code, so I am adding arrays. But I am not quite sure that this is the best solution. Maybe in body tag it is possible to write two different functions, or only one can be onload? If it is possible with several functions onload, then the number array shouldnt't be used. My code below. Maybe anyone knows the solution?
<style>
.myProgress {
width: 100%;
background-color: #000000;
}
#myBar1, #myBar2 {
width: 1%;
height: 30px;
background-color: #4CAF50;
}
</style>
<body onload="move()">
<div class="myProgress">
<div id="myBar1"></div>
</div>
<div class="myProgress">
<div id="myBar2"></div>
</div>
<script>
function move() {
var ids = ["myBar1", "myBar2"];
var number = [60, 90]
var length = ids.length;
for(i = 1; i<=length; i++){
var elem = document.getElementById("myBar"+i);
var width = 1;
var id = setInterval(frame, 10);
function frame() {
if (width >= number[i-1]) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
}
}
}
}
</script>
The problem was caused because you were mixing loops with async operations which usually doesn't turn out well. If you want to do that you should use let instead of var or do the operation in another function. Moreover you can set the width in the html element and read all the progress bars.
function move() {
for (var item of document.querySelectorAll(".myProgress")) {
loading(item.firstElementChild, +item.getAttribute("width") || 100); // replace 100 with default
}
}
function loading(bar, maxWidth) {
var width = 0;
var intervalId = setInterval(function() {
if (width >= maxWidth) clearInterval(intervalId);
else bar.style.width = ++width + '%';
}, 10);
}
.myProgress {
width: 100%;
background-color: #000000;
}
#myBar1,
#myBar2 {
width: 1%;
height: 30px;
background-color: #4CAF50;
}
<body onload="move()">
<div class="myProgress" width="60">
<div id="myBar1"></div>
</div>
<div class="myProgress" width="90">
<div id="myBar2"></div>
</div>
</body>
Related
I've been trying to add 1% to the width of the div using JS. I want to make it so that the bar's width increases in a smooth way ( I thought about using animations but it didn't work cause I need to specify conditions).
window.onload = function(){
for (let i = 0; i < 5; i++) {
const bar = document.querySelectorAll(".child-bar")[i];
for (let j = 0; j < 82; j++) {
//alert("j" + j);
console.log("bar width: "+ bar.style.width)
bar.style.width += '1%';
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="skill">
<label for="HTML">HTML</label>
<div class="parent-bar">
<span class="child-bar"></span>
<h4>82%</h4>
</div>
</div>
Maybe this example will help you?
window.onload = function() {
document.querySelectorAll(".parent-bar").forEach((el) => {
const barNode = el.querySelector(".child-bar");
const valueNode = el.querySelector("h4");
const max = 82;
const duration = 100;
let value = 0;
const tick = () => {
barNode.style.width = `${value}%`;
valueNode.innerHTML = `${value}%`;
if (value++ < max) setTimeout(tick, duration);
}
tick();
})
}
.child-bar {
display: block;
background: black;
height: 1rem;
width: 0;
transition: 0.1s 0s linear;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="skill">
<label for="HTML">HTML</label>
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
</div>
Here's a solution with verbose code and commentary for clarity, using setInterval.
(Note that span elements have display: inline by default, which is why setting their width has no effect.)
// Sets options and calls main function
const myOptions = {
MAX_WIDTH_PERCENT: 82,
FRAME_COUNT: 100,
FRAME_DURATION: 20
};
animateBars(myOptions);
// Defines main function
function animateBars(options){
const
// Destructures options object to make local variables
{ MAX_WIDTH_PERCENT, FRAME_COUNT, FRAME_DURATION } = options,
// Defines function to increment width
increment = (value) => value += MAX_WIDTH_PERCENT / FRAME_COUNT,
// Defines function to update bar (after incrementing width)
incrementAndupdateBar = (bar, oldWidth, timerId) => {
newWidth = Math.min(increment(oldWidth), MAX_WIDTH_PERCENT);
bar.style.width = newWidth + "%";
bar.nextElementSibling.textContent = Math.floor(newWidth) + "%"; // (For demo)
// Stops repeating the setInterval's function
if(newWidth == MAX_WIDTH_PERCENT){
clearInterval(timerId);
}
return newWidth; // Returns updated value
};
// Loops through bars
for(let bar of document.querySelectorAll(".child-bar")){
// Repeatedly updates current bar, keeping track of width as we go
let
width = 0, // Initializes width for the current bar
timerId; // ID for use by setInterval & clearInterval
timerId = setInterval( // (Returns an ID for later use)
// Takes 2 args: a func and a duration (in ms) to delay inbetween
function(){width = incrementAndupdateBar(bar, width, timerId);},
FRAME_DURATION
);
}
}
.parent-bar{ width: 300px; border: 1px dotted grey; }
/* spans ignore "width" by default; "inline-block" solves this */
.child-bar{ display: inline-block; height: 1em; background-color: lightgreen; }
h4{ margin: 0; text-align: center; }
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
I have made a progress bar with decrease from width 100 to 0 using setInterval function. So basically every 20ms my width decrease from 1. Then when the width arrives at 0, I set the width to 100 to run the progress bar again. At every loop, I change the text inside my progress bar. What I'd like to do now is change the time interval (the 20ms) at every loop.
Si in my code, when I increase from one, my 20 is replaced by interval[i]... but I am stack to put setInterval inside a loop...
The code below works to change the text at every loop, but don't know how to improve it to change the time interval at every iteration of i...
function move() {
var message = ['test', 'test2', 'test3'];
var interval = [10, 20, 30]
var elem = document.getElementById("myBar");
var width = 100;
var i = 0;
var id = setInterval(frame, 20);
function frame() {
width = width - 1;
elem.style.width = width + "%";
elem.textContent = message[i];
if (width == 0 && i < 3) {
width = 100;
i++;
}
if (i == 3) {
clearInterval(id);
}
}
}
#myProgress {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 100%;
height: 30px;
background-color: #4CAF50;
}
<h1>JavaScript Progress Bar</h1>
<div id="myProgress">
<div id="myBar"> </div>
</div>
<br>
<button onclick="move()">Click Me</button>
<html>
<style>
#myProgress {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 100%;
height: 30px;
background-color: #4CAF50;
}
</style>
<body>
<h1>JavaScript Progress Bar</h1>
<div id="myProgress">
<div id="myBar"> </div>
</div>
<br>
<button onclick="move()">Click Me</button>
<script>
function move() {
var message = ['test','test2','test3'];
var interval = [10,20,30]
var elem = document.getElementById("myBar");
var width = 100;
var i = 0;
var id = setInterval(frame, interval[i]);
function frame() {
width = width - 1;
elem.style.width = width + "%";
elem.textContent = message[i];
if (width == 0 && i < 3) {
width = 100;
i++;
clearInterval(id);
id = setInterval(frame, interval[i]);
}
if (i == 3) {
clearInterval(id);
}
}
}
</script>
</body>
</html>
You could declare a variable outside function move that holds the iteration time step, like:
let iterationStep = 0;
Then inside
let iterationStep = 0;
function move() {
//...blabla
var id = setInterval(frame, interval[iterationStep]);
function frame() {
// blablabla
if (width == 0 && i < 3) {
width = 100;
i++;
// HERE
iterationStep = i;
}
//blablabla
}
}
So each time you are increasing i you are also increasing the value of iterationStep by i value. And it is the value that will be used to access the postition inside the array of intervals of the iteration once you click in move().
I have a series of images I want to transition from 0 opacity to 1 opacity when they come into the view port. I have the viewport check part done and the adding classes, however I would like them to be on an interval, so once the first 3 images come into the view port they appear 1, 2, 3 every .5seconds or so. Instead of all 3 at the same time.
here's a JS fiddle of how it works currently
reveal();
function reveal() {
var reveal = document.querySelectorAll(".reveal");
window.onscroll = function() {
for(var i = 0; i < reveal.length; i++) {
if(checkVisible(reveal[i]) === true) {
reveal[i].classList.add("fade");
}
}
}
};
function checkVisible(elm) {
var rect = elm.getBoundingClientRect();
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
return !(rect.bottom < 0 || rect.top - viewHeight >= -200);
}
https://jsfiddle.net/u04sy7jb/
I've modified your code to add a transition-delay of an additional .5 seconds for each element after the first one, in each "group" that is revealed as you scroll. I left comments in the JavaScript so you can understand the changes.
Let me know if you have any questions!
Live demo:
reveal();
function reveal() {
var reveal = document.querySelectorAll(".reveal");
window.onscroll = function() {
// start a new count each time user scrolls
count = 0;
for (var i = 0; i < reveal.length; i++) {
// also check here if the element has already been faded in
if (checkVisible(reveal[i]) && !reveal[i].classList.contains("fade")) {
// add .5 seconds to the transition for each
// additional element currently being revealed
reveal[i].style.transitionDelay = count * 500 + "ms";
reveal[i].classList.add("fade");
// increment count
count++;
}
}
}
};
function checkVisible(elm) {
var rect = elm.getBoundingClientRect();
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
return !(rect.bottom < 0 || rect.top - viewHeight >= -200);
}
.container {
width: 100%;
height: 1200px;
background-color: orange;
}
.reveal {
display: inline-block;
width: 32%;
margin: 0 auto;
height: 400px;
background-color: pink;
border: 1px solid black;
opacity: 0;
}
.fade {
opacity: 1;
transition: 1s;
}
<div class="container">
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
</div>
You could be able to stick your reveal[i].classList.add("fade"); inside of a setTimeout that executes as a function of your ith element so they show up how you're describing. Here is an example of adding short function to add the class and using it in a setTimeout to make this happen, although you could change it up to meet any additional needs.
function reveal() {
var reveal = document.querySelectorAll(".reveal");
window.onscroll = function() {
for(var i = 0; i < reveal.length; i++) {
if(checkVisible(reveal[i]) === true) {
addMyFadeClass(reveal[i], i)
}
}
}
};
function addMyFadeClass(element, i) {
setTimeout(function() {
element.classList.add("fade");
}, i * 500)
}
You can also use :nth-child CSS selectors without the need to change the JS:
.reveal:nth-child(3n+1).fade {
opacity: 1;
transition: 1s;
}
.reveal:nth-child(3n+2).fade {
opacity: 1;
transition: 1.5s;
}
.reveal:nth-child(3n).fade {
opacity: 1;
transition: 2s;
}
JSFiddle: https://jsfiddle.net/u04sy7jb/8/
function scrollWin() {
setInterval(function(){ for(var i = 0; i < 1250; i++){
window.scrollTo(0, i);} }, 3);
}
li {
float: left;
list-style: none;
margin: 10px;
}
.reset {
clear: both;
}
div {
width: 500px;
height: 600px;
background-color: blue;
margin: 20px;
}
<ul>
<li>Home</li>
<li><button onclick="scrollWin()"></a>about</button>
<li>profile</li>
<li>contact</li>
</ul>
<div class="reset"></div>
<section>
<div id="home1"></div>
<div id="about1">About</div>
<div id="profile1"></div>
<div id="contact"></div>
</section>
so im trying to make the for loop increase the height by 1 each loop which will make the screen drop by the height of one. Using a time interval for a very short amount of time I would believe this would make a smooth scroll down the page.
I'm writing a sample code in php where scroll bar appears if the loop run for second time as in the question you asked I hope.
so define a variable first and then increase it in your loop as follows:
<?php
$i=1;
for(condition;condition;condition){
//your code here
$i++;
}
if($i<1){
echo '<script>
$(".yourdivclass").css("overflow","scroll");
</script>';
}
?>
This bit of JavaScript should perform nicely what you are asking. I have a fiddle that I have set up as a usage example. Please check it out and let me know if you have any questions.
https://jsfiddle.net/6gp7srfr/1/
function smoothScroll(x, y) {
var b = document.body;
var xIncrement = 1;
var yIncrement = 1;
var scrollY = function () {
yIncrement += 1;
window.scroll(b.scrollLeft, b.scrollTop + yIncrement);
if (b.scrollTop < y) {
if (requestAnimationFrame) {
requestAnimationFrame(scrollY);
} else {
setTimeout(scrollY, 15);
}
}
};
var scrollX = function () {
xIncrement += 1;
window.scroll(b.scrollLeft + xIncrement, b.scrollTop);
if (b.scrollLeft < x) {
if (requestAnimationFrame) {
requestAnimationFrame(scrollX);
} else {
setTimeout(scrollX, 15);
}
}
};
if (y > 0) {
scrollY();
}
if (x > 0) {
scrollX();
}
}
So, I'm trying to make an animation in JavaScript (I want a navigation bar to pull down when I click it). The problem is that every time I click this navigation bar, it only moves down one pixel. How do I make it to where I can make the "Move" function repeat over and over so that it realizes the navigation bar is below "0", and move it up? Here's the code I have atm:
var i = -43 //original position of div
function Move(x)
{
if (i < 0)
{
i++;
x.style.top = i + "px";
}
}
function setPosition(x)
{
setInterval(Move(x), 500);
}
P.S. I have the "div onclick" equal to "setInterval(this)"
I would use a setTimeout() (so you don't have to worry about canceling the setInterval()), and note the use of an anonymous function (function(){}) for the first argument of the setTimeout() call:
#slider {
position: absolute;
top: -43px;
left: 200px;
width: 200px;
height: 50px;
border: 1px solid blue;
background: #dff;
}
<div id='slider'>This is a slidout</div>
<div id="clicker">Click me!</div>
var slider = document.getElementById('slider'),
clicker = document.getElementById('clicker');
clicker.onclick = function(){
Move(slider, -43);
};
function Move(x, i)
{
if (i < 0)
{
i++;
x.style.top = i + "px";
setTimeout(function(){
Move(x, i);
}, 50);
}
}
http://jsfiddle.net/h2C3A/