How to render a svg circle using start and endAngle

后端 未结 2 1823
生来不讨喜
生来不讨喜 2021-02-06 15:09

I have rendered the svg circle using start and endAngle. It was worked fine. But when i render the complete circle(startAngle as 70 and endAngle as 70) the output is huge differ

2条回答
  •  攒了一身酷
    2021-02-06 15:27

    This difference between the circles is due to the effects of numerical accuracy. Due to the way SVG arcs and floating point arithmetic works, minuscule changes in the start and end points can be exaggerated in the final arc. The bigger the angle that your arc spans, the more the effect comes into play.

    To draw the arc, the renderer needs to first determine the centre of the circle. If you try to make an arc of 360 degrees, your start and end points are going to be almost the same.

    Consider the following illustration:

    The green and red points are the start and end points of the arc. The grey point is the centre of the circle that the render calculates in order to draw the arc.

    The arc in the illustration represents roughly 359 degrees. Now imagine moving the red and the green points closer together. The calculation required to determine the centre point is going to become more and more susceptible to inaccuracies in the start and end coordinates and in the floating point arithmetic functions.

    Add to that the fact that the sin() and cos() functions are only approximations of the sin and cos curves. Remember that browser Javascript engines have to balance speed and accuracy.

    Then add to that the fact that most (if not all) SVG rendering engines approximate arcs using bezier curves. But beziers can not perfectly represent a circular arc.

    Hopefully you can now see why you are getting the results you are. Trying to represent large angles with a single arc is a bad idea. My personal recommendation is use at least three or four arcs for a full circle.

    function getPathArc(center, start, end, radius) {
      if (end == start) end += 360;
      var degree = end - start;
      degree = degree < 0 ? (degree + 360) : degree;
      var points = [];
      points.push( getLocationFromAngle(start, radius, center) );
      points.push( getLocationFromAngle(start+degree/3, radius, center) );
      points.push( getLocationFromAngle(start+degree*2/3, radius, center) );
      points.push( getLocationFromAngle(end, radius, center) );
      return this.getCirclePath(points, radius, (degree < 180) ? 0 : 1);
    }
    			
    function getCirclePath(points, radius, clockWise) {
      return ['M', points[0].x, points[0].y,
              'A', radius, radius, 0, 0, clockWise, points[1].x, points[1].y,
              'A', radius, radius, 0, 0, clockWise, points[2].x, points[2].y,
              'A', radius, radius, 0, 0, clockWise, points[3].x, points[3].y
             ].join(' ');
    }
    			
    function getLocationFromAngle(degree, radius, center) {
      var radian = (degree * Math.PI) / 180;
      return {
        x : Math.cos(radian) * radius + center.x,
        y : Math.sin(radian) * radius + center.y
      }
    }
    			
    document.getElementById("arc1").setAttribute("d", getPathArc({x:250,y:250}, 90, 90, 200));
    document.getElementById("arc2").setAttribute("d", getPathArc({x:250,y:250}, 70, 70, 200));
    
      
      
    

提交回复
热议问题