The principle of creating dynamic pie chart with path of svg

Keywords: Front-end angular IE


There are three steps:

  • Fan shaped
  • Draw a circle with a fan
  • Animating

The following three steps are detailed

Fan shaped

As mentioned in the previous article, the command of drawing arc is also used in the previous article. If you don't know clearly, you can go to my previous article: path application of svg , let's briefly mention it here

  • First, you need to draw a straight line from the center of the circle to a coordinate with a long radius.

    • In this step, we need to use a coordinate function. The first thing we need to solve is how to find coordinates. To find out the coordinates, we need to find them according to the angle. We need to know the center coordinates of the radius, give the angle, and find the coordinates.
                    function d2a(ang) {//Angular radian
                        return ang * Math.PI / 180;
                    }
                    
                    function point(ang) {//Coordinate according to angle
                        return {
                            x: cx + r * Math.sin(d2a(ang)),
                            y: cy - r * Math.cos(d2a(ang))
                        }
                    }
  • And then from the coordinates we get to, we call it the starting point, we call it the starting point, we call it the ending point.
  • Finally, the closed path leads to a sector.

Draw a circle with a fan

After drawing the sector, we can draw as many arcs as there are data, and finally draw a circle.
We can sum the data to get a total data, and then we can transfer each data * 360 / total data = the angle occupied by this data, which can be passed to the above point function to get the coordinates, and then draw the sector, and then cycle each data to draw the sector corresponding to the angle, and finally draw a circle.

Animating

The principle of animation is that if we change the length of the sector radius r, the mouse moves in R longer and out R shorter. It's just that in the process of changing again, we are not in place in one step, but complete it in many steps, for example, from 150 to 200, the middle distance is 50, we walk 1 at a time, and keep walking. When we stop, we will have animation effect.

Complete code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        window.onload = function () {
            let oSvg = document.getElementById('s1');

            let cx = 400, cy = 300, r = 200,  sum = 0;//Initial center radius
            let data = [140, 100, 110, 90, 170,125];//Data to draw a sector
            data.forEach(item => {//Find the sum of data
                sum += item; 
            })
            let now = 0;
            data.forEach(item => {//Circle drawing
                let ang = 360 * item / sum;
                pie(now, now + ang);
                now += ang;
            })
            function pie(ang1, ang2) {
                let oPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                oPath.setAttribute('stroke', 'white');
                oPath.setAttribute('fill', `rgb(${Math.floor(Math.random() * 256)},${Math.floor(Math.random() * 256)},${Math.floor(Math.random() * 256)})`);
                oPath.setAttribute('stroke-width', 2);

                function calcD(r) {
                    function d2a(ang) {//Angular radian
                        return ang * Math.PI / 180;
                    }
                    function point(ang) {//Coordinate according to angle
                        return {
                            x: cx + r * Math.sin(d2a(ang)),
                            y: cy - r * Math.cos(d2a(ang))
                        }
                    }
                    //Three steps to draw a fan                   
                    let arr = [];
                    //First step
                    let { x: x1, y: y1 } = point(ang1);
                    arr.push(`M ${cx} ${cy} L ${x1} ${y1}`);//Draw the first line
                    //The second step
                    let { x: x2, y: y2 } = point(ang2);
                    arr.push(`A ${r} ${r} 0 ${ang2 - ang1 > 180 ? 1 : 0} 1 ${x2} ${y2}`);//Arc drawing
                    //The third step
                    arr.push('Z');//Close

                    oPath.setAttribute('d', arr.join(' '));//Splicing strings, executing drawing commands
                    oSvg.appendChild(oPath);//Add to svg
                }
                //animation
                calcD(r);
                let fnNext=null;
                let curR=r;
                let size=40;

                function move(end){
                    let start=curR//starting point
                    let dis=end-start;//How far is it to go?
                    let count=0;//Pace taking
                    
                    fnNext=function(){
                        let a=1-count/size;//ratio
                        count++;//Step by step
                        curR=start+dis*(1-a*a*a);//Where to go now
                        calcD(curR);//Calculate and draw
                        if(count>=size){//Stop Animation if you get there
                            fnNext=null;
                        }
                    }
                }
                next();//Keep walking
                function next(){
                    fnNext&&fnNext();//If the fnNext function is reached, it will be null. Otherwise, continue.
                    requestAnimationFrame(next);
                }

                oPath.onmouseover = function () {
                    move(r * 1.2);//Move the mouse into the sector to enlarge
                }
                oPath.onmouseout = function () {
                    move(r);//Mouse out sector area recovery
                }
            }
        }
    </script>
</head>
<body>
    <svg id="s1" width=800 height=600></svg>
</body>
</html>

Posted by RottenBananas on Tue, 22 Oct 2019 18:15:27 -0700