Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(442)

Side by Side Diff: third_party/polymer/components/web-animations-js/src/timing-utilities.js

Issue 3010683002: Update Polymer components. (Closed)
Patch Set: Rebase Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 (function(shared, testing) {
16
17 var fills = 'backwards|forwards|both|none'.split('|');
18 var directions = 'reverse|alternate|alternate-reverse'.split('|');
19 var linear = function(x) { return x; };
20
21 function cloneTimingInput(timingInput) {
22 if (typeof timingInput == 'number') {
23 return timingInput;
24 }
25 var clone = {};
26 for (var m in timingInput) {
27 clone[m] = timingInput[m];
28 }
29 return clone;
30 }
31
32 function AnimationEffectTiming() {
33 this._delay = 0;
34 this._endDelay = 0;
35 this._fill = 'none';
36 this._iterationStart = 0;
37 this._iterations = 1;
38 this._duration = 0;
39 this._playbackRate = 1;
40 this._direction = 'normal';
41 this._easing = 'linear';
42 this._easingFunction = linear;
43 }
44
45 function isInvalidTimingDeprecated() {
46 return shared.isDeprecated('Invalid timing inputs', '2016-03-02', 'TypeError exceptions will be thrown instead.', true);
47 }
48
49 AnimationEffectTiming.prototype = {
50 _setMember: function(member, value) {
51 this['_' + member] = value;
52 if (this._effect) {
53 this._effect._timingInput[member] = value;
54 this._effect._timing = shared.normalizeTimingInput(this._effect._timingI nput);
55 this._effect.activeDuration = shared.calculateActiveDuration(this._effec t._timing);
56 if (this._effect._animation) {
57 this._effect._animation._rebuildUnderlyingAnimation();
58 }
59 }
60 },
61 get playbackRate() {
62 return this._playbackRate;
63 },
64 set delay(value) {
65 this._setMember('delay', value);
66 },
67 get delay() {
68 return this._delay;
69 },
70 set endDelay(value) {
71 this._setMember('endDelay', value);
72 },
73 get endDelay() {
74 return this._endDelay;
75 },
76 set fill(value) {
77 this._setMember('fill', value);
78 },
79 get fill() {
80 return this._fill;
81 },
82 set iterationStart(value) {
83 if ((isNaN(value) || value < 0) && isInvalidTimingDeprecated()) {
84 throw new TypeError('iterationStart must be a non-negative number, recei ved: ' + timing.iterationStart);
85 }
86 this._setMember('iterationStart', value);
87 },
88 get iterationStart() {
89 return this._iterationStart;
90 },
91 set duration(value) {
92 if (value != 'auto' && (isNaN(value) || value < 0) && isInvalidTimingDepre cated()) {
93 throw new TypeError('duration must be non-negative or auto, received: ' + value);
94 }
95 this._setMember('duration', value);
96 },
97 get duration() {
98 return this._duration;
99 },
100 set direction(value) {
101 this._setMember('direction', value);
102 },
103 get direction() {
104 return this._direction;
105 },
106 set easing(value) {
107 this._easingFunction = parseEasingFunction(normalizeEasing(value));
108 this._setMember('easing', value);
109 },
110 get easing() {
111 return this._easing;
112 },
113 set iterations(value) {
114 if ((isNaN(value) || value < 0) && isInvalidTimingDeprecated()) {
115 throw new TypeError('iterations must be non-negative, received: ' + valu e);
116 }
117 this._setMember('iterations', value);
118 },
119 get iterations() {
120 return this._iterations;
121 }
122 };
123
124 function makeTiming(timingInput, forGroup, effect) {
125 var timing = new AnimationEffectTiming();
126 if (forGroup) {
127 timing.fill = 'both';
128 timing.duration = 'auto';
129 }
130 if (typeof timingInput == 'number' && !isNaN(timingInput)) {
131 timing.duration = timingInput;
132 } else if (timingInput !== undefined) {
133 Object.getOwnPropertyNames(timingInput).forEach(function(property) {
134 if (timingInput[property] != 'auto') {
135 if (typeof timing[property] == 'number' || property == 'duration') {
136 if (typeof timingInput[property] != 'number' || isNaN(timingInput[pr operty])) {
137 return;
138 }
139 }
140 if ((property == 'fill') && (fills.indexOf(timingInput[property]) == - 1)) {
141 return;
142 }
143 if ((property == 'direction') && (directions.indexOf(timingInput[prope rty]) == -1)) {
144 return;
145 }
146 if (property == 'playbackRate' && timingInput[property] !== 1 && share d.isDeprecated('AnimationEffectTiming.playbackRate', '2014-11-28', 'Use Animatio n.playbackRate instead.')) {
147 return;
148 }
149 timing[property] = timingInput[property];
150 }
151 });
152 }
153 return timing;
154 }
155
156 function numericTimingToObject(timingInput) {
157 if (typeof timingInput == 'number') {
158 if (isNaN(timingInput)) {
159 timingInput = { duration: 0 };
160 } else {
161 timingInput = { duration: timingInput };
162 }
163 }
164 return timingInput;
165 }
166
167 function normalizeTimingInput(timingInput, forGroup) {
168 timingInput = shared.numericTimingToObject(timingInput);
169 return makeTiming(timingInput, forGroup);
170 }
171
172 function cubic(a, b, c, d) {
173 if (a < 0 || a > 1 || c < 0 || c > 1) {
174 return linear;
175 }
176 return function(x) {
177 if (x <= 0) {
178 var start_gradient = 0;
179 if (a > 0)
180 start_gradient = b / a;
181 else if (!b && c > 0)
182 start_gradient = d / c;
183 return start_gradient * x;
184 }
185 if (x >= 1) {
186 var end_gradient = 0;
187 if (c < 1)
188 end_gradient = (d - 1) / (c - 1);
189 else if (c == 1 && a < 1)
190 end_gradient = (b - 1) / (a - 1);
191 return 1 + end_gradient * (x - 1);
192 }
193
194 var start = 0, end = 1;
195 while (start < end) {
196 var mid = (start + end) / 2;
197 function f(a, b, m) { return 3 * a * (1 - m) * (1 - m) * m + 3 * b * (1 - m) * m * m + m * m * m};
198 var xEst = f(a, c, mid);
199 if (Math.abs(x - xEst) < 0.00001) {
200 return f(b, d, mid);
201 }
202 if (xEst < x) {
203 start = mid;
204 } else {
205 end = mid;
206 }
207 }
208 return f(b, d, mid);
209 }
210 }
211
212 var Start = 1;
213 var Middle = 0.5;
214 var End = 0;
215
216 function step(count, pos) {
217 return function(x) {
218 if (x >= 1) {
219 return 1;
220 }
221 var stepSize = 1 / count;
222 x += pos * stepSize;
223 return x - x % stepSize;
224 }
225 }
226
227 var presets = {
228 'ease': cubic(0.25, 0.1, 0.25, 1),
229 'ease-in': cubic(0.42, 0, 1, 1),
230 'ease-out': cubic(0, 0, 0.58, 1),
231 'ease-in-out': cubic(0.42, 0, 0.58, 1),
232 'step-start': step(1, Start),
233 'step-middle': step(1, Middle),
234 'step-end': step(1, End)
235 };
236
237 var styleForCleaning = null;
238 var numberString = '\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*';
239 var cubicBezierRe = new RegExp('cubic-bezier\\(' + numberString + ',' + number String + ',' + numberString + ',' + numberString + '\\)');
240 var stepRe = /steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/;
241
242 function normalizeEasing(easing) {
243 if (!styleForCleaning) {
244 styleForCleaning = document.createElement('div').style;
245 }
246 styleForCleaning.animationTimingFunction = '';
247 styleForCleaning.animationTimingFunction = easing;
248 var normalizedEasing = styleForCleaning.animationTimingFunction;
249 if (normalizedEasing == '' && isInvalidTimingDeprecated()) {
250 throw new TypeError(easing + ' is not a valid value for easing');
251 }
252 return normalizedEasing;
253 }
254
255 function parseEasingFunction(normalizedEasing) {
256 if (normalizedEasing == 'linear') {
257 return linear;
258 }
259 var cubicData = cubicBezierRe.exec(normalizedEasing);
260 if (cubicData) {
261 return cubic.apply(this, cubicData.slice(1).map(Number));
262 }
263 var stepData = stepRe.exec(normalizedEasing);
264 if (stepData) {
265 return step(Number(stepData[1]), {'start': Start, 'middle': Middle, 'end': End}[stepData[2]]);
266 }
267 var preset = presets[normalizedEasing];
268 if (preset) {
269 return preset;
270 }
271 // At this point none of our parse attempts succeeded; the easing is invalid .
272 // Fall back to linear in the interest of not crashing the page.
273 return linear;
274 }
275
276 function calculateActiveDuration(timing) {
277 return Math.abs(repeatedDuration(timing) / timing.playbackRate);
278 }
279
280 function repeatedDuration(timing) {
281 // https://w3c.github.io/web-animations/#calculating-the-active-duration
282 if (timing.duration === 0 || timing.iterations === 0) {
283 return 0;
284 }
285 return timing.duration * timing.iterations;
286 }
287
288 var PhaseNone = 0;
289 var PhaseBefore = 1;
290 var PhaseAfter = 2;
291 var PhaseActive = 3;
292
293 function calculatePhase(activeDuration, localTime, timing) {
294 // https://w3c.github.io/web-animations/#animation-effect-phases-and-states
295 if (localTime == null) {
296 return PhaseNone;
297 }
298
299 var endTime = timing.delay + activeDuration + timing.endDelay;
300 if (localTime < Math.min(timing.delay, endTime)) {
301 return PhaseBefore;
302 }
303 if (localTime >= Math.min(timing.delay + activeDuration, endTime)) {
304 return PhaseAfter;
305 }
306
307 return PhaseActive;
308 }
309
310 function calculateActiveTime(activeDuration, fillMode, localTime, phase, delay ) {
311 // https://w3c.github.io/web-animations/#calculating-the-active-time
312 switch (phase) {
313 case PhaseBefore:
314 if (fillMode == 'backwards' || fillMode == 'both')
315 return 0;
316 return null;
317 case PhaseActive:
318 return localTime - delay;
319 case PhaseAfter:
320 if (fillMode == 'forwards' || fillMode == 'both')
321 return activeDuration;
322 return null;
323 case PhaseNone:
324 return null;
325 }
326 }
327
328 function calculateOverallProgress(iterationDuration, phase, iterations, active Time, iterationStart) {
329 // https://w3c.github.io/web-animations/#calculating-the-overall-progress
330 var overallProgress = iterationStart;
331 if (iterationDuration === 0) {
332 if (phase !== PhaseBefore) {
333 overallProgress += iterations;
334 }
335 } else {
336 overallProgress += activeTime / iterationDuration;
337 }
338 return overallProgress;
339 }
340
341 function calculateSimpleIterationProgress(overallProgress, iterationStart, pha se, iterations, activeTime, iterationDuration) {
342 // https://w3c.github.io/web-animations/#calculating-the-simple-iteration-pr ogress
343
344 var simpleIterationProgress = (overallProgress === Infinity) ? iterationStar t % 1 : overallProgress % 1;
345 if (simpleIterationProgress === 0 && phase === PhaseAfter && iterations !== 0 &&
346 (activeTime !== 0 || iterationDuration === 0)) {
347 simpleIterationProgress = 1;
348 }
349 return simpleIterationProgress;
350 }
351
352 function calculateCurrentIteration(phase, iterations, simpleIterationProgress, overallProgress) {
353 // https://w3c.github.io/web-animations/#calculating-the-current-iteration
354 if (phase === PhaseAfter && iterations === Infinity) {
355 return Infinity;
356 }
357 if (simpleIterationProgress === 1) {
358 return Math.floor(overallProgress) - 1;
359 }
360 return Math.floor(overallProgress);
361 }
362
363 function calculateDirectedProgress(playbackDirection, currentIteration, simple IterationProgress) {
364 // https://w3c.github.io/web-animations/#calculating-the-directed-progress
365 var currentDirection = playbackDirection;
366 if (playbackDirection !== 'normal' && playbackDirection !== 'reverse') {
367 var d = currentIteration;
368 if (playbackDirection === 'alternate-reverse') {
369 d += 1;
370 }
371 currentDirection = 'normal';
372 if (d !== Infinity && d % 2 !== 0) {
373 currentDirection = 'reverse';
374 }
375 }
376 if (currentDirection === 'normal') {
377 return simpleIterationProgress;
378 }
379 return 1 - simpleIterationProgress;
380 }
381
382 function calculateIterationProgress(activeDuration, localTime, timing) {
383 var phase = calculatePhase(activeDuration, localTime, timing);
384 var activeTime = calculateActiveTime(activeDuration, timing.fill, localTime, phase, timing.delay);
385 if (activeTime === null)
386 return null;
387
388 var overallProgress = calculateOverallProgress(timing.duration, phase, timin g.iterations, activeTime, timing.iterationStart);
389 var simpleIterationProgress = calculateSimpleIterationProgress(overallProgre ss, timing.iterationStart, phase, timing.iterations, activeTime, timing.duration );
390 var currentIteration = calculateCurrentIteration(phase, timing.iterations, s impleIterationProgress, overallProgress);
391 var directedProgress = calculateDirectedProgress(timing.direction, currentIt eration, simpleIterationProgress);
392
393 // https://w3c.github.io/web-animations/#calculating-the-transformed-progres s
394 // https://w3c.github.io/web-animations/#calculating-the-iteration-progress
395 return timing._easingFunction(directedProgress);
396 }
397
398 shared.cloneTimingInput = cloneTimingInput;
399 shared.makeTiming = makeTiming;
400 shared.numericTimingToObject = numericTimingToObject;
401 shared.normalizeTimingInput = normalizeTimingInput;
402 shared.calculateActiveDuration = calculateActiveDuration;
403 shared.calculateIterationProgress = calculateIterationProgress;
404 shared.calculatePhase = calculatePhase;
405 shared.normalizeEasing = normalizeEasing;
406 shared.parseEasingFunction = parseEasingFunction;
407
408 if (WEB_ANIMATIONS_TESTING) {
409 testing.normalizeTimingInput = normalizeTimingInput;
410 testing.normalizeEasing = normalizeEasing;
411 testing.parseEasingFunction = parseEasingFunction;
412 testing.calculateActiveDuration = calculateActiveDuration;
413 testing.calculatePhase = calculatePhase;
414 testing.PhaseNone = PhaseNone;
415 testing.PhaseBefore = PhaseBefore;
416 testing.PhaseActive = PhaseActive;
417 testing.PhaseAfter = PhaseAfter;
418 }
419
420 })(webAnimationsShared, webAnimationsTesting);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698