| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Implementations can be used to simulate the deceleration of an element within | 6 * Implementations can be used to simulate the deceleration of an element within |
| 7 * a certain region. To use this behavior you need to provide an initial | 7 * a certain region. To use this behavior you need to provide an initial |
| 8 * velocity that is meant to represent the gesture that is initiating this | 8 * velocity that is meant to represent the gesture that is initiating this |
| 9 * deceleration. You also provide the bounds of the region that the element | 9 * deceleration. You also provide the bounds of the region that the element |
| 10 * exists in, and the current offset of the element within that region. The | 10 * exists in, and the current offset of the element within that region. The |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 | 271 |
| 272 /** | 272 /** |
| 273 * Helper method to calculate initial velocity. | 273 * Helper method to calculate initial velocity. |
| 274 * The [velocity] passed here should be in terms of number of | 274 * The [velocity] passed here should be in terms of number of |
| 275 * pixels / millisecond. Returns the adjusted x and y velocities. | 275 * pixels / millisecond. Returns the adjusted x and y velocities. |
| 276 */ | 276 */ |
| 277 void _adjustInitialVelocityAndBouncingState(num v) { | 277 void _adjustInitialVelocityAndBouncingState(num v) { |
| 278 velocity = v * _MS_PER_FRAME * _INITIAL_VELOCITY_BOOST_FACTOR; | 278 velocity = v * _MS_PER_FRAME * _INITIAL_VELOCITY_BOOST_FACTOR; |
| 279 | 279 |
| 280 if (velocity.abs() < _MIN_VELOCITY) { | 280 if (velocity.abs() < _MIN_VELOCITY) { |
| 281 if (_minCoord !== null && _currentOffset < _minCoord) { | 281 if (_minCoord != null && _currentOffset < _minCoord) { |
| 282 velocity = (_minCoord - _currentOffset) * _POST_BOUNCE_COEFFICIENT; | 282 velocity = (_minCoord - _currentOffset) * _POST_BOUNCE_COEFFICIENT; |
| 283 velocity = Math.max(velocity, _MIN_STEP_VELOCITY); | 283 velocity = Math.max(velocity, _MIN_STEP_VELOCITY); |
| 284 _bouncingState = BouncingState.BOUNCING_BACK; | 284 _bouncingState = BouncingState.BOUNCING_BACK; |
| 285 } else if (_maxCoord !== null && _currentOffset > _maxCoord) { | 285 } else if (_maxCoord != null && _currentOffset > _maxCoord) { |
| 286 velocity = (_currentOffset - _maxCoord) * _POST_BOUNCE_COEFFICIENT; | 286 velocity = (_currentOffset - _maxCoord) * _POST_BOUNCE_COEFFICIENT; |
| 287 velocity = -Math.max(velocity, _MIN_STEP_VELOCITY); | 287 velocity = -Math.max(velocity, _MIN_STEP_VELOCITY); |
| 288 _bouncingState = BouncingState.BOUNCING_BACK; | 288 _bouncingState = BouncingState.BOUNCING_BACK; |
| 289 } | 289 } |
| 290 } | 290 } |
| 291 } | 291 } |
| 292 | 292 |
| 293 /** | 293 /** |
| 294 * Apply deceleration. | 294 * Apply deceleration. |
| 295 */ | 295 */ |
| 296 void _adjustVelocity() { | 296 void _adjustVelocity() { |
| 297 num speed = velocity.abs(); | 297 num speed = velocity.abs(); |
| 298 velocity *= _DECELERATION_FACTOR; | 298 velocity *= _DECELERATION_FACTOR; |
| 299 if (customDecelerationFactor != null) { | 299 if (customDecelerationFactor != null) { |
| 300 velocity *= customDecelerationFactor; | 300 velocity *= customDecelerationFactor; |
| 301 } | 301 } |
| 302 // This isn't really how static friction works but it is a plausible | 302 // This isn't really how static friction works but it is a plausible |
| 303 // approximation. | 303 // approximation. |
| 304 if (speed < _MAX_VELOCITY_STATIC_FRICTION) { | 304 if (speed < _MAX_VELOCITY_STATIC_FRICTION) { |
| 305 velocity *= _DECELERATION_FACTOR_STATIC_FRICTION; | 305 velocity *= _DECELERATION_FACTOR_STATIC_FRICTION; |
| 306 } | 306 } |
| 307 | 307 |
| 308 num stretchDistance; | 308 num stretchDistance; |
| 309 if (_minCoord !== null && _currentOffset < _minCoord) { | 309 if (_minCoord != null && _currentOffset < _minCoord) { |
| 310 stretchDistance = _minCoord - _currentOffset; | 310 stretchDistance = _minCoord - _currentOffset; |
| 311 } else { | 311 } else { |
| 312 if (_maxCoord !== null && _currentOffset > _maxCoord) { | 312 if (_maxCoord != null && _currentOffset > _maxCoord) { |
| 313 stretchDistance = _maxCoord - _currentOffset; | 313 stretchDistance = _maxCoord - _currentOffset; |
| 314 } | 314 } |
| 315 } | 315 } |
| 316 if (stretchDistance != null) { | 316 if (stretchDistance != null) { |
| 317 if (stretchDistance * velocity < 0) { | 317 if (stretchDistance * velocity < 0) { |
| 318 _bouncingState = _bouncingState == BouncingState.BOUNCING_BACK ? | 318 _bouncingState = _bouncingState == BouncingState.BOUNCING_BACK ? |
| 319 BouncingState.NOT_BOUNCING : BouncingState.BOUNCING_AWAY; | 319 BouncingState.NOT_BOUNCING : BouncingState.BOUNCING_AWAY; |
| 320 velocity += stretchDistance * _PRE_BOUNCE_COEFFICIENT; | 320 velocity += stretchDistance * _PRE_BOUNCE_COEFFICIENT; |
| 321 } else { | 321 } else { |
| 322 _bouncingState = BouncingState.BOUNCING_BACK; | 322 _bouncingState = BouncingState.BOUNCING_BACK; |
| 323 velocity = stretchDistance > 0 ? | 323 velocity = stretchDistance > 0 ? |
| 324 Math.max(stretchDistance * _POST_BOUNCE_COEFFICIENT, | 324 Math.max(stretchDistance * _POST_BOUNCE_COEFFICIENT, |
| 325 _MIN_STEP_VELOCITY) : | 325 _MIN_STEP_VELOCITY) : |
| 326 Math.min(stretchDistance * _POST_BOUNCE_COEFFICIENT, | 326 Math.min(stretchDistance * _POST_BOUNCE_COEFFICIENT, |
| 327 -_MIN_STEP_VELOCITY); | 327 -_MIN_STEP_VELOCITY); |
| 328 } | 328 } |
| 329 } else { | 329 } else { |
| 330 _bouncingState = BouncingState.NOT_BOUNCING; | 330 _bouncingState = BouncingState.NOT_BOUNCING; |
| 331 } | 331 } |
| 332 } | 332 } |
| 333 | 333 |
| 334 void step() { | 334 void step() { |
| 335 // It is common for scrolling to be disabled so in these cases we want to | 335 // It is common for scrolling to be disabled so in these cases we want to |
| 336 // avoid needless calculations. | 336 // avoid needless calculations. |
| 337 if (velocity !== null) { | 337 if (velocity != null) { |
| 338 _currentOffset += velocity; | 338 _currentOffset += velocity; |
| 339 _adjustVelocity(); | 339 _adjustVelocity(); |
| 340 } | 340 } |
| 341 } | 341 } |
| 342 | 342 |
| 343 void stepAll() { | 343 void stepAll() { |
| 344 while(!isDone()) { | 344 while(!isDone()) { |
| 345 step(); | 345 step(); |
| 346 } | 346 } |
| 347 } | 347 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 Coordinate calculateVelocity(Coordinate start_, Coordinate target, | 429 Coordinate calculateVelocity(Coordinate start_, Coordinate target, |
| 430 [num decelerationFactor = null]) { | 430 [num decelerationFactor = null]) { |
| 431 return new Coordinate( | 431 return new Coordinate( |
| 432 physicsX.solve(start_.x, target.x, decelerationFactor), | 432 physicsX.solve(start_.x, target.x, decelerationFactor), |
| 433 physicsY.solve(start_.y, target.y, decelerationFactor)); | 433 physicsY.solve(start_.y, target.y, decelerationFactor)); |
| 434 } | 434 } |
| 435 | 435 |
| 436 bool start(Coordinate velocity, Coordinate minCoord, Coordinate maxCoord, | 436 bool start(Coordinate velocity, Coordinate minCoord, Coordinate maxCoord, |
| 437 Coordinate initialOffset, [num decelerationFactor = null]) { | 437 Coordinate initialOffset, [num decelerationFactor = null]) { |
| 438 _customDecelerationFactor = _defaultDecelerationFactor; | 438 _customDecelerationFactor = _defaultDecelerationFactor; |
| 439 if (decelerationFactor !== null) { | 439 if (decelerationFactor != null) { |
| 440 _customDecelerationFactor = decelerationFactor; | 440 _customDecelerationFactor = decelerationFactor; |
| 441 } | 441 } |
| 442 | 442 |
| 443 if (_stepTimeout !== null) { | 443 if (_stepTimeout != null) { |
| 444 Env.cancelRequestAnimationFrame(_stepTimeout); | 444 Env.cancelRequestAnimationFrame(_stepTimeout); |
| 445 _stepTimeout = null; | 445 _stepTimeout = null; |
| 446 } | 446 } |
| 447 | 447 |
| 448 assert (_stepTimeout === null); | 448 assert (_stepTimeout == null); |
| 449 assert(minCoord.x <= maxCoord.x); | 449 assert(minCoord.x <= maxCoord.x); |
| 450 assert(minCoord.y <= maxCoord.y); | 450 assert(minCoord.y <= maxCoord.y); |
| 451 _previousOffset = initialOffset.clone(); | 451 _previousOffset = initialOffset.clone(); |
| 452 physicsX.configure(minCoord.x, maxCoord.x, initialOffset.x, | 452 physicsX.configure(minCoord.x, maxCoord.x, initialOffset.x, |
| 453 _customDecelerationFactor, velocity.x); | 453 _customDecelerationFactor, velocity.x); |
| 454 physicsY.configure(minCoord.y, maxCoord.y, initialOffset.y, | 454 physicsY.configure(minCoord.y, maxCoord.y, initialOffset.y, |
| 455 _customDecelerationFactor, velocity.y); | 455 _customDecelerationFactor, velocity.y); |
| 456 if (!physicsX.isDone() || !physicsY.isDone()) { | 456 if (!physicsX.isDone() || !physicsY.isDone()) { |
| 457 _calculateMoves(); | 457 _calculateMoves(); |
| 458 if (!_moves.isEmpty) { | 458 if (!_moves.isEmpty) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 483 | 483 |
| 484 /** | 484 /** |
| 485 * Calculate the next offset of the element and animate it to that position. | 485 * Calculate the next offset of the element and animate it to that position. |
| 486 */ | 486 */ |
| 487 void _step(num timestamp) { | 487 void _step(num timestamp) { |
| 488 _stepTimeout = null; | 488 _stepTimeout = null; |
| 489 | 489 |
| 490 // Prune moves that are more than 1 frame behind when we have more | 490 // Prune moves that are more than 1 frame behind when we have more |
| 491 // available moves. | 491 // available moves. |
| 492 num lastEpoch = timestamp - SingleDimensionPhysics._MS_PER_FRAME; | 492 num lastEpoch = timestamp - SingleDimensionPhysics._MS_PER_FRAME; |
| 493 while (!_moves.isEmpty && _moves.first !== _moves.last | 493 while (!_moves.isEmpty && !identical(_moves.first, _moves.last) |
| 494 && _moves.first.time < lastEpoch) { | 494 && _moves.first.time < lastEpoch) { |
| 495 _moves.removeFirst(); | 495 _moves.removeFirst(); |
| 496 } | 496 } |
| 497 | 497 |
| 498 if (!_moves.isEmpty) { | 498 if (!_moves.isEmpty) { |
| 499 final move = _moves.removeFirst(); | 499 final move = _moves.removeFirst(); |
| 500 _delegate.onDecelerate(move.x, move.y); | 500 _delegate.onDecelerate(move.x, move.y); |
| 501 if (!_moves.isEmpty) { | 501 if (!_moves.isEmpty) { |
| 502 num nextTime = _moves.first.time; | 502 num nextTime = _moves.first.time; |
| 503 assert(_stepTimeout === null); | 503 assert(_stepTimeout == null); |
| 504 _stepTimeout = Env.requestAnimationFrame(_step, null, nextTime); | 504 _stepTimeout = Env.requestAnimationFrame(_step, null, nextTime); |
| 505 } else { | 505 } else { |
| 506 stop(); | 506 stop(); |
| 507 } | 507 } |
| 508 } | 508 } |
| 509 } | 509 } |
| 510 | 510 |
| 511 void abort() { | 511 void abort() { |
| 512 _decelerating = false; | 512 _decelerating = false; |
| 513 _moves.clear(); | 513 _moves.clear(); |
| 514 if (_stepTimeout !== null) { | 514 if (_stepTimeout != null) { |
| 515 Env.cancelRequestAnimationFrame(_stepTimeout); | 515 Env.cancelRequestAnimationFrame(_stepTimeout); |
| 516 _stepTimeout = null; | 516 _stepTimeout = null; |
| 517 } | 517 } |
| 518 } | 518 } |
| 519 | 519 |
| 520 Coordinate stop() { | 520 Coordinate stop() { |
| 521 final wasDecelerating = _decelerating; | 521 final wasDecelerating = _decelerating; |
| 522 _decelerating = false; | 522 _decelerating = false; |
| 523 Coordinate velocity; | 523 Coordinate velocity; |
| 524 if (!_moves.isEmpty) { | 524 if (!_moves.isEmpty) { |
| 525 final move = _moves.first; | 525 final move = _moves.first; |
| 526 // This is a workaround for the ugly hacks that get applied when a user | 526 // This is a workaround for the ugly hacks that get applied when a user |
| 527 // passed a velocity in to this Momentum implementation. | 527 // passed a velocity in to this Momentum implementation. |
| 528 num velocityScale = SingleDimensionPhysics._MS_PER_FRAME * | 528 num velocityScale = SingleDimensionPhysics._MS_PER_FRAME * |
| 529 SingleDimensionPhysics._INITIAL_VELOCITY_BOOST_FACTOR; | 529 SingleDimensionPhysics._INITIAL_VELOCITY_BOOST_FACTOR; |
| 530 velocity = new Coordinate( | 530 velocity = new Coordinate( |
| 531 move.vx / velocityScale, move.vy / velocityScale); | 531 move.vx / velocityScale, move.vy / velocityScale); |
| 532 } else { | 532 } else { |
| 533 velocity = new Coordinate(0, 0); | 533 velocity = new Coordinate(0, 0); |
| 534 } | 534 } |
| 535 _moves.clear(); | 535 _moves.clear(); |
| 536 if (_stepTimeout !== null) { | 536 if (_stepTimeout != null) { |
| 537 Env.cancelRequestAnimationFrame(_stepTimeout); | 537 Env.cancelRequestAnimationFrame(_stepTimeout); |
| 538 _stepTimeout = null; | 538 _stepTimeout = null; |
| 539 } | 539 } |
| 540 if (wasDecelerating) { | 540 if (wasDecelerating) { |
| 541 _delegate.onDecelerationEnd(); | 541 _delegate.onDecelerationEnd(); |
| 542 } | 542 } |
| 543 return velocity; | 543 return velocity; |
| 544 } | 544 } |
| 545 | 545 |
| 546 Coordinate get destination { | 546 Coordinate get destination { |
| 547 if (!_moves.isEmpty) { | 547 if (!_moves.isEmpty) { |
| 548 final lastMove = _moves.last; | 548 final lastMove = _moves.last; |
| 549 return new Coordinate(lastMove.x, lastMove.y); | 549 return new Coordinate(lastMove.x, lastMove.y); |
| 550 } else { | 550 } else { |
| 551 return null; | 551 return null; |
| 552 } | 552 } |
| 553 } | 553 } |
| 554 } | 554 } |
| OLD | NEW |