【问题标题】:Transition speeds up after pause/resume暂停/恢复后过渡速度加快
【发布时间】:2019-06-28 19:06:23
【问题描述】:

我正在尝试创建一个类似媒体栏的组件,它具有暂停和恢复等功能。 红色竖线是从左到右,点击暂停键会停止转场,点击播放键会继续转场。

我也为这个问题创建了codepen

感谢您的帮助;

const ANIMATIONLENGTH = 10000;

let pauseValues = {
  lastT: 0,
  currentT: 0,
  currentPos: 0
};

const svg = d3
  .select("#mediabar")
  .append("svg")
  .attr("width", 640)
  .attr("height", 18);

svg.append("rect")
  .attr("width", "100%")
  .attr("height", "100%")
  .attr("fill", "#D3D3D3");

const line = svg
  .append("rect")
  .attr("height", 18)
  .attr("width", 2)
  .attr("fill", "red")
  .attr("class", "slider");
const scaleTimeline = d3.scale
  .linear()
  .domain([0, 1])
  .range([0, 640]);
const play = () => {
  line
    .transition()
    .duration(ANIMATIONLENGTH * (1 - pauseValues.lastT))
    .ease("linear")
    .attrTween("x", () => t => {
      const time = t + pauseValues.lastT;
      pauseValues.currentT = time;
      pauseValues.currentPos = scaleTimeline(time);
      return pauseValues.currentPos;
    })
    .each("end", () => {
      pauseValues = {
        lastT: 0,
        currentT: 0,
        currentPos: 0
      };
      play();
    });
};

const pause = () => {
  line.transition().duration(0);
  setTimeout(() => {
    pauseValues.lastT = pauseValues.currentT;
  }, 100);
};
.buttons {
  display: flex;
  flex-direction: row;
  margin-bottom: 4px;
}

.buttons-pause {
  padding: 2px;
  border: 1px solid black;
  border-radius: 3px;
  cursor: pointer;
}

.buttons-play {
  padding: 2px;
  border: 1px solid black;
  border-radius: 3px;
  margin-right: 4px;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div class='buttons'>
  <div class="buttons-play" onclick="play()">play</div>
  <div class="buttons-pause" onclick="pause()">pause</div>
</div>

<div id='mediabar'></div>

【问题讨论】:

    标签: javascript html animation d3.js transition


    【解决方案1】:

    在我看来,在这里使用过渡不仅是矫枉过正,而且您必须向后弯腰(就像您一样!)才能使事情正常进行。就个人而言,我宁愿使用 D3 间隔或 D3 计时器。

    回到问题:

    问题只是attrTween 方法中的工厂。如您所知,当您暂停动画时,t 从 0 变为 1,这使得 time 超出了限制(即 1,给定您的 scaleTimeline 刻度的域):

    const time = t + pauseValues.lastT;
    

    因此,time 的最后一个值始终大于 1(因为 pauseValues.lastT 大于 0),并且越接近结束暂停过渡,最后一个值就越高(因此,线的速度越高)。

    简单的解决方法是:

    const time = pauseValues.lastT + (1 - pauseValues.lastT) * t;
    

    如您所见,通过使用(1 - pauseValues.lastT) * t,我们确保time 的最后一个值(当t 达到1 时)为1。

    这是更改后的代码:

    const ANIMATIONLENGTH = 10000;
    
    let pauseValues = {
      lastT: 0,
      currentT: 0,
      currentPos: 0
    };
    
    const svg = d3
      .select("#mediabar")
      .append("svg")
      .attr("width", 640)
      .attr("height", 18);
    
    svg.append("rect")
      .attr("width", "100%")
      .attr("height", "100%")
      .attr("fill", "#D3D3D3");
    
    const line = svg
      .append("rect")
      .attr("height", 18)
      .attr("width", 2)
      .attr("fill", "red")
      .attr("class", "slider");
    const scaleTimeline = d3.scale
      .linear()
      .domain([0, 1])
      .range([0, 640]);
    const play = () => {
      line
        .transition()
        .duration(ANIMATIONLENGTH * (1 - pauseValues.lastT))
        .ease("linear")
        .attrTween("x", () => t => {
          const time = pauseValues.lastT + (1 - pauseValues.lastT) * t;
          pauseValues.currentT = time;
          pauseValues.currentPos = scaleTimeline(time);
          return pauseValues.currentPos;
        })
        .each("end", () => {
          pauseValues = {
            lastT: 0,
            currentT: 0,
            currentPos: 0
          };
          play();
        });
    };
    
    const pause = () => {
      line.transition().duration(0);
      setTimeout(() => {
        pauseValues.lastT = pauseValues.currentT;
      }, 100);
    };
    .buttons {
      display: flex;
      flex-direction: row;
      margin-bottom: 4px;
    }
    
    .buttons-pause {
      padding: 2px;
      border: 1px solid black;
      border-radius: 3px;
      cursor: pointer;
    }
    
    .buttons-play {
      padding: 2px;
      border: 1px solid black;
      border-radius: 3px;
      margin-right: 4px;
      cursor: pointer;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <div class='buttons'>
      <div class="buttons-play" onclick="play()">play</div>
      <div class="buttons-pause" onclick="pause()">pause</div>
    </div>
    
    <div id='mediabar'></div>

    【讨论】:

    • 感谢您的快速回答,它解决了问题。
    猜你喜欢
    • 2014-05-27
    • 2013-03-28
    • 2015-06-07
    • 2014-11-20
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    相关资源
    最近更新 更多