SVG rounded corner

前端 未结 12 2058
谎友^
谎友^ 2020-11-28 22:21

I have the following SVG:



        
12条回答
  •  無奈伤痛
    2020-11-28 22:43

    I've happened upon this problem today myself and managed to solve it by writing a small JavaScript function.

    From what I can tell, there is no easy way to give a path element in an SVG rounded corners except if you only need the borders to be rounded, in which case the (CSS) attributes stroke, stroke-width and most importantly stroke-linejoin="round" are perfectly sufficient.

    However, in my case I used a path object to create custom shapes with n corners that are filled out with a certain color and don't have visible borders, much like this:

    I managed to write a quick function that takes an array of coordinates for an SVG path and returns the finished path string to put in the d attribute of the path html element. The resulting shape will then look something like this:

    Here is the function:

    /**
     * Creates a coordinate path for the Path SVG element with rounded corners
     * @param pathCoords - An array of coordinates in the form [{x: Number, y: Number}, ...]
     */
    function createRoundedPathString(pathCoords) {
        const path = [];
        const curveRadius = 3;
    
        // Reset indexes, so there are no gaps
        pathCoords = pathCoords.slice();
    
        for (let i = 0; i < pathCoords.length; i++) {
    
          // 1. Get current coord and the next two (startpoint, cornerpoint, endpoint) to calculate rounded curve
          const c2Index = ((i + 1) > pathCoords.length - 1) ? (i + 1) % pathCoords.length : i + 1;
          const c3Index = ((i + 2) > pathCoords.length - 1) ? (i + 2) % pathCoords.length : i + 2;
    
          const c1 = pathCoords[i];
          const c2 = pathCoords[c2Index],
          const c3 = pathCoords[c3Index];
    
          // 2. For each 3 coords, enter two new path commands: Line to start of curve, bezier curve around corner.
    
          // Calculate curvePoint c1 -> c2
          const c1c2Distance = Math.sqrt(Math.pow(c1.x - c2.x, 2) + Math.pow(c1.y - c2.y, 2));
          const c1c2DistanceRatio = (c1c2Distance - curveRadius) / c1c2Distance;
          const c1c2CurvePoint = [
            ((1 - c1c2DistanceRatio) * c1.x + c1c2DistanceRatio * c2.x).toFixed(1),
            ((1 - c1c2DistanceRatio) * c1.y + c1c2DistanceRatio * c2.y).toFixed(1)
          ];
    
          // Calculate curvePoint c2 -> c3
          const c2c3Distance = Math.sqrt(Math.pow(c2.x - c3.x, 2) + Math.pow(c2.y - c3.y, 2));
          const c2c3DistanceRatio = curveRadius / c2c3Distance;
          const c2c3CurvePoint = [
            ((1 - c2c3DistanceRatio) * c2.x + c2c3DistanceRatio * c3.x).toFixed(1),
            ((1 - c2c3DistanceRatio) * c2.y + c2c3DistanceRatio * c3.y).toFixed(1)
          ];
    
          // If at last coord of polygon, also save that as starting point
          if (i === pathCoords.length - 1) {
            path.unshift('M' + c2c3CurvePoint.join(','));
          }
    
          // Line to start of curve (L endcoord)
          path.push('L' + c1c2CurvePoint.join(','));
          // Bezier line around curve (Q controlcoord endcoord)
          path.push('Q' + c2.x + ',' + c2.y + ',' + c2c3CurvePoint.join(','));
        }
        // Logically connect path to starting point again (shouldn't be necessary as path ends there anyway, but seems cleaner)
        path.push('Z');
    
        return path.join(' ');
    }
    

    You can determine the rounding strength by setting the curveRadius variable at the top. The default is 3 for a 100x100 (viewport) coordinate system, but depending on the size of your SVG, you may need to adjust this.

提交回复
热议问题