it-roy-ru.com

SVG закругленный угол

У меня есть следующий 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-radius и border-top-bottom-radius.

Как я могу добиться такого эффекта закругления угла?

51
Danis

Я знаю, что уже поздно отвечать на этот вопрос, но, ради SO, вот как вы можете создать прямоугольник круглее с помощью SVG Path:

<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 X, радиусом Y 20px по часовой стрелке до точки с разницей в 20px по оси X и Y

v200: нарисуйте вертикальную линию 200px от того места, где мы находимся

a20,20 0 0 1 -20,20: нарисовать дугу с радиусом X и Y 20px по часовой стрелке до точки с разницей в -20px и разницей в 20px по оси Y

h-200: нарисуем горизонтальную линию -200px от того места, где мы находимся

a20,20 0 0 1 -20, -20: нарисовать дугу с радиусом X и Y 20px по часовой стрелке до точки с разницей в -20px и разностью -20px по оси Y

v-200: нарисовать вертикальную линию -200px от того места, где мы находимся

a20,20 0 0 1 20, -20: нарисовать дугу с радиусом X и Y 20px по часовой стрелке до точки с разницей X и X на -20px по оси Y

z: закрыть путь

<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>

70
Hossein Maktoobian

Не уверен, почему никто не опубликовал фактический ответ SVG. Вот прямоугольник SVG с закругленными углами (радиус 3) сверху:

<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 , а дополнительные справочные материалы по путям SVG можно найти в этой статье .

44
vallismortis

Как указано в моем ответе на Применение закругленных углов к путям/полигонам , я написал подпрограмму в javascript для общего округления углов путей SVG, с примерами, здесь: http://plnkr.co/edit/ kGnGGyoOCKil02k04snu .

Он будет работать независимо от любых возможных эффектов удара. Чтобы использовать, включите файл rounding.js из Plnkr и вызовите функцию следующим образом:

roundPathCorners(pathString, radius, useFractionalRadius)

Результатом будет округленный путь.

Результаты выглядят так:

SVG Path Rounding Examples

34
Yona Appletree

Вы явно установили для 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, и сделать фактическую округлую форму.

24
Phrogz

Я также хотел бы рассмотреть возможность использования старого старого <rect>, который предоставляет атрибуты rx и ry

MDN SVG docs <- обратите внимание на второй нарисованный прямоугольный элемент

18
Joshua

Этот вопрос является первым результатом Googling "svg закругленные углы пути". Предложение Phrogz об использовании stroke имеет некоторые ограничения (а именно, что я не могу использовать обводку для других целей и что размеры должны быть скорректированы с учетом ширины обводки).

Предложение Jlange использовать кривую лучше, но не очень конкретно. Я использовал квадратные кривые Безье для рисования закругленных углов. Рассмотрим изображение угла, помеченного синей точкой и двумя красными точками на соседних краях:

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

Две строки можно сделать с помощью команды L. Чтобы превратить этот острый угол в закругленный угол, начните рисовать кривую с левой красной точки (используйте M x,y для перемещения к этой точке). Теперь у квадратичной кривой Безье есть только одна контрольная точка, которую вы должны установить на синюю точку. Установите конец кривой в правой красной точке. Поскольку касательная в двух красных точках находится в направлении предыдущих линий, вы увидите плавный переход, «закругленные углы».

Теперь, чтобы продолжить форму после закругленного угла, можно получить прямую линию на кривой Безье, установив контрольную точку между линиями между двумя углами.

Чтобы помочь мне с определением пути, я написал этот скрипт на 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 <[email protected]>

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)
4
Lekensteyn

Я сам столкнулся с этой проблемой сегодня и сумел решить ее, написав небольшую функцию JavaScript.

Из того, что я могу сказать, нет простого способа задать элемент пути в svg с закругленными углами кроме, если вам нужно только, чтобы границы были округлены, и в этом случае (CSS) атрибуты обводка, stroke-width и, самое главное, stroke-linejoin = "round" вполне достаточно.

Однако в моем случае я использовал объект контура для создания пользовательских фигур с углами n, которые заполнены определенным цветом и не имеют видимых границ, во многом так:

 enter image description here

Мне удалось написать быструю функцию, которая принимает массив координат для пути svg и возвращает готовую строку пути для добавления в атрибут d элемента html path. Получившаяся форма будет выглядеть примерно так:

 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 в верхней части. По умолчанию 3 для системы координат 100x100 (область просмотра), но в зависимости от размера вашего svg, вам, возможно, придется изменить это.

1
Mvin

Вот несколько путей для вкладок:

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.

Пути в ручке делают основную работу, значения могут быть изменены, чтобы соответствовать любым желаемым размерам.

0
Jackie