/
filter.html
185 lines (171 loc) · 7.61 KB
/
filter.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Animation</title>
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 750px;
height: 405px;
background-color: #fbf9eb;
}
img {
transform: translate(50px, 50px);
}
</style>
</head>
<body>
<div>
<img id="mitarashi" src="images/mitarashi_200.png">
</div>
<script>
// みたらしくんを1秒後に1秒かけて座標(500, 150)へ、加速〜減速しながらアニメーションさせる
animateTranslate('mitarashi', 1000, 'easeInOutExpo', 500, 150, 1000, {blur: 10, brightness: 2.0});
/**
* 対象オブジェクトをアニメーションして移動させます。
* @param {string} targetID スクロール時間のミリ秒です。
* @param {number} time アニメーションさせる時間です(ミリ秒)。
* @param {string} easing 変化に使用するイージング。
* @param {number} endX X座標の目標値です。
* @param {number} endY Y座標の目標値です。
* @param {number} delay アニメーションを開始するまでの遅延時間です(ミリ秒)。
* @param {object} filters 各フィルターの目標値です。
*/
function animateTranslate(targetID, time, easing, endX, endY, delay, filters) {
const target = document.getElementById(targetID); // アニメーションの対象
const style = getComputedStyle(target); // 対象のスタイルを取得
const reg = /matrix\((.*)\)/; // 不要な文字列を取り除くための正規表現
const transform = style.transform.match(reg)[1].split(','); // transform を配列として取得
const startX = parseFloat(transform[4]); // X座標の始点
const startY = parseFloat(transform[5]); // Y座標の始点
const diffX = endX - startX; // X座標の変化量
const diffY = endY - startY; // Y座標の変化量
const ease = getEasing(easing); // 使用するイージング関数
let progress = 0;
let easeProgress = 0;
// フィルター関連の変数の宣言
const styleFilter = style.filter; // 対象の設定されているフィルターを取得
const regBlur = /blur\((.*px)\)/; // 不要な文字列を取り除くための正規表現
const regBrightness = /brightness\((.*)\)/; // 不要な文字列を取り除くための正規表現
let startBlur = 0; // ぼかしの始点
let startBrightness = 1.0; // 明るさの始点
let diffBlur = 0; // ぼかしの変化量
let diffBrightness = 0; // 明るさの変化量
// フィルターアニメーションを使用する場合
if (filters !== null) {
// 対象にフィルターが設定されている場合
if (styleFilter !== 'none') {
// フィルターの始点の設定
if (styleFilter.includes('blur')) {
startBlur = parseFloat(styleFilter.match(regBlur)[1]);
}
if (styleFilter.includes('brightness')) {
startBrightness = parseFloat(styleFilter.match(regBrightness)[1]);
}
}
// フィルターの変化量の算出
if (filters.hasOwnProperty('blur')) {
diffBlur = filters.blur - startBlur;
}
if (filters.hasOwnProperty('brightness')) {
diffBrightness = filters.brightness - startBrightness;
}
}
// アップデートを実行する
requestAnimationFrame(update);
function update(timestanp) {
// 遅延時間を含めた進捗率を算出
progress = (timestanp - delay) / time;
// 進捗率が100%を超えないよう丸める
progress = Math.min(progress, 1);
// 進捗率がプラスの場合のみ値を算出し反映する
if (progress >= 0) {
// X、Y座標
easeProgress = ease(progress, 0, 1, 1); // 進捗率からイージング関数を通した変化割合を算出
const resultX = startX + diffX * easeProgress; // X座標
const resultY = startY + diffY * easeProgress; // Y座標
target.style.transform = `translate( ${resultX}px, ${resultY}px )`;
// フィルター
if (filters !== null) {
let resultFilter = '';
// 各フィルターの値を算出
resultFilter += `blur( ${startBlur + diffBlur * easeProgress}px ) `;
resultFilter += `brightness( ${startBrightness + diffBrightness * easeProgress} )`;
// フィルターの値を反映
target.style.filter = resultFilter;
}
}
// 進捗が1未満の場合はアップデートを再実行する
if (progress < 1) {
requestAnimationFrame(update);
}
}
}
/*
*
* TERMS OF USE - EASING EQUATIONS
*
* Open source under the BSD License.
*
* Copyright © 2001 Robert Penner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the author nor the names of contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* イージング関数を取得します。
* @param {number} easingName イージング関数の名称です。
*/
function getEasing(easingName) {
let ease;
switch (easingName) {
// t: current time, b: begInnIng value, c: change In value, d: duration
case 'easeInExpo':
ease = function (t, b, c, d) {
return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
}
break;
case 'easeOutExpo':
ease = function (t, b, c, d) {
return (t == d) ? b + c: c * (-Math.pow(2, -10 * t / d) + 1) + b;
}
break;
case 'easeInOutExpo':
ease = function (t, b, c, d) {
if (t == 0) return b;
if (t == d) return b + c;
if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
}
break;
}
return ease;
}
</script>
</body>
</html>