H5扇形

使用H5 canvas繪製的可交互扇形javascript

requestAnimationFrame()

現有動畫實現方式的不足css

setTimeoutsetInterval都不十分精確。爲它們傳入的第二個參數,實際上只是指定了把動畫代碼添加到瀏覽器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。瀏覽器

caniuse1


easing緩衝動畫

當初學習的時候的文章找不到了,大體的理解是:時間間隔一直,每一個間隔運行的距離不一樣。css3動畫

//iteration當前執行次數
//startValue執行開始的位置
//changeValue須要執行到的最終位置
//totalIterations須要執行的總次數

easing.easeOutBounce(iteration, startValue, changeValue, totalIterations);

看上面的參數能瞭解到,easing產生的是與直線的偏移,iteration表示的是偏移的延續,totalIterations表示的動畫進行速度,startValue表示的是偏移的起始,changeValue表示的是偏移的量。


canvas方法

用到的一些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

爲了能更酷炫點,再加上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;

相鄰兩條直線創建二元一次不等式組,便可肯定中間區域;

circle3

動畫緩動

將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

相關文章
相關標籤/搜索