pause/resume 后转换速度加快
Transition speeds up after pause/resume
我正在尝试创建一个类似 mediabar 的组件,它具有暂停和恢复等功能。
红色垂直线从左到右,当我点击暂停按钮时它会停止过渡,当我点击播放按钮时它会恢复过渡。
我也为这个问题创建了一个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>
在我看来,使用过渡不仅在这里是一种矫枉过正,而且您必须向后弯腰(就像您一样!)才能使事情正常进行。就个人而言,我宁愿使用 D3 间隔或 D3 计时器。
回到问题:
问题只是 attrTween
方法中的工厂。如您所知,t
从 0 变为 1,当您暂停动画时,这会使 time
超出限制(给定 scaleTimeline
比例的域,即 1) :
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>
我正在尝试创建一个类似 mediabar 的组件,它具有暂停和恢复等功能。 红色垂直线从左到右,当我点击暂停按钮时它会停止过渡,当我点击播放按钮时它会恢复过渡。
我也为这个问题创建了一个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>
在我看来,使用过渡不仅在这里是一种矫枉过正,而且您必须向后弯腰(就像您一样!)才能使事情正常进行。就个人而言,我宁愿使用 D3 间隔或 D3 计时器。
回到问题:
问题只是 attrTween
方法中的工厂。如您所知,t
从 0 变为 1,当您暂停动画时,这会使 time
超出限制(给定 scaleTimeline
比例的域,即 1) :
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>