簡體   English   中英

如何使圓形進度條流暢?

[英]How can I make a circle progress bar fluid?

我正在嘗試使計時器中的圓形進度條流動起來。 進度條表示計時器持續時間的進度。 我為進度條制作了一個 svg <circle>圓形元素。 每隔 10 秒,我更改圓的 css 屬性stroke-dashoffset 這很好用,但如果我們選擇的時間少於 5 分鍾,則進度條的移動不流暢。 我能做些什么來制造這種液體?

 class Timer { constructor(circle, text) { this.circle = circle this.text = text this.text.innerHTML } async start(hours, minutes, seconds) { this.circle.style["stroke-dasharray"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width) this.circle.style["stroke-dashoffset"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width) await this.countdown() this.circle.classList = "progress" var remaining, interval, duration, end; duration = parseInt(hours) * 3600000 + parseInt(minutes) * 60000 + (parseInt(seconds) + 1) * 1000 end = Date.now() + duration interval = setInterval(async () => { remaining = end - Date.now() this.circle.style["stroke-dashoffset"] = remaining * parseInt(Math.PI * this.circle.getBoundingClientRect().width) / duration; if (remaining < 0) { this.circle.style["stroke-dashoffset"] = 0 clearInterval(interval) window.location.href = "./" return true } else { this.text.innerHTML = `${("0" + parseInt(remaining / 3600000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 / 60000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 % 60000 / 1000)).slice(-2)}` } }, 100) } countdown() { var duration; duration = 2 this.text.innerHTML = 3 return new Promise(resolve => { setInterval(async () => { if (duration <= 0) { resolve(true) } else { this.text.innerHTML = duration duration -= 1 } }, 1000) }) } } const timer = new Timer(document.getElementById("progress"), document.getElementById("text")) const params = new URLSearchParams(window.location.search) timer.start(0, 0, 10)
 :root { --pi: 3.141592653589793 } circle.progress { display: block; position: absolute; fill: none; stroke: url(#circle.progress.color); stroke-width: 4.5vmin; stroke-linecap: round; transform-origin: center; transform: rotate(-90deg); } circle.progress.animation { animation: circle 3s linear forwards; }.progress-container { left: 50vw; top: 50vh; width: 90vmin; height: 90vmin; margin-top: -45vmin; margin-left: -45vmin; position: absolute; padding: none; }.outer { margin: none; width: 100%; height: 100%; border-radius: 50%; box-shadow: 6px 6px 10px -1px rgba(0, 0, 0, 0.15), -6px -6px 10px -1px rgba(255, 255, 255, 0.7); padding: 2.5%; }.inner { margin: 2.5%; width: 95%; height: 95%; border-radius: 50%; box-shadow: inset 4px 4px 6px -1px rgba(0, 0, 0, 0.15), inset -4px -4px 6px -1px rgba(255, 255, 255, 0.7); } svg { display: block; position: absolute; left: 50vw; top: 50vh; width: 90.5vmin; height: 90.5vmin; margin-top: -45.25vmin; margin-left: -45.25vmin; } svg text { font-size: 10vmin; font-family: 'Roboto', sans-serif; } @keyframes circle { 0% { stroke-dashoffset: 0; } 100% { stroke-dashoffset: calc(45.5vmin * var(--pi) * 2); } }
 <link href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@1.2.1/dist/css/materialize.min.css" rel="stylesheet"/> <div class="progress-container"> <div class="outer center-align"> <div class="inner"></div> </div> </div> <svg xmlns="http://www.w3.org/2000/svg" class="center" version="1.1"> <defs> <linearGradient id="circle.progress.color"> <stop offset="0%" stop-color="BlueViolet" /> <stop offset="100%" stop-color="MediumVioletRed" /> </linearGradient> </defs> <circle id="progress" class="progress animation" cy="45.25vmin" cx="45.25vmin" r="42.75vmin" /> <text id="text" text-anchor="middle" x="50%" y="50%">Temps restant</text> </svg> <script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@1.2.1/dist/js/materialize.min.js"></script>

此處的代碼運行計時器 10 秒。 通常,您必須在另一頁中選擇時間。 要輸入時間,go 到該頁面(該頁面為法語)。

我無法解釋這個問題,所以這里我有一個替代解決方案。 function setInterval 的計時有問題(也許這實際上是您發出的...)。 你不能指望它是精確的。 除了使用 setInterval 控制進度之外,您還可以使用關鍵幀 animation 和Web 動畫 API 這是 JavaScript animation 的更好替代方案,您可以在其中更新屬性/樣式,並且更容易使用 SVG SMIL 動畫。

因此,我依靠 animation 完成其工作,然后通過詢問 animation object 上的當前時間來更新顯示的時間。

 const progress = document.getElementById('progress'); const text = document.getElementById('text'); document.forms.form01.addEventListener('click', e => { if(e.target.value){ var progressKeyframes = new KeyframeEffect( progress, [ { strokeDasharray: '0 100' }, { strokeDasharray: '100 100' } ], { duration: parseInt(e.target.value), fill: 'forwards' } ); var a1 = new Animation(progressKeyframes, document.timeline); a1.play(); let timer = setInterval(function(){ if(a1.playState == 'running'){ text.textContent = Math.floor(a1.currentTime/1000); }else if(a1.playState == 'finished'){ text.textContent = Math.round(e.target.value/1000); clearInterval(timer); } }, 100); } });
 <form name="form01"> <input type="button" value="2000" /> <input type="button" value="5000" /> <input type="button" value="10000" /> </form> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="300"> <defs> <linearGradient id="circle.progress.color"> <stop offset="0%" stop-color="BlueViolet" /> <stop offset="100%" stop-color="MediumVioletRed" /> </linearGradient> <filter id="shadow"> <feDropShadow dx=".4" dy=".4" stdDeviation="1" flood-color="gray"/> </filter> </defs> <circle r="40" stroke="white" stroke-width="8" fill="none" transform="translate(50 50)" filter="url(#shadow)"/> <circle id="progress" r="40" stroke="url(#circle.progress.color)" stroke-width="8" fill="none" pathLength="100" stroke-dasharray="0 100" transform="translate(50 50) rotate(-90)" stroke-linecap="round"/> <text id="text" dominant-baseline="middle" text-anchor="middle" x="50" y="50">0</text> </svg>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM