この質問は、グーグルの「svg丸めコーナーパス」の最初の結果です。使用するPhrogzの提案にstroke
は、いくつかの制限があります(つまり、ストロークを他の目的に使用できないこと、およびストロークの幅に合わせて寸法を修正する必要があること)。
曲線を使用するというJlangeの提案の方が優れていますが、あまり具体的ではありません。丸い角を描くために二次ベジェ曲線を使用することになりました。青い点と隣接するエッジ上の2つの赤い点でマークされたコーナーのこの写真を考えてみましょう。
このL
コマンドで2行を作成できます。この鋭い角を丸い角に変えるには、左の赤い点から曲線を描き始めます(M x,y
その点に移動するために使用します)。これで、2次ベジエ曲線には、青い点に設定する必要のある制御点が1つだけあります。曲線の終点を右の赤い点に設定します。2つの赤い点の接線が前の線の方向にあるため、「丸みを帯びた角」という滑らかな遷移が表示されます。
角を丸めた後も形状を継続するために、2つの角の間の線上に制御点を設定することにより、ベジェ曲線の直線を実現できます。
パスを決定するのに役立つように、エッジと半径を受け入れるこの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)
border-radius
とそのバリアントがSVGで機能しないのは残念です。