Progress Bar

Публікації

Progress Bar (індикатор виконання) використовується для відображення процесу виконання операції.

Розглянемо способи реалізації progress bar на веб-сторінці, та змінення індикації виконання за допомогою JavaScript.

progress

У HTML 5 є елемент progress для для відображення індикатора який показує хід виконання операції.

Елемент progress має два основні атрибути: max - максимальне значення позиції процесу, value - поточне значення позиції процесу. Зазвичай вказується max=100 і value=від 0 до 100.

var progress=document.getElementById('progres'); progress.value=50;

Progress bar за допомогою CSS

Для створення Progress Bar на сайті за допомогою CSS використовується два елемента.

<div id="progressbar"> <div id="progressbar_position"></div> </div> <style> #progressbar{ width:300px; height:18px; background-color:#d8d9d9; } #progressbar_position{ width:10%; height:100%; background-color:#4caf50; } </style>

Зміна значення через JavaScript вказується стиль width від 0 до 100% :

var progressbar_position=document.querySelector('#progressbar_position'); progressbar_position.style.width='80%'; //від 0 до 100 %

Відображення під час циклу

Під час циклу операцій у JavaScript відображати стан progress виявляється не так просто. Це пов'язано з тим що JavaScript є однопотоковим, тобто усі операції відбуваються в одному потоці і цикл блокує цей потік виконання.

function myFunc(){ var s='', n=12345, progres=document.getElementById('progress2'); progres.value=0; progres.max=n; for(var i=0;i<n;i++){ s+=(Math.random()*i)+' '; progres.value=i; } return s; } myFunc();

Щоб не блокувати потік виконання можна розбити цикл на частини і виконувати їх ці частини через таймер. Це дозволить не блокувати потік виконання і показувати процес виконання операції у progress.

При цьому загальний час виконання функції може не суттєво збільшитися.

//необхідні змінні оголошуємо як глобальні (глобальна видимість) var s='', n=123456, progres=document.getElementById('progress3'); function myFunc(a){ if(a==undefined){ //якщо перший виклик функції (не через таймер) a=0; progres.value=0; progres.max=n; } for(var i=a;i<a+100;i++){ //якщо i більше n тоді дійшли операцію завершено if(i>n){ /* що необхідно зробити при завершенні операції */ } s+=(Math.random()*i)+' '; } progres.value=i; if(a<n)setTimeout(myFunc, 25, a+100); //викликаємо функцію через 25мс з параметром a+100 } myFunc(); //виклик функції

Функція-конструктор myFunc2 створює об'єкт приймаючи параметри: progress - CSS селектор елемента progress, функція яка виконається коли progres досягне "100%".

function myFunc2(progress, onfinish){ this.start=function(){ for(var i=this.index;i<this.index+this.count;i++){ if(i>this.max){ this.onfinish(this.result); this._clear(); return; } //виконуємо потрібні операції this.result+=Math.random()*100; } this.index=i; this.progress.value=this.index; setTimeout(this.start.bind(this),25,this.index); } this._clear=function(){ this.result=0; this.max=123456; //загальна кількість необхідних циклів this.count=1000; //кількість циклів в одному фрагменті виконанні функції this.index=0; this.progress.value=this.index; this.progress.max=this.max; } this.progress=document.querySelector(progress); this._clear(); this.onfinish=onfinish || function(){}; } var ob=new myFunc2('#progress4', function(res){ alert('результат виконання: '+res); }); ob.start();

Реалізація на основі Promise:

function myFunc3(progress){ return new Promise(function(resolve){ var ob={}; ob.start=function(){ for(var i=this.index;i<this.index+this.count;i++){ if(i>this.max){ this.onfinish(this.result); this._clear(); return; } //виконуємо потрібні операції this.result+=Math.random()*100; } this.index=i; this.progress.value=this.index; setTimeout(this.start.bind(this),25,this.index); } ob._clear=function(){ this.result=0; this.max=123456; //загальна кількість необхідних циклів this.count=1000; //кількість циклів в одному фрагменті виконанні функції this.index=0; this.progress.value=this.index; this.progress.max=this.max; } ob.progress=document.querySelector(progress); ob._clear(); ob.onfinish=resolve || function(){}; ob.start(); }); } myFunc3('#progress5').then(function(res){ alert('результат виконання: '+res); });

Визначаємо скільки ще часу залишилося до повного виконання.

Час будемо отримувати з performance.now() який дає більш точний результат.

function myFunc4(progress, label){ return new Promise(function(resolve){ var ob={}; ob.start=function(){ for(var i=this.index;i<this.index+this.count;i++){ if(i>this.max){ this.onfinish(this.result); this._clear(); return; } //виконуємо потрібні операції this.result+=Math.random()*100; } this.index=i; //визначаємо скільки необхідно часу var p=(this.index/this.max)*100; //визначаємо відсоток % виконання var tm=performance.now(); var pt=(tm-this.time)/p; //скільки часу виконання зайняв 1% var tz=parseInt(((100-p)*pt)/1000); //визначаємо скільки часу потрібно на % які ще залишилися this.label.innerText='залишилося '+(isNaN(tz)?'??:??':this.secToTime(tz)); this.progress.value=this.index; setTimeout(this.start.bind(this),25,this.index); } ob._clear=function(){ this.result=0; this.max=1234567; //загальна кількість необхідних циклів this.count=1000; //кількість циклів в одному фрагменті виконанні функції this.index=0; this.progress.value=this.index; this.progress.max=this.max; } ob.secToTime=function(s){ var h,m,s; h=parseInt(s/3600); //кількість годин m=parseInt((s-(0*3600))/60); //кількість хвилин s=parseInt(s-(m*60)); //кількість секунд return (h<10?'0'+h:h)+':'+(m<10?'0'+m:m)+':'+(s<10?'0'+s:s); }; ob.progress=document.querySelector(progress); ob.label=document.querySelector(label); ob._clear(); ob.onfinish=resolve || function(){}; ob.time=performance.now(); ob.start(); }); } myFunc4('#progress6', '#label6').then(function(res){ alert('результат виконання: '+res); });
Адмін 2020-04-11 11:08:20

Тільки зареєстровані користувачі можуть писати коментарі.