使用 setInterval 创建动画

时间:2021-05-30 17:14:42

标签: javascript html css

我正在尝试构建此图形实用程序并使用 setInterval 来制作条形高度的动画。
我不知道如何使用 CSS Transition 实现这一点,但我也不确定使用 javascript 的效率如何。

虽然代码工作正常(至少在我这边),但它似乎非常占用 CPU。

    let scaleFrag = new DocumentFragment();
    for(let i = 100; i > -1; i-=5){
        let div = document.createElement('div');
        div.innerHTML = i;
        scaleFrag.append(div);
    }

    document.getElementsByClassName('scale')[0].append(scaleFrag);
    let graph = getComputedStyle(document.getElementsByClassName('graph')[0]);
    let arblenth = Math.floor(Math.random()*50);
    let array = [];
    for(let i=0; i < arblenth; i++){
        array.push(Math.floor(Math.random()*101));
    }
    let gw = parseInt(graph.width, 10);
    let gh = parseInt(graph.height, 10);
    gw = gw - 2*arblenth;
    console.log(graph.width)
    let barFrag = new DocumentFragment();
    for(let i=0; i < array.length ; i++){
        let cl = document.createElement('div');
        cl.innerHTML = array[i];
        cl.className = i%2 == 0 ? 'cl-o' : 'cl-e';
        cl.style.width = gw + 'px';
        barFrag.append(cl);
    }
    document.getElementsByClassName('graph')[0].append(barFrag);

    function animateHeight(cls) {
        let cl = document.getElementsByClassName(cls);
        
        for(let i = 0; i < cl.length; i++){
            let maxHeight = Math.floor(gh*(parseInt(cl[i].innerHTML)/100));
            let h = 0;
            let si = setInterval(() => {
                if(h == maxHeight){
                    clearInterval(si);
                }
                
                cl[i].style.height = h++ + 'px';
            },0.1)
        }
    }
    animateHeight('cl-o');
    animateHeight('cl-e');
html, body  {
    height: 100%;
    width: 100%;
    margin: 0px;
    padding: 0px;
    font-family: sans-serif;
}
* {
    box-sizing: border-box ;
}
body {
    padding-top: 5vh;
}
.grid {
    height: 90vh;
    width: 70vw;
    margin: 0 auto;
    text-align: center;
    box-shadow: 3px 4px 15px -2px rgba(49,41,41,0.9);
    padding: 1rem;
    display: flex;
    justify-content: center;
    align-items: center;
}
.scale {
    width: 5%;
    height: 90%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    border-right: 1px solid grey;
}

.graph {
    width: 90%;
    height: 90%;
    border-left: none;
    display: flex;
    align-items: flex-end;
}
.cl-o{
    background-color: limegreen;
    transition: height;
}
.cl-e{
    background-color: lightslategray;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Portfolio</title>

    <link rel='stylesheet' href="./style.css">
</head>
<body>
    <div class="grid">
        <div class="scale"></div>
        <div class="graph">
        </div>
    </div>
</body>
</html>

我已经尝试了这 500 个高度随机设置的条形图,但它似乎仍然有效。 我应该这样做还是可以改进?

2 个答案:

答案 0 :(得分:0)

在这种情况下最好使用 CSS 过渡。

这里是css的样子:

.cl-o{
   background-color: limegreen;
   height: 0px;
   transition: 1s all;
}
.cl-e{
    background-color: lightslategray;
    height: 0px;
    transition: 1s all;
}

所以这里的高度最初是 0,如果你立即在 JavaScript 中设置高度,没有动画(我只在 CodePen 上尝试过),所以你可以使用非常小的超时。这是新的 animateHeight 函数。

function animateHeight(cls) {
    let cl = document.getElementsByClassName(cls);
    
    for(let i = 0; i < cl.length; i++){
        let maxHeight = Math.floor(gh*(parseInt(cl[i].innerHTML)/100));
        setTimeout(() => {
          cl[i].style.height = maxHeight + "px"
        }, 10)
    }
}

答案 1 :(得分:0)

我对代码做了一些小改动:

  1. 将代码重构为方法,因此更易于阅读。

  2. document.getElementsByClassName 替换为 document.getElementByIddocument.querySelectorAll('#graph > div')

function createScaleFrag() {
  let scaleFrag = new DocumentFragment();

  for (let i = 100; i > -1; i -= 5) {
    let div = document.createElement('div');
    div.innerHTML = i;
    scaleFrag.append(div);
  }
  
  return scaleFrag;
}

function createBarFrag() {
  let arblenth = Math.floor(Math.random() * 50);
  let array = [];

  for (let i = 0; i < arblenth; i++) {
    array.push(Math.floor(Math.random() * 101));
  }

  gw = gw - 2 * arblenth;

  let barFrag = new DocumentFragment();
  for (let i = 0; i < array.length; i++) {
    let cl = document.createElement('div');
    cl.innerHTML = array[i];
    cl.className = i % 2 == 0 ? 'cl-o' : 'cl-e';
    cl.style.width = gw + 'px';
    barFrag.append(cl);
  }
  
  return barFrag;
}

document.getElementById('scale').append(createScaleFrag());

const grafElement = document.getElementById('graph');
let graph = getComputedStyle(grafElement);
let gw = parseInt(graph.width, 10);
let gh = parseInt(graph.height, 10);

grafElement.append(createBarFrag());

function animateHeight(cl) {
  for (let i = 0; i < cl.length; i++) {
    let maxHeight = Math.floor(gh * (parseInt(cl[i].innerHTML) / 100));
    let h = 0;
    let si = setInterval(() => {
      if (h == maxHeight) {
        clearInterval(si);
      }

      cl[i].style.height = h++ + 'px';
    }, 0.1)
  }
}

animateHeight(document.querySelectorAll('#graph > div'));
html,
body {
  margin: 0px;
  padding: 0px;
  font-family: sans-serif;
}

* {
  box-sizing: border-box;
}

.grid {
  height: 90vh;
  width: 70vw;
  margin: 0 auto;
  text-align: center;
  box-shadow: 3px 4px 15px -2px rgba(49, 41, 41, 0.9);
  padding: 1rem;
  display: flex;
  justify-content: center;
  align-items: center;
}

#scale {
  width: 5%;
  height: 90%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  border-right: 1px solid grey;
}

#graph {
  width: 90%;
  height: 90%;
  border-left: none;
  display: flex;
  align-items: flex-end;
}

.cl-o {
  background-color: limegreen;
  transition: height;
}

.cl-e {
  background-color: lightslategray;
}
<div class="grid">
  <div id="scale"></div>
  <div id="graph">
  </div>
</div>

您的代码的问题在于,您执行的时间间隔与图中的列数一样多,(我认为)这会强制对每次更新进行重绘。你应该做的是做所有的计算,然后然后更新屏幕一次。您可以通过使用 requestAnimationFrame 来做到这一点。

我希望代码是不言自明的。

function createScaleFrag() {
  let scaleFrag = new DocumentFragment();

  for (let i = 100; i > -1; i -= 5) {
    let div = document.createElement('div');
    div.innerHTML = i;
    scaleFrag.append(div);
  }
  
  return scaleFrag;
}

function createBarFrag() {
  let arblenth = Math.floor(Math.random() * 50);
  let array = [];

  for (let i = 0; i < arblenth; i++) {
    array.push(Math.floor(Math.random() * MAX_COLUMN_HEIGHT));
  }

  gw = gw - 2 * arblenth;

  let barFrag = new DocumentFragment();
  for (let i = 0; i < array.length; i++) {
    let cl = document.createElement('div');
    cl.innerHTML = array[i];
    cl.className = i % 2 == 0 ? 'cl-o' : 'cl-e';
    cl.style.width = gw + 'px';
    barFrag.append(cl);
  }
  
  return barFrag;
}

const MAX_COLUMN_HEIGHT = 101;

document.getElementById('scale').append(createScaleFrag());
const grafElement = document.getElementById('graph');
let graph = getComputedStyle(grafElement);
let gw = parseInt(graph.width, 10);
let gh = parseInt(graph.height, 10);

grafElement.append(createBarFrag());

function animateHeight(cl) {
  const ANIMATION_DURATION = 2000;
  let start;
  
  function updateHeight(timestamp) {
    if (start === undefined) { start = timestamp; }
    
    let elapsed = timestamp - start;
    let progress = elapsed / ANIMATION_DURATION;
    let globalHeight = progress * MAX_COLUMN_HEIGHT;
    
    let maxHeight, shouldContinueGrow;
    
    for (let i = 0; i < cl.length; i++) {
      maxHeight = parseInt(cl[i].innerHTML);
      shouldContinueGrow = globalHeight <= maxHeight;
      
      if (shouldContinueGrow) {
        cl[i].style.height = gh * progress + 'px';
      }
    }
    
    if (elapsed < ANIMATION_DURATION) {
      requestAnimationFrame(updateHeight);
    }
  }
  
  requestAnimationFrame(updateHeight);
}

animateHeight(document.querySelectorAll('#graph > div'));
html,
body {
  margin: 0px;
  padding: 0px;
  font-family: sans-serif;
}

* {
  box-sizing: border-box;
}

.grid {
  height: 90vh;
  width: 70vw;
  margin: 0 auto;
  text-align: center;
  box-shadow: 3px 4px 15px -2px rgba(49, 41, 41, 0.9);
  padding: 1rem;
  display: flex;
  justify-content: center;
  align-items: center;
}

#scale {
  width: 5%;
  height: 90%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  border-right: 1px solid grey;
}

#graph {
  width: 90%;
  height: 90%;
  border-left: none;
  display: flex;
  align-items: flex-end;
}

.cl-o {
  background-color: limegreen;
  transition: height;
}

.cl-e {
  background-color: lightslategray;
}
<div class="grid">
  <div id="scale"></div>
  <div id="graph"></div>
</div>

相关问题