development

SVG 둥근 모서리

big-blog 2020. 12. 13. 10:12
반응형

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효과를.

둥근 모서리 효과를 어떻게 얻을 수 있습니까?


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 : point (100,100)로 이동

h200 : 현재 위치에서 200px의 수평선을 그립니다.

a20,200 0 1 20,20 : X 및 Y 축에서 20px 차이가있는 지점에 시계 방향으로 20px X 반경, 20px Y 반경을 갖는 호를 그립니다.

v200 : 현재 위치에서 200px 수직선을 그립니다.

a20,2000-1-20,20 : X와 Y 반경이 20px 인 호를 시계 방향으로 X에서 -20px 차이가 있고 Y 축에서 20px 차이가 나는 지점에 그립니다.

h-200 : 현재 위치에서 -200px의 수평선을 그립니다.

a20,2000-1-20, -20 : X 및 Y 반경이 20px 인 호를 시계 방향으로 X 축에서 -20px 차이가있는 점과 Y 축에서 -20px 차이가있는 지점까지 그립니다.

v-200 : 현재 위치에서 -200px 수직선을 그립니다.

a20,20 0 0 1 20, -20 : X와 Y 반경이 20px 인 호를 시계 방향으로 X에서 20px 차이가 있고 Y 축에서 -20px 차이가있는 지점까지 그립니다.

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>


아무도 실제 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" />

이것은 Move To (M), Line To (L), Arc To (A), Line To (L), Arc To (A), Line To (L), Close Path (Z)입니다.

쉼표로 구분 된 숫자는 절대 좌표입니다. 호는 반지름과 호 유형을 지정하는 추가 매개 변수로 정의됩니다. 이것은 또한 상대 좌표를 사용하여 수행 할 수 있습니다 (L 및 A에 소문자 사용).

이러한 명령에 대한 전체 참조는 W3C SVG 경로 페이지에 있으며 SVG 경로에 대한 추가 참조 자료는 이 문서 에서 찾을 수 있습니다 .


Applying rounded corners to paths / polygons에 대한 내 답변에서 언급했듯이 SVG 경로의 일반적으로 둥근 모서리에 대한 자바 스크립트 루틴을 http://plnkr.co/edit/kGnGGyoOCKil02k04snu 와 함께 작성했습니다 .

그것은 당신이 가질 수있는 뇌졸중 효과와 독립적으로 작동합니다. 사용하려면 Plnkr의 rounding.js 파일을 포함하고 다음과 같이 함수를 호출합니다.

roundPathCorners(pathString, radius, useFractionalRadius)

결과는 둥근 경로가됩니다.

결과는 다음과 같습니다.

SVG 경로 반올림 예


당신은 명시 적으로 설정 한 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가 말한대로 실제 둥근 모양을 만들어야합니다.


나는 또한 속성 <rect>을 제공 하는 평범한 오래된 것을 사용하는 것을 고려할 것입니다rxry

MDN SVG 문서 <-두 번째로 그려진 rect 요소에 유의하십시오.


이 질문은 인터넷 검색 "svg rounded corners path"에 대한 첫 번째 결과입니다. 사용에 대한 Phrogz 제안 stroke에는 몇 가지 제한 사항이 있습니다 (즉, 다른 용도로 스트로크를 사용할 수 없으며 스트로크 너비에 맞게 치수를 수정해야 함).

곡선을 사용하는 Jlange 제안이 더 좋지만 구체적이지 않습니다. 둥근 모서리를 그리기 위해 2 차 베 지어 곡선을 사용했습니다. 인접한 가장자리에 파란색 점과 두 개의 빨간색 점으로 표시된 모서리 그림을 고려하십시오.

인접한 모서리에 두 점이있는 파란색으로 표시된 그림의 모서리

두 줄은 L명령 으로 만들 수 있습니다 . 이 날카로운 모서리를 둥근 모서리로 바꾸려면 왼쪽 빨간색 점에서 곡선 그리기를 시작합니다 (사용 M x,y하여 해당 점으로 이동). 이제 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)

나는 오늘이 문제를 직접 겪었고 작은 JavaScript 함수를 작성하여 해결할 수있었습니다.

내가 알 수 있듯이 둥근 테두리 만 필요한 경우를 제외하고 는 svg 둥근 모서리에 경로 요소를 제공하는 쉬운 방법이 없습니다 .이 경우 (CSS) 속성 stroke , stroke-width 및 가장 중요한 stroke- linejoin = "round"면 충분합니다.

그러나 필자의 경우 경로 개체를 사용 하여 다음과 같이 특정 색상으로 채워지고 테두리가 표시되지 않는 n 개의 모서리가있는 사용자 지정 모양을 만들었습니다 .

여기에 이미지 설명 입력

나는 svg 경로에 대한 좌표 배열을 취하고 완료된 경로 문자열을 반환 하여 경로 html 요소 d 속성에 넣는 빠른 함수를 작성했습니다 . 결과 모양은 다음과 같습니다.

여기에 이미지 설명 입력

기능은 다음과 같습니다.

/**
* 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의 크기에 따라이를 조정해야 할 수도 있습니다.


다음은 탭 경로입니다.

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의 답변이 마음에 들었습니다.

펜의 경로는 작업을 방해하며 값은 원하는 치수에 맞게 수정할 수 있습니다.


나는 해결책을 찾았지만 약간 해키 이므로 항상 작동하지 않을 수 있습니다. 정말 작은 값을 가진 호 (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>


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

경로 요소를 사용하고 있는데 경로에 곡선을 지정하지 않는 이유는 무엇입니까? 경로 요소를 사용하여 곡선을 만드는 방법은 여기를 참조하십시오. http://www.w3.org/TR/SVG/paths.html#PathDataCurveCommands

참고 URL : https://stackoverflow.com/questions/10177985/svg-rounded-corner

반응형