<!-- progress button --> <div id="progress-button" class="progress-button"> <!-- button with text --> <button><span>Submit</span></button> <!-- svg circle for progress indication --> <svg class="progress-circle" width="70" height="70"> <path d="m35,2.5c17.955803,0 32.5,14.544199 32.5,32.5c0,17.955803 -14.544197,32.5 -32.5,32.5c-17.955803,0 -32.5,-14.544197 -32.5,-32.5c0,-17.955801 14.544197,-32.5 32.5,-32.5z"/> </svg> <!-- checkmark to show on success --> <svg class="checkmark" width="70" height="70"> <path d="m31.5,46.5l15.3,-23.2"/> <path d="m31.5,46.5l-8.5,-7.1"/> </svg> <!-- cross to show on error --> <svg class="cross" width="70" height="70"> <path d="m35,35l-9.3,-9.3"/> <path d="m35,35l9.3,9.3"/> <path d="m35,35l-9.3,9.3"/> <path d="m35,35l9.3,-9.3"/> </svg> </div><!-- /progress-button -->
.progress-button { position: relative; display: inline-block; text-align: center; }
.progress-button button { display: block; margin: 0 auto; padding: 0; width: 250px; height: 70px; border: 2px solid #1ECD97; border-radius: 40px; background: transparent; color: #1ECD97; letter-spacing: 1px; font-size: 18px; font-family: 'Montserrat', sans-serif; -webkit-transition: background-color 0.3s, color 0.3s, width 0.3s, border-width 0.3s, border-color 0.3s; transition: background-color 0.3s, color 0.3s, width 0.3s, border-width 0.3s, border-color 0.3s; }
.progress-button button:hover { background-color: #1ECD97; color: #fff; }
.progress-button button:focus { outline: none; }
.progress-button svg { position: absolute; top: 0; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); pointer-events: none; }
.progress-button svg path { opacity: 0; fill: none; }
.progress-button svg.progress-circle path { stroke: #1ECD97; stroke-width: 5; }
.progress-button svg.checkmark path, .progress-button svg.cross path { stroke: #fff; stroke-linecap: round; stroke-width: 4; -webkit-transition: opacity 0.1s; transition: opacity 0.1s; }
.loading.progress-button button { width: 70px; /* make a circle */ border-width: 5px; border-color: #ddd; background-color: transparent; color: #fff; }
.loading.progress-button span { -webkit-transition: opacity 0.15s; transition: opacity 0.15s; }
.loading.progress-button span, .success.progress-button span, .error.progress-button span { opacity: 0; /* keep it hidden in all states */ }
/* Transition for when returning to default state */ .progress-button button span { -webkit-transition: opacity 0.3s 0.1s; transition: opacity 0.3s 0.1s; }
.success.progress-button button, .error.progress-button button { -webkit-transition: background-color 0.3s, width 0.3s, border-width 0.3s; transition: background-color 0.3s, width 0.3s, border-width 0.3s; }
.success.progress-button button { border-color: #1ECD97; background-color: #1ECD97; } .error.progress-button button { border-color: #FB797E; background-color: #FB797E; }
.loading.progress-button svg.progress-circle path, .success.progress-button svg.checkmark path, .error.progress-button svg.cross path { opacity: 1; -webkit-transition: stroke-dashoffset 0.3s; transition: stroke-dashoffset 0.3s; }
.elastic.progress-button button { -webkit-transition: background-color 0.3s, color 0.3s, width 0.3s cubic-bezier(0.25, 0.25, 0.4, 1), border-width 0.3s, border-color 0.3s; -webkit-transition: background-color 0.3s, color 0.3s, width 0.3s cubic-bezier(0.25, 0.25, 0.4, 1.6), border-width 0.3s, border-color 0.3s; transition: background-color 0.3s, color 0.3s, width 0.3s cubic-bezier(0.25, 0.25, 0.4, 1.6), border-width 0.3s, border-color 0.3s; } .loading.elastic.progress-button button { -webkit-transition: background-color 0.3s, color 0.3s, width 0.3s cubic-bezier(0.6, 0, 0.75, 0.75), border-width 0.3s, border-color 0.3s; -webkit-transition: background-color 0.3s, color 0.3s, width 0.3s cubic-bezier(0.6, -0.6, 0.75, 0.75), border-width 0.3s, border-color 0.3s; transition: background-color 0.3s, color 0.3s, width 0.3s cubic-bezier(0.6, -0.6, 0.75, 0.75), border-width 0.3s, border-color 0.3s; }
function UIProgressButton( el, options ) { this.el = el; this.options = extend( {}, this.options ); extend( this.options, options ); this._init(); } UIProgressButton.prototype._init = function() { this.button = this.el.querySelector( 'button' ); this.progressEl = new SVGEl( this.el.querySelector( 'svg.progress-circle' ) ); this.successEl = new SVGEl( this.el.querySelector( 'svg.checkmark' ) ); this.errorEl = new SVGEl( this.el.querySelector( 'svg.cross' ) ); // init events this._initEvents(); // enable button this._enable(); }
function SVGEl( el ) { this.el = el; // the path elements this.paths = [].slice.call( this.el.querySelectorAll( 'path' ) ); // we will save both paths and its lengths in arrays this.pathsArr = new Array(); this.lengthsArr = new Array(); this._init(); } SVGEl.prototype._init = function() { var self = this; this.paths.forEach( function( path, i ) { self.pathsArr[i] = path; path.style.strokeDasharray = self.lengthsArr[i] = path.getTotalLength(); } ); // undraw stroke this.draw(0); } // val in [0,1] : 0 - no stroke is visible, 1 - stroke is visible SVGEl.prototype.draw = function( val ) { for( var i = 0, len = this.pathsArr.length; i < len; ++i ){ this.pathsArr[ i ].style.strokeDashoffset = this.lengthsArr[ i ] * ( 1 - val ); } }
UIProgressButton.prototype._initEvents = function() { var self = this; this.button.addEventListener( 'click', function() { self._submit(); } ); } UIProgressButton.prototype._submit = function() { classie.addClass( this.el, 'loading' ); var self = this, onEndBtnTransitionFn = function( ev ) { if( support.transitions ) { this.removeEventListener( transEndEventName, onEndBtnTransitionFn ); } this.setAttribute( 'disabled', '' ); if( typeof self.options.callback === 'function' ) { self.options.callback( self ); } else { self.setProgress(1); self.stop(); } }; if( support.transitions ) { this.button.addEventListener( transEndEventName, onEndBtnTransitionFn ); } else { onEndBtnTransitionFn(); } }
UIProgressButton.prototype.stop = function( status ) { var self = this, endLoading = function() { self.progressEl.draw(0); if( typeof status === 'number' ) { var statusClass = status >= 0 ? 'success' : 'error', statusEl = status >=0 ? self.successEl : self.errorEl; statusEl.draw( 1 ); // add respective class to the element classie.addClass( self.el, statusClass ); // after options.statusTime remove status and undraw the respective stroke and enable the button setTimeout( function() { classie.remove( self.el, statusClass ); statusEl.draw(0); self._enable(); }, self.options.statusTime ); } else { self._enable(); } classie.removeClass( self.el, 'loading' ); }; // give it a little time (ideally the same like the transition time) so that the last progress increment animation is still visible. setTimeout( endLoading, 300 ); }
Source: https://habr.com/ru/post/271881/
All Articles