SVG圆角

时间:2012-04-16 16:27:34

标签: xml image svg vector-graphics

我有以下SVG:

<g>
  <path id="k9ffd8001" d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z" stroke="#808600" stroke-width="0" transform="rotate(0 0 0)" stroke-linecap="square" stroke-linejoin="round" fill-opacity="1" stroke-opacity="1" fill="#a0a700"></path>
  <path id="kb8000001" d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z" stroke="#808600" stroke-width="0" transform="rotate(0 0 0)" stroke-linecap="square" stroke-linejoin="round" fill-opacity="1" stroke-opacity="1" fill="url(#k9ffb0001)"></path>
</g>

我希望获得类似CSS的border-top-right-radiusborder-top-bottom-radius效果。

如何实现圆角效果?

14 个答案:

答案 0 :(得分:77)

以下是使用SVG路径创建圆角矩形的方法:

<path d="M100,100 h200 a20,20 0 0 1 20,20 v200 a20,20 0 0 1 -20,20 h-200 a20,20 0 0 1 -20,-20 v-200 a20,20 0 0 1 20,-20 z" />

<强>解释

m100,100: 移至点(100,100)

h200: 从我们所在的位置划出200px水平线

a20,20 0 0 1 20,20: 绘制一个半径为20px,半径为20px,顺时针方向的弧,到X轴和Y轴相差20px的点

v200: 从我们所在位置绘制一条200px的垂直线

a20,20 0 0 1 -20,20: 以20px X和Y半径(顺时针方向)绘制一个圆弧,其中X与-20px的差异和Y的20px差异轴

h-200: 从我们所在的地方画一条-200px的水平线

a20,20 0 0 1 -20,-20: 以20px X和Y半径(顺时针方向)绘制一个弧线,在X和-20px之间差异为-20px的点在Y轴

v-200: 从我们所在的地方画一条-200px的垂直线

a20,20 0 0 1 20,-20: 以20px X和Y半径(顺时针方向)绘制一个圆弧,在X和20px之间的差异为20px,差异为Y轴

z: 关闭路径

&#13;
&#13;
<svg width="440" height="440">
  <path d="M100,100 h200 a20,20 0 0 1 20,20 v200 a20,20 0 0 1 -20,20 h-200 a20,20 0 0 1 -20,-20 v-200 a20,20 0 0 1 20,-20 z" fill="none" stroke="black" stroke-width="3" />
</svg>
&#13;
&#13;
&#13;

答案 1 :(得分:44)

不确定为什么没有人发布实际的SVG答案。这是一个顶部有圆角(半径3)的SVG矩形:

<svg:path d="M0,0 L0,27 A3,3 0 0,0 3,30 L7,30 A3,3 0 0,0 10,27 L10,0 Z" />

这是移动到(M),线到(L),弧到(A),线到(L),弧到(A),线到(L),关闭路径(Z)。

逗号分隔的数字是绝对坐标。弧是使用指定弧的半径和类型的附加参数定义的。这也可以用相对坐标来完成(使用L和A的小写字母)。

这些命令的完整参考位于W3C SVG Paths页面,有关SVG路径的其他参考资料可在this article中找到。

答案 2 :(得分:37)

正如我在Applying rounded corners to paths/polygons的回答中所提到的,我在javascript中编写了一个例程,用于对SVG路径的角进行一般舍入,例如:http://plnkr.co/edit/kGnGGyoOCKil02k04snu

它可以独立于您可能拥有的任何笔触效果。要使用,请包含来自Plnkr的rounding.js文件,并像这样调用函数:

roundPathCorners(pathString, radius, useFractionalRadius)

结果将是圆角路径。

结果如下:

SVG Path Rounding Examples

答案 3 :(得分:24)

您已明确将stroke-linejoin设置为round,但将stroke-width明确设置为0,因此当然您将不会看到如果你没有中风可以圆角。

以下是通过笔划制作圆角的修改示例:
http://jsfiddle.net/8uxqK/1/

<path d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z"
      stroke-width="5"
      stroke-linejoin="round"
      stroke="#808600"
      fill="#a0a700" />

否则 - 如果你需要一个实际的圆形填充而不仅仅是一个圆润的脂肪笔触 - 你必须做@Jlange所说的并做一个实际的圆形。

答案 4 :(得分:19)

我还考虑使用提供<rect>rx属性的普通旧ry

MDN SVG docs&lt; - 注意第二个绘制的矩形元素

答案 5 :(得分:3)

这个问题是谷歌搜索“svg圆角路径”的第一个结果。 Phrogz建议使用stroke有一些限制(即,我不能将笔划用于其他目的,并且必须针对笔划宽度校正尺寸)。

Jlange建议使用曲线更好,但不是很具体。我最终使用二次Bézier曲线绘制圆角。考虑一张标有蓝点和相邻边缘两个红点的角落的图片:

corner of a figure marked blue with two points on the adjacent edges

可以使用L命令创建两行。要将此锐角转变为圆角,请从左侧红点开始绘制曲线(使用M x,y移动到该点)。现在,二次Bézier曲线只有一个控制点,您必须在蓝点上设置。将曲线的末端设置在右侧红点。由于两个红点处的切线位于前一行的方向,因此您将看到一个流畅的过渡,“圆角”。

现在要在圆角后继续形状,可以通过在两个角之间的线之间设置控制点来实现贝塞尔曲线中的直线。

为了帮助我确定路径,我编写了这个接受边和半径的Python脚本。矢量数学使这实际上非常容易。输出结果图像:

shape created from script output

#!/usr/bin/env python
# Given some vectors and a border-radius, output a SVG path with rounded
# corners.
#
# Copyright (C) Peter Wu <peter@lekensteyn.nl>

from math import sqrt

class Vector(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def sub(self, vec):
        return Vector(self.x - vec.x, self.y - vec.y)

    def add(self, vec):
        return Vector(self.x + vec.x, self.y + vec.y)

    def scale(self, n):
        return Vector(self.x * n, self.y * n)

    def length(self):
        return sqrt(self.x**2 + self.y**2)

    def normal(self):
        length = self.length()
        return Vector(self.x / length, self.y / length)

    def __str__(self):
        x = round(self.x, 2)
        y = round(self.y, 2)
        return '{},{}'.format(x, y)

# A line from vec_from to vec_to
def line(vec_from, vec_to):
    half_vec = vec_from.add(vec_to.sub(vec_from).scale(.5))
    return '{} {}'.format(half_vec, vec_to)

# Adds 'n' units to vec_from pointing in direction vec_to
def vecDir(vec_from, vec_to, n):
    return vec_from.add(vec_to.sub(vec_from).normal().scale(n))

# Draws a line, but skips 'r' units from the begin and end
def lineR(vec_from, vec_to, r):
    vec = vec_to.sub(vec_from).normal().scale(r)
    return line(vec_from.add(vec), vec_to.sub(vec))

# An edge in vec_from, to vec_to with radius r
def edge(vec_from, vec_to, r):
    v = vecDir(vec_from, vec_to, r)
    return '{} {}'.format(vec_from, v)


# Hard-coded border-radius and vectors
r = 5
a = Vector(  0,  60)
b = Vector(100,   0)
c = Vector(100, 200)
d = Vector(  0, 200 - 60)

path = []
# Start below top-left edge
path.append('M {} Q'.format(a.add(Vector(0, r))))

# top-left edge...
path.append(edge(a, b, r))
path.append(lineR(a, b, r))
path.append(edge(b, c, r))
path.append(lineR(b, c, r))
path.append(edge(c, d, r))
path.append(lineR(c, d, r))
path.append(edge(d, a, r))
path.append(lineR(d, a, r))

# Show results that can be pushed into a <path d="..." />
for part in path:
    print(part)

答案 6 :(得分:2)

我今天亲自遇到了这个问题,并通过编写一个小的JavaScript函数来解决了这个问题。

据我所知,如果只需要对边界进行圆角处理,那么没有简单的方法可以在svg圆角中提供路径元素除外,在这种情况下(CSS)属性 stroke stroke-width 和最重要的 stroke-linejoin =“ round” 都足够。

但是,在我的情况下,我使用路径对象来创建具有 n 个角的自定义形状,这些角填充有某种颜色并且没有可见的边框,就像这样:

enter image description here

我设法编写了一个快速函数,该函数接受svg路径的坐标数组,并返回完成的路径字符串以放入path html元素的 d 属性中。生成的形状将如下所示:

enter image description here

功能如下:

/**
* 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}, ...]
*/
createRoundedPathString (pathCoords) {
    const path = [];
    const curveRadius = 3;

    // Reset indexes, so there are no gaps
    pathCoords = pathCoords.filter(() => true);

    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],
            c2 = pathCoords[c2Index],
            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(' ');
}

您可以通过在顶部设置 curveRadius 变量来确定舍入强度。对于100x100(视口)坐标系,默认值为3,但是根据svg的大小,您可能需要对其进行调整。

答案 7 :(得分:1)

为了简化实现@ hmak.me的答案,这是一段注释过的React代码,用于生成圆角矩形。

const Rect = ({width, height, round, strokeWidth}) => {
    // overhang over given width and height that we get due to stroke width
    const s = strokeWidth / 2;

    // how many pixels do we need to cut from vertical and horizontal parts
    // due to rounded corners and stroke width
    const over = 2 * round + strokeWidth;

    // lengths of straight lines
    const w = width - over;
    const h = height - over;

    // beware that extra spaces will not be minified
    // they are added for clarity
    const d = `
        M${round + s},${s}
        h${w}
        a${round},${round} 0 0 1 ${round},${round}
        v${h}
        a${round},${round} 0 0 1 -${round},${round}
        h-${w}
        a${round},${round} 0 0 1 -${round},-${round}
        v-${h}
        a${round},${round} 0 0 1 ${round},-${round}
        z
    `;
    return (
        <svg width={width} height={height}>
            <path d={d} fill="none" stroke="black" strokeWidth={strokeWidth} />
        </svg>
    );
};

ReactDOM.render(
    <Rect width={64} height={32} strokeWidth={2} round={4} />,
    document.querySelector('#app'),
);

Jsfiddle link.

答案 8 :(得分:1)

对于我的情况,我需要将 path 的开始和结束设为半径:

enter image description here

使用 stroke-linecap: round; 我将其更改为我想要的:

enter image description here

答案 9 :(得分:0)

以下是标签的一些路径:

https://codepen.io/mochime/pen/VxxzMW

<!-- left tab -->
<div>
  <svg width="60" height="60">
    <path d="M10,10 
             a10 10 0 0 1 10 -10
             h 50   
             v 47
             h -50
             a10 10 0 0 1 -10 -10
             z"
      fill="#ff3600"></path>
  </svg>
</div>

<!-- right tab -->
<div>
  <svg width="60" height="60">
    <path d="M10 0   
             h 40
             a10 10 0 0 1 10 10
             v 27
             a10 10 0 0 1 -10 10
             h -40
             z"
      fill="#ff3600"></path>
  </svg>
</div>

<!-- tab tab :) -->
<div>
  <svg width="60" height="60">
    <path d="M10,40 
             v -30
             a10 10 0 0 1 10 -10
             h 30
             a10 10 0 0 1 10 10
             v 30
             z"
      fill="#ff3600"></path>
  </svg>
</div>

其他答案解释了机制。我特别喜欢hossein-maktoobian的答案。

笔中的路径首当其冲,可以修改值以适应任何所需的尺寸。

答案 10 :(得分:0)

我找到了一个解决方案,但这是一个 hacky ,因此它可能并不总是有效。我发现,如果您的圆弧(A或a)的值非常小,则会强制其在一个点上创建曲线,从而形成圆角……

<svg viewBox="0 0 1 0.6" stroke="black" fill="grey" style="stroke-width:0.05px;">
  <path d="M0.7 0.2 L0.1 0.1 A0.0001 0.0001 0 0 0 0.099 0.101 L0.5 0.5Z"></path>
</svg>

答案 11 :(得分:0)

这基本上与Proxy 2, README相同,但是压缩程度和简化程度更高。通过退回与拐角相邻的线的半径距离并将两端与贝塞尔曲线相连,该贝塞尔曲线的控制点位于原始拐角点。

function createRoundedPath(coords, radius, close) {
  let path = ""
  const length = coords.length + (close ? 1 : -1)
  for (let i = 0; i < length; i++) {
    const a = coords[i % coords.length]
    const b = coords[(i + 1) % coords.length]
    const t = Math.min(radius / Math.hypot(b.x - a.x, b.y - a.y), 0.5)

    if (i > 0) path += `Q${a.x},${a.y} ${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`

    if (!close && i == 0) path += `M${a.x},${a.y}`
    else if (i == 0) path += `M${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`

    if (!close && i == length - 1) path += `L${b.x},${b.y}`
    else if (i < length - 1) path += `L${a.x * t + b.x * (1 - t)},${a.y * t + b.y * (1 - t)}`
  }
  if (close) path += "Z"
  return path
}

答案 12 :(得分:-2)

<?php
$radius = 20;
$thichness = 4;
$size = 200;

if($s == 'circle'){
  echo '<svg width="' . $size . '" height="' . $size . '">';
  echo '<circle cx="' . ($size/2) . '" cy="' . ($size/2) . '" r="' . (($size/2)-$thichness) . '" stroke="black" stroke-width="' . $thichness . '" fill="none" />';
  echo '</svg>';
}elseif($s == 'square'){
  echo '<svg width="' . $size . '" height="' . $size . '">';
  echo '<path d="M' . ($radius+$thichness) . ',' . ($thichness) . ' h' . ($size-($radius*2)-($thichness*2)) . ' a' . $radius . ',' . $radius . ' 0 0 1 ' . $radius . ',' . $radius . ' v' . ($size-($radius*2)-($thichness*2)) . ' a' . $radius . ',' . $radius . ' 0 0 1 -' . $radius . ',' . $radius . ' h-' . ($size-($radius*2)-($thichness*2)) . ' a' . $radius . ',' . $radius . ' 0 0 1 -' . $radius . ',-' . $radius . ' v-' . ($size-($radius*2)-($thichness*2)) . ' a' . $radius . ',' . $radius . ' 0 0 1 ' . $radius . ',-' . $radius . ' z" fill="none" stroke="black" stroke-width="' . $thichness . '" />';
  echo '</svg>';
}
?>

答案 13 :(得分:-3)

您正在使用路径元素,为什么不直接给路径一个曲线?请参阅此处了解如何使用路径元素制作曲线:http://www.w3.org/TR/SVG/paths.html#PathDataCurveCommands