国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[源碼閱讀]解析Anime(JS動畫庫)核心(1)

魏憲會 / 1439人閱讀

摘要:初始位置結(jié)束位置和持續(xù)時間是作為參數(shù)傳入配置的,因此計算已消耗時間就是完成動畫的核心。下面就深入了解下它的核心。

本次解析將分為2篇文章,當前是第一篇,第二篇在這里

另外,為了能更好的理解這個庫,個人寫了一個此庫的壓縮版,實現(xiàn)了核心的功能(主要也是為了更好理解核心功能),內(nèi)容更少方便閱讀,
地址在這里

介紹

anime一個JS輕量動畫庫,摒棄了常規(guī)的left,top屬性,全面采用requestAnimateFrame+CSS3屬性能充分調(diào)用設備進行GPU渲染。

它的亮點有以下(直接引用官網(wǎng)):

Keyframes(幀動畫): Chain multiple animation properties.

Timeline(同步動畫): Synchronize multiple instances together.

Playback controls(暫停回放功能): Play, pause, restart, seek animations or timelines.

CSS transforms(CSS動畫): Animate CSS transforms individually.

Function based values(函數(shù)定義配置(注入了內(nèi)部屬性)): Multiple animated targets can have individual value.

SVG Animations(SVG動畫): Motion path, line drawing and morphing animations.

Easing functions(自定義貝塞爾函數(shù)): Use the built in functions or create your own Cubic Bézier curve easing.

這么多亮點,其實關鍵函數(shù)就3~4個。

因為這里都是使用緩動函數(shù)算法,也就是通過 初始位置, 結(jié)束位置, 持續(xù)時間,已消耗的時間 計算出當前所在位置。

初始位置結(jié)束位置持續(xù)時間是作為參數(shù)傳入配置的,因此計算已消耗時間就是完成動畫的核心。

下面就深入了解下它的核心。

深入理解

先了解幾個時間的變量,動畫都是算法+時間=位置這么算出來的:

// 記錄當前位置所對應的時間,根據(jù)lastTime計算
instance.cuurentTime
// 記錄當前位置所消耗的時間
engineTime
// 記錄上一次計算完畢賦值后的位置對應時間
lastTime
// 上一次調(diào)用raf的時間
startTime
// 當前位置所消耗時間(能匹配反轉(zhuǎn)狀態(tài)),根據(jù)engineTime計算
insTime
// 動畫持續(xù)時間
insDuration
// 延遲時間
delay
// 從什么時間點開始動畫
insOffset

接著看幾個關鍵函數(shù),這里先不放具體代碼,只是先知道是做什么的(按一個正常動畫順序排放):

// anime的核心機制, 遞歸調(diào)用raf執(zhí)行(關鍵)
const engine = (() => {
  // ...requestAnimateFrame
})();

// anime主體
function anime(params){
  
  // 定義instance 也是最終返回值
  let instance = createNewInstance(params);
  
  // 外部API 從當前位置開始執(zhí)行動畫
  instance.play = function() {}
  
  // 配置 startTime 和 engineTime(關鍵)
   instance.tick = function(t) {}
   
  // 對當前engineTime進行判斷,確定動畫方案(關鍵)
  function setInstanceProgress(engineTime) {}
  
  // 計算動畫當前位置 并且賦值(關鍵)
  function setAnimationsProgress(insTime){}

  // 直接跳到參數(shù)time的時間所在的位置
  instance.seek = function(time) {}
  // 外部API 暫停
  instance.pause = function() {}
  // 外部API 反轉(zhuǎn)
  instance.reverse = function() {}
  // 外部API reset
  instance.reset = function() {}
  // 外部API 重新開始
  instance.restart = function() {}
  /*...*/
  return instance
}

關鍵函數(shù)就4個,其他都是一些對關鍵函數(shù)的具體使用

接著一個個解析:

createNewInstance

其實就是對屬性和方法合并成一個整體對象,這個對象是貫穿全局的,因此里面什么都有...

 function createNewInstance(params) {
  
    /* 對params進行處理 */
    const instanceSettings = replaceObjectProps(defaultInstanceSettings, params);
    const tweenSettings = replaceObjectProps(defaultTweenSettings, params);
    const animatables = getAnimatables(params.targets);
    const properties = getProperties(instanceSettings, tweenSettings, params);
    const animations = getAnimations(animatables, properties);
        
    // mergeObjects(o1,o2)相當于 Object.assing({},o2,o1)
    return mergeObjects(instanceSettings, {
      children: [],
      animatables: animatables,
      animations: animations,
      duration: getInstanceTimings("duration", animations, instanceSettings, tweenSettings),
      delay: getInstanceTimings("delay", animations, instanceSettings, tweenSettings)
    });
  }

instance.play

此處先做了防護,只有paused狀態(tài)下才會執(zhí)行,lastTime這里是調(diào)取當前動畫的位置對應的時間,因此才可以實現(xiàn)從任意位置開始動畫。

 // 外部API 從當前位置開始執(zhí)行動畫
instance.play = function() {
  if (!instance.paused) return;
  instance.paused = false;
  // 從0 開始
  startTime = 0;
  // 調(diào)取當前動畫當前位置所對應的時間
  lastTime = adjustTime(instance.currentTime);
  // 給 activeInstances 添加當前實例,說明這是一個正在運行的動畫
  activeInstances.push(instance);
  // raf未啟動,調(diào)用engine
  if (!raf) engine();
}

engine

anime的核心機制,通過遞歸調(diào)用requestAnimateFrame,當檢測到需要執(zhí)行動畫的集合activeInstances有值,調(diào)用instance.tick。

  // IIFE 之后調(diào)用engine相當于執(zhí)行內(nèi)部的play
  const engine = (() => {
    // step收到一個參數(shù),
    function play() { raf = requestAnimationFrame(step); };
    // 這里的參數(shù)t是 raf的參數(shù)中可以接受的一個時間戳,表示觸發(fā)調(diào)用的時間
    function step(t) {
      // activeInstances指正在被執(zhí)行的動畫集合
      const activeLength = activeInstances.length;
      // 存在正在運行的動畫
      if (activeLength) {
        let i = 0;
        while (i < activeLength) {
          // 調(diào)用tick執(zhí)行
          if (activeInstances[i]) activeInstances[i].tick(t);
          i++;
        }
        play();
      } else {
        // 不存在正在運行的動畫 cancel
        cancelAnimationFrame(raf);
        raf = 0;
      }
    }
    return play;
  })();

instance.tick

tick的作用通過參數(shù)traf的一個時間戳概念,計算出距離上一次調(diào)用實際消耗的時間engineTime

例如:上一次調(diào)用時間戳是1000,也就是1秒,中途突然執(zhí)行一個巨大的任務,等任務結(jié)束,時間戳是20000
那么這次的engineTime就是lastTime+20000-1000,也就是計算這次動畫從上次位置再加上19秒的位置...
那么anime對于這種情況是怎么處理呢?繼續(xù)看下一個setInstanceProgress

// 配置 startTime 和 engineTime
instance.tick = function(t) {
  now = t;
  // startTime 如果首次執(zhí)行 就是now,否則就是上一次tick的時間
  if (!startTime) startTime = now;
  // lastTime 是上一次執(zhí)行結(jié)束后動畫對應位置的時間戳
  // engineTime 是到動畫目前為止消耗的總時間,一般理論上講是lastTime+16.6667
  const engineTime = (lastTime + now - startTime) * anime.speed;
  setInstanceProgress(engineTime);
}

setInstanceProgress

這個函數(shù)接受一個消耗的時間值,在內(nèi)部對其進行適配和定義了各種情況的動畫起始點,傳遞給setAnimationsProgress

例如,上面那個例子,如果消耗了19秒,就如進入這個判斷:從結(jié)束點開始動畫(考慮reverse的情況)。

// 消耗的時間超出了持續(xù)時間 并且當前位置不在終點  或者 未設定持續(xù)時間
if ((insTime >= insDuration && insCurrentTime !== insDuration) || !insDuration){
  if ((insTime >= insDuration && insCurrentTime !== insDuration) || !insDuration) {
    // 從結(jié)束點開始
    setAnimationsProgress(insDuration);
    if (!insReversed) countIteration();
  }
}

setInstanceProgress(省略了一些配置的定義)

// 對當前engineTime進行判斷,確定動畫方案
function setInstanceProgress(engineTime) {
  // 動畫持續(xù)時間
  const insDuration = instance.duration;
  // 從什么時間點開始動畫
  const insOffset = instance.offset;
  // 加上延遲后的開始時間
  const insStart = insOffset + instance.delay;
  // 記錄當前位置所對應的時間
  const insCurrentTime = instance.currentTime;
  // 是否是反轉(zhuǎn)狀態(tài)
  const insReversed = instance.reversed;
  // 當前位置所消耗時間(能匹配反轉(zhuǎn)狀態(tài))
  // 這里adjustTime就是如果是反轉(zhuǎn)狀態(tài),則返回 insDuration-engineTime
  const insTime = adjustTime(engineTime);
  /* ... */
  // 消耗的時間大于應該開始的時間 并且 消耗的時間在持續(xù)時間范圍內(nèi)
  if (insTime > insOffset && insTime < insDuration) {
    setAnimationsProgress(insTime);
  } else {
    // 消耗的時間小于應該開始的時間 并且 當前位置不在起點
    if (insTime <= insOffset && insCurrentTime !== 0) {
      // 從頭開始
      setAnimationsProgress(0);
      if (insReversed) countIteration();
    }
    // 消耗的時間超出了持續(xù)時間 并且當前位置不在終點  或者 未設定持續(xù)時間
    if ((insTime >= insDuration && insCurrentTime !== insDuration) || !insDuration) {
      // 從結(jié)束點開始
      setAnimationsProgress(insDuration);
      if (!insReversed) countIteration();
    }
  }
  setCallback("update");
  // 消耗時間大于持續(xù)時間 并且在終點(不在終點的上面已經(jīng)判斷了)
  if (engineTime >= insDuration) {
    if (instance.remaining) {
      startTime = now;
      if (instance.direction === "alternate") toggleInstanceDirection();
      // remaining為false,remaining>0說明還需要繼續(xù)動畫
    } else {
      // 完成動畫的執(zhí)行
      instance.pause();
      if (!instance.completed) {
        instance.completed = true;
        setCallback("complete");
        if ("Promise" in window) {
          resolve();
          promise = makePromise();
        }
      }
    }
    lastTime = 0;
  }
}

關鍵函數(shù)setAnimationsProgress和后續(xù)的操作函數(shù)都放在下一篇繼續(xù)解析。

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/97746.html

相關文章

  • [源碼閱讀]解析Anime(JS畫庫)核心(2)

    摘要:使用了緩動函數(shù),只需要通過當前動畫消耗的時間,搭配其他定義的配置項,就可以計算出當前動畫具體位置。此次解析就到這里結(jié)束,如有錯誤,請指出,感謝 本次解析將分為2篇文章,當前是第二篇,第一篇在這里 另外,為了能更好的理解這個庫,個人寫了一個此庫的壓縮版,實現(xiàn)了核心的功能(主要也是為了更好理解核心功能),內(nèi)容更少方便閱讀,地址在這里 繼續(xù)上一篇,先把結(jié)構(gòu)圖拉過來: // anime主體 ...

    Andrman 評論0 收藏0
  • 2018年值得期待11個Javascript畫庫

    摘要:超過的,是一個動畫庫,可以處理屬性,單個轉(zhuǎn)換,或任何屬性以及對象。在,是一個快速的動畫引擎,具有與的相同的。在,這個功能和反應動畫庫只重。由和其他人使用,這個庫既流行又令人驚訝地有用。 在瀏覽網(wǎng)頁尋找一個整潔的Javascript動畫庫時,我發(fā)現(xiàn)很多recommended的動畫庫一段時間都沒有維護。 經(jīng)過一些研究,我收集了11個最好的庫,在你的應用程序中使用。我還添加了一些,主要是非維...

    call_me_R 評論0 收藏0
  • 2018年值得期待11個Javascript畫庫

    摘要:超過的,是一個動畫庫,可以處理屬性,單個轉(zhuǎn)換,或任何屬性以及對象。在,是一個快速的動畫引擎,具有與的相同的。在,這個功能和反應動畫庫只重。由和其他人使用,這個庫既流行又令人驚訝地有用。 在瀏覽網(wǎng)頁尋找一個整潔的Javascript動畫庫時,我發(fā)現(xiàn)很多recommended的動畫庫一段時間都沒有維護。 經(jīng)過一些研究,我收集了11個最好的庫,在你的應用程序中使用。我還添加了一些,主要是非維...

    teren 評論0 收藏0
  • 2018年值得期待11個Javascript畫庫

    摘要:超過的,是一個動畫庫,可以處理屬性,單個轉(zhuǎn)換,或任何屬性以及對象。在,是一個快速的動畫引擎,具有與的相同的。在,這個功能和反應動畫庫只重。由和其他人使用,這個庫既流行又令人驚訝地有用。 在瀏覽網(wǎng)頁尋找一個整潔的Javascript動畫庫時,我發(fā)現(xiàn)很多recommended的動畫庫一段時間都沒有維護。 經(jīng)過一些研究,我收集了11個最好的庫,在你的應用程序中使用。我還添加了一些,主要是非維...

    skinner 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<