Try to do a progress bar in javascript - javascript

I'm starting to code this year and sorry if my english is not good enough,
I have a problem with a progress bar with JS,
I have on my console an "uncaught TypeError who charge infinitly and say to me that we can charge the properties on style...
The first step was working but when the bar is supposed to become interactive it's not working
const tll = gasp.timeline({
paused: true
});
tll.to("#percent", "#bar", {
duration: .2,
opacity: 0,
zIndex: -1
});
tll.to("#preloader", {
duration: .8,
width: "0%"
});
tll.from(".container", {
duration: 1.5,
y: "-150%"
}, "-=.2");
tll.to("container h1", {
opacity: 1,
textShadow: "12px 20px rgba(255, 255, 255,0.23)",
skewY: 10,
y: "10%",
stagger: {
amount: .4
}
});
var width = 1;
var bar = document.getElementById("barconfirm");
var id;
function move() {
id = setInterval(frame, 10);
}
function frame() {
if (width > 100) {
clearInterval(id);
tll.play();
} else {
width++;
bar.style.width = width + "%";
document.getElementById("percent").innerHTML = width + "%";
}
}
* {
margin: 0;
padding: 0;
overflow: hidden;
}
#preloader {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
z-index: 100;
background-color: #0f0f0f;
flex-direction: column;
}
#percent {
color: white;
font-family: "Neutral Face";
}
#bar {
width: 60%;
margin-top: 20%;
}
#barconfirm {
width: 1%;
padding: 1px 0px;
background-color: white;
}
.container {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
background-color: gray;
}
.container h1 {
font-family: 'Monument';
text-transform: uppercase;
font-size: 40px;
opacity: 0;
}
<body onload="move()">
<div id="preloader">
<div id="percent">1%</div>
<div id="bar">
<div id="barconfirm"></div>
</div>
</div>
<div class="container">
<h1>Leo Clemente</h1>
</div>
Thanks to you all for your help, I want if you can an explanation more than just a code because I'm here to learn too and have a great day!

The issue in passing the selector to the tll.to method, it accepts ONE selector, so choose one of yours for tll.to("#percent", "#bar", {...}).
It will work as well whether you choose percent or bar. Also, according to the document, the dependency variable name is gsap.
You can check out an online snippet from here

Related

How to use javascript to open the modal when connecting the API so that the user can see the animation effect?

let btn = document.querySelector('.btn');
let modal = document.querySelector('.modal');
let wrap = document.querySelector('.wrap');
let photo = document.querySelector('.photo');
let svg = document.querySelector('svg');
let data = [{
title: "dog",
age: 10,
rank: [{
rankStatus: 'behind'
},
{
rankStatus: 'generally',
rankNum: '20'
},
{
rankStatus: 'excellent'
}
]
}]
let rankStatusArr = data[0].rank.map(item => item.rankStatus);
let rankNum = data[0].rank.find(item => item.rankNum).rankNum;
btn.addEventListener('click', function(e) {
svg.style.display = "block"
axios.get("https://dog.ceo/api/breeds/image/random")
.then((response) => {
// 设置处理程序以在加载图像后显示图像
photo.addEventListener('load', () => {
svg.style.display = "none"
modal.style.display = "flex";
});
// 添加“加载”处理程序后设置图像源
photo.src = response.data.message;
})
.catch((error) => console.log(error));
// 排名狀態在 popup 打開後再載入動畫
let progress = rankNum;
let dot = document.getElementById("dot");
var dotPosition = (progress / 30) * 100;
dot.style.left = dotPosition + "%";
let txt = document.querySelectorAll('.txt');
for (let i = 0; i < txt.length; i++) {
txt[i].innerHTML = rankStatusArr[i];
}
})
wrap.addEventListener('click', function(e) {
e.stopPropagation();
})
modal.addEventListener('click', function() {
modal.style.display = "none"
})
.modal {
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
justify-content: center;
align-items: center;
}
.wrap {
width: 300px;
height: 300px;
padding: 20px;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 20px;
flex-direction: column;
}
.wrap .photo {
width: 100%;
height: 200px;
object-fit: cover;
margin-bottom: 20px;
}
.wrap #progress-bar-container {
width: 100%;
height: 5px;
background-color: #fff;
position: relative;
display: flex;
flex-wrap: nowrap;
}
.wrap #progress-bar-container .progress-bar {
width: 33.33%;
height: 5px;
background-color: #ccc;
margin-right: 8px;
border-radius: 20px;
}
.wrap #progress-bar-container .progress-bar .txt {
text-align: center;
color: #ccc;
margin-top: 20px;
}
#progress-bar-1 {
background-color: #ddd;
}
#progress-bar-2 {
background-color: #ddd;
}
#progress-bar-3 {
background-color: #ddd;
margin-right: 0;
}
#dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #333;
position: absolute;
top: -3px;
left: 0;
transition: left 0.2s ease-out;
}
svg {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
svg .load {
stroke-dasharray: 0 500;
animation: rot 1s linear infinite;
}
#keyframes rot {
100% {
stroke-dasharray: 500 500;
}
}
.green {
color: yellowgreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.2/axios.min.js"></script>
<button class='btn'>open</button>
<div class="modal">
<div class="wrap">
<img class="photo" src="" alt="photo">
<div id="progress-bar-container">
<div class="progress-bar" id="progress-bar-1">
<p class="txt">1</p>
</div>
<div class="progress-bar" id="progress-bar-2">
<p class="txt">2</p>
</div>
<div class="progress-bar" id="progress-bar-3">
<p class="txt">3</p>
</div>
<div id="dot"></div>
</div>
</div>
</div>
<!-- load -->
<svg width="240px" height="240px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="110" cy="110" r="90" stroke-width="10" stroke="gainsboro" fill="none"></circle>
<circle cx="110" cy="110" r="90" stroke-width="10" stroke="darkturquoise" fill="none" class="load"></circle>
</svg>
I encountered a little difficulty in the following requirements. The first difficulty is that I hope that the popup will not be opened until the picture is fully loaded! But I hope that when the popup is opened, the dot can add animation and run to the specified progress position, but it seems that the animation I want to appear has already run before it is opened, and the user will not see the moving animation effect. The second problem is that I want to add a green color to the rankStatus font on the screen if the rankNum is included in the rankStatus object, but I am a novice in programming and don't know which section to add to achieve this. Hope to get your help, thank you.
To solve the first difficulty, you can add an event listener to the photo element which will be triggered when the image is loaded. Inside this event listener, you can set the display of the modal to 'flex' and the display of the svg element to 'none'.
To solve the second difficulty, you can use an if statement inside your rankStatusArr loop. This statement should check if the rankNum is included in the rankStatus object and if so, add a class to the txt element which adds the green color style.
let txt = document.querySelectorAll('.txt');
for (let i = 0; i < txt.length; i++) {
txt[i].innerHTML = rankStatusArr[i];
if (rankNum === rankStatusArr[i]) {
txt[i].classList.add('green');
}
}

Can I use the same JavaScript Function on multiple Div's?

I'm new to javascript and I need to make circle progress that shows percentage with animated bar
luckily I have done it but the problem is I want to make 5 or more of the same circle with the different percentages and **I need to start on page load not by click **
So how to call the function on more than one div so that the circles appears with different percentages at the same time
Here's my JS code
let firstLayer = document.querySelector('.cardHolder'),
secondLayer = document.querySelector('.skillSecond'),
startValue = 0,
endValue = 50,
duration = 20;
let progress = setInterval(() => {
startValue++
secondLayer.textContent = `${startValue}%`
firstLayer.style.background = `conic-gradient(rgb(15, 176, 6) ${startValue * 3.6}deg, rgb(193, 193, 193) 0deg)`
if (startValue == endValue) {
clearInterval(progress)
}
}, duration);
.cardHolder {
display: flex;
justify-content: center;
align-items: center;
background: conic-gradient(rgb(15, 176, 6) 3.6deg, rgb(193, 193, 193) 0deg);
width: 100px;
height: 100px;
border-radius: 100%;
}
.skillFirst {
display: flex;
justify-content: center;
align-items: center;
background-color: #90697a;
width: 80%;
height: 80%;
border-radius: 100%;
}
.skillSecond {
font-family: 'Montserrat Subrayada', sans-serif;
font-size: 24px;
}
<div class="cardHolder">
<div class="skillFirst">
<div class="skillSecond">
<span class="skillContent"></span>
</div>
</div>
</div>
This is what i came up with. Basically it works by making an array of objects containing the specifications for each individual progressbar. Then loop over the specifications and start every Interval.
let progression = [
{
progressBarId: "first",
progressBarLabelId: "first_label",
startValue: 0,
endValue: 50,
duration: 20
},
{
progressBarId: "second",
progressBarLabelId: "second_label",
startValue: 10,
endValue: 100,
duration: 10
},
{
progressBarId: "third",
progressBarLabelId: "third_label",
startValue: 50,
endValue: 80,
duration: 20
}
];
window.onload = function() {
for(var i = 0; i < progression.length; i++) {
let firstLayer = document.getElementById(progression[i].progressBarId),
secondLayer = document.getElementById(progression[i].progressBarLabelId),
startValue = progression[i].startValue,
endValue = progression[i].endValue,
duration = progression[i].duration;
let progress = setInterval(() => {
startValue++
secondLayer.textContent = `${startValue}%`
firstLayer.style.background = `conic-gradient(rgb(15, 176, 6) ${startValue * 3.6}deg, rgb(193, 193, 193) 0deg)`
if (startValue == endValue) {
clearInterval(progress)
}
}, duration);
}
}
.cardHolder {
display: flex;
justify-content: center;
align-items: center;
background: conic-gradient(rgb(15, 176, 6) 3.6deg, rgb(193, 193, 193) 0deg);
width: 100px;
height: 100px;
border-radius: 100%;
}
.skillFirst {
display: flex;
justify-content: center;
align-items: center;
background-color: #90697a;
width: 80%;
height: 80%;
border-radius: 100%;
}
.skillSecond {
font-family: 'Montserrat Subrayada', sans-serif;
font-size: 24px;
}
<div class="cardHolder" id="first">
<div class="skillFirst">
<div class="skillSecond" id="first_label">
<span class="skillContent" ></span>
</div>
</div>
</div>
<div class="cardHolder" id="second">
<div class="skillFirst">
<div class="skillSecond" id="second_label">
<span class="skillContent" ></span>
</div>
</div>
</div>
<div class="cardHolder" id="third">
<div class="skillFirst">
<div class="skillSecond" id="third_label">
<span class="skillContent" ></span>
</div>
</div>
</div>
Hope this helps, if not, please comment!

jQuery animated number counter from zero to value - counter shows wrong value when a value is hundreds of thousands

I have tried to animate the numbers with the help of this URL: jQuery animated number counter from zero to value and followed this code:
$('.count').each(function () {
$(this).prop('Counter',0).animate({
Counter: $(this).text()
}, {
duration: 3000,
easing: 'swing',
step: function (now) {
$(this).text(Math.ceil(now));
}
});
});
The issue is, I gave a number 800 000 to increment in the numeric counter. Randomly this value is incremented and decremented again to 0. For e.g. After incrementing the value up to 800 000, it is again animating back to value 0.
Counter for zero to value is working fine for smaller values in thousands.
While researching how to do it, I realized that all solutions in the stack are with jquery. Now I write native (vanillajs) in projects, my solution is as follows.
var getCountItems = document.querySelectorAll('.count-item');
if(getCountItems){
getCountItems.forEach(function (countItem) {
var counterValueElement = countItem.querySelector('strong');
var storeCurrentValue = parseInt(counterValueElement.textContent);
var fromZero = 0;
if(fromZero === 0){
counterValueElement.textContent = "0";
}
setInterval(function () {
if(++fromZero <= storeCurrentValue){
counterValueElement.textContent = fromZero.toString();
}
}, 15); // set your speed (decrease)
});
}
section#countdown{
margin: 50px 0;
width: 100%;
color: #1C1E23;
}
section#countdown h3{
font-size: 28px;
text-align: center;
position: relative;
padding-bottom: 20px;
}
section#countdown h3:after{
content: ' ';
position: absolute;
bottom: 0;
left: 10%;
height: 1px;
width: 80%;
background: rgba(28, 30, 35, 0.44);
}
section#countdown .count-item{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
font-size: 24px;
color: rgba(28, 30, 35, 0.7);
margin: 15px 0;
/* set your anim count text for "all" */
transition: all .3s ease, color .4s ease-in;
}
section#countdown .count-item:hover{
transform: scale(1.25);
color: #C22429;
}
section#countdown .count-item span{
font-size: 18px;
color: rgba(28, 30, 35, 0.44);
}
#media only screen and (max-width: 992px){
section#countdown h3 + div{
flex-direction: column;
}
section#countdown .count-item{
transform: scale(1.5);
margin: 30px 0;
}
}
<section id="countdown" class="box-p">
<h3>STATISTICS</h3>
<div class="d-flex align-items-center justify-content-around">
<div class="count-item">
<strong>47</strong>
<span>YEAR EXPERIENCE</span>
</div>
<div class="count-item">
<strong>100</strong>
<span>EXPORT COUNTRIES</span>
</div>
<div class="count-item">
<strong>200</strong>
<span>BRANDS</span>
</div>
<div class="count-item">
<strong>500</strong>
<span>EMPLOYEE</span>
</div>
<div class="count-item">
<strong>7</strong>
<span>SUB BRANDS</span>
</div>
<div class="count-item">
<strong>2</strong>
<span>FACTORY</span>
</div>
</div>
</section>
UPDATE
Added, Pure JS version below the code;
var getCountItems = document.getElementsByClassName('count-item');
for(var i = 0; i < getCountItems.length; i++){
let item = getCountItems[i];
let counterValueElement = item.children[0]; // strong
let storeCurrentValue = parseInt(counterValueElement.textContent);
let fromZero = 0;
setInterval(function () {
if(fromZero <= storeCurrentValue){
counterValueElement.textContent = (fromZero++).toString();
}
}, 15); // set your speed (decrease)
}
Something like this should do the trick,
$('.count').each(function() {
$(this).prop('Counter', 8000)
.animate({
Counter: $(this).text()
}, {
duration: 3000,
easing: 'swing',
step: function(now, a) {
$(this).text(8000 - ~~this.Counter);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class='count'>0</span>
Hope this helps,

Compounding Value within an object used to slide dot across the page incrementally

I am unable to get a variable to function properly as the translateX value within my object. I am wanting to make the dot scroll across the page each time the next button is clicked. My code is only able to move it back and forth for the first step.
I am new to the animation API, and I have already made this work with CSS transitions but I am trying to get a good handle on the API.
html:
<div class="progress__container">
<div class="progress__bar">
<div id="progress__fill" class="step1"></div>
<div class="circ" id="circ__1"></div>
<div class="circ" id="circ__2"></div>
<div class="circ" id="circ__3"></div>
<div class="circ" id="circ__4"></div>
<div id="progress__dot" class="prog__1"></div>
</div>
<div class="backBar"></div>
<div class="flexrow">
<span class="stepName">Account</span>
<span class="stepName">Frequency</span>
<span class="stepName">Amount</span>
<span class="stepName">Taxes</span>
</div>
<div class="button__container">
<button class="buttonStep" id="back">Back</button>
<button class="buttonStep is-active" id="next">Next</button>
</div>
</div>
js:
// give a starting value for the transformation
var startVal = 0;
// define the keyframes
var moveDot = [
{ transform: `translateX(${startVal}px)`},
{ transform: `translateX(${startVal + 190}px)`}
];
// definte the timing
var dotTiming = {
duration: 400,
fill: "forwards",
easing: 'ease-in',
}
// make the animation happen
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
// pause the animation until called
movingDot.pause();
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
movingDot.playbackRate = 1;
if (startVal <= 380) {
movingDot.play();
startVal += 190;
}
});
document.getElementById('back').addEventListener('click', function() {
movingDot.playbackRate = -1;
if (startVal >= 0) {
movingDot.play();
startVal -= 190;
}
});
css:
#progress__fill {
height:2px;
position: absolute;
top: 7px;
left: 0;
background-color: darkred;
}
#progress__dot {
background-color: darkred;
color: #fff;
border-radius: 50%;
height: 8px;
width: 8px;
position: absolute;
text-align:center;
line-height: 8px;
padding: 6px;
top: 0;
font-size: 12px;
}
/* Static Bar Elements */
.progress__container {
width: 600px;
margin: 20px auto;
position: relative;
}
.backBar {
height:2px;
width:96%;
position: absolute;
top: 7px;
left: 2%;
background-color: lightgrey;
}
.progress__bar {
z-index: 100;
position: relative;
width: 96%;
margin: 0 auto;
}
.circ {
background-color: #fff;
border: 2px solid lightgrey;
border-radius: 50%;
height: 12px;
width: 12px;
display: inline-block;
}
#circ__2, #circ__3 {
margin-left: 30%
}
#circ__4 {
float: right;
}
.passed {
background-color: darkred;
border: 2px solid darkred;
}
.hide {
visibility: hidden
}
.flexrow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
/* Buttons */
.buttonStep {
background: grey;
color: #fff;
padding: 10px 25px;
border-radius: 10px;
font-size: 16px;
}
#back {
float: left;
}
#next {
float: right;
}
.is-active {
background: darkred;
}
The way I have it set up, I expect for the translateX values to increment or decrement depending on the click event listeners which would make the circle slide across the page. What is actually happening is that only the first step works. it will not go past the first stop point. If I log moveDot in the console it gives me the values that I am expecting, but it will only start/stop at 0 and 190. the back button functions the same way. link to fiddle
It is animated from and to the same place every time. Move the definition of moveDot into the event listener:
// give a starting value for the transformation
var startVal = 0;
// definte the timing
var dotTiming = {
duration: 400,
fill: "forwards",
easing: 'ease-in',
}
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
if (startVal > 380){return;}
// define the keyframes
var moveDot = [{transform: `translateX(${startVal}px)`},
{transform: `translateX(${startVal + 190}px)`}];
// make the animation happen
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
movingDot.playbackRate = 1;
movingDot.play();
startVal += 190;
});
document.getElementById('back').addEventListener('click', function() {
movingDot.playbackRate = -1;
if (startVal >= 0) {
movingDot.play();
startVal -= 190;
}
});

JS / CSS issue with Div Slider and Display:Table-Cell

I have a Div slider that rotates a set of Divs in and out of focus. Everything was working fine until I tried switching everything to (table / table-cell) in order to keep them all the Divs the same height in CSS. Now they still rotate out but one div remains visible with a reduced width off to the side of the stage. I get a sense that its position related but just can't figure out what's causing the issue.
Affected Page - https://www.harpercollege.edu/dev/blog-slider-test.php
JS Code:
$('.blog-posts').wrapInner('<div class="blog-posts-stage" />');
// Calculate Conditions & Set Vars
// var playTimer = 9,
slideQty = $('.well').length,
slideWidth = $('.well').width(),
stageWidth = $('.blog-posts-stage').width(),
contWidth = $('.blog-posts').width();
if ((slideQty * slideWidth) < contWidth) {
$('.blog-posts-prev').addClass('blog-posts-prev-disabled').removeClass('blog-posts-prev');
$('.blog-posts-next').addClass('blog-posts-next-disabled').removeClass('blog-posts-next');
} else {
$('.blog-posts-prev-disabled').addClass('blog-posts-prev').removeClass('blog-posts-prev-disabled');
$('.blog-posts-next-disabled').addClass('blog-posts-next').removeClass('blog-posts-next-disabled');
}
$(window).resize(function() {
var slideQty = $('.well').length,
slideWidth = $('.well').width(),
stageWidth = $('.blog-posts-stage').width(),
contWidth = $('.blog-posts').width();
if ((slideQty * slideWidth) < contWidth) {
$('.blog-posts-prev').addClass('blog-posts-prev-disabled').removeClass('blog-posts-prev');
$('.blog-posts-next').addClass('blog-posts-next-disabled').removeClass('blog-posts-next');
} else {
$('.blog-posts-prev-disabled').addClass('blog-posts-prev').removeClass('blog-posts-prev-disabled');
$('.blog-posts-next-disabled').addClass('blog-posts-next').removeClass('blog-posts-next-disabled');
}
});
$('.blog-posts-next').on('click', function(event) {
event.preventDefault();
$('.blog-posts-stage').animate({
left: -(slideWidth)
}, 500, function() {
$('.well:first').appendTo('.blog-posts-stage');
$('.blog-posts-stage').css({
left: '0px'
});
});
});
$('.blog-posts-prev').on('click', function(event) {
event.preventDefault();
$('.well:last').prependTo('.blog-posts-stage');
$('.blog-posts-stage').css({
left: -(slideWidth)
});
$('.blog-posts-stage').animate({
left: '0px'
}, 500, function() {});
});
function moveForward() {
$('.blog-posts-stage').animate({
left: -(slideWidth)
}, 500, function() {
$('.well:first').appendTo('.blog-posts-stage');
$('.blog-posts-stage').css({
left: '0px'
});
});
}
var timer = setInterval(moveForward, playTimer);
$('.blog-posts, .blog-posts-prev, .blog-posts-next').hover(function(ev) {
// clearInterval(timer);
}, function(ev) {
// timer = setInterval( moveForward, playTimer);
});
CSS Code:
<style>
.blog-posts {
width: 100%;
background: #eee;
font-size: 0;
position: relative;
}
.blog-posts-prev,
.blog-posts-next {
display: inline-block;
background: #eee;
color: #000;
text-decoration: none;
padding: 10px;
margin: 5px 0;
}
.blog-posts-prev:hover,
.blog-posts-next:hover {
background: #ccc;
}
.blog-posts-prev-disabled,
.blog-posts-next-disabled {
display: inline-block;
background: #eee;
color: #ccc;
text-decoration: none;
padding: 10px;
margin: 5px 0;
}
.blog-posts-stage {
position: relative;
white-space: normal;
width: 100%;
height: 100%;
float: none;
}
.well {
background: #ccc;
box-shadow: inset -1px 0px 0px 0px rgb(255, 255, 255);
width: 100%;
font-size: 12px;
text-align: left;
display: table-cell;
height: 100%;
width: 100%;
}
.well .row .col-sm-12.col-md-12 h2 {
float: left;
margin-top: 0px;
}
</style>
You could just use a lightbox library and save yourself the effort, but if you really want to do this why not try flex?
.blog-posts-stage {
display: flex;
flex-direction: row;
overflow: hidden;
}
.well-large {
flex-shrink: 0;
}

Categories

Resources