利用Canvas實現360度瀏覽
前言:最近幾個月來到新公司,主要從事移動端方面的開發,有時候也挺忙挺累的,于是就好一段時間沒寫博客了。其實自己在這幾個月里,自己對canvas以及createjs和egret都有了一定程度上的認識與掌握了,所以有挺多東西想總結一下的。趁著今天廣州下雪的日子,就寫點東西吧,先從簡單的demo開始吧。因為自己在走HTML5游戲方向,所以最近都在做小游戲。后續會再寫關于canvas和createjs的系列文章吧,畢竟國內的資料比較少。一旦愛上了canvas,我便逐漸嫌棄DOM了。
360度瀏覽效果
利用最簡單的多張圖片,讓產品實現360旋轉瀏覽效果。以往用DOM來實現圖片或者背景更換,是挺方便也容易,但是在移動端上面尤其安卓系統,流暢度真讓人堪憂。而且現在移動端基本上都支持canvas上下文2d,所以能用canvas實現的盡量避免使用DOM。當然,如果是數量或簡單少的動畫,還是用CSS3比較好。交互操作類的當下則非canvas莫屬。
準備工作:
首先是素材問題,圍繞商品的四周各拍幾張圖片,然后讓設計師重新修一下圖,最終分解成多張圖片素材。多則三四十張,小則十幾張,視情況而定。要說明的是,我這里用的只是替換圖片的方法實現仿3D旋轉,日后我會再寫一個僅需幾張圖片的3D全景瀏覽效果。
如圖所示(是不是很多,哈哈,簡單的方法實現肯定要犧牲點什么的,下次再寫另外的方法吧):
HTML+CSS:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no" /> 6 <title>360度旋轉瀏覽</title> 7 <style type="text/css"> 8 *{ 9 margin: 0; 10 padding: 0; 11 } 12 body,html{ 13 width: 100%; 14 height: 100%; 15 overflow: hidden; 16 } 17 .loading{ 18 position: absolute; 19 width: 100%; 20 height: 100%; 21 left: 0; 22 top: 0; 23 background-color: #888888; 24 z-index: 10; 25 } 26 .loading img{ 27 position: relative; 28 width: 32px; 29 height: 32px; 30 left: 50%; 31 top: 50%; 32 margin-left: -16px; 33 margin-top: -16px; 34 } 35 canvas{ 36 width: 100%; 37 height: 100%; 38 z-index: 100; 39 } 40 </style> 41 </head> 42 <body> 43 <div class="loading"> 44 <img src="img/loading.gif"/> 45 </div> 46 <canvas id="canvas" width="750" height="1254">你的瀏覽器太老啦,換瀏覽器啦!</canvas> 47 <script src="js/zepto.min.js"></script> 48 </body> 49 </html>
JavaScript:
1 var canvas = document.getElementById("canvas"), 2 DPR = window.devicePixelRatio,//獲取設備的物理像素比 3 viewW = window.innerWidth, 4 viewH = window.innerHeight, 5 cansW = viewW*DPR,//放大canvas 6 cansH = viewH*DPR, 7 ctx = canvas.getContext("2d"), 8 imgArr = [],//圖片數組 9 curDeg = 1,//代表當前顯示的圖片下標 10 imgTotal = 51,//圖片總數 11 imgRatio = (447/1000), //圖片高寬比 12 imgW = viewW*1.5,//圖寬 13 imgH = imgW*imgRatio;//圖高 14 15 //重設canvas寬高 16 //顯示的寬高 17 canvas.style.width = cansW + "px"; 18 canvas.style.height = cansH + "px"; 19 //畫布寬高 20 canvas.width = cansW; 21 canvas.height = cansH; 22 //loading 23 $(function(){ 24 var baseURL = "img/", 25 imgURL ="", 26 imgObj = null, 27 imgIndex = 1; 28 //loading 29 for(var i = 1;i <= imgTotal;i++){ 30 imgURL = baseURL + i + ".png"; 31 imgObj = new Image(); 32 imgObj.src = imgURL; 33 //將所有圖片對象壓入一個數組,方便調用 34 imgArr.push(imgObj); 35 imgObj.onload = function(){ 36 imgIndex ++; 37 if(imgIndex > 51){ 38 $(".loading").hide(); 39 //默認圖 40 drawImg(0); 41 } 42 } 43 } 44 //手指觸摸起點 45 var startPoint = 0, 46 //滑動多長距離,這里取(canvas寬/圖片總數的一半) 47 //數值越大約靈敏 48 distance = cansW/30; 49 //開始 50 $("#canvas").on({ 51 "touchstart":function(e){ 52 //記錄起始觸摸點 53 startPoint = e.touches[0].clientX; 54 //去掉默認事件,iPhone下可去除雙擊頁面默認跳動(翻頁)效果 55 e.preventDefault(); 56 }, 57 "touchmove":function(e){ 58 var tempPoint = e.touches[0].clientX; 59 //向右移動 60 if((tempPoint - startPoint) > distance){ 61 drawImg(curDeg,"right"); 62 //符合距離條件移動后,將記錄點設到手指最新位置 63 startPoint = tempPoint; 64 }else if((tempPoint - startPoint) < -distance){//左 65 drawImg(curDeg,"left"); 66 startPoint = tempPoint; 67 } 68 //禁止移動頁面 69 e.preventDefault(); 70 } 71 }); 72 }); 73 //繪圖 74 //參數:圖片對象下標,移動方向 75 function drawImg(n,type){ 76 if(type == "left"){ 77 if(curDeg > 0){ 78 curDeg--; 79 }else{ 80 curDeg = 50; 81 } 82 }else if(type == "right"){ 83 if(curDeg < 50){ 84 curDeg++; 85 }else{ 86 curDeg = 0; 87 } 88 } 89 ctx.clearRect(0,0,cansW,cansH); 90 //參數:圖片對象,X偏移量,Y偏移量,圖寬,圖高 91 ctx.drawImage(imgArr[n],-(imgW-viewW)*0.5,(viewH-imgH)*0.5,imgW,imgH); 92 }
代碼說明:
對于canvas,我還想說明的是,在移動端使用canvas畫布,一定要記得處理DPR,DPR全稱是 DevicePixelRatio (設備像素比)。意思是設備上物理像素和設備獨立像素(device-independent pixels (dips))的比例。也就是一個設備獨立像素(可以理解為CSS中的1px)相當于多少個物理像素。假如DPR=2,那么CSS中的1px就相當于設備物理像素的2px。但是在Canvas繪圖中,畫布大小跟可視區域大小是不一樣的。可視區域大小會根據DPR大小進行調整,但是畫布大小并不會。例如DPR=2,我在retina屏中設置canvas的可視寬高等于畫布寬高,那么畫布里的1px會在retina屏上以2px展示,所以會導致模糊現象。
關于DPR和view的參考文章: 移動前端開發之viewport的深入理解
所以為了解決模糊問題,我們需要根據DPR對畫布寬高進行調整,讓畫布大小等于物理像素大小。也就是把canvas的寬高變成對應的物理像素大小,然后把真正需要顯示的區域畫在屏幕位置,其余的隱藏掉。如圖所示:
另外,DPR通過window.devicePixelRatio即可獲取,基于webkit的瀏覽器都支持,IE不支持。
再者,這里的滑動我使用了原生方法touchstart和touchmove觸摸事件,通過記錄手指起點以及終點的X軸坐標大小判斷左右滑動。如果加入了zepto的TOUCH組件,則可以直接使用swipeLeft和swipeRight觸發(拖動使用drag),從而改變相應的圖片。
關于繪圖:
使用drawImage()方法繪圖,還要注意的是,一定要待圖片完全加載后才能進行繪圖,否則會報錯。
DEMO地址:
請使用移動設備或者谷歌瀏覽器的手機模式打開。
來自: http://www.cnblogs.com/chengguanhui/p/5155440.html