Гмстограмма с анимацией
Здравствуйте!
Пытаюсь вытащить из работающего сайта на wordpress блок с горизонтальной диаграммой: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <script src="http://code.jquery.com/jquery-1.8.3.js"></script> <style> .digram-line-box { background-color: #f4f6f7;} .diagram-wrapper.style-1 .digram-line-box .skill-line {margin-right: 0px;} .diagram-wrapper.style-1 .digram-line-box .skill-amount {margin-top: -30px;} .diagram-wrapper.style-1 .digram-line-box .skill-element {padding-top: 14px;} .diagram-item{margin-bottom:1.421em} .skill-element+.skill-element{margin:8px 0 0 0} .skill-title{font-size:89.5%;line-height:1.421;margin:0 0 5px 0} .skill-amount{float:right;font-size:126.3%;margin-top:-11px} .skill-line{font-size:0;line-height:1;height:10px;margin-right:55px} .skill-line div{display:inline-block;font-size:0;line-height:1;height:10px} .skill-line div.animation{-moz-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);-ms-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);-o-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);-webkit-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);transition:width 1.6s cubic-bezier(0.165,0.84,0.44,1)} .diagram-summary{font-size:89.5%;line-height:1.471;margin:0 0 0.766667em 0} .widget .diagram-summary{font-size:100%} .diagram-summary-text{margin:0 0 0.766667em 0} </style> </head> <body> <div class="diagram-item"> <div class="diagram-wrapper style-1"> <div class="" > <div class="digram-line-box " > <div class="skill-element"> <div class="skill-title">Оптимизация </div> <div class="clearfix"> <div style="color:#464c5c" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="98" style="background: #464c5c;"></div> </div> </div> </div> <div class="skill-element"> <div class="skill-title">Кроссплатформенность </div> <div class="clearfix"> <div style="color:#6d747a" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="100" style="background: #6d747a;"> </div> </div> </div> </div> <div class="skill-element"> <div class="skill-title">Удобство </div> <div class="clearfix"> <div style="color:#8c8274" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="99" style="background: #8c8274;"> </div> </div> </div> </div> <div class="skill-element"> <div class="skill-title">Дизайн </div> <div class="clearfix"> <div style="color:#d2c6b4" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="99" style="background: #d2c6b4;"> </div> </div> </div> </div> </div> </div> </div> </div> <script> (function($) { var prefixes = 'Webkit Moz ms Ms O'.split(' '); var docElemStyle = document.documentElement.style; function getStyleProperty( propName ) { if ( !propName ) { return; } // test standard property first if ( typeof docElemStyle[ propName ] === 'string' ) { return propName; } // capitalize propName = propName.charAt(0).toUpperCase() + propName.slice(1); // test vendor specific properties var prefixed; for ( var i=0, len = prefixes.length; i < len; i++ ) { prefixed = prefixes[i] + propName; if ( typeof docElemStyle[ prefixed ] === 'string' ) { return prefixed; } } } var transitionProperty = getStyleProperty('transition'); var transitionEndEvent = { WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', OTransition: 'otransitionend', transition: 'transitionend' }[ transitionProperty ]; function LineDiagram(element) { this.el = element; this.$el = jQuery(element); this.start(); } LineDiagram.prototype = { start: function() { if (!this.$el.hasClass('digram-line-box')) return; this.initTimer(); var diagram_lines_queue = []; jQuery('.skill-element', this.$el).each(function () { diagram_lines_queue.push(jQuery(this)); }); this.showLine(diagram_lines_queue, true); }, showLine: function(queue, first) { var self = this, $skill = queue.shift(); if ($skill == null || $skill == undefined) { return; } function thegem_show_digram_line_animation() { var $progress = $('.skill-line div', $skill), $skillAmount = $('.skill-amount', $skill), amount = parseFloat($progress.data('amount')); $progress.addClass('animation').css('width', amount + '%'); jQuery({countNum: 0}).animate({countNum: amount}, { duration: 1600, easing:'easeOutQuart', step: function() { var count = parseFloat(this.countNum); var pct = Math.ceil(count) + '%'; $skillAmount.html(pct); } }); self.showLine(queue, false); } if (first) { thegem_show_digram_line_animation(); } else { this.startTimer(thegem_show_digram_line_animation); } }, initTimer: function() { var self = this; this.timer = this.$el.data('timer'); this.timerCallback = function() {}; $(this.timer).bind(transitionEndEvent, function(event) { self.timerCallback(); }); }, startTimer: function(callback) { var self = this; this.timerCallback = callback; if (this.timer.className.indexOf('start-timer') != -1) { this.timer.className = this.timer.className.replace(' start-timer', ''); } else { this.timer.className += ' start-timer'; } } }; jQuery.fn.thegem_start_line_digram = function() { return new LineDiagram(this.get(0)); } })(jQuery); function thegem_show_diagram_line_mobile($box) { jQuery('.skill-element', $box).each(function () { jQuery('.skill-line div', this).width(jQuery('.skill-line div', this).data('amount') + '%'); }); } function thegem_start_line_digram(element) { jQuery(element).thegem_start_line_digram(); } jQuery('.digram-line-box').each(function () { var self = this; var timer = document.createElement('div'); timer.className = 'diagram-line-timer-element'; document.body.appendChild(timer); timer.className += ' start-timer'; jQuery(this).data('timer', timer); //jQuery('.skill-element .skill-amount', this).html('0%'); jQuery(document).ready(function() { if (!jQuery(self).hasClass('lazy-loading-item') || window.gemSettings.lasyDisabled) jQuery(self).thegem_start_line_digram(); }); }); </script> </body> </html> Но что-то не получается... в консоле вижу ошибку "Uncaught TypeError: jQuery.easing[this.easing] is not a function"... Где ошибка? ( |
easing Ключевое слово (строка), которое определяет кривую скорости для анимации (используется математическая функция - кубическая кривая Безье). Без использования внешних плагинов имеет только два значения - linear (эффект анимации с одинаковой скоростью от начала до конца) и swing (эффект анимации имеет медленный старт и медленное окончание, но скорость увеличивается в середине анимации). Значение по умолчанию swing.
|
да, я сейчас добавил
<script src='http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js'></script> заработала только первая диаграма из четырех... и анимации линии даже на ней нет (но это я возможно с scc "недотумкал") |
Igorsrt,
К какому/каким объектам вы применяете анимацию? jQuery({countNum: 0}).animate( |
Цитата:
|
Цитата:
.skill-line div{display:inline-block;font-size:0;line-height:1;height:10px;width : 0;} |
Цитата:
self.showLine(queue, true); |
Igorsrt,
и того <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script> jQuery.easing.easeOutQuart = function(x, t, b, c, d) { return -c * (t /= d) * (t - 2) + b } </script> <style> .digram-line-box { background-color: #f4f6f7;} .diagram-wrapper.style-1 .digram-line-box .skill-line {margin-right: 0px;} .diagram-wrapper.style-1 .digram-line-box .skill-amount {margin-top: -30px;} .diagram-wrapper.style-1 .digram-line-box .skill-element {padding-top: 14px;} .diagram-item{margin-bottom:1.421em} .skill-element+.skill-element{margin:8px 0 0 0} .skill-title{font-size:89.5%;line-height:1.421;margin:0 0 5px 0} .skill-amount{float:right;font-size:126.3%;margin-top:-11px} .skill-line{font-size:0;line-height:1;height:10px;margin-right:55px} .skill-line div{display:inline-block;font-size:0;line-height:1;height:10px;width : 0;} .skill-line div.animation{-moz-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);-ms-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);-o-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);-webkit-transition:width 1.6s cubic-bezier(0.165, 0.84, 0.44, 1);transition:width 1.6s cubic-bezier(0.165,0.84,0.44,1)} .diagram-summary{font-size:89.5%;line-height:1.471;margin:0 0 0.766667em 0} .widget .diagram-summary{font-size:100%} .diagram-summary-text{margin:0 0 0.766667em 0} </style> </head> <body> <div class="diagram-item"> <div class="diagram-wrapper style-1"> <div class="" > <div class="digram-line-box " > <div class="skill-element"> <div class="skill-title">Оптимизация </div> <div class="clearfix"> <div style="color:#464c5c" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="98" style="background: #464c5c;"></div> </div> </div> </div> <div class="skill-element"> <div class="skill-title">Кроссплатформенность </div> <div class="clearfix"> <div style="color:#6d747a" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="100" style="background: #6d747a;"> </div> </div> </div> </div> <div class="skill-element"> <div class="skill-title">Удобство </div> <div class="clearfix"> <div style="color:#8c8274" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="99" style="background: #8c8274;"> </div> </div> </div> </div> <div class="skill-element"> <div class="skill-title">Дизайн </div> <div class="clearfix"> <div style="color:#d2c6b4" class="skill-amount">0%</div> <div class="skill-line"> <div data-amount="99" style="background: #d2c6b4;"> </div> </div> </div> </div> </div> </div> </div> </div> <script> (function($) { var prefixes = 'Webkit Moz ms Ms O'.split(' '); var docElemStyle = document.documentElement.style; function getStyleProperty( propName ) { if ( !propName ) { return; } // test standard property first if ( typeof docElemStyle[ propName ] === 'string' ) { return propName; } // capitalize propName = propName.charAt(0).toUpperCase() + propName.slice(1); // test vendor specific properties var prefixed; for ( var i=0, len = prefixes.length; i < len; i++ ) { prefixed = prefixes[i] + propName; if ( typeof docElemStyle[ prefixed ] === 'string' ) { return prefixed; } } } var transitionProperty = getStyleProperty('transition'); var transitionEndEvent = { WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', OTransition: 'otransitionend', transition: 'transitionend' }[ transitionProperty ]; function LineDiagram(element) { this.el = element; this.$el = jQuery(element); this.start(); } LineDiagram.prototype = { start: function() { if (!this.$el.hasClass('digram-line-box')) return; this.initTimer(); var diagram_lines_queue = []; jQuery('.skill-element', this.$el).each(function () { diagram_lines_queue.push(jQuery(this)); }); this.showLine(diagram_lines_queue, true); }, showLine: function(queue, first) { var self = this, $skill = queue.shift(); if ($skill == null || $skill == undefined) { return; } function thegem_show_digram_line_animation() { var $progress = $('.skill-line div', $skill), $skillAmount = $('.skill-amount', $skill), amount = parseFloat($progress.data('amount')); $progress.addClass('animation').css('width', amount + '%'); jQuery({countNum: 0}).animate({countNum: amount}, { duration: 1600, easing:'easeOutQuart', step: function() { var count = parseFloat(this.countNum); var pct = Math.ceil(count) + '%'; $skillAmount.html(pct); } }); self.showLine(queue, true); } if (first) { thegem_show_digram_line_animation(); } else { this.startTimer(thegem_show_digram_line_animation); } }, initTimer: function() { var self = this; this.timer = this.$el.data('timer'); this.timerCallback = function() {}; $(this.timer).bind(transitionEndEvent, function(event) { self.timerCallback(); }); }, startTimer: function(callback) { var self = this; this.timerCallback = callback; if (this.timer.className.indexOf('start-timer') != -1) { this.timer.className = this.timer.className.replace(' start-timer', ''); } else { this.timer.className += ' start-timer'; } } }; jQuery.fn.thegem_start_line_digram = function() { return new LineDiagram(this.get(0)); } })(jQuery); function thegem_show_diagram_line_mobile($box) { jQuery('.skill-element', $box).each(function () { jQuery('.skill-line div', this).width(jQuery('.skill-line div', this).data('amount') + '%'); }); } function thegem_start_line_digram(element) { jQuery(element).thegem_start_line_digram(); } jQuery('.digram-line-box').each(function () { var self = this; var timer = document.createElement('div'); timer.className = 'diagram-line-timer-element'; document.body.appendChild(timer); timer.className += ' start-timer'; jQuery(this).data('timer', timer); //jQuery('.skill-element .skill-amount', this).html('0%'); jQuery(document).ready(function() { if (!jQuery(self).hasClass('lazy-loading-item') || window.gemSettings.lasyDisabled) jQuery(self).thegem_start_line_digram(); }); }); </script> </body> </html> |
Цитата:
|
Еще один вопрос возник: Как заставить анимацию этой диаграммы срабатывать при прокрутке страницы (она у меня оказалась ниже первого экрана)?
|
var fl = true; onscroll = function(){ if(document.querySelector("селектор_элемента_с_анимацией").getBoundingClientRect().top - innerHeight < 0 && fl) { fl = false; //сюда запуск анимации } }; если запуск нужен ниже, вместо 0 свою цифру -n |
Разве вместо такого сложного и трудно поддерживаемого набора элементов не достаточно было бы использовать только 4 элемента <meter>?
j0hnik, у вас всё время, пока крутишь и видишь элемент, запускается анимация |
Malleys,
поправил |
Анимация запускается каждый раз, как только элемент входит в область видимости + только 4 <meter>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> .skills { margin: 125vh 0; } body::before { content: "Крути вниз!"; } .skill { width: 100%; background: #eee; padding-top: 2em; display: flex; flex-flow: wrap; } .skill .level { flex: 1; text-align: right; font-size: 125%; } .skill meter { width: 100%; background: transparent; } .skill meter::-webkit-meter-bar { background: transparent; border: 0; /* убирает рамку в IE */ } .skill meter::-moz-meter-bar { background: currentColor; } .skill meter::-webkit-meter-optimum-value { background: currentColor; } </style> </head> <body> <section class="skills"> <meter min="0" max="100" value="98" style="color: #464c5c" title="Оптимизация"></meter> <meter min="0" max="100" value="100" style="color: #6d747a" title="Кроссплатформенность"></meter> <meter min="0" max="100" value="99" style="color: #8c8274" title="Удобство"></meter> <meter min="0" max="100" value="99" style="color: #d2c6b4" title="Дизайн"></meter> </section> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script> jQuery.easing.easeOutQuart = function(x, t, b, c, d) { return -c * (t /= d) * (t - 2) + b }; jQuery(".skills meter").each(function(index, { value, title, style }) { const descr = jQuery(`<span class="title">${title}</span>`); const level = jQuery(`<span class="level" style="color: ${style.color}"></span>`); const skill = jQuery(`<section class="skill"></section>`); skill.append(descr, level); $(this).replaceWith(skill); skill.append(this); document.addEventListener("meter:animate", () => jQuery({ value: 0 }).animate({ value }, { duration: 1600, easing: "easeOutQuart", step: value => { this.value = value; level.text(`${value | 0}%`); } })); }); let _isInView = false; onscroll = () => { const rect = document.querySelector(".skills").getBoundingClientRect(); const y = rect.bottom / (innerHeight + rect.bottom - rect.top); const isInView = y > 0 && y < 1; if(_isInView !== isInView) { _isInView = isInView; if(isInView) document.dispatchEvent(new Event("meter:animate", { bubbles: true })); } }; </script> </body> </html> |
Malleys,
:thanks: |
О, прикольно.. А что такое этот <meter> (раньше не видел такого тега). Он везде будет работать?
|
а, все-таки, может лучше "по старинке": куда что добавить в первоначальный скрипт, что бы он срабатывал при прокрутке до блока с диаграммой один раз? :)
|
Igorsrt,
тогда мой пост смотрите |
Цитата:
|
анимация чисел в зоне видимости гистограмма jquery
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> .meter { width: 100%; height: 8px; color: #fff ; text-align: center; margin: 30px 0; position: relative; } .meter:after { font-size: 18px; content: attr(data-max); color: #000; position: absolute; right: 5px; top: -20px; } .meter:before { font-size: 18px; content: attr(data-title); color: #000; position: absolute; left: 5px; top: -20px; } p { height: 2000px; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script> $(function() { jQuery.easing.easeOutQuart = function(x, t, b, c, d) { return -c * (t /= d) * (t - 2) + b }; var num = $(".meter"); var duration = 1200; num.each(function(indx, el) { var max = $(el).data("max"); var color = $(el).data("color"); var visibility = checkViewport(el); $(el).on("animeNum", function() { $({ n: 0 }).animate({ n: max }, { easing: "easeOutQuart", duration: duration, step: function(now, fx) { now |= 0; now += "%"; var gradient = "linear-gradient(to right, " + color + " , " + color + " " + now + ", #FFFFFF " + now + ")"; $(el).attr("data-max", now).css({ "backgroundImage": gradient }) } }) }).data("visibility", visibility); visibility && $(el).trigger("animeNum") }); function checkViewport(elem) { var rect = elem.getBoundingClientRect(); var y = rect.bottom / (innerHeight + rect.bottom - rect.top); var isInView = y > 0 && y < 1; return isInView } jQuery.fn.scrollComplete = function(fn, ms) { var timer = null; this.scroll(function() { if (timer) clearTimeout(timer); timer = setTimeout(fn, ms) }) }; $(window).scrollComplete(function() { num.each(function(indx, el) { var visibility = checkViewport(el); el = $(el); var old = el.data("visibility"); old != visibility && el.data("visibility", visibility) && !old && el.trigger("animeNum") }) }, 100) }); </script> </head> <body> <p></p> <div class="meter" data-max="98" data-title="Оптимизация" data-color="#464c5c"></div> <div class="meter" data-max="100" data-title="Кроссплатформенность" data-color="#6d747a"></div> <div class="meter" data-max="99" data-title="Удобство" data-color="#8c8274"></div> <div class="meter" data-max="99" data-title="Дизайн" data-color="#d2c6b4"></div> <p></p> </body> </html> |
рони,
мне в этом варианте не нравится, что скрипт с анимацией каждый раз заново запускается при прокрутке "вверх-вниз"...мне бы хотелось что бы один раз после попадания в зону видимости сработала анимация и все... или я может недопонимаю чего-то опять |
Цитата:
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> .meter { width: 100%; height: 8px; color: #fff ; text-align: center; margin: 30px 0; position: relative; } .meter:after { font-size: 18px; content: attr(data-max); color: #000; position: absolute; right: 5px; top: -20px; } .meter:before { font-size: 18px; content: attr(data-title); color: #000; position: absolute; left: 5px; top: -20px; } p { height: 2000px; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script> $(function() { jQuery.easing.easeOutQuart = function(x, t, b, c, d) { return -c * (t /= d) * (t - 2) + b }; var num = $(".meter"); var duration = 1200; num.each(function(indx, el) { var max = $(el).data("max"); var color = $(el).data("color"); $(el).on("animeNum", function() { $({ n: 0 }).delay(indx * 200).animate({ n: max }, { easing: "easeOutQuart", duration: duration, step: function(now, fx) { now |= 0; now += "%"; var gradient = "linear-gradient(to right, " + color + " , " + color + " " + now + ", #FFFFFF " + now + ")"; $(el).attr("data-max", now).css({ "backgroundImage": gradient }) } }) }) }); function checkViewport(elem) { var rect = elem.getBoundingClientRect(); var y = rect.bottom / (innerHeight + rect.bottom - rect.top); var isInView = y > 0 && y < 1; return isInView } function visibility() { return $.makeArray(num).some(checkViewport) } visibility() ? num.trigger("animeNum") : $(window).scroll(function anime() { visibility() && num.trigger("animeNum") && $(window).off("scroll", anime) }) }); </script> </head> <body> <p></p> <div class="meter" data-max="98" data-title="Оптимизация" data-color="#464c5c"></div> <div class="meter" data-max="100" data-title="Кроссплатформенность" data-color="#6d747a"></div> <div class="meter" data-max="99" data-title="Удобство" data-color="#8c8274"></div> <div class="meter" data-max="99" data-title="Дизайн" data-color="#d2c6b4"></div> <p></p> </body> </html> |
рони,
благодарю, именно так и хотел ) |
рони,
блин, только я хочу еще что бы полоски с задержкой анимировались (т.е. первая полоска сразу, вторая через 0.2s, третья через 0.4s и т.д.)... в прошлом варианте я через css это смог сделать (transition-delay)... А здесь как? |
Цитата:
}).delay(indx * 200).animate({ |
супер! спасибо
|
Часовой пояс GMT +3, время: 09:54. |