var container = document.querySelector(".container");
var bar = document.querySelector(".bar");
var barL = document.getElementsByClassName("barLayer");
var value = document.getElementsByClassName("value");
var compare = document.getElementsByClassName("compare"); // array vallue to show than code can't get the correct result of that bar's height
var pixelStep = 4; // cooficient to expand bar height. if val=100 => bar.height = 400px
var barNum = 12; // number of bars
var spaceBetween = 100; // space between bars
var intervalTime = 10; // ms reading transition changes
var delayTime = 50; // ms after drawing previous bar.
const data = [
{ brand : "SAMSUNG", val : 40, color : "#c00"},
{ brand : "APPLE", val : 46, color : "#0c0"},
{ brand : "HUAWEI", val : 43, color : "#f84"},
{ brand : "ASUS", val : 71, color : "#248"},
{ brand : "XIAOMI", val : 53, color : "#0cc"},
{ brand : "OPPO", val : 100, color : "#cc0"},
{ brand : "VIVO", val : 66, color : "#c0c"},
{ brand : "MOTOROLA", val : 86, color : "#ccc"},
{ brand : "LENOVO", val : 61, color : "#c40"},
{ brand : "LG", val : 93, color : "#333"},
{ brand : "NOKIA", val : 83, color : "#088"},
{ brand : "OTHERS", val : 51, color : "#06c"} ];
sortFunction(data, "val"); //sort Array
clone(bar, container); // clone bar for (barNum-1) times
for(let i = 0; i < data.length; i++){ barL[i].style.backgroundColor = data[i].color; } // colorize every bar with corresponding array color value
//---------------
var myInterval = [];
function anim(j){ // draw bars one after the other in sequence
const computedStyleObj = getComputedStyle(barL[j]);
value[j].textContent = Math.round(parseInt(computedStyleObj.height)/pixelStep) + "K";
compare[j].textContent = data[j].val;
barL[j].style.height = value[j].style.bottom = (data[j].val * pixelStep) + "px" //transiton value of height
//console.log("j : ", data[j].val + " - " + parseInt(computedStyleObj.height));
barL[j].addEventListener("transitionEnd", () =>{clearInterval(myInterval[j]);}); // when transition ends, clear interval
barL[j].addEventListener("webkitTransitionEnd", () =>{clearInterval(myInterval[j]);});
}
for (let i = 0; i < data.length; i++) {
setTimeout(function() {
myInterval[i] = setInterval(function() {anim(i);}, intervalTime); // after delayTime ms start the next bar animation
}, i * delayTime);
}
//----------------
function clone(item, container) { // clone an item in a container function
for(let i = 0; i < barNum-1 ; i++){
var cln = item.cloneNode(true);
container.appendChild(cln);
cln.style.left = ((i+1) * spaceBetween ) + "px";
}
}
function sortFunction(arr, key) { // sort an array of objects by given key
arr.sort(function(a, b){
let x = a[key];
let y = b[key];
if (x < y) {return -1;}
if (x > y) {return 1;}
return 0;
});
data.reverse(); // reverse for descending array
}
:root {
--barWidth : 80px;
--color : #aaa;
--contentWidth : 1200px;
}
* {
margin : 0;
padding : 0;
box-sizing : border-box;
}
body {
width : 100%;
display : flex;
align-content : center;
justify-content : center;
flex-direction : column;
background : var(--color);
font-family : 'Roboto Mono', monospace;
}
.container {
position : relative;
width : var(--contentWidth);
height : 500px;
border : 1px solid #0005;
background : #fff4;
margin : 10px auto;
}
.bar {
position : absolute;
width : var(--barWidth);
margin : 10px;
display : inline-block;
border : 0px solid #0005;
bottom : 0px;
}
.barLayer {
position : absolute;
width : var(--barWidth);;
height : 0px;
bottom : 0;
border : 0px solid #0005;
}
.value, .compare {
position : absolute;
width : var(--barWidth);
height : calc(var(--barWidth)/2);
bottom : 0px;
font-size : calc(var(--barWidth)/4);
text-align : center;
border : 0px solid #fff;
line-height : calc(var(--barWidth)/2);
}
.barLayer, .value {
transition : all 1s linear;
}
<div class="container">
<div class="bar">
<div class="barLayer"></div>
<div class="value"></div>
<div class="compare"></div>
</div>
</div>
I want to clear "interval" after transition end (drawing bar with transition animation) not to busy CPU in vain, but I can't get the correct height value.
You can see the result using snipped link below.
Top is wrong value, bottom is the data from array. I tried some arithmetic methods, but want to use "transitionend" eventListener. Thanks! :)
TL;DR: for animation stuff, use requestAnimationFrame
Usually for animation related things, we prefer using
requestAnimationFramethan intervals or timeout. You can think ofrequestAnimationFrameas asetTimeoutthat will trigger on the next frame. So I'm proposing this as a replacement for your setInterval.As for the measure of "how far along is this bar" to animate the numbers, I think you'll get a good enough approximation by just watching how much time has elapsed and how long the transition is supposed to last. This will not be precise by any means, but measuring the elements with
getComputedStyleorgetBoundingClientRecton every frame would be a disaster for fluidity. So this is why I'm using timestamps inwatchAnimation.And for the rest, I didn't change much. Just re-wrote your code because (sorry but) it was a bit of a mess, and way too many things that didn't have anything to do with the problem at hand.