使用 canvas 为圆环图中的线条设置动画

Animate lines in a donut chart using a canvas

基本上,我尝试为圆环图中的线条设置动画(参见 example), so that each of them is counted up with document.ready. I tried to adopt the solution from and here

如您所见,countUp 解决方案已经运行良好,但它需要连接到图表,以便在页面加载时绘制。

我对 canvas 的了解并不惊人。如果有人能提供帮助,我会很高兴。这是代码:https://jsfiddle.net/9oyoh67x/10/

$(document).ready(function () {        
var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext('2d');
            console.log(ctx);
            ctx.lineWidth = 19;
            ctx.lineCap = 'round';
            ctx.shadowBlur = 10;
            donutChart(); 
            function degtoRad(degree) {
                var factor = Math.PI / 180; // = 1 deg = 0.01745 rad
                return degree * factor; // for 360 = 6.28 = 360°
            }

            /*function move() {
                var elem = document.getElementById("canvas");
                var width = 0;
                var id = setInterval(countUp, 1000); }
            */

            $(function () {
                var countUp = setInterval(function () { donutChart }, 40);
                function count($this) {
                    var current = parseInt($this.html(), 10);
                    $this.html(++current);
                    if (current !== $this.data('count')) {
                        setTimeout(function () { count($this) }, 50);
                    }
                }
                $(".testspan1").each(function () {
                    $(this).data('count', parseInt($(this).html(), 10));
                    $(this).html('0');
                    count($(this));
                });   
                 $(".testspan2").each(function () {
                    $(this).data('count', parseInt($(this).html(), 10));
                    $(this).html('0');
                    count($(this));
                });   
                 $(".testspan3").each(function () {
                    $(this).data('count', parseInt($(this).html(), 10));
                    $(this).html('0');
                    count($(this));
                });   
                 $(".testspan4").each(function () {
                    $(this).data('count', parseInt($(this).html(), 10));
                    $(this).html('0');
                    count($(this));
                });   
            });            

            function donutChart() {
                var factor_calc = Math.PI / 180;
                var record = $('.testspan1').text(); // equal to 100% or 360°
                var average = $('.testspan2').text();
                var income = $('.testspan2').text();
                var target = $('.testspan3').text();


                // Record
                ctx.strokeStyle = 'rgba(115, 100, 164, 1)';
                ctx.beginPath();
                ctx.arc(250, 250, 200, degtoRad(270), degtoRad(270 + (record / record) * 360));
                ctx.stroke();

                // Average
                ctx.strokeStyle = 'rgba(125, 131, 164, 1)';
                ctx.beginPath();
                ctx.arc(250, 250, 170, degtoRad(270), degtoRad(270 + (average / record) * 360));
                ctx.stroke();

                //Income
                ctx.strokeStyle = 'rgba(75, 181, 164, 1)';
                ctx.beginPath();
                ctx.arc(250, 250, 140, degtoRad(270), degtoRad(270 + (income / record) * 360));
                ctx.stroke();

                // Target
                ctx.strokeStyle = 'rgba(26, 221, 164, 1)';
                ctx.beginPath();
                ctx.arc(250, 250, 110, degtoRad(270), degtoRad(270 + (target / record) * 360));
                ctx.stroke();

                // Record
                ctx.font = "25px Philosopher";
                ctx.fillStyle = 'rgba(115, 100, 164, 1)';
                ctx.fillText(record, 220, 200);

                //Average
                ctx.font = "25px Philosopher";
                ctx.fillStyle = 'rgba(125, 131, 164, 1)';
                ctx.fillText(average, 220, 230);

                //Income
                ctx.font = "30px Philosopher";
                ctx.fillStyle = 'rgba(75, 181, 164, 1)';
                ctx.fillText(income, 220, 260);

                // Target
                ctx.font = "35px Philosopher";
                ctx.fillStyle = 'rgba(26, 221, 164, 1)';
                ctx.fillText(target, 220, 290);

                // Euro
                ctx.font = "60px Philosopher";
                ctx.fillStyle = 'rgba(26, 221, 164, 1)';
                ctx.fillText('€', 280, 255);
            }

            var options = {
                useEasing: true,
                useGrouping: true,
                separator: ',',
                decimal: '',
                prefix: '',
                suffix: '€'

            };
        });

HTML:

        <div class="canvasdiv">
        <canvas id="canvas" width="500" height="500"></canvas>
        <img id="myImage" />
        <span class='testspan1'>1250</span>
        <span class='testspan2'>250</span>
        <span class='testspan3'>450</span>
        <span class='testspan4'>130</span>
    </div>

对于有类似问题的人,这里有一些进一步的相关链接(不使用 canvas):

我做到了。这是我的解决方案 (https://jsfiddle.net/9oyoh67x/12/):

// requestAnimationFrame Shim
(function start() {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
})();

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
console.log(ctx);
ctx.lineWidth = 19;
ctx.lineCap = 'round';
ctx.shadowBlur = 10;
var record = 820; // equal to 100% or 360°
var record_count = (record / record * 100)
var average = (229 / record * 100);
var income = (490 / record * 100);
var target = (750 / record * 100);
var counterClockwise = true;
var circ = Math.PI * 2;
var quart = Math.PI / 2;
var startTime1 = null;
var startTime2 = null;
var startTime3 = null;
var startTime4 = null;
var duration = null;
var duration1 = null;
var duration2 = null;
var duration3 = null;
var duration4 = null;
var options = {
    useEasing: true,
    useGrouping: true,
    separator: ',',
    decimal: '0',
    prefix: '',
    suffix: ''
};


function animate_rec(time) {

    if (!startTime1) {
        startTime1 = time;
    }

    var delta1 = Math.min(1, (time - startTime1) / duration1);
    var curPerc = ((2 * Math.PI) / 100) * (record_count * delta1);
    console.log(curPerc)
    var innerNumRec = (record * delta1);
    //console.log(innerNumRec);

    ctx.strokeStyle = 'rgba(115, 100, 164, 1)';
    ctx.beginPath();
    ctx.arc(250, 250, 200, -quart, curPerc - quart);
    ctx.stroke();

    if (delta1 < 1) {
        requestAnimationFrame(animate_rec);
        ctx.clearRect(215, 180, 50, 30);
    } else {
        startTime1 = null;
        ctx.clearRect(215, 180, 50, 30);
    }



    // Record
    ctx.font = "25px Philosopher";
    ctx.fillStyle = 'rgba(115, 100, 164, 1)';
    ctx.fillText(Math.round(innerNumRec), 220, 200);
}

var startAnim_rec = function () {
    duration1 = 3000;
    requestAnimationFrame(animate_rec);
};

function animate_avg(time) {

    if (!startTime2) {
        startTime2 = time;
    }

    var delta2 = Math.min(1, (time - startTime2) / duration2);
    var curPerc = ((2 * Math.PI) / 100) * (average * delta2);
    var innerNumAvg = ((average * record / 100) * delta2);
    console.log(innerNumAvg);

    ctx.strokeStyle = 'rgba(125, 131, 164, 1)';
    ctx.beginPath();
    ctx.arc(250, 250, 170, -quart, curPerc - quart);
    ctx.stroke();

    if (delta2 < 1) {
        requestAnimationFrame(animate_avg);
        ctx.clearRect(215, 210, 70, 50);
    } else {
        startTime2 = null;
        ctx.clearRect(215, 210, 70, 50);
    }

    // Average
    ctx.font = "30px Philosopher";
    ctx.fillStyle = 'rgba(125, 131, 164, 1)';
    ctx.fillText(Math.round(innerNumAvg), 220, 230);

}

var startAnim_avg = function () {
    duration2 = 3200;
    requestAnimationFrame(animate_avg);
};

function animate_inc(time) {

    if (!startTime3) {
        startTime3 = time;
    }

    var delta3 = Math.min(1, (time - startTime3) / duration3);
    var curPerc = ((2 * Math.PI) / 100) * (income * delta3);
    var innerNumInc = ((income * record / 100) * delta3);
    console.log(innerNumInc);

    ctx.strokeStyle = 'rgba(75, 181, 164, 1)';
    ctx.beginPath();
    ctx.arc(250, 250, 140, -quart, curPerc - quart);
    ctx.stroke();

    if (delta3 < 1) {
        requestAnimationFrame(animate_inc);
        ctx.clearRect(215, 230, 70, 50);
    } else {
        startTime3 = null;
        ctx.clearRect(215, 230, 70, 50);
    }

    // Income
    ctx.font = "35px Philosopher";
    ctx.fillStyle = 'rgba(75, 181, 164, 1)';
    ctx.fillText(Math.round(innerNumInc), 220, 260);
}

var startAnim_inc = function () {
    duration3 = 3400;
    requestAnimationFrame(animate_inc);
};

function animate_tar(time) {
    if (!startTime4) {
        startTime4 = time;
    }

    var delta4 = Math.min(1, (time - startTime4) / duration4);
    var curPerc = ((2 * Math.PI) / 100) * (target * delta4);
    var innerNumTar = ((target * record / 100) * delta4);
    console.log(innerNumTar);

    ctx.strokeStyle = 'rgba(26, 221, 164, 1)';
    ctx.beginPath();
    ctx.arc(250, 250, 110, -quart, curPerc - quart);
    ctx.stroke();

    if (delta4 < 1) {
        requestAnimationFrame(animate_tar);
        ctx.clearRect(220, 260, 70, 50);
    } else {
        startTime4 = null;
        ctx.clearRect(220, 260, 70, 50);
    }

    // Target
    ctx.font = "40px Philosopher";
    ctx.fillStyle = 'rgba(26, 221, 164, 1)';
    ctx.fillText(Math.round(innerNumTar), 220, 290);
}

var startAnim_tar = function () {
    duration4 = 3600;
    requestAnimationFrame(animate_tar);
};

startAnim_rec();
startAnim_avg();
startAnim_inc();
startAnim_tar();

// Euro
ctx.font = "60px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText('€', 280, 255);});