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!
Related
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');
}
}
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
I currently use a marquee effect in the project!
I hope that in class = "placard", there is only one set of placard item, and the marquee stops executing. If
there is more than one set of placard item, the marquee will be executed. How to write my JavaScript What?
Since I am a newbie to JavaScript, I don't know how to implement it at all. I hope I can get your help.
function slideLine(box, stf, delay, speed, h) {
console.log('slideLine')
var slideBox = document.getElementById(box);
var delay = delay || 500,
speed = speed || 20,
h = h || 20;
var tid = null,
pause = false;
var s = function() {
tid = setInterval(slide, speed);
}
var slide = function() {
if (pause) return;
slideBox.scrollTop += 1;
if (slideBox.scrollTop % h == 0) {
clearInterval(tid);
slideBox.appendChild(slideBox.getElementsByTagName(stf)[0]);
slideBox.scrollTop = 0;
setTimeout(s, delay);
}
}
slideBox.onmouseover = function() {
pause = true;
}
slideBox.onmouseout = function() {
pause = false;
}
setTimeout(s, delay);
}
slideLine('js-placard', 'div', 1000, 25, 20);
.contact_placard .placard {
background-color: #fff0d8;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 8px 0px;
margin-top: 58px;
margin-bottom: 12px;
height: 20px;
overflow: hidden;
}
.contact_placard .placard_item {
display: flex;
align-items: center;
line-height: 5px;
}
.contact_placard .placard .megaphone {
display: inline-block;
width: 20px;
height: 20px;
background-size: cover;
margin-right: 8px;
}
.contact_placard .placard .placard_text {
font-size: 13px;
letter-spacing: 0.43px;
}
.contact_placard .placard .placard_link {
font-size: 13px;
letter-spacing: 0.43px;
margin-left: 8px;
color: red;
}
<section class="contact_placard">
<div class="placard" id="js-placard">
<div class="placard_item">
<span class="megaphone"></span>
<h3 class="placard_text">apple</h3>
</div>
<div class="placard_item">
<span class="megaphone"></span>
<h3 class="placard_text">Strawberry</h3>
</div>
<div class="placard_item">
<span class="megaphone"></span>
<h3 class="placard_text">banana</h3>
</div>
</div>
</section>
Thank you for your help~
At the beginning of the slideLine function you can test whether there are more than one elaments in the marquee - i.e. with class placard_item.
If there aren't then this snippet just returns without doing anything.
if (document.querySelectorAll('.placard_item').length <= 1) return;
Note: the test is put within the function rather than just before it is called because I don't know how dynamic your situation is. If more things are added or removed at run time and this function is called then it will do what is required.
function slideLine(box, stf, delay, speed, h) {
if (document.querySelectorAll('.placard_item').length <= 1) return;
console.log('slideLine')
var slideBox = document.getElementById(box);
var delay = delay || 500,
speed = speed || 20,
h = h || 20;
var tid = null,
pause = false;
var s = function() {
tid = setInterval(slide, speed);
}
var slide = function() {
if (pause) return;
slideBox.scrollTop += 1;
if (slideBox.scrollTop % h == 0) {
clearInterval(tid);
slideBox.appendChild(slideBox.getElementsByTagName(stf)[0]);
slideBox.scrollTop = 0;
setTimeout(s, delay);
}
}
slideBox.onmouseover = function() {
pause = true;
}
slideBox.onmouseout = function() {
pause = false;
}
setTimeout(s, delay);
}
slideLine('js-placard', 'div', 1000, 25, 20);
.contact_placard .placard {
background-color: #fff0d8;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 8px 0px;
margin-top: 58px;
margin-bottom: 12px;
height: 20px;
overflow: hidden;
}
.contact_placard .placard_item {
display: flex;
align-items: center;
line-height: 5px;
}
.contact_placard .placard .megaphone {
display: inline-block;
width: 20px;
height: 20px;
background-size: cover;
margin-right: 8px;
}
.contact_placard .placard .placard_text {
font-size: 13px;
letter-spacing: 0.43px;
}
.contact_placard .placard .placard_link {
font-size: 13px;
letter-spacing: 0.43px;
margin-left: 8px;
color: red;
}
<section class="contact_placard">
<div class="placard" id="js-placard">
<div class="placard_item">
<span class="megaphone"></span>
<h3 class="placard_text">apple</h3>
</div>
<div class="placard_item">
<span class="megaphone"></span>
<h3 class="placard_text">Strawberry</h3>
</div>
<div class="placard_item">
<span class="megaphone"></span>
<h3 class="placard_text">banana</h3>
</div>
</div>
</section>
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,
I made a clock where the format is the following.
HH:MM AM
HH:MM S
My problem is that whenever the seconds changed, the minutes and the hours get pushed around to fit the number. My font, Modern Sans, is not monospace, which is probably the main cause for this, but I would like to keep that font, of course only if possible. I would also like to keep the clock centered on the page.
Thanks for your help!
EDIT: Please view the snippet in fullscreen. It acts a little weird(er) in the regular box.
function updateClock() {
var date = new Date();
var h = (date.getHours() + 24) % 12 || 12,
m = date.getMinutes(),
s = date.getSeconds(),
dm = "AM";
if (h >= 12)
dm = "PM";
if (m < 10) m = '0' + m;
if (s < 10) s = '0' + s;
$(".mt.h").html(h);
$(".mt.m").html(m);
$(".mt.s").html(s);
$(".mt.dm").html(dm);
setTimeout(updateClock, 1000);
}
body,
html {
height: 100%;
margin: 0;
padding: 0;
width: 100%;
display: table;
}
* {
font-family: "Modern Sans", Helvetica;
}
.main-content {
text-align: center;
display: table-cell;
vertical-align: middle;
padding: 10px;
}
.search {
vertical-align: middle;
}
.clock {
color: rgba(0, 0, 0, 0.65);
}
.clock .unflex div {
display: inline-block;
}
.clock .unflex {
display: inline;
}
.mt.h,
.mt.m,
.mt.c {
font-size: 250px;
}
.mt.s {
font-size: 125px;
color: rgba(250, 0, 0, 0.45);
}
.mt.dm {
font-size: 75px;
}
.flexclock {
position: relative;
top: -125.5px;
display: inline-flex;
justify-content: flex-start;
flex-wrap: wrap;
align-content: center;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.2.1.js" type="text/javascript"></script>
</head>
<body onload="updateClock()">
<div class="main-content">
<div class="clock">
<div class="unflex">
<div class="mt h"></div>
<div class="mt c">:</div>
<div class="mt m"></div>
</div>
<div class="flexclock">
<div class="mtsdm">
<div class="mt dm"></div>
<div class="mt s"></div>
</div>
</div>
</div>
</div>
</body>
</html>
As different number characters have different width, and to avoid text to move in cases like this, one can set a width wide enough on each item so they won't effect their surroundings.
An alternative is also absolute positioning, though I find the below better and more responsive.
Here I added/updated these rules
.mt.h {
width: 160px;
}
.mt.m {
width: 320px;
}
.mt.c {
width: 80px;
}
.mt.s {
font-size: 125px;
color: rgba(250, 0, 0, 0.45);
width: 160px;
}
Stack snippet
function updateClock() {
var date = new Date();
var h = (date.getHours() + 24) % 12 || 12,
m = date.getMinutes(),
s = date.getSeconds(),
dm = "AM";
if (h >= 12)
dm = "PM";
if (m < 10) m = '0' + m;
if (s < 10) s = '0' + s;
$(".mt.h").html(h);
$(".mt.m").html(m);
$(".mt.s").html(s);
$(".mt.dm").html(dm);
setTimeout(updateClock, 1000);
}
body,
html {
height: 100%;
margin: 0;
padding: 0;
width: 100%;
display: table;
}
* {
font-family: "Modern Sans", Helvetica;
}
.main-content {
text-align: center;
display: table-cell;
vertical-align: middle;
padding: 10px;
}
.search {
vertical-align: middle;
}
.clock {
color: rgba(0, 0, 0, 0.65);
}
.clock .unflex div {
display: inline-block;
}
.clock .unflex {
display: inline;
}
.mt.h,
.mt.m,
.mt.c {
font-size: 250px;
}
.mt.h {
width: 160px;
}
.mt.m {
width: 320px;
}
.mt.c {
width: 80px;
}
.mt.s {
font-size: 125px;
color: rgba(250, 0, 0, 0.45);
width: 160px;
}
.mt.dm {
font-size: 75px;
}
.flexclock {
position: relative;
top: -125.5px;
display: inline-flex;
justify-content: flex-start;
flex-wrap: wrap;
align-content: center;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.2.1.js" type="text/javascript"></script>
</head>
<body onload="updateClock()">
<div class="main-content">
<div class="clock">
<div class="unflex">
<div class="mt h"></div>
<div class="mt c">:</div>
<div class="mt m"></div>
</div>
<div class="flexclock">
<div class="mtsdm">
<div class="mt dm"></div>
<div class="mt s"></div>
</div>
</div>
</div>
</div>
</body>
</html>