Skip to content

this commit depends on sprite-timeline's getMethod(ntime), the goal i… #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 95 additions & 10 deletions src/animator.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,29 @@ export default class {
return state;
}

getPlayState(ntime) {
const timeline = this.timeline,
{iterations, duration, endDelay} = this[_timing];
let state = 'running';

if(timeline == null) {
state = 'idle';
} else if(timeline.paused) {
state = 'paused';
} else if(timeline.getCurrentTime(ntime) < 0) { // 开始 pending
state = 'pending';
} else {
const ed = timeline.getCurrentTime(ntime) - iterations * duration;
if(ed > 0 && ed < endDelay) { // 结束 pending
state = 'pending';
} else if(ed >= endDelay) {
state = 'finished';
}
}
return state;
}


get progress() {
if(!this.timeline) return 0;

Expand Down Expand Up @@ -148,6 +171,37 @@ export default class {
return p;
}

getProgress(ntime) {
if(!this.timeline) return 0;

const {duration, iterations} = this[_timing];
const timeline = this.timeline,
playState = this.getPlayState(ntime);

let p;

if(playState === 'idle') {
p = 0;
} else if(playState === 'paused' && timeline.getCurrentTime(ntime) < 0) {
p = 0;
} else if(playState === 'pending') {
if(timeline.getCurrentTime(ntime) < 0) {
p = 0;
} else {
const time = timeline.seekLocalTime(iterations * duration);
p = periodicity(time, duration)[1] / duration;
}
} else if(playState === 'running' || playState === 'paused') {
p = periodicity(timeline.getCurrentTime(ntime), duration)[1] / duration;
}

if(playState === 'finished') {
p = periodicity(iterations, 1)[1];
}

return p;
}

get frame() {
const playState = this.playState,
initState = this[_initState],
Expand All @@ -160,7 +214,35 @@ export default class {
const {currentTime} = this.timeline,
keyframes = this[_keyframes].slice(0);

const {p, inverted} = getProgress(this.timeline, this[_timing], this.progress);
const {p, inverted} = getProgress(currentTime, this[_timing], this.progress);

let frameState = initState;
if(currentTime < 0 && playState === 'pending') {
// 在开始前 delay 阶段
if(fill === 'backwards' || fill === 'both') {
frameState = inverted ? keyframes[keyframes.length - 1] : keyframes[0];
}
} else if((playState !== 'pending' && playState !== 'finished')
|| fill === 'forwards' || fill === 'both') {
// 不在 endDelay 或结束状态,或 forwards
frameState = getCurrentFrame(this[_timing], keyframes, this[_effects], p);
}
return frameState;
}

getFrame(ntime) {
const playState = this.getPlayState(ntime),
initState = this[_initState],
{fill} = this[_timing];

if(playState === 'idle') {
return initState;
}

const currentTime = this.timeline.getCurrentTime(ntime),
keyframes = this[_keyframes].slice(0);

const {p, inverted} = getProgress(currentTime, this[_timing], this.getProgress(ntime));

let frameState = initState;
if(currentTime < 0 && playState === 'pending') {
Expand Down Expand Up @@ -192,13 +274,14 @@ export default class {
return this[_timing].timeline;
}

[_activeReadyTimer]() {
[_activeReadyTimer](ntime) {
if(this[_readyDefer] && !this[_readyDefer].timerID) {
if(this.timeline.currentTime < 0) {
var currentTime = this.timeline.getCurrentTime(ntime);
if(currentTime < 0) {
this[_readyDefer].timerID = this.timeline.setTimeout(() => {
this[_readyDefer].resolve();
delete this[_readyDefer];
}, {delay: -this.timeline.currentTime, heading: false});
}, {delay: -currentTime, heading: false});
} else {
this[_readyDefer].timerID = this.timeline.setTimeout(() => {
this[_readyDefer].resolve();
Expand All @@ -208,9 +291,9 @@ export default class {
}
}

[_activeFinishTimer]() {
[_activeFinishTimer](ntime) {
const {duration, iterations, endDelay} = this[_timing];
const delay = Math.ceil(duration * iterations + endDelay - this.timeline.currentTime) + 1;
const delay = Math.ceil(duration * iterations + endDelay - this.timeline.getCurrentTime(ntime)) + 1;
if(this[_finishedDefer] && !this[_finishedDefer].timerID) {
this[_finishedDefer].timerID = this.timeline.setTimeout(() => {
this[_finishedDefer].resolve();
Expand All @@ -226,7 +309,7 @@ export default class {
}
}

play() {
play(ntime) {
if(this.playState === 'finished') {
this.cancel();
}
Expand All @@ -235,16 +318,18 @@ export default class {
if(this.playbackRate <= 0) {
return;
}
ntime = ntime === undefined ? Timeline.nowtime() : ntime;
const {delay, playbackRate, timeline} = this[_timing];
this.timeline = new Timeline({
originTime: delay,
playbackRate,
ntime
}, timeline);
this[_activeReadyTimer]();
this[_activeFinishTimer]();
this[_activeReadyTimer](ntime);
this[_activeFinishTimer](ntime);
} else if(this.playState === 'paused') {
this.timeline.playbackRate = this.playbackRate;
this[_activeReadyTimer]();
this[_activeReadyTimer](ntime);
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ export function calculateFramesOffset(keyframes) {
return keyframes;
}

export function getProgress(timeline, timing, p) {
const {currentTime} = timeline,
{direction, duration} = timing;
export function getProgress(currentTime, timing, p) {
const {direction, duration} = timing;
let inverted = false;
if(direction === 'reverse') {
p = 1 - p;
Expand Down
92 changes: 71 additions & 21 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const test = require("ava")
const colors = require('colors')

import {Animator} from '../lib/index'
import {Animator} from '../src/index'

function sleep(time) {
const startTime = Date.now()
Expand All @@ -13,45 +13,45 @@ function sleep(time) {
}


function makeTimeCompare(caseID, startTime){
return function(actual, expect, passedTime = Math.max(Date.now() - startTime, 100)){
function makeTimeCompare(caseID, startTime) {
return function (actual, expect, passedTime = Math.max(Date.now() - startTime, 100)) {
const precision = Math.abs(actual - expect).toFixed(2),
percent = precision / passedTime
percent = precision / passedTime

let color = colors.green,
pass = true
pass = true

if(percent > 0.05 && percent <= 0.10){
if(percent > 0.05 && percent <= 0.10) {
color = colors.cyan
}
if(percent > 0.10 && percent <= 0.20){
if(percent > 0.10 && percent <= 0.20) {
color = colors.yellow
}
if(percent > 0.20 || Number.isNaN(percent)){
if(percent > 0.20 || Number.isNaN(percent)) {
color = colors.red
pass = false
}

console.log(color(`${caseID} - actual: ${actual}, expect: ${expect}, precision: ${precision} | ${percent.toFixed(2)}`))

return pass
return pass
}
}

function _case(fn){
function _case(fn) {
const caseID = _case.caseID || 0
_case.caseID = caseID + 1
return async function(t){
return async function (t) {
const startTime = Date.now()
t.time_compare = makeTimeCompare(caseID, startTime)
return await fn(t)
}
}

function _caseSync(fn){
function _caseSync(fn) {
const caseID = _case.caseID || 0
_case.caseID = caseID + 1
return function(t){
return function (t) {
const startTime = Date.now()
t.time_compare = makeTimeCompare(caseID, startTime)
return fn(t)
Expand Down Expand Up @@ -79,12 +79,12 @@ test('normal animation', _case(async t => {
}))

test('animation delay', _case(async t => {
const animator = new Animator({x: 10}, [{x: 20, y: 0, c:'red'}, {x: 50, y: 100, c:'green'}],
{delay: 200, duration:500, endDelay: 300})
const animator = new Animator({x: 10}, [{x: 20, y: 0, c: 'red'}, {x: 50, y: 100, c: 'green'}],
{delay: 200, duration: 500, endDelay: 300})

t.truthy(t.time_compare(animator.progress, 0, 1))
t.is(animator.playState, 'idle')

animator.play()
t.is(animator.playState, 'pending')

Expand All @@ -105,13 +105,13 @@ test('animation delay', _case(async t => {

await sleep(400)
t.truthy(t.time_compare(animator.progress, 1, 1))
t.is(animator.playState, 'finished')
t.is(animator.playState, 'finished')
t.is(animator.frame.c, undefined)
}))

test('animation ready', _case(async t => {
const animator = new Animator({x: 10}, [{x: 20, y: 0, c:'red'}, {x: 50, y: 100, c:'green'}],
{delay: 200, duration:500, endDelay: 300})
const animator = new Animator({x: 10}, [{x: 20, y: 0, c: 'red'}, {x: 50, y: 100, c: 'green'}],
{delay: 200, duration: 500, endDelay: 300})

t.is(animator.playState, 'idle')

Expand Down Expand Up @@ -139,8 +139,8 @@ test('animation ready', _case(async t => {
}))

test('animation finished', _case(async t => {
const animator = new Animator({x: 10}, [{x: 20, y: 0, c:'red'}, {x: 50, y: 100, c:'green'}],
{delay: 200, duration:500, endDelay: 300})
const animator = new Animator({x: 10}, [{x: 20, y: 0, c: 'red'}, {x: 50, y: 100, c: 'green'}],
{delay: 200, duration: 500, endDelay: 300})

t.is(animator.playState, 'idle')
animator.play()
Expand All @@ -166,3 +166,53 @@ test('animation finished', _case(async t => {
t.truthy(t.time_compare(Date.now() - now, 100))
}))

test('animation getProgress', t => {
const animator = new Animator(
{x: 10},
[{x: 20, y: 0, c: 'red'}, {x: 50, y: 100, c: 'green'}],
{delay: 10, duration: 100, endDelay: 40}
)


animator.play(0);

var p = animator.getProgress(5);
t.is(p, 0);

var p = animator.getProgress(10);
t.is(p, 0);

var p = animator.getProgress(60);
t.is(p, .5);

p = animator.getProgress(110);
t.is(p, 1);

p = animator.getProgress(120);
t.is(p, 1);
})


test('animation getFrame', t => {
const animator = new Animator(
{x: 10},
[{x: 20, y: 0, c: 'red'}, {x: 50, y: 100, c: 'green'}],
{delay: 10, duration: 100, endDelay: 40}
)
animator.play(0);
var f = animator.getFrame(5);
t.deepEqual(f, {x: 10});

var f = animator.getFrame(10);
t.deepEqual(f, {x: 20, y:0, c: 'red'});

f = animator.getFrame(60);
t.deepEqual(f, {x: 35, y: 50, c: 'red'});

f = animator.getFrame(110);
t.deepEqual(f, {x: 50, y: 100, c: 'green'});

f = animator.getFrame(120);
t.deepEqual(f, {x: 10});
})