blob: 9673c1ef26511420b2207087149624801396f9a1 [file] [log] [blame]
// 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 '../scheduler.dart' as scheduler;
import 'curves.dart';
import 'dart:async';
import 'dart:math' as math;
import 'mechanics.dart';
abstract class Generator {
Stream<double> get onTick;
void cancel();
}
class FrameGenerator extends Generator {
Function onDone;
StreamController _controller;
Stream<double> get onTick => _controller.stream;
int _animationId = 0;
bool _cancelled = false;
FrameGenerator({this.onDone}) {
_controller = new StreamController(
sync: true,
onListen: _scheduleTick,
onCancel: cancel);
}
void cancel() {
if (_cancelled) {
return;
}
if (_animationId != 0) {
scheduler.cancelAnimationFrame(_animationId);
}
_animationId = 0;
_cancelled = true;
if (onDone != null) {
onDone();
}
}
void _scheduleTick() {
assert(_animationId == 0);
_animationId = scheduler.requestAnimationFrame(_tick);
}
void _tick(double timeStamp) {
_animationId = 0;
_controller.add(timeStamp);
if (!_cancelled) {
_scheduleTick();
}
}
}
class AnimationGenerator extends Generator {
Stream<double> get onTick => _stream;
final double initialDelay;
final double duration;
final double begin;
final double end;
final Curve curve;
FrameGenerator _generator;
Stream<double> _stream;
bool _done = false;
double _lastTime;
AnimationGenerator({
this.initialDelay: 0.0,
this.duration,
this.begin: 0.0,
this.end: 1.0,
this.curve: linear,
Function onDone
}) {
assert(curve != null);
assert(duration != null && duration > 0.0);
_generator = new FrameGenerator(onDone: onDone);
double startTime = 0.0;
_stream = _generator.onTick.map((timeStamp) {
if (startTime == 0.0)
startTime = timeStamp;
double t = (timeStamp - (startTime + initialDelay)) / duration;
_lastTime = math.max(0.0, math.min(t, 1.0));
return _lastTime;
})
.takeWhile(_checkForCompletion)
.where((t) => t >= 0.0)
.map(_transform);
}
double get remainingTime {
if (_lastTime == null)
return duration;
return duration - _lastTime;
}
void cancel() {
_generator.cancel();
}
double _transform(double t) {
if (_done)
return end;
return begin + (end - begin) * curve.transform(t);
}
// This is required because Dart Streams don't have takeUntil (inclusive).
bool _checkForCompletion(double t) {
if (_done)
return false;
_done = t >= 1;
return true;
}
}
class Simulation extends Generator {
Stream<double> get onTick => _stream;
final System system;
FrameGenerator _generator;
Stream<double> _stream;
double _previousTime = 0.0;
Simulation(this.system, {Function terminationCondition, Function onDone}) {
_generator = new FrameGenerator(onDone: onDone);
_stream = _generator.onTick.map(_update);
if (terminationCondition != null) {
bool done = false;
_stream = _stream.takeWhile((_) {
if (done)
return false;
done = terminationCondition();
return true;
});
}
}
void cancel() {
_generator.cancel();
}
double _update(double timeStamp) {
double previousTime = _previousTime;
_previousTime = timeStamp;
if (previousTime == 0.0)
return timeStamp;
double deltaT = timeStamp - previousTime;
system.update(deltaT);
return timeStamp;
}
}