網易新聞《娛樂圈畫傳》H5技術簡析

網易新聞採用一鏡到底(畫中畫)的動畫形式,呈現了2017年的娛樂圈熱門事件。css

網易新聞《娛樂圈畫傳》H5連接html

對於之內容展現爲主的H5,此種形式新穎獨特,瀏覽體驗優秀,但對設計師的要求也較高。
此H5值得學習的的技術點以下:html5

  • 逐幀動畫代替GIF
  • 動態部分和背景分離
  • 畫中畫

一. 逐幀動畫

利用雪碧圖將動畫幀合併到一張圖片,用css的背景定位來顯示須要的圖片部分。

經過css3的animation屬性將@keyframes動畫規則綁定的html元素。形如css3

<div class="people"></div>

.people { 
    animation: people_ani 1s steps(1,end) infinite; 
    background: url(images/cover_people.png) no-repeat;
    position: absolute;
    left: 20px;
    bottom: -4px;
    width: 500px;
    height: 1000px;
}
@keyframes people_ani {
    0%{background-position:0 0}
    12.5%{background-position:-500px 0}
    25%{background-position:-1000px 0}
    37.5%{background-position:-1500px 0}
    50%{background-position:0 -1000px}
    62.5%{background-position:-500px -1000px}
    75%{background-position:-1000px -1000px}
    87.5%{background-position:-1500px -1000px}
    100%{background-position:-2000px -1000px}
}
複製代碼

這裏須要注意animation的速度曲線屬性使用了step()函數,而很是用的線性函數。
step()函數和線性函數的區別在於,前者是關鍵幀之間的直接跳躍,後者會在線性變化時加入補間動畫來使動畫更加連貫流暢。
關於step函數內關鍵字start和end的理解。start表示時間開始已執行一步,忽略第一步,end表示時間結束動畫已結束,忽略最後一步。canvas

二. 動態部分和背景分離

優勢: 減小圖片的大小。

三. 畫中畫的實現

畫中畫的實現,主要經過屏幕內外兩張圖片的重疊渲染,在關鍵的時候替換圖片的方式。

這裏採用了html5中canvas的drawImage方法畫圖。drawImage的三種函數形式,
drawImage(image, dx, dy)
drawImage(image, dx, dy, dw, dh)
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)bash

sx, sy, sw, sh針對的是圖片,dx, dy, dw, dh針對的是canvas畫布區域。
sx和sy是image所要繪製的起始位置,
sw和sh是image所要繪製區域(相對image的sx和sy座標的偏移量)的寬度和高度值。
dx和dy是image在canvas中定位的座標值
dw和dh是image在canvas中即將繪製區域(相對dx和dy座標的偏移量)的寬度和高度值;app

H5將屏幕外部圖片不斷乘以一個係數逐漸縮小至手機屏幕,再將屏幕內圖片一樣基於係數縮小至外圖的關鍵位置,二者保持重疊,達到一鏡到底的效果。ide

H5兩個關鍵繪圖方法以下:函數

function drawImgOversize(img, imgNextWidth, imgNextHeight, imgNextAreaWidth, imgNextAreaHeight, imgNextAreaL, imgNextAreaT, radio) {
    var sx = imgNextAreaL - (imgNextAreaWidth / radio - imgNextAreaWidth) * (imgNextAreaL / (imgNextWidth - imgNextAreaWidth)),
        sy = imgNextAreaT - (imgNextAreaHeight / radio - imgNextAreaHeight) * (imgNextAreaT / (imgNextHeight - imgNextAreaHeight)),
        sw = imgNextAreaWidth / radio,
        sh = imgNextAreaHeight / radio,
        dx = 0,
        dy = 0,
        dw = 750,
        dh = 1206;
    var c = document.querySelector('#app')
    var ctx = c.getContext('2d');
    ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);

};

function drawImgMinisize(img, imgCurWidth, imgCurHeight, imgNextWidth, imgNextHeight, imgNextAreaWidthidth, imgNextAreaHeight, imgNextAreaL, imgNextAreaT, radio) {
    var sx = 0,
        sy = 0,
        sw = imgCurWidth,
        sh = imgCurHeight,
        dx = (imgNextAreaWidth / radio - imgNextAreaWidth) * (imgNextAreaL / (imgNextWidth - imgNextAreaWidth)) * radio * 750 / imgNextAreaWidth,
        dy = (imgNextAreaH / radio - imgNextAreaH) * (imgNextAreaT / (imgNextHeight - imgNextAreaH)) * radio * 1206 / imgNextAreaH,
        dw = 750 * radio,
        dh = 1206 * radio;
    var c = document.querySelector('#app')
    var ctx = c.getContext('2d');
    ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
};
複製代碼

以上H5做者的兩個方法,研究了許久,並不能清楚地理解其中的計算邏輯,故而本身重寫了其中的計算方法。學習

function drawInsideImg(img, imgCurWidth, imgCurHeight, imgNextWidth, imgNextHeight, imgNextAreaW, imgNextAreaH, imgNextAreaL, imgNextAreaT, radio) {
    var sx = 0,
        sy = 0,
        sw = imgCurWidth,
        sh = imgCurHeight,
        dx = (imgNextAreaL / (imgNextWidth - imgNextAreaW)) * (750 - 750 * radio),
        dy = (imgNextAreaT / (imgNextHeight - imgNextAreaH)) * (1206 - 1206 * radio),
        dw = 750 * radio,
        dh = 1206 * radio;
    this.ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
}

function drawOutsideImg (img, imgNextWidth, imgNextHeight, imgNextAreaWidth, imgNextAreaHeight, imgNextAreaL, imgNextAreaT, radio) {
    var sx = (imgNextAreaL / (imgNextWidth - imgNextAreaWidth)) * (imgNextWidth - imgNextAreaWidth / radio),
        sy = (imgNextAreaT / (imgNextHeight - imgNextAreaHeight)) * (imgNextHeight - imgNextAreaHeight / radio),
        sw = imgNextAreaWidth / radio,
        sh = imgNextAreaHeight / radio,
        dx = 0,
        dy = 0,
        dw = 750,
        dh = 1206;
    this.ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
}
複製代碼

這裏有兩個恆等的量做爲內外圖重疊渲染的橋樑,即
(imgNextAreaL / (imgNextWidth - imgNextAreaWidth))
(imgNextAreaT / (imgNextHeight - imgNextAreaHeight))

部份內容參考自https://mp.weixin.qq.com/s/xScwM7Z3I7wXYmZg7y9ajg

相關文章
相關標籤/搜索