How to add width to an element using jquery each function? - javascript

I want to build a loading bar effect using two seperate divs inside each other. I got it all positioned and all that but how can I make one of them increase its width from %1 to %100 with transition? I want it to be filled in 10 sec.
Thanks.
<div class="loading-container">
<div class="outside-loading"></div>
<div class="inside-loading"></div>
</div>

Fairly simple with jQuery animate() which you can customize for step or easing and also use callbacks for start or complete as needed
$('.outside-loading').animate({width: '100%'}, 3000);// using 3 sec for demo
.outside-loading {
background: blue;
width: 0;
height: .5em
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="loading-container">
<div class="outside-loading"></div>
<div class="inside-loading"></div>
</div>

Vanilla Javascript
Create a function and increase the width with your set interval function. Add a conditional that checks if the width is 100% and if it is, then clear the interval. I also moved the divs within each other and set the display of the inner span tag to inline-block...
You can also target the elements textContent and display the widths progress in percent as well...
var i = 0;
function move() {
if (i == 0) {
i = 1;
var elem = document.getElementsByClassName("inside-loading");
var width = 1;
var id = setInterval(frame, 100);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem[0].style.width = width + "%";
elem[0].textContent = width + "%";
}
}
}
}
move();
.outside-loading {
width: 100%;
height: 30px;
background-color: grey;
}
.inside-loading {
display: inline-block;
width: 1%;
height: 100%;
background-color: red;
text-align: right;
vertical-align: middle;
font-size: 30px;
font-weight: bold;
font-family: Arial, Helvetica, sans-serif;
}
<br><br><br>
<div class="loading-container">
<div class="outside-loading">
<span class="inside-loading">
</span>
</div>
</div>

Related

Mobile browsers add a gap at the end of final element via css gap property

I'm back on Stack Overflow after a long time because I'm truly stuck at an issue I cannot get around even after hours piling up in front of the screen.
I have made a simple widget using CSS + HTML + JavaScript which scrolls elements in an overflowing-x container.
It works in a simple way, there is JavaScript code that adds a 205 value to the property scrollLeft of the overflowing container. The number comes from the fixed width of the images + the gap value which is 5px. Here is the code:
HTML:
<div id="controlContainer">
<a class="adButton" onclick="Scroll(-1)">❮</a>
<div id="topics">
<div class="adItem" onclick="ChangeTopic(1)">
<p>History</p>
<img src="images/other_samples/hundredgates.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(2)">
<p>Oceans</p>
<img src="images/other_samples/goldensea.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(3)">
<p>Sports</p>
<img src="images/other_samples/kite_surf.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(4)">
<p>Travel</p>
<img src="images/other_samples/antiparos_church.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(5)">
<p>Nightlife</p>
<img src="images/other_samples/nightlife.png">
</div>
</div>
<a class="adButton" onclick="Scroll(1)">❯</a>
</div>
CSS:
#controlContainer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 20px;
}
#topics {
display: inherit;
gap: 5px;
overflow:hidden;
white-space: nowrap;
scroll-behavior: smooth;
}
.adItem {
position: relative;
}
.adItem img {
width: 200px;
height: 200px;
object-fit: cover;
border-radius: 20px;
}
.adItem p {
position: absolute;
left: 16px;
top: 8px;
text-align: center;
color: #ffff;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 50px;
margin: 0px;
user-select: none;
pointer: default:
}
And finally JS, which still needs some work tbh:
var LastClick;
var Delay = 300;
var SelectedElement;
var adControl;
var currentScroll;
window.onload = function () {SelectedElement = document.getElementById("ad1"); adControl = document.getElementById("topics"); resizeController();};
window.onresize = debounce(() => resizeController());; //resize the container when the screen does
//window.addEventListener('DOMContentLoaded', (event) => {SelectedElement = document.getElementById("ad1")});
function Scroll(n) {
if (LastClick >= (Date.now() - Delay)) {
return;
}
if (n == 1) {
adControl.scrollLeft += 205;
checkPos();
} else if (n == -1) {
adControl.scrollLeft -= 205;
checkPos();
}
LastClick = Date.now();
console.log(adControl.scrollLeft);
}; // This function is what's handling scrolling. THey are called via onclick events on the HTML Button elements
function checkPos() {
var elementWidth = adControl.scrollLeft;
if (elementWidth % 5 === 0) {
// do nothing
} else {
var newWidth = Math.ceil(elementWidth/5)*5;
console.log("old width: %s, new width: %s", elementWidth, newWidth)
adControl.scrollLeft = newWidth;
}
}; //Some position checks... it basically calculates if scrollLeft is divisible by 5, because all images are 200px long plus the 5px gap, so that should always be a multiple of 5.
function ChangeTopic(id) {
SelectedElement.style.display = "none";
SelectedElement = document.getElementById("ad" + id);
SelectedElement.style.display = "flex";
}; //That just changes the topic of another element.
function debounce(func, timeout = 1000){
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}; //This is a debounce function for the resize event, it prevents it from firing it too much.
function resizeController() {
adControl.style.maxWidth = "";
var elementWidth = adControl.offsetWidth;
var scroll = adControl.ScrollLeft;
var itemNo = (Math.floor(elementWidth / 200))
if (itemNo > 3) {
itemNo = 3
};
var newWidth = (itemNo*200);
newWidth = newWidth+(5*itemNo)
adControl.style.maxWidth = (newWidth + "px");
if (currentNo = itemNo) {
adControl.scrollLeft = scroll;
}
}; //resizes the container if need be (for mobile or tablet devices)
It actually works very well on Desktop, but on mobile, the CSS gap property which adds the gap between the images also adds a gap at the last element, like this:
That's even when I use a different browser from Firefox, like Chrome
On desktop, this gap does not exist, regardless of browser once again:
What is this? And how can I solve it? The main problem this causes is it will scroll in that tiny 5 gap space, which throws the position of my elements out of place, making them look like this:
I've thought of different methods like checking the property of ScrollLeft to detect when the view is out of the elements, but that property is completely unpredictable. For instance, when I scroll to the beginning of the element, it's not going to be necessarily zero, and even if I reach the end, the 205 value will be added even if there is not any space on the container. So that isn't reliable.
In short, I'd either need some kind of method to keep that gapping behaviour in check or solve the root problem altogether.
Yes... I'm not using any framework at all, my entire project is built on pure JavaScript. I'm not sure why I did this to myself, but oh well, all the challenge I guess.
Try and resize your font on the paragraph elements in your
div class="adItem" it appears to be overlapping the container and causing what would appear to be extra padding and i don't think it's happening on the others because the text is not long enough on others.
var LastClick;
var Delay = 300;
var SelectedElement;
var adControl;
var currentScroll;
window.onload = function () {SelectedElement = document.getElementById("ad1"); adControl = document.getElementById("topics"); resizeController();};
window.onresize = debounce(() => resizeController());; //resize the container when the screen does
//window.addEventListener('DOMContentLoaded', (event) => {SelectedElement = document.getElementById("ad1")});
function Scroll(n) {
if (LastClick >= (Date.now() - Delay)) {
return;
}
if (n == 1) {
adControl.scrollLeft += 205;
checkPos();
} else if (n == -1) {
adControl.scrollLeft -= 205;
checkPos();
}
LastClick = Date.now();
console.log(adControl.scrollLeft);
}; // This function is what's handling scrolling. THey are called via onclick events on the HTML Button elements
function checkPos() {
var elementWidth = adControl.scrollLeft;
if (elementWidth % 5 === 0) {
// do nothing
} else {
var newWidth = Math.ceil(elementWidth/5)*5;
console.log("old width: %s, new width: %s", elementWidth, newWidth)
adControl.scrollLeft = newWidth;
}
}; //Some position checks... it basically calculates if scrollLeft is divisible by 5, because all images are 200px long plus the 5px gap, so that should always be a multiple of 5.
function ChangeTopic(id) {
SelectedElement.style.display = "none";
SelectedElement = document.getElementById("ad" + id);
SelectedElement.style.display = "flex";
}; //That just changes the topic of another element.
function debounce(func, timeout = 1000){
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}; //This is a debounce function for the resize event, it prevents it from firing it too much.
function resizeController() {
adControl.style.maxWidth = "";
var elementWidth = adControl.offsetWidth;
var scroll = adControl.ScrollLeft;
var itemNo = (Math.floor(elementWidth / 200))
if (itemNo > 3) {
itemNo = 3
};
var newWidth = (itemNo*200);
newWidth = newWidth+(5*itemNo)
adControl.style.maxWidth = (newWidth + "px");
if (currentNo = itemNo) {
adControl.scrollLeft = scroll;
}
}; //resizes the container if need be (for mobile or tablet devices)
#controlContainer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 20px;
}
#topics {
display: inherit;
gap: 5px;
overflow:hidden;
white-space: nowrap;
scroll-behavior: smooth;
}
.adItem {
position: relative;
}
.adItem img {
width: 200px;
height: 200px;
object-fit: cover;
border-radius: 20px;
}
.adItem p {
position: absolute;
left: 16px;
top: 8px;
text-align: center;
color: #ffff;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 50px;
margin: 0px;
user-select: none;
pointer: default:
}
<div id="controlContainer">
<a class="adButton" onclick="Scroll(-1)">❮</a>
<div id="topics">
<div class="adItem" onclick="ChangeTopic(1)">
<p>History</p>
<img src="images/other_samples/hundredgates.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(2)">
<p>Oceans</p>
<img src="images/other_samples/goldensea.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(3)">
<p>Sports</p>
<img src="images/other_samples/kite_surf.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(4)">
<p>Travel</p>
<img src="images/other_samples/antiparos_church.jpg">
</div>
<div class="adItem" onclick="ChangeTopic(5)">
<p>Nightlife</p>
<img src="images/other_samples/nightlife.png">
</div>
</div>
<a class="adButton" onclick="Scroll(1)">❯</a>
</div>

How to make jquery scrolling effect work on multiple element/classes?

I'm trying to make a very light script for multiple classes class"demo" that can work on my onScrollDown responsive animation.
I don't really understand about writing arrays. but, I believe that if I use document.getElementsByClassName("demo")[i] , i < 0 and some function(i) I can implement it for individual classes. Because I use getBoundingClientRect() instead of fixed value.
So, how can I write it correctly using i as arrays?
Thank you..
Here is my working script :
<script>
var e = document.getElementById("demo");
var rect = e.getBoundingClientRect();
var x = rect.top;
$(window).bind('scroll', function () {
if ($(window).scrollTop() > x-300) {
$('#demo').addClass('animate');
} else {
$('#demo').removeClass('animate');
}
});
</script>
*work only for a single element.
Here is what I'm trying to do, that not working yet
<script>
var e = document.getElementsClassName("test")[i];
var rect = e.getBoundingClientRect();
var x = rect.top;
var i;
for (i = 0; i < e.length; i++) {
$(window).bind('scroll', function (i) {
if ($(window).scrollTop() > x-300) {
$e.addClass('animate');
} else {
$e.removeClass('animate');
}
});
}
</script>
CSS :
<style>
.test {
background:#345;
color:#FFF;
height:2em;
padding:.5em;
top:50px;
margin-top: 100px;
width:100%;
}
.animate {
width: 60px;
}
</style>
HTML
<div style="color: red; margin-bottom: 400px;">(Top!)</div>
<div class="test" id="demo">Menu</div>
<div class="test" id="demo">Menu</div>
<div class="test" id="demo">Menu</div>
<div style="color: red; margin-top: 400px;">(Bottom!)</div>
Okay so I've achieved what you're trying to do. Here are the changes I made:
Used the JQuery each function. This will loop all of the demo elements every time a scroll is detected. There are other ways of looping the elements but because you've already imported JQuery we may as well use it's functions.
Changed #demo to .demo. In other words, I've changed id to class. id should only be used when working with elements that are completely unique. In this case, there are multiple demos so we use class instead.
Final code (as you scroll each element will turn red showing that the animate class has been added:
$(window).on('scroll', function() {
$('.demo').each(function(i, obj) {
var rect = obj.getBoundingClientRect();
var x = rect.top;
if ($(window).scrollTop() > x - 300) {
$(obj).addClass('animate');
} else {
$(obj).removeClass('animate');
}
});
});
.body {
height: 200vh;
background-color: #f1f1f1;
}
.demo {
height: 200px;
width: 100%;
background-color: #f9f9f9;
}
.demo.animate {
background-color: #ff0000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="body">
<div class="demo"></div>
<div class="demo"></div>
<div class="demo"></div>
<div class="demo"></div>
</div>
There are few notes in regards to your code:
In jQuery you can get elements offset by using .offset() function.
you should not use the same id more than once per page.
.bind() has been deprecated since jQuery 3.0. Use .on() instead.
To toggle class you can use .toggleClass(className, state). State is used to determine if you want to remove or add the class.
See this example:
$(window).on('scroll', function() {
jQuery(".test").each(function() {
let isTop = $(window).scrollTop() > jQuery(this).offset().top - 300;
jQuery(this).toggleClass('animate', isTop);
});
});
.test {
background: #345;
color: #FFF;
height: 2em;
padding: .5em;
top: 50px;
margin-top: 100px;
width: 100%;
}
.animate {
width: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="color: red; margin-bottom: 400px;">(Top!)</div>
<div class="test">Menu</div>
<div class="test">Menu</div>
<div class="test">Menu</div>
<div style="color: red; margin-top: 400px;">(Bottom!)</div>

Update text of an element when another element property changes

I get a code from other app that changes progress. Based on progress bar width property, can I change progress text?
I want an event that update the progress-indicator-text when progress-indicator-bar width changes. Code here:
$(function() {
//For demo purpose only
$('button').click(function() {
var percentWidth = $('.progress-indicator-bar').width() / $('.progress-indicator-bar').parent().width() * 100;
if (percentWidth < 100) $('.progress-indicator-bar').width(percentWidth + 10 + "%");
})
//Requires appropriate event/approach to change the text of .progress-indicator-text when width of .progress-indicator-bar changes.
$('.progress-indicator-bar').change(function() {
$('.progress-indicator-text').html($('.progress-indicator-bar').width() / $('.progress-indicator-bar').parent().width() * 100 + "%");
})
});
.progress-indicator-bar-holder {
width: 100px;
height: 10px;
background: #e4e4e4;
float: left;
}
.progress-indicator-bar {
background: #008000;
height: 10px;
}
.progress-indicator-text {
font-weight: bold;
font-size: 11px;
line-height: 8px;
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- This code embeds from another application -->
<div class="progress-indicator">
<div class="progress-indicator-bar-holder">
<div class="progress-indicator-bar" style="width: 30%;"></div>
</div>
</div>
<!-- Based on progress-indicator-bar width the progress-indicator-text should change -->
<div class="progress-indicator-text">30%</div>
<br>
<button>Change</button>
It's a bit like breaking a butterfly on a wheel but you can utilize the MutationObserver API to watch for changes in the DOM.
Just register the div holding the percentage bar and whenever it's style attribute changes update the div containing the text.
Here's an example:
//For demo purpose only
$('button').click(function() {
var percentWidth = $('.progress-indicator-bar').width() / $('.progress-indicator-bar').parent().width() * 100;
if (percentWidth < 100) $('.progress-indicator-bar').width(percentWidth + 10 + "%");
})
var target = document.getElementsByClassName('progress-indicator-bar');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName == "style") {
$('.progress-indicator-text').html($('.progress-indicator-bar').width() / $('.progress-indicator-bar').parent().width() * 100 + "%");
}
});
});
var config = {
attributes: true,
childList: true,
characterData: true
};
observer.observe(target[0], config);
.progress-indicator-bar-holder {
width: 100px;
height: 10px;
background: #e4e4e4;
float: left;
}
.progress-indicator-bar {
background: #008000;
height: 10px;
}
.progress-indicator-text {
font-weight: bold;
font-size: 11px;
line-height: 8px;
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="progress-indicator">
<div class="progress-indicator-bar-holder">
<div class="progress-indicator-bar" style="width: 30%;"></div>
</div>
</div>
<!-- Based on progress-indicator-bar width the progress-indicator-text should change -->
<div class="progress-indicator-text">30%</div>
<br>
<button>Change</button>
You can trigger events in jQuery with the .trigger method when you are in a handler.
$(function() {
//For demo purpose only
$('button').click(function() {
var percentWidth = $('.progress-indicator-bar').width() / $('.progress-indicator-bar').parent().width() * 100;
if (percentWidth < 100) $('.progress-indicator-bar').width(percentWidth + 10 + "%");
$('.progress-indicator-bar').trigger('change') // i added this line
})
//Requires appropriate event/approach to change the text of .progress-indicator-text when width of .progress-indicator-bar changes.
$('.progress-indicator-bar').change(function() {
$('.progress-indicator-text').html($('.progress-indicator-bar').width() / $('.progress-indicator-bar').parent().width() * 100 + "%");
})
});
.progress-indicator-bar-holder {
width: 100px;
height: 10px;
background: #e4e4e4;
float: left;
}
.progress-indicator-bar {
background: #008000;
height: 10px;
}
.progress-indicator-text {
font-weight: bold;
font-size: 11px;
line-height: 8px;
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- This code embeds from another application -->
<div class="progress-indicator">
<div class="progress-indicator-bar-holder">
<div class="progress-indicator-bar" style="width: 30%;"></div>
</div>
</div>
<!-- Based on progress-indicator-bar width the progress-indicator-text should change -->
<div class="progress-indicator-text">30%</div>
<br>
<button>Change</button>
you can use the ResizeSensor to detect the width change of the element.
please refer this page How to detect DIV's dimension changed?

Auto Animate Scroll to Right of an Element that Overflows its Container?

I have a group of elements which fade in and out, (one after another), within a containing div (.info). Some of the elements stay within the container when they appear, while others overflow the container, which is not preferred.
When such a circumstance occurs, I would like for some kind of horizontal/auto-scroll effect to be applied, so it can reveal the beginning to the end of the overflowing text element, while still remaining on a single line. Is there any way to accomplish this with JQuery?
Here is a snippet of the progress I have made so far:
(function() {
var tab = $(".info .tab");
var tabIndex = -1;
function showNextTab() {
++tabIndex;
tab
.eq(tabIndex % tab.length)
.fadeIn(2000)
.delay(2000)
.fadeOut(2000, showNextTab);
}
showNextTab();
})();
.info {
background: skyblue;
display: inline-block;
line-height: 1;
width: 500px;
padding: 20px;
box-sizing: border-box;
}
.info .tab {
display: none;
}
h2.tab {
margin: 0;
padding: 0;
border: 0;
white-space: nowrap;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="info">
<h2 class="tab">This is the first line.</h2>
<h2 class="tab">This is the second line.</h2>
<h2 class="tab">This is the third line (which is longer than the first and second line.)</h2>
<h2 class="tab">This is the fourth line (which is longer than the first, second, and third line.)</h2>
</div>
UPDATE: Scroll Effect Added/Still Troubleshooting
Here is an updated snippet, with recent recommendations applied:
var myVar = "";
(function() {
var tab = $(".info .tab");
var tabIndex = -1;
function showNextTab() {
++tabIndex;
myVar = setInterval(myTimer, 1000);
tab
.eq(tabIndex % tab.length)
.fadeIn(2000)
.delay(2000)
.fadeOut(2000, showNextTab);
}
showNextTab();
})();
function myTimer() {
var leftPos = $(".info").scrollLeft();
$(".info").animate({
scrollLeft: leftPos + 200
}, 800);
myStopFunction();
}
function myStopFunction() {
clearInterval(myVar);
}
.info-wrap {
background: skyblue;
display: inline-block;
line-height: 1;
width: 500px;
padding: 20px;
}
.info {
display: inline-block;
line-height: 1;
width: 500px;
overflow: hidden;
}
.info .tab {
display: none;
}
h2.tab {
margin: 0;
padding: 0;
border: 0;
line-height: 1;
white-space: nowrap;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<duv class="info-wrap">
<div class="info">
<h2 class="tab">This is the first line.</h2>
<h2 class="tab">This is the second line.</h2>
<h2 class="tab">This is the third line (which is longer than the first and second line.)</h2>
<h2 class="tab">This is the fourth line (which is longer than the first, second, and third line.)</h2>
</div>
</div>
Question 1: Why is the fourth <h2 class="tab"> element not scrolling from the beginning? It seems to be starting from a halfway point, to the right.
Question 2: How can the speed of the slide-left animation be modified? I am trying to understand what the myVar = setInterval(myTimer, 1000); is targeting, and also scrollLeft: leftPos + 200}, 800);.
EXPLANATION:
Question1 : Because the width of scroll maximum is relative based on how many characters are created to make the width of scroll size. Right when the function is initialed, the variable $('.info').scrollLeft() seems save the previous point. Therefore, I re-initial that code by adding this code:
$(".info").animate({scrollLeft: 0}, 0); //$(.info) point = 0
Question2 : The left side animation can be speed up by increasing the value of leftPos. And this myVar = setInterval(myTimer, 1000); is to determine the start point. It means the function will begin at 1 sec.
Anyway here is the example below
var myVar = "";
(function() {
var tab = $(".info .tab");
var tabIndex = -1;
function showNextTab() {
++tabIndex;
myVar = setInterval(myTimer, 1000);
tab
.eq(tabIndex % tab.length)
.fadeIn(2000)
.delay(1000)
.fadeOut(2000, showNextTab);
$(".info").animate({scrollLeft: 0}, 0);
}
showNextTab();
})();
function myTimer() {
var leftPos = $('.info').scrollLeft();
$(".info").animate({scrollLeft: leftPos + 1500}, 800);
myStopFunction();
}
function myStopFunction() {
clearInterval(myVar);
}
.info {
background: skyblue;
display: inline-block;
line-height: 1;
width: 500px;
padding: 20px;
box-sizing: border-box;
overflow:scroll;
}
.info .tab {
display: none;
}
h2.tab {
margin: 0;
padding: 0;
border: 0;
white-space: nowrap;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="info">
<h2 class="tab">This is the first line. testtesttesttesttesttesttttttttttt</h2>
<h2 class="tab">This is the second line.</h2>
<h2 class="tab">This is the third line (which is longer than the first and second line.)</h2>
<h2 class="tab">This is the fourth line (which is longer than the first, second, and third line.)</h2>
</div>

Animating the percent of a "percentage bar" during the transition

I have created a very basic animated percentage bar with HTML, CSS, and JS the only problem is that I am trying to devise a way to also animate the increase and/or decrease of the percentage output to go along with an animated percentage bar. In the example below and in this JsFiddle I have successfully created that with the only problem being that it doesn't seem to be the most efficient or effective way of doing it.
In the code snippet directly below I'm creating this animated effect by...
Setting x equal to setInterval
Capturing the width of percent bar on the left and removing the px from the end of the string.
Capturing the width of percent bar on the right and removing the px from the end of the string.
Displays the percent value for the left (blue) bar inside the tooltip that can be seen when hovered over.
Displays the percent value for the right (red) bar inside the tooltip that can be seen when hovered over.
Displays the percent value of the left (blue) bar below the percent bar.
Displays the percent value of the right (red) bar below the percent bar.
All of this code below will run every 64 Milliseconds.
This code will only run for 2000 Milliseconds which is the same amount of time that I have set the transition for the percent bars.
Note: The whole point of the code below is to give the illusion that the percent values are increasing as either of the percent bars are increasing. In short, the goal is to make it seem more animated rather than the number all of a sudden seeing the number jump from one number to the next.
There just has to be a better way of achieving the same effect (or better) rather than pulling data from the DOM every 64 Milliseconds. There are tons of real-time graph's out on the web that achieve the same effect but I can't figure out how so I came up with my own and don't really think that they do it this way either. Any ideas??? I would only like to use pure Javascript with no libraries such as jQuery.
var x = setInterval(function() {
var left = parseInt(window.getComputedStyle(p_bar_left).getPropertyValue('width').replace(/px/i, '')) / (parseInt(window.getComputedStyle(p_bar_left).getPropertyValue('width').replace(/px/i, '')) + parseInt(window.getComputedStyle(p_bar_right).getPropertyValue('width').replace(/px/i, ''))) * 100;
var right = parseInt(window.getComputedStyle(p_bar_right).getPropertyValue('width').replace(/px/i, '')) / (parseInt(window.getComputedStyle(p_bar_left).getPropertyValue('width').replace(/px/i, '')) + parseInt(window.getComputedStyle(p_bar_right).getPropertyValue('width').replace(/px/i, ''))) * 100;
p_bar_left.querySelector('.percent-value').innerText = left.toFixed(2) + '%';
document.querySelector('#blue').querySelector('.percent-amount').innerText = left.toFixed(2) + '%';
p_bar_right.querySelector('.percent-value').innerText = right.toFixed(2) + '%';
document.querySelector('#red').querySelector('.percent-amount').innerText = right.toFixed(2) + '%';
}, 64);
setTimeout(function() {
clearInterval(x)
}, 2000);
var good = document.querySelector('#good');
var bad = document.querySelector('#bad');
var p_bar_left = document.querySelector('#progressbar-left');
var p_bar_right = document.querySelector('#progressbar-right');
var counter_left = 0;
var counter_right = 0;
var percent_left = 0;
var percent_right = 0;
function changePercent(increment, which) {
if (which == 'left') {
counter_left += increment;
} else if (which == 'right') {
counter_right += increment;
} else {
throw "Don't know which value to increase.";
}
percent_left = (counter_left / (counter_left + counter_right)) * 100;
percent_right = (counter_right / (counter_left + counter_right)) * 100;
p_bar_left.style.width = percent_left + '%';
p_bar_right.style.width = percent_right + '%';
document.querySelector('#total-amount').innerText = counter_right + counter_left;
var x = setInterval(function() {
var left = parseInt(window.getComputedStyle(p_bar_left).getPropertyValue('width').replace(/px/i, '')) / (parseInt(window.getComputedStyle(p_bar_left).getPropertyValue('width').replace(/px/i, '')) + parseInt(window.getComputedStyle(p_bar_right).getPropertyValue('width').replace(/px/i, ''))) * 100;
var right = parseInt(window.getComputedStyle(p_bar_right).getPropertyValue('width').replace(/px/i, '')) / (parseInt(window.getComputedStyle(p_bar_left).getPropertyValue('width').replace(/px/i, '')) + parseInt(window.getComputedStyle(p_bar_right).getPropertyValue('width').replace(/px/i, ''))) * 100;
p_bar_left.querySelector('.percent-value').innerText = left.toFixed(2) + '%';
document.querySelector('#blue').querySelector('.percent-amount').innerText = left.toFixed(2) + '%';
p_bar_right.querySelector('.percent-value').innerText = right.toFixed(2) + '%';
document.querySelector('#red').querySelector('.percent-amount').innerText = right.toFixed(2) + '%';
}, 64);
setTimeout(function() {
clearInterval(x)
}, 2000);
}
good.addEventListener('click', function() {
changePercent(1, 'left');
});
bad.addEventListener('click', function() {
changePercent(1, 'right');
});
var tooltip = document.querySelectorAll('.tooltip');
var tooltipelement = document.querySelectorAll('#progressbar-left, #progressbar-right');
for (var x = tooltipelement.length; x--;) {
tooltipelement[x].addEventListener('mousemove', function(e) {
for (var i = tooltip.length; i--;) {
tooltip[i].style.left = e.pageX + 20 + 'px';
tooltip[i].style.top = e.pageY + 'px';
}
});
}
#progressbar-container {
display: flex;
position: relative;
width: 50vw;
height: 32px;
border: 2px solid black;
background-color: #ccc;
justify-content: space-between;
}
#progressbar-left {
position: relative;
height: 100%;
background-color: blue;
transition: width 2s;
align-items: center;
justify-content: center;
}
#progressbar-right {
position: relative;
height: 100%;
background-color: red;
transition: width 2s;
align-items: center;
justify-content: center;
}
.tooltip {
display: none;
position: fixed;
width: auto;
height: auto;
padding: 6px;
background-color: black;
text-align: center;
border-radius: 6px;
z-index: 1;
}
.object {
display: inline-block;
color: #fff;
}
.percent-value {
display: inline-block;
color: #fff;
}
#progressbar-left:hover .tooltip {
display: block;
}
#progressbar-right:hover .tooltip {
display: block;
}
#total {
display: block;
font-weight: bold;
}
#total-amount {
display: inline-block;
font-weight: normal;
}
#blue,
#red {
display: block;
font-weight: bold;
}
.percent-amount {
display: inline-block;
font-weight: normal;
}
<body>
<input type="button" value="Good" id="good">
<input type="button" value="Bad" id="bad">
<div id="progressbar-container">
<div id="progressbar-left">
<div class="tooltip">
<span class="tooltiptext">
<span class="object">Blue</span>
<span class="percent-value"></span>
</span>
</div>
</div>
<div id="progressbar-right">
<div class="tooltip">
<span class="tooltiptext">
<span class="object">Red</span>
<span class="percent-value"></span>
</span>
</div>
</div>
</div>
<span id="total">Total: <p id="total-amount">0</p></span>
<span id="blue">Percent Blue: <p class="percent-amount">0%</p></span>
<span id="red">Percent Red: <p class="percent-amount">0%</p></span>
</body>
JsFiddle

Categories