繁体   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