SVG góc tròn


83

Tôi có SVG sau:

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

Tôi muốn có hiệu ứng border-top-right-radiusvà giống CSS border-top-bottom-radius.

Làm thế nào tôi có thể đạt được hiệu ứng góc tròn đó?


Thật tệ khi CSS ' border-radiusvà các biến thể của nó không hoạt động trong SVG.
Steven Vachon

7
BTW. Nếu bạn có hình chữ nhật, bạn có thể thêm rx=3hoặc ry=3làm tròn các góc. developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rx
Lukas Liesis

Câu trả lời:


125

Đây là cách bạn có thể tạo một hình chữ nhật tròn với 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" />

Giải trình

m100,100: di chuyển đến điểm (100,100)

h200: vẽ một đường ngang 200px từ vị trí của chúng ta

a20,20 0 0 1 20,20: vẽ một cung tròn có bán kính X 20px, bán kính Y 20px, theo chiều kim đồng hồ, đến một điểm có trục X và Y chênh lệch 20px

v200: vẽ một đường thẳng đứng 200px từ vị trí của chúng ta

a20,20 0 0 1 -20,20: vẽ một cung tròn với bán kính X và Y 20px, theo chiều kim đồng hồ, đến một điểm có độ chênh lệch -20px ở X và chênh lệch 20px ở trục Y

h-200: vẽ một đường ngang -200px từ vị trí của chúng ta

a20,20 0 0 1 -20, -20: vẽ một cung tròn có bán kính X và Y 20px, theo chiều kim đồng hồ, đến một điểm có độ chênh lệch -20px trong trục X và -20px trong trục Y

v-200: vẽ một đường thẳng đứng -200px từ vị trí của chúng ta

a20,20 0 0 1 20, -20: vẽ một cung tròn có bán kính X và Y 20px, theo chiều kim đồng hồ, tới một điểm có độ chênh lệch 20px ở trục X và -20px ở trục Y

z: đóng đường dẫn

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


3
Đối với bất kỳ ai quan tâm đến thông tin chi tiết về vòng cung, đây là API: A rx ry x-axis-rotation large-arc-flag sweep-flag x y( developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths )
Nic Scozzaro

Nếu bạn chỉ muốn một hình chữ nhật tròn chứ không phải một hình dạng phức tạp hơn (đó là cách tôi tìm thấy điều này trong khi googling) và cách tiếp cận đơn giản hơn có thể là sử dụng <svg viewBox="0 0 110 110" xmlns="http://www.w3.org/2000/svg"> `<direct x =" 5 "y =" 5 "width =" 100 "height = "100" rx = "15" style = "stroke: # 000000; fill: #FFFFFF" /> `</svg>
John Sither

58

Không chắc tại sao không ai đăng câu trả lời SVG thực tế. Đây là một hình chữ nhật SVG với các góc tròn (bán kính 3) ở trên cùng:

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

Đây là Move To (M), Line To (L), Arc To (A), Line To (L), Arc To (A), Line To (L), Close Path (Z).

Các số được phân tách bằng dấu phẩy là tọa độ tuyệt đối. Các cung được xác định với các tham số bổ sung xác định bán kính và loại cung. Điều này cũng có thể được thực hiện với các tọa độ tương đối (sử dụng các chữ cái viết thường cho L và A).

Tài liệu tham khảo đầy đủ cho các lệnh đó có trên trang Đường dẫn SVG của W3C và có thể tìm thấy tài liệu tham khảo bổ sung về đường dẫn SVG trong bài viết này .


12
Đây không phải là câu trả lời trực tiếp mà tôi đang tìm kiếm, nhưng chúa ơi nếu nó không hữu ích. Luôn tự hỏi những lá thư đó dùng để làm gì.
Alex McCabe

1
Thanx cho lời giải thích :)
Osman Erdi

47

Như được đề cập trong câu trả lời của tôi cho Áp dụng góc làm tròn cho đường dẫn / đa giác , tôi đã viết một quy trình trong javascript để làm tròn các góc chung của đường dẫn SVG, với các ví dụ, tại đây: http://plnkr.co/edit/kGnGGyoOCKil02k04snu .

Nó sẽ hoạt động độc lập với bất kỳ tác động đột quỵ nào mà bạn có thể có. Để sử dụng, hãy bao gồm tệp rounding.js từ Plnkr và gọi hàm như sau:

roundPathCorners(pathString, radius, useFractionalRadius)

Kết quả sẽ là đường dẫn được làm tròn.

Kết quả như sau:

Ví dụ về làm tròn đường dẫn SVG


Tốt, mặc dù hỗ trợ cho các lệnh tương đối sẽ thậm chí còn đẹp hơn.
Joachim Breitner,

1
Tôi đồng ý :) Đây chỉ là một bước nhỏ để giải quyết vấn đề của tôi, không phải là một nỗ lực tại một thư viện chính thức. Tôi hoan nghênh một ngã ba với chức năng đó!
Yona Appletree

Bạn có repo với cái này trong đó không? Thật tuyệt, cảm ơn rất nhiều vì đã làm ra nó.
Djave

1
Tôi không bao giờ bận tâm để thực hiện một repo cho nó ... mặc dù tôi có lẽ nên.
Yona Appletree 27/09/18

Tôi muốn quay lại câu hỏi của @ Djave về repo; -]
t3chb0t

36

Bạn đã dứt khoát thiết lập của bạn stroke-linejoinđể roundnhưng bạn stroke-widthđến 0, vì vậy tất nhiên bạn sẽ không thấy các góc tròn nếu bạn không có đột quỵ vào vòng.

Đây là một ví dụ đã sửa đổi với các góc được làm tròn bằng các nét vẽ:
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" />

Mặt khác — nếu bạn cần tô một hình tròn thực sự chứ không chỉ là một nét tròn béo — bạn phải làm những gì @Jlange nói và tạo hình tròn thực sự.


Tôi thấy điều này chính xác trên jsfiddle, nhưng khi sao chép vào tài liệu HTML cục bộ, nó chỉ là một hình chữ nhật đơn giản.
Mads Skjern

6
Bạn có thể sử dụng stroke-linecapthay thế stroke-linejoin. Nó làm việc cho tôi.
lobodart

32

Tôi cũng sẽ cân nhắc sử dụng một cái cũ đơn giản <rect>cung cấp các thuộc tính rxry

MDN SVG docs <- lưu ý phần tử trực tràng được vẽ thứ hai


2
Nhưng OP chỉ muốn một số góc được làm tròn.
Robert Longson

9
Điều này trả lời câu hỏi của TÔI, đó là điều đã đưa tôi đến trang này. Vì vậy, cảm ơn!
Steven Vachon

1
Nếu bạn cần sử dụng các góc tròn vào một số nhóm phần tử và không chỉ vào một hình chữ nhật, bạn có thể làm điều đó bằng cách sử dụng clipPath developer.mozilla.org/pt-BR/docs/Web/SVG/Element/clipPath như bạn có thể thấy ở đây jsfiddle.net/thiagomata/mp28rnj6/1
Thiago Mata

Liên kết chết trong OP. :(
posfan

@ posfan12 Đã sửa điều đó cho bạn :)
Joshua

12

Hôm nay tôi đã tự mình gặp phải vấn đề này và đã tìm cách giải quyết nó bằng cách viết một hàm JavaScript nhỏ.

Từ những gì tôi có thể nói, không có cách nào dễ dàng để đưa ra một yếu tố đường dẫn trong tập tin SVG lên góc tròn trừ khi bạn chỉ cần biên giới để được làm tròn, trong trường hợp này (CSS) thuộc tính stroke, stroke-widthvà quan trọng nhất stroke-linejoin="round"là hoàn toàn đủ.

Tuy nhiên, trong trường hợp của tôi, tôi đã sử dụng đối tượng đường dẫn để tạo các hình dạng tùy chỉnh với n góc được tô bằng một màu nhất định và không có đường viền hiển thị, giống như thế này:

nhập mô tả hình ảnh ở đây

Tôi đã cố gắng viết một hàm nhanh chóng lấy một mảng tọa độ cho đường dẫn SVG và trả về chuỗi đường dẫn đã hoàn thành để đưa vào dthuộc tính của phần tử html đường dẫn. Hình dạng kết quả sau đó sẽ giống như sau:

nhập mô tả hình ảnh ở đây

Đây là chức năng:

/**
 * 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(' ');
}

Bạn có thể xác định cường độ làm tròn bằng cách đặt biến curveRadius ở trên cùng. Giá trị mặc định là 3 cho hệ tọa độ 100x100 (khung nhìn), nhưng tùy thuộc vào kích thước SVG của bạn, bạn có thể cần điều chỉnh điều này.


1
Toán học này thật tuyệt vời. Tôi hiểu nó và tôi đã triển khai nó trong android để làm cho đa giác có góc tròn.
Adil Soomro

1
Đây là lý do tại sao tôi yêu thích StackOverflow.
Bangkokian

5

Câu hỏi này là kết quả đầu tiên cho "đường dẫn các góc tròn svg" của Google. Đề xuất sử dụng của Phrogz strokecó một số hạn chế (cụ thể là tôi không thể sử dụng nét vẽ cho các mục đích khác và kích thước phải được hiệu chỉnh cho chiều rộng nét vẽ).

Jlange gợi ý sử dụng một đường cong là tốt hơn, nhưng không cụ thể lắm. Cuối cùng tôi đã sử dụng các đường cong Bézier bậc hai để vẽ các góc tròn. Hãy xem xét hình ảnh này về một góc được đánh dấu bằng một chấm màu xanh lam và hai điểm màu đỏ trên các cạnh liền kề:

góc của một hình được đánh dấu màu xanh lam với hai điểm trên các cạnh liền kề

Hai dòng có thể được thực hiện bằng Llệnh. Để biến góc nhọn này thành góc tròn, hãy bắt đầu vẽ một đường cong từ điểm màu đỏ bên trái (dùng M x,yđể di chuyển đến điểm đó). Bây giờ, một đường cong Bézier bậc hai chỉ có một điểm điều khiển duy nhất mà bạn phải đặt trên điểm màu xanh lam. Đặt phần cuối của đường cong tại điểm màu đỏ bên phải. Khi tiếp tuyến tại hai điểm màu đỏ theo hướng của các đường trước đó, bạn sẽ thấy sự chuyển đổi trôi chảy, "các góc tròn".

Bây giờ để tiếp tục hình dạng sau khi góc tròn, một đường thẳng trong đường cong Bézier có thể đạt được bằng cách thiết lập điểm điều khiển giữa trên đường giữa hai góc.

Để giúp tôi xác định đường dẫn, tôi đã viết tập lệnh Python này chấp nhận các cạnh và bán kính. Toán học vectơ làm cho điều này thực sự rất dễ dàng. Hình ảnh kết quả từ đầu ra:

hình dạng được tạo từ đầu ra tập lệnh

#!/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)

3

Dưới đây là một số đường dẫn cho các tab:

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>

Các câu trả lời khác giải thích cơ học. Tôi đặc biệt thích câu trả lời của hossein-maktoobian.

Các đường dẫn trong bút thực hiện toàn bộ tác phẩm, các giá trị có thể được sửa đổi để phù hợp với bất kỳ kích thước mong muốn nào.


1

Tôi đã tìm thấy một giải pháp nhưng nó hơi khó xử nên có thể không phải lúc nào cũng hoạt động. Tôi thấy rằng nếu bạn có một cung tròn (A hoặc a) với các giá trị thực sự nhỏ, nó buộc nó phải tạo ra một đường cong ở một điểm do đó tạo thành một đường cong tròn ...

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


1

Chỉ để đơn giản hóa việc triển khai câu trả lời của @ hmak.me, đây là một đoạn mã React được nhận xét để tạo ra các hình chữ nhật tròn.

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'),
);

Liên kết jsfiddle.


-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>';
}
?>

-5

Bạn đang sử dụng một phần tử đường dẫn, tại sao bạn không chỉ cho đường dẫn một đường cong? Xem tại đây để biết cách tạo đường cong bằng cách sử dụng các phần tử đường dẫn: http://www.w3.org/TR/SVG/paths.html#PathDataCurveCommands


Cảm ơn câu trả lời của bạn. Chúng thực sự hữu ích, nhưng vấn đề là tôi sử dụng biểu đồ KendoUI và các đường dẫn đang tạo động. Tôi đã cố gắng thay đổi chúng bằng phương pháp cung cấp Phrogz, nhưng tôi nhận được hiệu ứng border-radius = 10px, nhưng tôi cần border-top- Chỉ left-radius = 10px và border-bottom-left-radius = 10px. Tôi thực sự mới trong SVG vì vậy phương pháp thứ hai không dành cho tôi. Vì vậy, bạn có thể viết các điều phối đường dẫn cho tôi. Cảm ơn trước
Danis

Tôi rất muốn làm điều này cho bạn, đơn giản là tôi không có thời gian để xem qua vị trí toán học / tọa độ. Sẽ không quá khó nếu bạn sử dụng các lệnh cung elip trong liên kết.
RestingRobot
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.