网易新闻《娱乐圈画传》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

相关文章
相关标签/搜索