我一直在原地打转
我使用 Web Animation API transform:translate()
让我的玩家在基地周围奔跑。
runto("first").then(() => runto("second"));
执行正确动画,
但随后删除第一个/上一个翻译
到第一个基础,
因此我的玩家最终出现在错误的位置
我已经尝试了每种组合
- https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/composite
- https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/iterationComposite
是否可以将所有翻译保留在一个元素上?
JSFiddle Playground :https://jsfiddle.net/WebComponents/8df2qsop/
let field = document.getElementById("FIELD");
let player = field.getElementById("player");
function getCenter(el , { left, top, width, height } = el.getBoundingClientRect()) {
let point = Object.assign(field.createSVGPoint(),{ x : left + width / 2, y : top + height / 2 }).matrixTransform(field.getScreenCTM().inverse());
return { cx:~~point.x, cy:~~point.y };
}
function runto(destination) {
let {cx:playerX,cy:playerY} = getCenter(player);
let {cx:baseX ,cy:baseY } = getCenter(field.getElementById(destination));
let translateX = baseX - playerX;
let translateY = baseY- playerY;
let track = `<line x1="${playerX}" y1="${playerY}" x2="${baseX}" y2="${baseY}" stroke-width="10" stroke="black"/>`;
field.insertAdjacentHTML("beforeend",track);
return player.animate([{
//transform: `translate(${0}px,${0}px)`
}, { transform: `translate(${translateX}px,${translateY}px)` }],
{ duration:500, fill:"forwards", composite:"add" }
).finished; // return Promise
}
runto("first").then(() => runto("second"));
<style>
#FIELD { background: lightgreen; width: 150px; margin: 20px }
</style>
<svg id=FIELD viewBox="0 0 250 250" transform="rotate(45)">
<g fill="brown">
<path id="home" d="M 150 150 h 80 v 80 h -80 v -80z" fill="green"/>
<path id="first" d="M 150 20 h 80 v 80 h -80 v -80z"/>
<path id="second" d="M 20 20 h 80 v 80 h -80 v -80z"/>
<path id="third" d="M 20 150 h 80 v 80 h -80 v -80z"/>
</g>
<circle id="player" cx="190" cy="190" r="30" fill="gold"/>
</svg>
最佳答案
您可以调用Animation#commitStyles()
动画完成后,其状态将“写入”您的播放器。
您现在需要返回到默认的 composite: "replace"
选项,并且还需要修改初始播放器设置,以便使用 CSS translate()
进行定位使用其 cx
和 cy
值(或者您也可以修改您的计算,以便它们返回相对位置)。
let field = document.getElementById("FIELD");
let player = field.getElementById("player");
function getCenter(el, { left, top, width, height } = el.getBoundingClientRect()) {
let point = Object.assign(field.createSVGPoint(), {
x: left + width / 2,
y: top + height / 2
}).matrixTransform(field.getScreenCTM().inverse());
return {
cx: ~~point.x,
cy: ~~point.y
};
}
async function runto(destination) {
let { cx: playerX, cy: playerY } = getCenter(player);
let { cx: baseX, cy: baseY } = getCenter(field.getElementById(destination));
let translateX = baseX - playerX;
let translateY = baseY - playerY;
let track = `<line x1="${playerX}" y1="${playerY}" x2="${baseX}" y2="${baseY}" stroke-width="10" stroke="black"/>`;
field.insertAdjacentHTML("beforeend", track);
const anim = player.animate([{
transform: `translate(${baseX}px,${baseY}px)`
}], {
duration: 500,
fill: "forwards"
});
await anim.finished;
anim.commitStyles(); // write the current state to the animated element
anim.cancel(); // no need to keep it around anymore
}
runto("first").then(() => runto("second"));
<style>
#FIELD {
background: lightgreen;
width: 150px;
margin: 20px
}
</style>
<svg id=FIELD viewBox="0 0 250 250" transform="rotate(45)">
<g fill="brown">
<path id="home" d="M 150 150 h 80 v 80 h -80 v -80z" fill="green"/>
<path id="first" d="M 150 20 h 80 v 80 h -80 v -80z"/>
<path id="second" d="M 20 20 h 80 v 80 h -80 v -80z"/>
<path id="third" d="M 20 150 h 80 v 80 h -80 v -80z"/>
</g>
<circle id="player" cx="0" cy="0" r="30" style="transform:translate(190px, 190px)" fill="gold"/>
</svg>
关于javascript - 在 Web 动画 API 中堆叠/添加/复合/累积多个转换=翻译动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74769431/