• HTML5之创新的视频拼图剖析式学习之二


    昨天我们剖析了一下翻阅体验的实现。今天要剖析另外一个很有意思的效果——视频拼图。

    网站中第一部分第二页《月熊的标志》是月熊志中互动性较强的一页,页面上会随机分布9块视频碎片,用户可以通过鼠标或者触控移动碎片完成拼图。

    在这个Demo中,我们需要引用2个JavaScript库,jQuery和Hammer.js。

    Hammer.js 是一个手势触控JS库,能够为网页加入Tap、Swipe、Drag等事件,并且同时支持鼠标和触控输入,免去自己监听事件和判断浏览器兼容等问题。

    建立九宫格

    首先,我们在页面中建立一个九宫格:

     1 HTML:
     2 <div id="puzzle">
     3     <div class="container"><i></i></div>
     4  5     <div class="container"><i></i></div>
     6 </div>
     7 
     8 CSS:
     9 #puzzle {
    10     position: absolute;
    11     top: 50%;
    12     left: 38%;
    13     margin-top: -190px;
    14      678px;
    15     height: 381px;
    16 }
    17 
    18 #puzzle .container {
    19     float: left;
    20      226px;
    21     height: 127px;
    22 }
    23 
    24 #puzzle .container i {
    25     display: block;
    26     margin: 4px;
    27      218px;
    28     height: 119px;
    29     background: #fff;
    30 }

    每个宫格(.container)的大小是226*127,其中白色部分(.container i)是218*119。

    插入视频

    接着我们在页面中插入视频,我们使用HTML5 中新增的Video标签,并且为了兼容多数浏览器,使用了2种格式的视频源,然后设置视频为自动播放(Autoplay)和循环播放(Loop),视频源的大小建议和九宫格保持一致:

    1 HTML:
    2 <video width="678" height="381" id="video" autoplay loop>
    3     <source src="../video/findjasper.mp4" type="video/mp4">
    4     <source src="../video/findjasper.ogv" type="video/ogg; codecs='theora, vorbis'">
    5 </video>

    最后把视频隐藏起来,在幕后默默的运行即可:

    1 CSS:
    2 #video {
    3     display: none;
    4 }

    创建视频碎片

    视频碎片本身是一个个canvas元素,通过JS将Video的帧画面分块循环绘制到canvas上。

     1 JS:
     2 //为数组添加随机打乱方法
     3 Array.prototype.shuffle = function () {
     4     var l = this.length,
     5         i = l;
     6     while (i--) {
     7         var p = parseInt(Math.random() * l),
     8             t = this[i];
     9         this[i] = this[p];
    10         this[p] = t;
    11     };
    12     return this;
    13 };
    1 //随机函数,随机返回min~max中的任一数值
    2 function random(min, max) {
    3     return parseInt(Math.random() * (max - min + 1) + min);
    4 };

    上面的JS方法/函数接下来会用到。

     1 S:
     2 var PIECE_WIDTH = 226,
     3     PIECE_HEIGHT = 127,
     4     $body = $("body"),
     5     video = $("#video")[0],
     6 $puzzle = $("#puzzle"),
     7 $puzzleItems = $puzzle.find(".container"),
     8     zIndex = 2,
     9     ctxs = [],
    10 rndArray = [0, 1, 2, 3, 4, 5, 6, 7, 8].shuffle();

    以上是会用到的变量,其中需要特别说明的是zIndex用来保存碎片的z-index值,ctxs用来保存碎片的canvas上下文,rndArray是一个0~8的随机数组。

     1 JS:
     2 //循环创建碎片
     3 for (var i = 0; i < 9; i++) {
     4     var index = rndArray[i], //分配随机位置
     5         piece = document.createElement("canvas"); //创建canvas元素
     6 
     7     piece.className = "piece";
     8     piece.width = PIECE_WIDTH;
     9     piece.height = PIECE_HEIGHT;
    10     ctxs.push(piece.getContext("2d")); //把上下文push到ctxs数组,方便绘制时调用
    11 
    12 //使用random函数给碎片设置一个随机的位置
    13 //使用css3 transform旋转碎片角度,使拼图更加真实
    14 //最后把碎片所对应的宫格(.container)保存到data("container")中
    15     $(piece).css({
    16         left: random(50, window.innerWidth - PIECE_WIDTH),
    17         top: random(50, window.innerHeight - PIECE_HEIGHT),
    18         transform: "rotate(" + random(-25, 25) + "deg)"
    19     }).data("container", $puzzleItems.eq(index)).appendTo($body);
    20 };

    目前并没有限制碎片出现的位置,所以碎片可能会遮盖页面上的文字,你可以自己加以完善。

    如果现在运行页面,你就能看到页面上出现的随机碎片了,但是由于还没有把视频绘制到页面上,所以只能看到黑色。

    绘制视频碎片

    绘制视频到canvas其实十分简单,主要用到的是canvas的drawImage方法。

    drawImage方法接收9个参数。

    context.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight)

    image指向要使用的来源,可以是图片、视频或者Canvas元素,

    sourceX和sourceY指image上绘制的左上角坐标,

    sourceWidth 和 sourceHeight指从image上要绘制的宽和高,

    destX和destY表示将image绘制到画布上的左上角坐标,

    destWidth 和destHeight表示绘制到画布上的宽和高。

    看文字的话可能比较难懂,看下面这张图应该能帮助你理解:

    我们创建一个drawVideo函数绘制视频

     1 JS:
     2 function drawVideo() {
     3     for (var i = 0; i < 9; i++) {
     4         var index = rndArray[i], //当前碎片位置
     5             row = Math.floor(index / 3), //因为宫格是3x3的,所以用取余数获取行数
     6             col = Math.floor(index % 3); //与3取模获得列数
     7         ctxs[i].drawImage(video, (col * PIECE_WIDTH), (row * PIECE_HEIGHT), PIECE_WIDTH, PIECE_HEIGHT, 0, 0, PIECE_WIDTH, PIECE_HEIGHT); //row和col分别乘以宫格的宽高就是要从视频上绘制的左上角坐标
     8     };
     9 };
    10 setInterval(drawVideo, 50);

    然后调用setInterval每隔50毫秒循环绘制。

    处理拖拽操作

    hammer.js的事件对象添加一个gesture对象,里面保存了关于此次操作的相关信息,比如移动距离、移动速率、移动角度、持续时间等。

    我们先创建3个函数,对应拖拽过程中的3个事件。

    开始拖拽碎片时,加上.dragging(添加box-shadow),并设置更高一层的z-index保证在所有碎片之上,最后保存当前的位置到data("offset")中。

    1 function dragStart(){
    2     var $piece = $(this);
    3     $piece.addClass("dragging").css("z-index", zIndex++).data("offset", $piece.offset());
    4 };

    在拖拽碎片时,只需要给之前保存的offset加上移动距离(deltaX/ deltaY),就是现在的正确位置。

    1 function drag(event){
    2     var $piece = $(this),
    3         pieceOffset = $piece.data("offset");
    4     $piece.css({
    5         left: pieceOffset.left + event.gesture.deltaX,
    6         top: pieceOffset.top + event.gesture.deltaY
    7     });
    8 };

    最后拖拽结束,移除dragging类。

    如果碎片的中心点在对应的宫格内部,就移动的宫格内,并关闭hammer。

    如果九宫格内有9块碎片,就完成拼图了!

     1 function dragEnd(event){
     2     var $piece = $(this),
     3         pieceOffset = $piece.data("offset");
     4 
     5     $piece.removeClass("dragging");
     6 
     7     var centerX = pieceOffset.left + event.gesture.deltaX + PIECE_WIDTH / 2,
     8         centerY = pieceOffset.top + event.gesture.deltaY + PIECE_HEIGHT / 2,
     9         $container = $piece.data("container"),
    10         containerOffset = $container.offset();
    11 
    12 
    13     if (centerX > containerOffset.left && (centerX < containerOffset.left + PIECE_WIDTH) && centerY > containerOffset.top && centerY < (containerOffset.top + PIECE_HEIGHT)) {
    14         $container.prepend($piece.removeAttr("style").data("hammer").off());
    15         if ($puzzle.find(".piece").length == 9) {
    16             // bingo.
    17         };
    18     };
    19 };
    20 
    21 
    22 $(".piece").hammer({
    23     prevent_default: true
    24 }).on("dragstart", dragStart).on("drag", drag).on("dragend", dragEnd);

    最后初始化碎片并绑定函数到对应的事件上,这个互动小游戏就完成了。

    其实,网站上还有很多特效的制作,大家可以自己前去体验:http://moonbear.animalsasia.org/ie/。希望本文能给大家带来一些灵感,运用到自己的网站开发上面去。

  • 相关阅读:
    SQL批量更新
    使用PLSQL导入导出数据库
    Oracle 的Blob使用小结
    基于java的邮件服务器以及webmail的搭建
    Tomcat 系统架构与设计模式 【2】
    修改Oracle XE Listener 占用的1521、8080端口
    nls_lang pl/sql 设置编码
    oracle提高查询效率的解析
    Tomcat 系统架构与设计模式
    hql与sql的区别(转)
  • 原文地址:https://www.cnblogs.com/huoxingren/p/3499915.html
Copyright © 2020-2023  润新知