下面的代碼為 SVG 圓改變顏色設定影片并按預期作業。
如果SVG.addAnimatedCircle(this.root)從callback方法內部呼叫 ,而不是在它的下面,在 內部constructor,則影片在加載檔案時開始 - 因此除非單擊視窗否則不可見 - 而不是在觸發事件時。
class SVG {
constructor() {
const root = document.createElementNS(
'http://www.w3.org/2000/svg', 'svg');
root.setAttribute('viewBox', '-50 -50 100 100');
this.root = root;
this.callback = this.callback.bind(this);
window.addEventListener('click', this.callback);
SVG.addAnimatedCircle(this.root);
}
callback() {
// SVG.addAnimatedCircle(this.root);
}
static addAnimatedCircle(toElement) {
const el = document.createElementNS(
'http://www.w3.org/2000/svg', 'circle');
el.setAttribute('cx', '0');
el.setAttribute('cy', '0');
el.setAttribute('r', '10');
el.setAttribute('fill', 'red');
toElement.appendChild(el);
const anim = document.createElementNS(
'http://www.w3.org/2000/svg', 'animate');
anim.setAttribute('attributeName', 'fill');
anim.setAttribute('from', 'blue');
anim.setAttribute('to', 'red');
anim.setAttribute('dur', '3s');
el.appendChild(anim);
}
}
const svg = new SVG();
document.body.appendChild(svg.root);
(class當然上面不需要在 a 里面,我正在簡化一個更復雜的類)。
這是為什么?影片不是應該在創建元素并將其添加到 DOM 時開始嗎?
uj5u.com熱心網友回復:
<animate>您創建的元素將begin計算其屬性0s(因為未設定)。
這個0s值是相對于“檔案開始時間”的,在這個 HTML 檔案中它本身對應于 root<svg>的當前時間。
這意味著如果你<animate>在根<svg>元素已經在 DOM之后創建這樣的元素,它的影片狀態將取決于根<svg>元素在 DOM 中的時間:
顯示代碼片段
const root = document.querySelector("svg");
const circles = document.querySelectorAll("circle");
const duration = 3;
// will fully animate
circles[0].append(makeAnimate());
// will produce only half of the animation
setTimeout(() => {
circles[1].append(makeAnimate());
}, duration * 500);
// will not animate
setTimeout(() => {
circles[2].append(makeAnimate());
}, duration * 1000);
function makeAnimate() {
const anim = document.createElementNS("http://www.w3.org/2000/svg", "animate");
anim.setAttribute("attributeName", "fill");
anim.setAttribute("from", "blue");
anim.setAttribute("to", "red");
anim.setAttribute("fill", "freeze");
anim.setAttribute("dur", duration "s");
return anim;
}
circle { fill: blue }
<svg height="60">
<circle cx="30" cy="30" r="25"/>
<circle cx="90" cy="30" r="25"/>
<circle cx="150" cy="30" r="25"/>
</svg>
<p>left circle starts immediately, and fully animates</p>
<p>middle circle starts after <code>duration / 2</code> and matches the same position as left circle</p>
<p>right circle starts after <code>duration</code>, the animation is already completed by then, nothing "animates"</p>
我們可以<svg>通過它的SVGSVGElement.setCurrentTime()方法設定的當前時間。
因此,要創建<animate>將在創建時開始的一個,無論何時,我們都可以使用它,但是,這也會影響<animate>已經在<svg>.
顯示代碼片段
const root = document.querySelector("svg");
const circles = document.querySelectorAll("circle");
const duration = 3;
circles[0].append(makeAnimate());
root.setCurrentTime(0); // reset <animate> time
setTimeout(() => {
circles[1].append(makeAnimate());
root.setCurrentTime(0); // reset <animate> time
}, duration * 500);
setTimeout(() => {
circles[2].append(makeAnimate());
root.setCurrentTime(0); // reset <animate> time
}, duration * 1000);
function makeAnimate() {
const anim = document.createElementNS("http://www.w3.org/2000/svg", "animate");
anim.setAttribute("attributeName", "fill");
anim.setAttribute("from", "blue");
anim.setAttribute("to", "red");
anim.setAttribute("fill", "freeze");
anim.setAttribute("dur", duration "s");
return anim;
}
circle { fill: blue }
<svg height="60">
<circle cx="30" cy="30" r="25"/>
<circle cx="90" cy="30" r="25"/>
<circle cx="150" cy="30" r="25"/>
</svg>
因此,雖然它可能適用于某些用戶,但在大多數情況下,最好只設定<animate>'sbegin屬性。
幸運的是,我們還可以使用該SVGSVGElement.getCurrentTime()方法獲取當前時間。
顯示代碼片段
const root = document.querySelector("svg");
const circles = document.querySelectorAll("circle");
const duration = 3;
circles[0].append(makeAnimate());
setTimeout(() => {
circles[1].append(makeAnimate());
}, duration * 500);
setTimeout(() => {
circles[2].append(makeAnimate());
}, duration * 1000);
function makeAnimate() {
const anim = document.createElementNS("http://www.w3.org/2000/svg", "animate");
anim.setAttribute("attributeName", "fill");
anim.setAttribute("from", "blue");
anim.setAttribute("to", "red");
anim.setAttribute("fill", "freeze");
anim.setAttribute("dur", duration "s");
// set the `begin` to "now"
anim.setAttribute("begin", root.getCurrentTime() "s");
return anim;
}
circle { fill: blue }
<svg height="60">
<circle cx="30" cy="30" r="25"/>
<circle cx="90" cy="30" r="25"/>
<circle cx="150" cy="30" r="25"/>
</svg>
但是我們通常這樣做的方式是完全使用 API 并通過 JS 來控制它,因為您已經開始使用 JS。
為此,我們將begin屬性設定為“不確定”,以便它不會自動啟動,然后我們呼叫SVGAnimateElement ( <animate>) 的beginElement()方法,該方法將在我們需要時手動啟動影片:
顯示代碼片段
const root = document.querySelector("svg");
const circles = document.querySelectorAll("circle");
const duration = 3;
{
const animate = makeAnimate();
circles[0].appendChild(animate);
animate.beginElement();
}
setTimeout(() => {
const animate = makeAnimate();
circles[1].appendChild(animate);
animate.beginElement();
}, duration * 500);
setTimeout(() => {
const animate = makeAnimate();
circles[2].appendChild(animate);
animate.beginElement();
}, duration * 1000);
function makeAnimate() {
const anim = document.createElementNS("http://www.w3.org/2000/svg", "animate");
anim.setAttribute("attributeName", "fill");
anim.setAttribute("from", "blue");
anim.setAttribute("to", "red");
anim.setAttribute("fill", "freeze");
anim.setAttribute("dur", duration "s");
// set the `begin` to "manual"
anim.setAttribute("begin", "indefinite");
return anim;
}
circle { fill: blue }
<svg height="60">
<circle cx="30" cy="30" r="25"/>
<circle cx="90" cy="30" r="25"/>
<circle cx="150" cy="30" r="25"/>
</svg>
uj5u.com熱心網友回復:
(不是答案,只是提出問題以便可能適應OP 在他們的評論中建議的問題和/或正確答案。
<style>svg {outline: #0FF6 solid; outline-offset: -2px;}</style>
<table role="presentation" border><tr><td>
1. Static SVG with animated circle:
<td>
<svg viewBox="-50 -50 100 100" width="30" height="30">
<circle r="40" fill="black">
<animate begin="0.5s" fill="freeze" attributeName="fill" from="blue" to="red" dur="5s"></animate>
</circle>
</svg>
<tr><td>
2. Empty SVG,
<button onclick='
emptySVG.innerHTML = document.querySelector("circle").outerHTML;
'>Put similar animated circle into it</button>:
<td>
<svg id="emptySVG" viewBox="-50 -50 100 100" width="30" height="30">
<!-- empty -->
</svg>
<tr><td>
3. <button onclick='
sampleCell.innerHTML = document.querySelector("svg").outerHTML
'>Create new SVG with animated circle</button>:
<td id="sampleCell">
(here.)
</table>
<p>
<button onclick="location.reload()">Reload page</button>
<button onclick="
[...document.querySelectorAll('animate')].forEach(a=>{
//a.setAttribute('begin','indefinite'); // does not seem to be necessary
a.beginElement();
})
">Reset all animations</button>
將影片圓圈置于第二個 SVG 會產生與現有空 SVG 中已經經過的持續時間相對應的狀態:它與第一個相匹配,因此它要么同步運行,要么已完成。目標是在圓圈出現時運行影片。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/312452.html
標籤:javascript svg
上一篇:如何通過坐標獲取SVG元素?
