Переход ускоряется после паузы / возобновления - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь создать компонент, похожий на панель мультимедиа, в котором есть функции, такие как пауза и возобновление.Красная вертикальная линия идет слева направо, и когда я нажимаю кнопку паузы, он останавливает переход, а когда я нажимаю кнопку воспроизведения, он возобновляет переход.

Я создал 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>

1 Ответ

0 голосов
/ 05 февраля 2019

Мне кажется, что использование перехода здесь не только излишнее, но и то, что вам придется наклониться назад (как вы!), Чтобы заставить вещи работать.Лично я бы предпочел использовать интервал 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>
...