canvas水球動畫

yakelande發表於2018-04-09
    toBalling = () => {
        // 水球
        let canvas = this.refs.c;
        let ctx = canvas.getContext("2d");
        let waterBallValue = this.state.waterBallValue;//水球上顯示的數值
        let M = Math;
        let Sin = M.sin;
        let Cos = M.cos;
        let Sqrt = M.sqrt;
        let Pow = M.pow;
        let PI = M.PI;
        let Round = M.round;

        let oW = canvas.width = 300;
        let oH = canvas.height = 300;

// 線寬
        let lineWidth = 4;

// 大半徑
        let r = (oW / 2);
        let cR = r - 8 * lineWidth;

        ctx.beginPath();

        ctx.lineWidth = lineWidth;

// 水波動畫初始引數
        let axisLength = 2 * r - 16 * lineWidth;  // Sin 圖形長度
        let unit = axisLength / 8; // 波浪寬
        let range = .2 // 浪幅
        let nowrange = range;
        let xoffset = 8 * lineWidth; // x 軸偏移量
        let data = ~~waterBallValue / 100;   // 資料量
        let sp = 0; // 週期偏移量
        let nowdata = 0;
        let waveupsp = 0.002; // 水波上漲速度

// 圓動畫初始引數
        let arcStack = [];  // 圓棧
        let bR = r - 8 * lineWidth;
        let soffset = -(PI / 2); // 圓動畫起始位置
        let circleLock = true; // 起始動畫鎖

// 獲取圓動畫軌跡點集
        for (var i = soffset; i < soffset + 2 * PI; i += 1 / (8 * PI)) {
            arcStack.push([
                r + bR * Cos(i),
                r + bR * Sin(i)
            ])
        }

        let cStartPoint = arcStack.shift();  // 圓起始點

        ctx.strokeStyle = "#ffffff";//圓環的顏色
        ctx.moveTo(cStartPoint[0], cStartPoint[1])

        render();  // 開始渲染

        function drawSine() {
            ctx.beginPath();
            ctx.save();
            var Stack = []; // 記錄起始點和終點座標
            for (var i = xoffset; i <= xoffset + axisLength; i += 20 / axisLength) {
                var x = sp + (xoffset + i) / unit;
                var y = Sin(x) * nowrange;

                var dx = i;

                var dy = 2 * cR * (1 - nowdata) + (r - cR) - (unit * y);

                ctx.lineTo(dx, dy);
                Stack.push([dx, dy])
            }

            // 獲取初始點和結束點
            var startP = Stack[0]
            var endP = Stack[Stack.length - 1]

            ctx.lineTo(xoffset + axisLength, oW);
            ctx.lineTo(xoffset, oW);
            ctx.lineTo(startP[0], startP[1])
            ctx.fillStyle = "#506be9";//波浪的顏色
            ctx.fill()
            ctx.restore();
        }

        function drawText() {
            ctx.globalCompositeOperation = 'source-over';

            var size = 0.4 * cR;
            ctx.font = size + 'px Microsoft Yahei';

            let txt = (nowdata.toFixed(2) * 100).toFixed(0);

            var fonty = r + size / 2;
            var fontx = r - size * 0.8;
            ctx.fillStyle = "white";//水波字型顏色
            ctx.fillText(txt, fontx, fonty)
        }

        function render() {
            ctx.clearRect(0, 0, oW, oH);

            if (circleLock) {
                if (arcStack.length) {
                    var temp = arcStack.shift();
                    ctx.lineTo(temp[0], temp[1])
                    ctx.stroke();
                } else {
                    circleLock = false;
                    ctx.lineTo(cStartPoint[0], cStartPoint[1])
                    ctx.stroke();
                    arcStack = null;

                    ctx.globalCompositeOperation = 'destination-over';
                    ctx.beginPath();
                    ctx.lineWidth = lineWidth;
                    ctx.arc(r, r, bR, 0, 2 * PI, 1);

                    ctx.beginPath();
                    ctx.save();
                    ctx.arc(r, r, r - 16 * lineWidth, 0, 2 * PI, 1);
                    ctx.restore();
                    ctx.clip();

                    ctx.fillStyle = "#1c86d1";

                }
            } else {
                // 開始水波動畫
                // 控制波幅
                if (data >= 0.85) {
                    if (nowrange > range / 4) {
                        var t = range * 0.01;
                        nowrange -= t;
                    }
                } else if (data <= 0.1) {
                    if (nowrange < range * 1.5) {
                        var t = range * 0.01;
                        nowrange += t;
                    }
                } else {
                    if (nowrange <= range) {
                        var t = range * 0.01;
                        nowrange += t;
                    }

                    if (nowrange >= range) {
                        var t = range * 0.01;
                        nowrange -= t;
                    }
                }

                if ((data - nowdata) > 0) {
                    nowdata += waveupsp;
                }

                if ((data - nowdata) < 0) {
                    nowdata -= waveupsp
                }

                sp += 0.07;
                drawSine();
                drawText();
            }
            requestAnimationFrame(render)
        }

        // 水球end
    };
<canvas id="c" ref="c">當前瀏覽器不支援canvas 請升級!</canvas>

相關文章