利用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