Chromium Code Reviews| Index: sky/sdk/lib/animation/timeline.dart |
| diff --git a/sky/sdk/lib/animation/timeline.dart b/sky/sdk/lib/animation/timeline.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f91ebdea8aa86686a4f33e1a9ebbb2a8ea175a26 |
| --- /dev/null |
| +++ b/sky/sdk/lib/animation/timeline.dart |
| @@ -0,0 +1,136 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +import 'dart:async'; |
| + |
| +import '../base/scheduler.dart' as scheduler; |
| +import 'curves.dart'; |
| + |
| +class Ticker { |
| + Ticker(Function onTick) : _onTick = onTick; |
| + |
| + final Function _onTick; |
| + |
| + Completer _completer; |
| + int _animationId; |
| + |
| + Future start() { |
| + assert(!isTicking); |
| + _completer = new Completer(); |
| + _scheduleTick(); |
| + return _completer.future; |
| + } |
| + |
| + void stop() { |
| + if (!isTicking) |
| + return; |
| + |
| + if (_animationId != null) { |
| + scheduler.cancelAnimationFrame(_animationId); |
| + _animationId = null; |
| + } |
| + |
| + Completer localCompleter = _completer; |
| + _completer = null; |
| + |
| + // We take the _completer into a local variable so that !isTicking when we |
| + // actually complete the future. |
| + assert(!isTicking); |
| + localCompleter.complete(); |
| + } |
| + |
| + bool get isTicking => _completer != null; |
| + |
| + void _tick(double timeStamp) { |
| + assert(isTicking); |
| + assert(_animationId != null); |
| + _animationId = null; |
| + |
| + _onTick(timeStamp); |
| + |
| + if (isTicking) |
| + _scheduleTick(); |
| + } |
| + |
| + void _scheduleTick() { |
| + assert(isTicking); |
| + assert(_animationId == null); |
| + _animationId = scheduler.requestAnimationFrame(_tick); |
| + } |
| +} |
| + |
| +class Timeline { |
| + |
| + Timeline(Function onTick) : _onTick = onTick { |
| + _ticker = new Ticker(_tick); |
| + } |
| + |
| + final Function _onTick; |
| + Ticker _ticker; |
| + |
| + double _value; |
| + double get value => _value; |
| + void set value(double newValue) { |
| + assert(newValue != null && newValue >= 0.0 && newValue <= 1.0); |
| + assert(!_ticker.isTicking); |
| + _value = newValue; |
| + _onTick(_value); |
| + } |
| + |
| + double _duration; |
| + double _begin; |
| + double _end; |
| + |
| + double _startTime; |
| + |
| + Future start({ |
| + double duration, |
| + double begin: 0.0, |
|
Matt Perry
2015/07/09 17:52:57
I don't even think we need a begin/end value. Alwa
abarth-chromium
2015/07/09 17:55:37
AnimationPerformance uses different begin and end
Matt Perry
2015/07/09 18:10:39
Oh right. Makes sense.
|
| + double end: 1.0 |
| + }) { |
| + assert(duration != null && duration > 0.0); |
| + assert(begin != null && begin >= 0.0 && begin <= 1.0); |
| + assert(end != null && end >= 0.0 && end <= 1.0); |
| + assert(begin <= end); |
| + |
| + assert(!_ticker.isTicking); |
| + |
| + _duration = duration; |
| + _begin = begin; |
| + _end = end; |
| + |
| + _startTime = null; |
| + _value = begin; |
| + |
| + return _ticker.start(); |
| + } |
| + |
| + Future animateTo(double target, { double duration }) { |
| + return start(duration: duration, begin: _value, end: target); |
| + } |
| + |
| + void stop() { |
| + _duration = null; |
| + _begin = null; |
| + _end = null; |
| + _startTime = null; |
| + _ticker.stop(); |
| + } |
| + |
| + bool get isAnimating => _ticker.isTicking; |
| + |
| + void _tick(double timeStamp) { |
| + if (_startTime == null) |
| + _startTime = timeStamp; |
| + |
| + final double t = ((timeStamp - _startTime) / _duration).clamp(0.0, 1.0); |
| + final bool isLastTick = t >= 1.0; |
| + |
| + _value = isLastTick ? _end : _begin + (_end - _begin) * t; |
| + _onTick(_value); |
| + |
| + if (isLastTick) |
| + stop(); |
| + } |
| +} |