亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

多屏互動(dòng)——H5 中級(jí)進(jìn)階

wdzgege / 3172人閱讀

摘要:手機(jī)屏幕朝上,水平靜止放置,軸重力加速度為,為。當(dāng)手機(jī)水平放置,撥動(dòng)手機(jī),使其慢慢旋轉(zhuǎn),重力加速度的數(shù)據(jù)并沒有變化。四元數(shù)的基本數(shù)學(xué)方程為其中表示旋轉(zhuǎn)角度,表示旋轉(zhuǎn)軸。四元數(shù)表示一個(gè)完整的旋轉(zhuǎn)。

前言

隨著智能硬件的普及,手機(jī),平板,PC甚至路邊的電子廣告牌,現(xiàn)代瀏覽器已經(jīng)無處不在。在瀏覽器里編織出我們自己的一片天地已經(jīng)輕車熟路,但是這還不夠,H5賦予了瀏覽器太多的新特性,等待我們?nèi)ナ褂?。這篇文章介紹利用手機(jī)瀏覽器的羅盤API,在PC的瀏覽器實(shí)時(shí)地繪制一個(gè)3D盒模型。

這種炫酷的玩法叫做“多屏互動(dòng)”,就像是把手機(jī)當(dāng)做游戲手柄,PC顯示器當(dāng)做電視機(jī),不過這些都是在瀏覽器里實(shí)現(xiàn)的。

先上效果圖

(測(cè)試機(jī)是刷了小米系統(tǒng)的裂了屏幕的HTC霹靂2+Chrome瀏覽器)

源碼請(qǐng)戳這里:https://coding.net/u/OverTree...

本地測(cè)試過程:

在PC上,使用命令 node index.js,自動(dòng)打開項(xiàng)目主頁。(請(qǐng)關(guān)閉ADsafe,如有虛擬機(jī),請(qǐng)停用虛擬網(wǎng)卡)

創(chuàng)建一個(gè)“房間”并自動(dòng)進(jìn)入“房間”。

用手機(jī)掃描“房間”內(nèi)任意位置的二維碼。

確保手機(jī)和PC可以相互PING通

ADsafe是個(gè)很好用的去廣告軟件,但是會(huì)阻止本機(jī)IP訪問,可能造成項(xiàng)目首頁打不開,所以請(qǐng)先暫時(shí)關(guān)閉
本程序會(huì)自動(dòng)獲取本機(jī)IP,如果有虛擬網(wǎng)卡,IP地址可能獲取不正確

客戶端(瀏覽器) 1. 手機(jī)瀏覽器端

一個(gè)物體在空間內(nèi)的旋轉(zhuǎn)體位,都可以用一個(gè)方向向量(x,y,z)和旋轉(zhuǎn)角度(angle)來表示。也就是CSS3transformrotate3d(x,y,z,angle)這個(gè)函數(shù)的4個(gè)參數(shù)。

想要在瀏覽器里方便的繪制一個(gè)立體模型的的旋轉(zhuǎn),重點(diǎn)就是利用手機(jī)瀏覽器的H5新特性去獲取手機(jī)旋轉(zhuǎn)狀態(tài)的數(shù)據(jù),然后轉(zhuǎn)化成這4個(gè)參數(shù)。

1.1 重力感應(yīng)API

devicemotion 顧名思義設(shè)備運(yùn)動(dòng)
其實(shí)不僅僅有重力感應(yīng)的數(shù)據(jù),還有移動(dòng)加速度,擺動(dòng)角度。
不過這個(gè)接口傾向于運(yùn)動(dòng)時(shí)瞬間的數(shù)據(jù)展示,靜止時(shí),除了重力加速度,其他數(shù)據(jù)(移動(dòng)加速度,擺動(dòng)角度)基本為0。

window.addEventListener("devicemotion", deviceMotionHandler, true);
function deviceMotionHandler(evt){
   if(evt.accelerationIncludingGravity){
       document.body.innerHTML = 
          "x軸加速度: " + evt.accelerationIncludingGravity.x + "
" + "y軸加速度: " + evt.accelerationIncludingGravity.y + "
" + "z軸加速度: " + evt.accelerationIncludingGravity.z + "
" } if(evt.rotationRate ){ document.body.innerHTML += "x軸扭轉(zhuǎn): " + evt.rotationRate.beta + "
" + "y軸扭轉(zhuǎn): " + evt.rotationRate.gamma + "
" + "z軸扭轉(zhuǎn): " + evt.rotationRate.alpha + "
" } }

(魅族老機(jī)型,安卓4.4.4的自帶瀏覽器對(duì)此API支持不完全,請(qǐng)另外安裝QQ瀏覽器)
在手機(jī)瀏覽器里運(yùn)行以上代碼,并稍微晃動(dòng),會(huì)看到打印數(shù)據(jù)狂跳。
拿到了數(shù)據(jù),接下來開始觀察規(guī)律。
手機(jī)屏幕朝上,水平靜止放置,Z軸重力加速度為9.8,Y,X為0。
手機(jī)屏幕朝下,水平靜止放置,Z軸重力加速度為-9.8,Y,X為0。
手機(jī)話筒朝下,豎直靜止放置,Y重力加速度為9.8, X,Z為0。
手機(jī)話筒朝上,豎直靜止放置,Y重力加速度為-9.8, X,Z為0。
手機(jī)右側(cè)朝上,豎直靜止放置,X重力加速度為9.8, Y,Z為0。
手機(jī)左側(cè)朝下,豎直靜止放置,X重力加速度為-9.8, Y,Z為0。

那么手機(jī)的空間坐標(biāo)如下圖:

箭頭指向都是坐標(biāo)正方向。

當(dāng)手機(jī)開始傾斜,X,Y,Z軸的加速度分量都有值,且絕對(duì)值都小于9.8。根據(jù)分量的數(shù)值,是可以算出手機(jī)在三維空間的傾斜狀態(tài),只不過這個(gè)計(jì)算過程復(fù)雜,而且在手機(jī)運(yùn)動(dòng)時(shí),重力加速度的值并不準(zhǔn)確表達(dá)當(dāng)前傾斜。一般不用這個(gè)數(shù)據(jù)去計(jì)算手機(jī)在三維空間的傾斜。

當(dāng)手機(jī)水平放置,撥動(dòng)手機(jī),使其慢慢旋轉(zhuǎn),重力加速度的數(shù)據(jù)并沒有變化。
所以,重力感應(yīng)的這個(gè)API,只能獲取設(shè)備當(dāng)前的傾斜狀態(tài),而無法獲取設(shè)備的旋轉(zhuǎn)方向。而一些簡(jiǎn)單的功能,比如搖一搖,晃一晃,就可以用這個(gè)接口去實(shí)現(xiàn)。

利用重力感應(yīng)的API,可以輕松利用高中數(shù)學(xué)的反三角函數(shù),實(shí)現(xiàn)XY二維平面的旋轉(zhuǎn),效果如下:

代碼如下:

function deviceMotionHandler(evt){
    var angle = 
    Math.atan2(
            0 - evt.accelerationIncludingGravity.x ,        
            evt.accelerationIncludingGravity.y
        ).toFixed(2) / Math.PI * 180 ; 
}

這個(gè) angle 就可以直接應(yīng)用在DOM的CSS屬性transform:rotate(angle deg)上。

1.2 羅盤API
window.addEventListener("deviceorientation", deviceOrientationHandler, true);
function deviceMotionHandler(evt){
     document.body.innerHTML = 
          "z軸旋轉(zhuǎn)(羅盤方向) alpha:  " + event.alpha + "
" + "y軸旋轉(zhuǎn) gamma:  " + event.gamma + "
" + "x軸旋轉(zhuǎn) beta:  " + event.beta }

重點(diǎn)來了,deviceorientation能夠很好的表現(xiàn)物體在空間中的狀態(tài),旋轉(zhuǎn)方向,傾斜角度,無論是靜止還是運(yùn)動(dòng)或者加速運(yùn)動(dòng)。

這里要和devicemotionevt.rotationRate區(qū)分一下,雖然都有alpha,gamma,beta 但是 devicemotion 描述的是旋轉(zhuǎn)變化了的角度值,物體角度變化才會(huì)有數(shù)據(jù),靜止了之后就變?yōu)?,而 deviceorientation 的是描述是靜止時(shí)的角度值。

這三個(gè)數(shù)值的單位都是deg,如何轉(zhuǎn)化為CSS3 transform:rotate3d(x,y,z,angle) 的4個(gè)參數(shù),對(duì)于沒有任何3D知識(shí)的前端狗來說是個(gè)挺麻煩的問題。

現(xiàn)在要引入一個(gè)概念:四元數(shù)

四元數(shù)是個(gè)高階復(fù)數(shù) q = [w,x,y,z]。
四元數(shù)的基本數(shù)學(xué)方程為 :
q = cos (a/2) + i(x sin(a/2)) + j(y sin(a/2)) + k(z * sin(a/2)) 其中a表示旋轉(zhuǎn)角度,(x,y,z)表示旋轉(zhuǎn)軸。
四元數(shù)表示一個(gè)完整的旋轉(zhuǎn)。
四元數(shù)可以由各軸旋轉(zhuǎn)角(alpha,beta,gamma)求得。
四元數(shù)可以轉(zhuǎn)換旋轉(zhuǎn)軸(x,y,z)和旋轉(zhuǎn)角度(angle)。

作為初試,本篇并不深入討論四元數(shù)的具體定義,難點(diǎn)是獲取四元數(shù)[w,x,y,z]。
好在官方提供了旋轉(zhuǎn)角(alpha,beta,gamma)轉(zhuǎn)換成四元數(shù)的方法
https://w3c.github.io/deviceo...
在這個(gè)頁面內(nèi)搜索 getQuaternion

另外我根據(jù)數(shù)學(xué)公式反求,寫了一個(gè)四元數(shù)轉(zhuǎn)(x,y,z,angle) 的函數(shù) getAcQuaternion
代碼如下:

var degtorad = Math.PI / 180;
function getQuaternion( alpha, beta, gamma ) {  //官方求四元數(shù)方法

  var _x = beta  ? beta  * degtorad : 0; // beta value
  var _y = gamma ? gamma * degtorad : 0; // gamma value
  var _z = alpha ? alpha * degtorad : 0; // alpha value

  var cX = Math.cos( _x/2 );
  var cY = Math.cos( _y/2 );
  var cZ = Math.cos( _z/2 );
  var sX = Math.sin( _x/2 );
  var sY = Math.sin( _y/2 );
  var sZ = Math.sin( _z/2 );

  var w = cX * cY * cZ - sX * sY * sZ;
  var x = sX * cY * cZ - cX * sY * sZ;
  var y = cX * sY * cZ + sX * cY * sZ;
  var z = cX * cY * sZ + sX * sY * cZ;

  return [ w, x, y, z ];

}

function getAcQuaternion( _w, _x, _y, _z ) {  //我的四元數(shù)轉(zhuǎn)旋轉(zhuǎn)軸和旋轉(zhuǎn)角度方法

  var rotate = 2 * Math.acos(_w)/degtorad ;

  var x = _x / Math.sin(degtorad * rotate/2) || 0;
  var y = _y / Math.sin(degtorad * rotate/2) || 0;
  var z = _z / Math.sin(degtorad * rotate/2) || 0;

  return {x:x,y:y,z:z,rotate:rotate};

}

function deviceMotionHandler(evt){  // deviceorientation 事件處理函數(shù)
  var qu = getQuaternion(evt.alpha,evt.beta,evt.gamma);
  var rotate3d = getAcQuaternion(qu[0],qu[1],qu[2],qu[3]);
  // rotate3d的參數(shù)已經(jīng)有了,隨你處理咯。我是把他送給服務(wù)器,交給PC,在PC上顯示旋轉(zhuǎn)
}
1.3 校準(zhǔn)

這里有個(gè)3D里的概念,攝像機(jī)位置。我們的PC顯示器就是一個(gè)攝像機(jī)。只能被動(dòng)的從某一個(gè)角度展示拍攝的景象。正常情況下,手機(jī)所在平面應(yīng)該和顯示器所在平面平行,且垂直于地平面的角度。就好比是,攝像機(jī)正對(duì)著手機(jī)正面拍攝。
如果校準(zhǔn)的時(shí)候手機(jī)并沒有垂直于地平面,攝像機(jī)的位置就不一定是正前方了。這時(shí)候展示的畫面并不是水平同步的了。
如下圖所示,校準(zhǔn)時(shí),手機(jī)屏幕朝上。這時(shí)候攝像機(jī)位置就在天花板上了,你看到的成像就是俯視圖。

同理,校準(zhǔn)時(shí),手機(jī)屏幕朝下,這時(shí)候攝像機(jī)的位置就是在地上,往上拍攝,你看到的成像就是仰視圖。

總結(jié)起來就是:校準(zhǔn)時(shí),手機(jī)屏幕朝著哪里,攝像機(jī)就在那里拍攝著屏幕,一動(dòng)不動(dòng)。

1.4 兼容性

demo的兼容性測(cè)試并不理想
在iOS平臺(tái)上測(cè)試良好,且流暢。

在安卓平臺(tái)上,除了chrome瀏覽器之外的瀏覽器,會(huì)出現(xiàn)各種問題,主要表現(xiàn)在羅盤數(shù)據(jù)不準(zhǔn)確。
而chrome瀏覽器并沒有掃一掃功能,因?yàn)樵趪?guó)外并不流行這個(gè)玩意。所以在安卓平臺(tái)上就很蛋疼,還要多裝一個(gè)我查查,才能完整體驗(yàn)。
(如果出現(xiàn)旋轉(zhuǎn)不準(zhǔn)確的問題,可以嘗試校準(zhǔn)羅盤,大概就是拿著手機(jī)畫8。百度一下方法有很多)

代碼如果有兼容寫法,或者有其他兼容問題請(qǐng)賜教,可以在coding上私信我(OverTree ),不勝感激。

2. PC瀏覽器端

PC瀏覽器的作用就是能夠顯示房間信息,創(chuàng)建房間。

顯示房間,創(chuàng)建時(shí)間,參與人數(shù),點(diǎn)擊進(jìn)入。
創(chuàng)建一個(gè)房間,成功后自動(dòng)進(jìn)入房間。

在房間內(nèi),接受服務(wù)器轉(zhuǎn)發(fā)的手機(jī)端的消息,并作出相應(yīng)動(dòng)作,包括上線,校準(zhǔn),旋轉(zhuǎn),下線。

上線時(shí),安排就坐(隱藏二維碼,顯示模型)
校準(zhǔn)時(shí),重新設(shè)置模型的顯示角度。
旋轉(zhuǎn)時(shí),就旋轉(zhuǎn)咯。
下線時(shí),重新顯示二維碼(顯示二維碼,隱藏模型)

2.1初始化, 建立ws連接

重點(diǎn)是房間里的事情。所以這里就只介紹進(jìn)入房間發(fā)生的事吧。
首先房間參數(shù)要正確,至少有房間編號(hào)。

房間路由:
/room/[roomNumber]
roomNumber是一串16位隨機(jī)字符串。
座位路由:
/room/[roomNumber]/[seatNumber]

var uri = win.location.pathname.split("/"),roomNumber;

function initUrlData(){
  if(uri.length>=3 && uri[1] == "room"){
    roomNumber = uri[2];
    document.title = "虛擬房間 "+ roomNumber + "號(hào)"
    return 1;
  }else{
    window.location.href = "/index";
    return 0;
  }
}

function initWebSocket(){
   var wsUri = "ws://"+ window.location.hostname +":<%= config.wsport %>"+"/ws/room"; //這里用了一個(gè)ejs的占位符,已便在服務(wù)器更改websocket端口時(shí)可以及時(shí)使用正確端口。
   
   var websocket = new WebSocket(wsUri); 
   websocket.onopen = function(evt) { 
       websocket.send(JSON.stringify({room:roomNumber})); 
   }; //鏈接建立后,發(fā)送一個(gè)消息,表明在哪個(gè)房間

   websocket.onclose = function(evt) { 

   }; 

   websocket.onmessage = function(evt) { 
       parseMessage(evt.data) //解析數(shù)據(jù)
   }; 
   websocket.onerror = function(evt) { 

   }; 
   //綁定了這些處理函數(shù)之后,websocket開始建立鏈接,而不是 New 的時(shí)候開始建立
}


$(".room-place .qrcode").each(function(index,item){
    $(item).qrcode({
        "size": 200,
        "color": "#3a3",
        "text": window.location.origin + "/room/" + roomNumber + "/" + (index+1)
    });
    //這里用jQuery的插件,jquery-qrcode 按照座位路由初始化二維碼
})

2.2 純CSS3立體模型

做為一名普通的前端人員,想要畫一個(gè)3D的模型,按照最熟悉的方法就是用CSS3了。
(如果是用Three.js的大神請(qǐng)?zhí)^本節(jié))
不過要很快畫出一個(gè)六面體出來,還是需要想一想的,畢竟這個(gè)技能很少用。

畫一個(gè)長(zhǎng)方體

對(duì)這樣的css有什么要吐槽的么?

這樣的stylesheet簡(jiǎn)直是刀耕火種時(shí)期的

如果用sass寫法,那么只需要寫一次#box和多層嵌套就可以了。

效果如下:

如果我們使用webGL去繪制的話,導(dǎo)入一些現(xiàn)成的3D模型,無論物體還是人物,都可以360度無死角的玩弄于手掌了。
(如果有蒼老師的模型,想想還有點(diǎn)小激動(dòng)呢,VR的感覺說來就來啊 - -)

接下來就是等待來自手機(jī)端的旋轉(zhuǎn)信息,x,y,z,angle,使#box進(jìn)行transform旋轉(zhuǎn)就是了。

$seat.find("#box").
css("transform","rotate3d("
+ (-parseFloat(content.x))+","  //取反
+ (+parseFloat(content.y))+","
+ (-parseFloat(content.z))+","  //取反
+ content.rotate +"deg)"); 

不取反的話,旋轉(zhuǎn)是錯(cuò)誤的。我曾多次嘗試給不同的坐標(biāo)取反,最終得出這個(gè)取反方法,是唯一顯示正常的組合。

無法理解這兩個(gè)取反,猜測(cè)是因?yàn)閏ss的x,y,z的坐標(biāo)和物理設(shè)備x,y,z的坐標(biāo)方向有差異吧。畢竟顯示器是平面的,他的x,y,z的定義不能和手機(jī)傳感器一致。

2.3 校準(zhǔn)

PC端的校準(zhǔn)就簡(jiǎn)單多了,在#box外套一層div.adjust。
當(dāng)接受來自手機(jī)端的校準(zhǔn)信息 x,y,z,angle,設(shè)置外套的 div.adjust 的旋轉(zhuǎn)為 x,y,z,-angle 就好了。

$seat.find(".adjust").
css("transform","rotate3d("
+ (-parseFloat(content.x))+","  
+ (+parseFloat(content.y))+","
+ (-parseFloat(content.z))+","  
+ (-parseFloat(content.rotate)) +"deg)");  //取反

當(dāng)然,這個(gè)adjust的樣式至少包含以下樣式

.adjust{
  position: absolute;
  transform-style:preserve-3d;
}
2.4 兼容性

PC端的兼容性就好多了,只要是現(xiàn)代H5瀏覽器基本上沒有兼容性問題。

服務(wù)端 1.數(shù)據(jù)結(jié)構(gòu)

這個(gè)服務(wù)只做臨時(shí)數(shù)據(jù)的保存和消息轉(zhuǎn)發(fā)。
臨時(shí)數(shù)據(jù):比如,各端的webSocket連接句柄,房間信息等,我把它們放在global全局對(duì)象下,就好比是共享內(nèi)存,訪問方便,速度快。

global.ShareMem = {
  rooms:{
       "12345678":{          //房間號(hào)做為key,方便查找
         player:[{socket:connection,place:place}],          //手機(jī)端數(shù)組:連接句柄,座位號(hào)
         projector:[],       //PC端數(shù)組
         id:"12345678",
         startTime:Date.now(),
         maxplayer:2,        //最多座位數(shù)
         type:"ffffd"          //房間類型
       }
  }
};
2.webServer

如果您是nodejs的大神,或者在用koajs、express等nodejs框架,請(qǐng)?zhí)^本大節(jié)。因?yàn)槲矣迷膎odejs寫了一遍webServer,雖然重復(fù)造輪子不好,但是復(fù)習(xí)復(fù)習(xí)webServer的基本知識(shí),還是不錯(cuò)的,本節(jié)適合新手入門。
包含知識(shí)點(diǎn):header解析,靜態(tài)文件查找,gzip,文件hash計(jì)算,狀態(tài)碼。

2.1 目錄結(jié)構(gòu)
/API
    /funMap.js            /*http功能函數(shù)集合*/
    /xxx.js
/socketAPI
    /funMap.js          /*webSocket功能函數(shù)集合*/
    /xxx.js
/Util                    /*工具目錄,獲取本地IP,打開默認(rèn)瀏覽器*/
/webRoot
    /common             /*公共資源目錄*/
        /js
            /lib
        /css
    /m                  /*移動(dòng)端html,js,css等*/
    /p                  /*PC端html,js,css等*/
/index.js                  /*入口文件*/
/config.js                /*配置文件,端口號(hào),ws最大數(shù)據(jù)包大小等*/
/socketServer.js        /*webSocket處理函數(shù)*/
/webServer.js           
    
2.2 webServer

基本規(guī)則是這樣的,搭建靜態(tài)服務(wù)器,靜態(tài)資源正常讀取返回,html文件用ejs渲染后返回。

由于ejs的原因,html文件并沒有被修改,但是渲染后的內(nèi)容被修改,比如,更改了ws的端口,但是html文件沒有修改。所以不能使用Last-Modified來判斷是文件是否最新,而是要根據(jù)返回內(nèi)容有沒有被改變來判斷,所以要用Etag。

Etag需要根據(jù)內(nèi)容算出hash值,一般用md5計(jì)算。

返回內(nèi)容之前,需要進(jìn)行g(shù)zip壓縮,用來節(jié)省帶寬。90KB的jquery.min.js可以被gzip到30KB,壓縮才是王道。

因?yàn)槭謾C(jī)端和PC端執(zhí)行的是完全不同的代碼,所以要判斷從客戶端傳過來的user-agent是否包含Mobile字符串,以來區(qū)分客戶端是PC還是手機(jī),以便返回正確的資源。

通過簡(jiǎn)單的約定,來區(qū)分靜態(tài)文件和REST請(qǐng)求

    if (libPath.extname(pathName) == "") {
      //如果路徑?jīng)]有擴(kuò)展名 
      if(params.length<=2){
        pathName += "/"; //訪問根目錄 
      }else if(params[1]=="api"){   //訪問以api開頭
        parseAPI(params,req,res);  //功能函數(shù)
        return ;
      }else{
        pathName = params[1]+".html";
      }
    }

我在這里做了一個(gè)簡(jiǎn)單的框架,在API目錄或者socketAPI目錄下新增js文件,一個(gè)js文件對(duì)應(yīng)一個(gè)處理函數(shù),然后在funMap.js中聚合為一個(gè)Map,方便查找函數(shù),也容易隔離和修改函數(shù)名。

var funMap = {
  "room":require("./room"),
  "changeName":require("./xxx"),
  "changeName2":require("./xxxyyy")
};
module.exports = funMap;

客戶端訪問時(shí)就可以通過 /api/[functionName] 來訪問想要的服務(wù)了。

3 webSocketServer

nodejs本身并沒有提供webSockerServer的模塊,所以需要另外安裝一個(gè)。

在npm install的時(shí)候會(huì)安裝一個(gè)ws模塊,require("ws") 就可以用了。用法與http模塊相似,都用 createServer({options},MainHandlerFunction) 創(chuàng)建服務(wù),只是ws多了幾個(gè)參數(shù)。

主要是port,注意不要和webserver端口重復(fù)。
還有一個(gè) maxPayload 就是單個(gè)ws數(shù)據(jù)包最大大小,單位是bytes,自己估計(jì)項(xiàng)目傳輸數(shù)據(jù)時(shí)候數(shù)據(jù)包大小。默認(rèn)值是65535 即 64KB。一般webSocket用于小包傳輸,不用太大,我設(shè)置了1024 , 1KB。

主處理函數(shù)MainHandlerFunction,在有客戶端連接進(jìn)來時(shí)會(huì)傳入一個(gè)參數(shù)connection,這個(gè)對(duì)象內(nèi)容非常豐富,不看手冊(cè),可以打印出來也慢慢研究。
成功建立連接的方法就是要connection綁定message方法。

由于wsSocket訪問是可以帶著url的,所以我們可以用url隔離不同的功能函數(shù),而不是去解析message主體。

var connectHandler = function(connection){
  // :4002/api/Function1 
  var URIarray = connection.upgradeReq.url.split("/")
  if(funMap[URIarray[2]]){
    funMap[URIarray[2]](connection);
  }else{
    connection.send("{err:Function Not Found!!}");
  }
}
3.1 消息,廣播,保活

每當(dāng)有ws連接進(jìn)來,都有類似文件描述符的id來區(qū)分每個(gè)不同的連接。
connection._ultron.id 用它可以區(qū)分自己與別人的連接,很有用。

//消息格式
function msgPack(){
  return JSON.stringify({
    "who":arguments[0],      // Mobile , PC
    "place":arguments[1],    // 座位
    "dowhat":arguments[2],   // "connect","ready","message","lost"
    "content":arguments[3]||"" // 內(nèi)容
  })
} 

//以room為單位廣播,廣播房間內(nèi)所有角色
function boradCast(room,msg,ignore){
  room.projector.forEach(function(item,index){
    if(ignore&&ignore._ultron.id===item.socket._ultron.id){
      // console.log("ignore!!!")
      // 忽略自己不發(fā)送給自己
    }
    else{
      try{
        item.socket.send(msg);
      }catch(e){
        console.log(e);
      }
    }
  });
  room.player.forEach(function(item,index){
    if(ignore&&ignore._ultron.id===item.socket._ultron.id){
      // console.log("ignore!!!")
      // 忽略自己不發(fā)送給自己
    }
    else{
      try{
        item.socket.send(msg);
      }catch(e){
        console.log(e);
      }
    }
  });
}

為了檢查客戶端是否掉線,在建立連接時(shí)手動(dòng)加入?;顧C(jī)制,方法很簡(jiǎn)單:
給客戶端發(fā)送空消息時(shí)lastkeeplife為1,只要客戶端返回任意消息,那么更新lastkeeplife為0,如果5秒之內(nèi),沒有任何回復(fù)判定為掉線。
如果客戶端掉線,那么關(guān)閉連接,從連接池中移除。并廣播掉線消息給房間內(nèi)其他角色。

  var keeplifeHandler = setInterval(function(){
    if(lastkeeplife == 0){
      connection.close();
      connection.emit("close");
      clearInterval(keeplifeHandler);
    }
    try{
      lastkeeplife = 0;
      connection.send("{}");
    }catch(e){
      console.log("keep live error! "+ e +"

");
      connection.close();
      connection.emit("close");
      clearInterval(keeplifeHandler);
    }
  },5000)

  connection.on("close",function(msg){
      if(keeplifeHandler){  //關(guān)閉?;钛h(huán)
        clearInterval(keeplifeHandler);
      }
      console.log("close!",roomid,place);
      var room = global.ShareMem.rooms[roomid];
      if(!room)
        return;
      
      //從連接池移除連接句柄
      if(platform === PC){
          room.projector.forEach(function(item,index){
              if(item.socket === connection){
                  room.projector.splice(index,1);
                  return false;
              }
          })
      }else{
          room.player.forEach(function(item,index){
              if(item.socket === connection){
                  room.player.splice(index,1);
                  return false;
              }
          })
      }
      //發(fā)送掉線消息
      boradCast( room, msgPack(platform,place,"lost") , connection );
  });

iOS設(shè)備如果鎖屏,會(huì)發(fā)送斷開信息給服務(wù)器,而安卓不會(huì)。想要斷開鏈接,必須等到默認(rèn)120秒超時(shí)后關(guān)閉。
ws初始化時(shí)并沒有提供初始化timeout的配置。通過修改
ws._server.timeout = 1000;//1秒超時(shí)
并不會(huì)生效。問題來了,怎么修改才能設(shè)置超時(shí)時(shí)間呢?

目前只能用上述比較捉急的方法來及時(shí)斷開掉線設(shè)備。

最后

多屏互動(dòng)已經(jīng)不是新鮮的東西了,我做這個(gè)Demo還是受chrome實(shí)驗(yàn)室一個(gè)叫做【光劍出鞘】的項(xiàng)目的啟發(fā)。因?yàn)轶w驗(yàn)時(shí)需要手機(jī)端和PC同時(shí)翻-墻,導(dǎo)致體驗(yàn)差,然后自己才想做一個(gè)。做出來的時(shí)候感覺好酷炫,好神奇,好興奮。
后續(xù)還是有很多可以拓展和改進(jìn)的,希望最終可以變?yōu)橐粋€(gè)成熟的產(chǎn)品,而不是僅僅止步于Demo。

相關(guān)閱讀

無需Flash實(shí)現(xiàn)圖片裁剪——HTML5中級(jí)進(jìn)階

5個(gè)提高Node.js應(yīng)用性能的技巧

瀏覽器存儲(chǔ)及使用

作者信息
作者來自力譜宿云 LeapCloud 團(tuán)隊(duì)_UX成員:王詩詩 【原創(chuàng)】
首發(fā)地址:https://blog.maxleap.cn/archi...

王詩詩,前端新人,專職前端工作兩年。曾供職于AMI做底層軟件開發(fā)。喜歡分析H5代碼,追崇用簡(jiǎn)單的CSS,構(gòu)建精美動(dòng)效,做前端之前,這些是業(yè)余愛好?,F(xiàn)任職于MaxLeap UX 組,負(fù)責(zé)MaxWon 的開發(fā)和維護(hù)?,F(xiàn)熱衷于Real-time WebApp。

歡迎關(guān)注微信訂閱號(hào):MaxLeap_yidongyanfa

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/87810.html

相關(guān)文章

  • 無需Flash錄視頻——HTML5中級(jí)進(jìn)階

    摘要:比如就會(huì)報(bào)出警告,并執(zhí)行出錯(cuò)。視頻的寬高,并不會(huì)因?yàn)樘顚懙臄?shù)值比例不合法而失真。通過綁定事件,來獲取視頻片段數(shù)據(jù),并在內(nèi)存中累積。執(zhí)行之后會(huì)停止觸發(fā)事件。錄制結(jié)束后,把累計(jì)的片段數(shù)據(jù)保存為對(duì)象,并從瀏覽器下載存為視頻文件。 前言 HTML5的權(quán)限越來越大了,瀏覽器可以直接調(diào)用攝像頭、麥克風(fēng)了,好激動(dòng)啊。我們要用純潔的HTML代碼造出自己的天地。 視頻采集 本篇介紹的栗子 都是在chro...

    Cruise_Chan 評(píng)論0 收藏0
  • 投屏類H5應(yīng)用開發(fā)分析

    摘要:最近公司設(shè)計(jì)了一款基于自己產(chǎn)品的投屏類應(yīng)用,能夠使得用戶通過我們的產(chǎn)品平臺(tái)來設(shè)計(jì)啟用用于投屏功能的頁面,實(shí)現(xiàn)留言互動(dòng)等功能。使用場(chǎng)景投屏類應(yīng)用操作簡(jiǎn)便,用戶僅需要填寫簡(jiǎn)單信息便可實(shí)現(xiàn)上墻服務(wù),進(jìn)行活動(dòng)現(xiàn)場(chǎng)創(chuàng)意互動(dòng),點(diǎn)燃現(xiàn)場(chǎng)情緒。 最近公司設(shè)計(jì)了一款基于自己產(chǎn)品的投屏類H5應(yīng)用,能夠使得用戶通過我們的產(chǎn)品平臺(tái)來設(shè)計(jì)啟用用于投屏功能的H5頁面,實(shí)現(xiàn)留言互動(dòng)等功能。整體的實(shí)現(xiàn)和用戶體驗(yàn)都是基...

    hss01248 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<