使用H5 canvas繪製的可交互扇形javascript
現有動畫實現方式的不足css
setTimeout
和setInterval
都不十分精確。爲它們傳入的第二個參數,實際上只是指定了把動畫代碼添加到瀏覽器UI線程隊列中以等待執行的時間。若是隊列前面已經加入了其餘任務,那動畫代碼就要等前面的任務完成後再執行。html
css3動畫有侷限性,好比不是全部屬性都能參與動畫、動畫緩動效果太少、沒法徹底控制動畫過程等。java
requestAnimationFrame()的優點css3
它告訴瀏覽器某些JavaScript代碼將要執行動畫,瀏覽器能夠再運行某些代碼後進行適當的優化,十分精確,沒有css3的侷限問題,可對全部屬性操做,動畫緩動效果能夠依據緩動公式,十分豐富。web
requestAnimationFrame()
就是爲了繪製canvas而生,再合適不過了。canvas
代碼實現數組
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame; function updateProgress() { var div = document.getElementById("status"); div.style.width = (parseInt(div.style.width, 10) + 5) + "%"; if(div.style.left != "100%") { requestAnimationFrame(uploadProgress); } } requestAnimationFrame(uploadProgress);
這裏展現高級瀏覽器版本,兼容版請自行google。瀏覽器
當初學習的時候的文章找不到了,大體的理解是:時間間隔一直,每一個間隔運行的距離不一樣。css3動畫
//iteration當前執行次數 //startValue執行開始的位置 //changeValue須要執行到的最終位置 //totalIterations須要執行的總次數 easing.easeOutBounce(iteration, startValue, changeValue, totalIterations);
看上面的參數能瞭解到,easing產生的是與直線的偏移,iteration表示的是偏移的延續,totalIterations表示的動畫進行速度,startValue表示的是偏移的起始,changeValue表示的是偏移的量。
用到的一些canvas方法:
fillRect():在畫布上繪製的矩形會填充指定顏色,由fillStyle屬性指定
strokeRect():在畫布上繪製的矩形會使用指定的顏色描邊,由strokeStyle屬性指定
clearRect():清除畫布上的矩形區域
arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x, y)爲圓心繪製一條弧線,弧線半徑爲radius,起始和結束角度(用弧度表示)分別爲startAngle和endAngle。最後一個參數表示是否按逆時針方向計算,值爲false表示順時針方向計算
lineTo(x, y):從上一點開始繪製一條直線,到(x, y)爲止
drawImage(image, x, y, width, height):繪製圖像到畫布上,參數有3種,不一一介紹
save()與restore():保存上下文環境,操做...,恢復上次保存的上下文環境
這裏只用到了這些,其餘方法之後再介紹
爲了能更酷炫點,再加上css3的3D翻轉效果
transform-style:指定嵌套元素如何在3D空間中呈現。它主要有兩個屬性值:flat和preserve-3d,它自己須要設置在父元素中,若是設置了transform-style值爲preserve-3d,就不能設置overflow值爲hidden
perspective:設置查看者的位置,並將可視內容映射到一個視錐上,繼而投到一個2D視平面上,就是視距
perspective-origin:決定perspective屬性的源點角度
transition:過渡效果
translateZ():使一個元素在三維空間移動
rotateY():指定一個元素圍繞Y軸旋轉,旋轉的量被定義爲指定的角度;若是值爲正值,元素圍繞Y軸順時針旋轉;反之,若是值爲負值,元素圍繞Y軸逆時針旋轉
這裏只用到了這些,不作詳細介紹,太多了...
準備工做先進行到這裏,接下來進行本例的講解。
參數數組
value:所佔比重,百分之幾
color:選中時顏色
highlight:選中時鼠標懸停時顏色
grey:未選中時顏色
greylight:未選中時鼠標懸停時顏色
我本身設置傳入的參數:
var pieData = [ { value: 0.32, color:"#E8264b", highlight: "#FF0049", grey: "#5B5B5B", greylight: "#333" }, { value: 0.13, color: "#E64261", highlight: "#FF5A5E", grey: "#666", greylight: "#333" }, { value: 0.13, color: "#E05070", highlight: "#FF5A5E", grey: "#727272", greylight: "#444" }, { value: 0.1, color: "#E05D7D", highlight: "#FF5A5E", grey: "#7F7F7F", greylight: "#444" }, { value: 0.09, color: "#DB7691", highlight: "#FF5A5E", grey: "#8E8E8E", greylight: "#666" }, { value: 0.09, color: "#D6829C", highlight: "#FF5A5E", grey: "#999", greylight: "#666" }, { value: 0.07, color: "#D497AA", highlight: "#FF5A5E", grey: "#A5A5A5", greylight: "#666" }, { value: 0.07, color: "#D497AA", highlight: "#FF5A5E", grey: "#A5A5A5", greylight: "#666" } ];
繪製圓盤
function drawing (ctx, i) {//傳入canvas的context startValue = endValue;//每一個扇形開始繪製的位置 endValue = startValue + Math.PI * pieData[i].value * 2;//每一個扇形結束繪製的位置 ctx.beginPath();//開始繪製 ctx.arc(225, 225, radiusBig, startValue, endValue, false);//繪製扇形的弧線 ctx.lineTo(225,225);//繪製扇形連接圓心的兩條直線 ctx.lineWidth = 2;//設置線的寬度 ctx.closePath();//結束繪製 ctx.fillStyle = pieData[i].grey;//設置扇形顏色 ctx.strokeStyle = "#fff";//設置線的顏色 ctx.fill();//填充 ctx.stroke();//描邊 }
繪製文字及其位置
putIcon()用來計算繪製位置,r爲半徑,θ爲角度,x = r + r sinθ, y = r - r cosθ,left和top的值爲x和y。
(先寫在這,本人不會畫圖,等學會再來畫)
function drawThing(ctx) { var i = 0; var icon = undefined; for( ; i < pieLen ; i++ ) { drawing(ctx, i); } for(i = 0 ; i < pieLen ; i++ ) { if( !effects[i].clicked ) { icon = putIcon(i, 225, 140); ctx.font = "bold 30px Arial"; ctx.textAlign = "center"; ctx.fillStyle = "#fff"; ctx.fillText(i + 1, icon.x, icon.y); } } } function putIcon(count, radiusW, radiusN) { var values = angle = i = 0; for( ; i < count; i++) { values += pieData[i].value; } angle = Math.PI * 2 * (values + pieData[count].value / 2); return { x: Math.floor(radiusW + Math.sin(angle) * radiusN), y: Math.floor(radiusW - Math.cos(angle) * radiusN) } }
肯定交互區域
肯定交互區域本人的思路是獲取鼠標在視口上的(x ,y),再將這個點是不是可交互區域,能耗可能會比較大,沒想到更好的作法,不過看到css3的clip-path屬性能夠實現相似效果,以後會研究下。
首先肯定點擊區域爲外層大圓與內層小圓之間,公式:(x - r) (x - r) + (y - r) (y - r) = r * r;
直線方程:(x - x1)/(x2 - x1) = (y - y1)/(y2 - y1);
兩點便可判斷一條直線,先肯定圓心點(r, r),再根據角度肯定直線與圓交點(r + r sinθ, y = r - r cosθ)
獲得的直線方程爲:y = (x - r) (-r cosθ) / (r * sinθ) + r;
相鄰兩條直線創建二元一次不等式組,便可肯定中間區域;
動畫緩動
將easing與requestAnimationFrame()的結合使用,這是實現掉落效果的動畫
function clickThing (ctx, i) { var iteration = 0; var totalIterations = 30; var backX, backY; var icon = putIcon(i, 225, 140, true); var ty = icon.y - 25; //當即執行的遞歸方法 (function miniIcon () { ctx.clearRect(0, 0, 500, 500); backY = easing.easeOutBounce(iteration, ty, 25, totalIterations); ctx.font = "bold 30px Arial"; ctx.textAlign = "center"; ctx.fillStyle = "#fff"; ctx.fillText(i + 1, icon.x, backY); if(iteration < totalIterations) { iteration++; requestAnimationFrame(function () { miniIcon(); }); } })(); }
使用css3實現3D翻轉效果
最外層設置視距perspective: 2000px;perspective-origin:right top;
父級設置transition: all 0.7s ease-out;transform-style: preserve-3d;子級設置left和top爲自身高寬的一半,使圓心位置爲翻轉中心點,back-c爲背面,front-c爲正面,改變rotatey(0deg)爲rotatey(-180deg)表示從正面翻轉180度到背面,反之亦然,translateZ()在這裏用來表示層疊關係,一層蓋在另外一層上面。
.wrap { perspective: 2000px; perspective-origin:right top; position: relative; width: 450px; height: 450px; } .wrap .wrap-box { transition: all 0.7s ease-out; transform-style: preserve-3d; position: absolute; top: 50%; left: 50%; } #back-c { position: absolute; top: -225px; left: -225px; transform: translateZ(1px) rotatey(0deg); } #white-c { position: absolute; top: -225px; left: -225px; transform: translateZ(-2px) rotatey(0deg); } #front-c { position: absolute; top: -225px; left: -225px; transform: translateZ(-1px) rotatey(-180deg); }
html內容
寫了不少canvas,white-c是翻轉以後蓋在上面的白色小圓,每次繪製都要畫一次,因此拿出來減小能耗,text-c也是出於這個緣由,text-c用來繪製小動畫,line-c是拿出來當觸發器用的,不必單拎出來,只是想區分用途纔拿出來的。
<div class="content"> <div class="wrap"> <div class="wrap-box"> <canvas id="back-c" height="450" width="450"></canvas> <canvas id="front-c" height="450" width="450"></canvas> <canvas id="white-c" height="450" width="450"></canvas> </div> </div> <canvas id="text-c" height="450" width="450"></canvas> <canvas id="line-c" height="450" width="450"></canvas> </div>
花了點時間看了下本身的代碼,找尋下迷失的本身,繼續啓程。
感興趣的看官點擊這裏:coding:circle
本文轉載自筆者的我的博客:Gaoxuefeng's Blog