106 lines
3.2 KiB
Dart
106 lines
3.2 KiB
Dart
// 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 'package:newton/newton.dart';
|
|
import 'package:sky/src/animation/animated_value.dart';
|
|
import 'package:sky/src/animation/curves.dart';
|
|
import 'package:sky/src/animation/ticker.dart';
|
|
|
|
/// A simulation that varies from [begin] to [end] over [duration] using [curve]
|
|
///
|
|
/// This class is an adaptor between the Simulation interface and the
|
|
/// AnimatedValue interface.
|
|
class _TweenSimulation extends Simulation {
|
|
_TweenSimulation(double begin, double end, Duration duration, Curve curve)
|
|
: _durationInSeconds = duration.inMicroseconds.toDouble() / Duration.MICROSECONDS_PER_SECOND,
|
|
_tween = new AnimatedValue<double>(begin, end: end, curve: curve) {
|
|
assert(_durationInSeconds > 0.0);
|
|
assert(begin != null);
|
|
assert(end != null);
|
|
}
|
|
|
|
final double _durationInSeconds;
|
|
final AnimatedValue<double> _tween;
|
|
|
|
double x(double timeInSeconds) {
|
|
assert(timeInSeconds >= 0.0);
|
|
final double t = (timeInSeconds / _durationInSeconds).clamp(0.0, 1.0);
|
|
_tween.setProgress(t, Direction.forward);
|
|
return _tween.value;
|
|
}
|
|
|
|
double dx(double timeInSeconds) => 1.0;
|
|
|
|
bool isDone(double timeInSeconds) => timeInSeconds > _durationInSeconds;
|
|
}
|
|
|
|
typedef TimelineCallback(double value);
|
|
|
|
/// Steps a simulation one per frame
|
|
class SimulationStepper {
|
|
SimulationStepper(TimelineCallback onTick) : _onTick = onTick {
|
|
_ticker = new Ticker(_tick);
|
|
}
|
|
|
|
final TimelineCallback _onTick;
|
|
Ticker _ticker;
|
|
Simulation _simulation;
|
|
|
|
/// The current value of the timeline
|
|
double get value => _value;
|
|
double _value = 0.0;
|
|
void set value(double newValue) {
|
|
assert(newValue != null);
|
|
assert(!isAnimating);
|
|
_value = newValue;
|
|
_onTick(_value);
|
|
}
|
|
|
|
/// Whether the timeline is currently animating
|
|
bool get isAnimating => _ticker.isTicking;
|
|
|
|
/// Animate value of the timeline to the given target over the given duration
|
|
///
|
|
/// Returns a future that resolves when the timeline stops animating,
|
|
/// typically when the timeline arives at the target value.
|
|
Future animateTo(double target, { Duration duration, Curve curve: linear }) {
|
|
assert(duration > Duration.ZERO);
|
|
assert(!isAnimating);
|
|
return _start(new _TweenSimulation(value, target, duration, curve));
|
|
}
|
|
|
|
/// Gives the given simulation control over the timeline
|
|
Future animateWith(Simulation simulation) {
|
|
stop();
|
|
return _start(simulation);
|
|
}
|
|
|
|
/// Start ticking the given simulation once per frame
|
|
///
|
|
/// Returns a future that resolves when the simulation stops ticking.
|
|
Future _start(Simulation simulation) {
|
|
assert(simulation != null);
|
|
assert(!isAnimating);
|
|
_simulation = simulation;
|
|
_value = simulation.x(0.0);
|
|
return _ticker.start();
|
|
}
|
|
|
|
/// Stop animating the timeline
|
|
void stop() {
|
|
_simulation = null;
|
|
_ticker.stop();
|
|
}
|
|
|
|
void _tick(Duration elapsed) {
|
|
double elapsedInSeconds = elapsed.inMicroseconds.toDouble() / Duration.MICROSECONDS_PER_SECOND;
|
|
_value = _simulation.x(elapsedInSeconds);
|
|
if (_simulation.isDone(elapsedInSeconds))
|
|
stop();
|
|
_onTick(_value);
|
|
}
|
|
}
|