这个问题是谷歌搜索“svg圆角路径”的第一个结果。Phrogz 的使用建议stroke
有一些限制(即,我不能将笔画用于其他目的,并且必须根据笔画宽度校正尺寸)。
Jlange 建议使用曲线更好,但不是很具体。我最终使用二次贝塞尔曲线来绘制圆角。考虑这张在相邻边缘上标有蓝点和两个红点的角的图片:
这两行可以用L
命令来完成。要将这个尖角变成一个圆角,从左边的红点开始画一条曲线(M x,y
用来移动到那个点)。现在,二次贝塞尔曲线只有一个控制点,您必须将其设置在蓝点上。将曲线的终点设置在右侧的红点。由于两个红点处的切线与前面的线的方向一致,您将看到流畅的过渡,“圆角”。
现在继续圆角之后的形状,可以通过在两个角之间的线上设置控制点来实现贝塞尔曲线中的直线。
为了帮助我确定路径,我编写了这个接受边缘和半径的 Python 脚本。矢量数学使这实际上非常容易。输出的结果图像:
#!/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)