renovations

This commit is contained in:
Ilya Kantor 2015-03-04 23:09:07 +03:00
parent 05d35d0d16
commit 951cf3f2ec
152 changed files with 2527 additions and 2179 deletions

View file

@ -1,28 +1,16 @@
# Алгоритм
Анимируйте одновременно свойства `left/top` и `width/height`.
Чтобы в процессе анимации таблица сохраняла геометрию -- создайте на месте `IMG` временный `DIV` фиксированного размера и переместите `IMG` внутрь него. После анимации можно вернуть как было.
Для начала анимации - добавьте класс изображению:
CSS-код для анимации одновременно `width` и `height`:
```css
.growing {
/* все свойства анимируются 3 секунды */
-webkit-transition: all 3s;
-moz-transition: all 3s;
-o-transition: all 3s;
-ms-transition: all 3s;
/* исходный класс */
#flyjet {
transition: all 3s;
}
/* JS добавляет .growing *.
#flyjet.growing {
width: 400px;
height: 240px;
}
```
При этом, чтобы анимация началась, может понадобиться отложить установку класса и новых свойств через `setTimeout(.., 0)`.
Для отлова конца анимации используйте событие `on<browser>TransitionEnd`. Оно сработает несколько раз, для каждого свойства, поэтому чтобы обработчик не вывел "OK" много раз -- можно обрабатывать окончание только при одном `event.propertyName`.
# Похожая задача
Аналогичная задача, решённая средствами JS: [](/task/animate-logo).
# Решение
[edit src="solution" task/]
Небольшая тонкость с окончанием анимации. Соответствующее событие `transitionend` сработает два раза -- по одному для каждого свойства. Поэтому, если не предпринять дополнительных шагов, сообщение из обработчика может быть выведено 2 раза.

View file

@ -2,38 +2,15 @@
<html>
<head>
<meta charset="utf-8">
<style>img { display: block; cursor: pointer; }</style>
<style>img { cursor: pointer; }</style>
<style>
/**
* до анимации: .flyjet
* в начале анимации .flyjet .growing-init
* в процессе анимации .flyjet .growing-init .growing
* в конце анимации .flyjet
*/
.flyjet {
width: 400px;
height: 240px;
#flyjet {
width: 40px;
height: 24px;
transition: all 3s;
}
.growing-init {
position: absolute;
height: 0;
width: 0;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
/* все свойства анимируются 3 секунды */
-webkit-transition: all 3s;
-moz-transition: all 3s;
-o-transition: all 3s;
-ms-transition: all 3s;
}
.growing {
#flyjet.growing {
width: 400px;
height: 240px;
}
@ -41,62 +18,21 @@
</head>
<body>
Кликните картинку для анимации. Расположение элементов при анимации не должно меняться!
<table>
<tr>
<td>Догнать</td>
<td><img onclick="growIn(this)" src="https://js.cx/clipart/flyjet.jpg" class="flyjet">
</td>
<td>..и перегнать!</td>
</tr>
</table>
<b>В процессе анимации повторные клики на изображение игнорировать.</b>
<img id="flyjet" src="https://js.cx/clipart/flyjet.jpg">
<script>
function growIn(img) {
if (img.classList.contains('growing-init')) return;
console.log("growIn!");
flyjet.onclick = function() {
var height = img.offsetHeight;
var width = img.offsetWidth;
var ended = false;
// переместить изображение в placeholder постоянного размера
var placeholder = document.createElement('div');
placeholder.style.position = 'relative';
placeholder.style.width = width + 'px';
placeholder.style.height = height + 'px';
img.parentNode.replaceChild(placeholder, img);
placeholder.appendChild(img);
img.classList.add('growing-init');
// откладываем на следующий фрейм, чтобы началась анимация
// иначе изменение свойств IMG не будет замечено
requestAnimationFrame(function() {
// Firefox иногда не стартует анимацию,
// если не отложить classList.add ещё на один кадр (tested: FF30-)
requestAnimationFrame(function() {
img.classList.add('growing');
img.addEventListener('transitionend', done);
});
flyjet.addEventListener('transitionend', function() {
if (!ended) {
ended = true;
alert('Готово!');
}
});
function done(e) {
// сработать только первый раз
img.removeEventListener('transitionend', done);
placeholder.parentNode.replaceChild(img, placeholder);
img.classList.remove('growing');
img.classList.remove('growing-init');
alert('ok');
}
flyjet.classList.add('growing');
}
</script>

View file

@ -1,92 +0,0 @@
/**
Docs: http://learn.javascript.ru/tutorial/lib
*/
function animate(opts) {
var start = new Date;
var delta = opts.delta || linear;
var timer = setInterval(function() {
var progress = (new Date - start) / opts.duration;
if (progress > 1) progress = 1;
opts.step( delta(progress) );
if (progress == 1) {
clearInterval(timer);
opts.complete && opts.complete();
}
}, opts.delay || 13);
return timer;
}
/**
Анимация стиля opts.prop у элемента opts.elem
от opts.from до opts.to продолжительностью opts.duration
в конце opts.complete
Например: animateProp({ elem: ..., prop: 'height', start:0, end: 100, duration: 1000 })
*/
function animateProp(opts) {
var start = opts.start, end = opts.end, prop = opts.prop;
opts.step = function(delta) {
var value = Math.round(start + (end - start)*delta);
opts.elem.style[prop] = value + 'px';
}
return animate(opts);
}
// ------------------ Delta ------------------
function elastic(progress) {
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress);
}
function linear(progress) {
return progress;
}
function quad(progress) {
return Math.pow(progress, 2);
}
function quint(progress) {
return Math.pow(progress, 5);
}
function circ(progress) {
return 1 - Math.sin(Math.acos(progress));
}
function back(progress) {
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5);
}
function bounce(progress) {
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2;
else
return (2 - delta(2*(1-progress))) / 2;
}
}
function makeEaseOut(delta) {
return function(progress) {
return 1 - delta(1 - progress);
}
}

View file

@ -2,30 +2,19 @@
<html>
<head>
<meta charset="utf-8">
<script src="animate.js"></script>
<style>img { display: block; cursor: pointer; }</style>
<style>img { cursor: pointer; }</style>
<style>
#flyjet {
width: 40px; /* -> 400px */
height: 24px; /* -> 240px */
}
</style>
</head>
<body>
Кликните картинку для анимации. Расположение элементов при анимации не должно меняться!
<table>
<tr>
<td>Догнать</td>
<td><img onclick="growIn(this)" src="https://js.cx/clipart/flyjet.jpg" width="400" height="240">
</td>
<td>..и перегнать!</td>
</tr>
</table>
<img id="flyjet" src="https://js.cx/clipart/flyjet.jpg">
<b>В процессе анимации повторные нажатия на изображение игнорируются.</b>
<script>
function growIn(img) {
/* ваш код */
}
</script>
</body>
</html>
</html>

View file

@ -1,12 +1,16 @@
# Анимировать лого (CSS)
# Анимировать самолёт (CSS)
[importance 5]
Реализуйте анимацию, как в демке ниже (клик на картинку):
[iframe src="solution" height=350]
Продолжительность анимации: 3 секунды.
[iframe src="solution" height=300]
Для анимации использовать CSS, по окончании вывести "ок".
<ul>
<li>Изображение растёт при клике с 40x24px до 400x240px .</li>
<li>Продолжительность анимации: 3 секунды.</li>
<li>По окончании вывести "Готово!".</li>
<li>Если в процессе анимации были дополнительные клики -- они не должны ничего "сломать".</li>
</ul>