SVG yuvarlak köşe


87

Aşağıdaki SVG'ye sahibim:

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

Bir CSS benzeri almak istiyorum border-top-right-radiusve border-top-bottom-radiusetkisi.

O yuvarlak köşe efektini nasıl elde edebilirim?


1
CSS'nin border-radiusve türevlerinin SVG'de çalışmaması çok kötü .
Steven Vachon

9
BTW. Dikdörtgene sahipseniz , köşeleri ekleyebilir rx=3veya ry=3yuvarlayabilirsiniz. developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rx
Lukas Liesis

Yanıtlar:


131

SVG Yolu ile yuvarlatılmış bir dikdörtgen oluşturmanın yolu:

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

Açıklama

m100,100: (100,100) noktasına git

h200: bulunduğumuz yerden 200 piksellik bir yatay çizgi çizin

a20,20 0 0 1 20,20: 20px X yarıçaplı, 20px Y yarıçaplı, saat yönünde, X ve Y ekseninde 20px fark olan bir noktaya bir yay çizin

v200: bulunduğumuz yerden 200 piksellik dikey bir çizgi çizin

a20,20 0 0 1 -20,20: 20px X ve Y yarıçaplı bir yay çizin, saat yönünde, X'de -20px ve Y ekseninde 20px fark olan bir noktaya

h-200: bulunduğumuz yerden -200 piksellik bir yatay çizgi çizin

a20,20 0 0 1 -20, -20: 20px X ve Y yarıçaplı bir yay çizin, saat yönünde, X'de -20px farkı ve Y ekseninde -20px farkı olan bir noktaya

v-200: bulunduğumuz yerden -200 piksellik dikey bir çizgi çizin

a20,20 0 0 1 20, -20: 20px X ve Y yarıçaplı bir yay çizin, saat yönünde, X'de 20px fark ve Y ekseninde -20px fark olan bir noktaya

z: yolu kapat

<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
Yay hakkında daha fazla ayrıntıyla ilgilenen herkes için bu 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

Yalnızca yuvarlatılmış bir dikdörtgen istiyorsanız ve daha karmaşık bir şekil istemiyorsanız (Google'da bunu böyle buldum) ve daha basit bir yaklaşım <svg viewBox="0 0 110 110" xmlns="http://www.w3.org/2000/svg"> "<rect x =" 5 "y =" 5 "genişlik =" 100 "yükseklik kullanmak olabilir = "100" rx = "15" style = "strok: # 000000; doldurun: #FFFFFF" /> `</svg>
John Sibly

58

Neden hiç kimsenin gerçek bir SVG yanıtı göndermediğinden emin değilim. İşte üstte yuvarlatılmış köşeleri (yarıçap 3) olan bir SVG dikdörtgeni:

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

Bu bir Taşı (M), Çizgiye (L), Yay Yönüne (A), Çizgiye (L), Yay Yönüne (A), Çizgiye (L), Yolu Kapat (Z).

Virgülle ayrılmış sayılar mutlak koordinatlardır. Yaylar, yay yarıçapını ve türünü belirten ek parametrelerle tanımlanır. Bu aynı zamanda göreceli koordinatlarla da gerçekleştirilebilir (L ve A için küçük harfler kullanın).

Bu komutların tam referansı W3C SVG Yolları sayfasındadır ve SVG yollarıyla ilgili ek referans materyalleri bu makalede bulunabilir .


12
Bu doğrudan aradığım cevap değil, ama yararlı değilse iyi tanrı. Harflerin ne için olduğunu hep merak ettim.
Alex McCabe

1
Açıklama için teşekkürler :)
Osman Erdi

50

Cevabım başvurulan gibi yollar / poligon yuvarlatılmış köşeler uygulamak , ben genel olarak burada, örneklerle, SVG yolları köşelerini yuvarlama için javascript bir rutin yazdım: http://plnkr.co/edit/kGnGGyoOCKil02k04snu .

Sahip olabileceğiniz herhangi bir felç etkisinden bağımsız olarak çalışacaktır. Kullanmak için, Plnkr'dan rounding.js dosyasını dahil edin ve işlevi şu şekilde çağırın:

roundPathCorners(pathString, radius, useFractionalRadius)

Sonuç, yuvarlatılmış yol olacaktır.

Sonuçlar şuna benzer:

SVG Yol Yuvarlama Örnekleri


Güzel, ancak göreceli komutlar için destek daha da güzel olurdu.
Joachim Breitner

1
Katılıyorum :) Bu, tam teşekküllü bir kütüphane girişimi değil, sorunumu çözmek için küçük bir seferlikti. Bu işlevselliğe sahip bir çatalı memnuniyetle karşılarım!
Yona Appletree

İçinde bunun olduğu bir deponuz var mı? Harika, bunu yaptığınız için çok teşekkürler.
Djave

1
Bunun için bir repo yapma zahmetine hiç girmedim ... gerçi muhtemelen yapmalıyım.
Yona Appletree

@ Djave'nin repo hakkındaki sorusuna geri dönmek istiyorum; -]
t3chb0t

38

Açıkça senin belirledik stroke-linejoinetmek roundama senin stroke-widthiçin 0, bu yüzden tabii ki size yuvarlak hiçbir inme varsa yuvarlatılmış köşeler görmeye gitmiyoruz.

Konturlarla yapılmış köşeleri yuvarlatılmış değiştirilmiş bir örnek:
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" />

Aksi takdirde - sadece yuvarlak yağlı bir vuruş yerine gerçek bir yuvarlak şekil dolgusuna ihtiyacınız varsa - @Jlange'ın dediğini yapmalı ve gerçek bir yuvarlak şekil yapmalısınız.


Bunu jsfiddle'da doğru görüyorum, ancak yerel bir HTML belgesine kopyalarken bu sadece düz bir dikdörtgendir.
Mads Skjern

6
Bunun stroke-linecapyerine kullanabilirsiniz stroke-linejoin. Benim için çalışıyor.
lobodart

33

Ayrıca ve özniteliklerini <rect>sağlayan sade bir eski kullanmayı da düşünürdüm.rxry

MDN SVG belgeleri <- ikinci çizilmiş rect öğesini not edin


2
Ancak OP sadece bazı köşelerin yuvarlatılmasını istiyor.
Robert Longson

9
Bu, sorumu yanıtlıyor, beni bu sayfaya getiren şey buydu. Bu yüzden teşekkürler!
Steven Vachon

1
Yuvarlatılmış köşeleri bazı öğe gruplarında kullanmanız gerekiyorsa ve yalnızca bir düzende değil, burada görebileceğiniz gibi clipPath developer.mozilla.org/pt-BR/docs/Web/SVG/Element/clipPath kullanarak bunu yapabilirsiniz. jsfiddle.net/thiagomata/mp28rnj6/1
Thiago Mata

OP'de ölü bağlantı. :(
posfan12

@ posfan12 Sizin için düzeltildi :)
Joshua

12

Bugün bu problemle ben başladım ve küçük bir JavaScript işlevi yazarak çözmeyi başardım.

Söyleyebileceğim kadarıyla, orada hiç de kolay bir SVG bir yol elementi vermek için bir yol köşeleri yuvarlatılmış dışında sadece (CSS) nitelikleri, bu durumda, sınırlar yuvarlanır gerekiyorsa stroke, stroke-widthve en önemlisi stroke-linejoin="round"mükemmel yeterlidir.

Ancak, benim durumumda, n köşeli, belirli bir renkle doldurulmuş ve görünür kenarlıkları olmayan özel şekiller oluşturmak için bir yol nesnesi kullandım , buna çok benzer:

görüntü açıklamasını buraya girin

Bir SVG yolu için bir koordinat dizisi alan dve yol html öğesinin özniteliğine koymak için bitmiş yol dizesini döndüren hızlı bir işlev yazmayı başardım . Ortaya çıkan şekil daha sonra şuna benzer:

görüntü açıklamasını buraya girin

İşte fonksiyon:

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

En üstte curveRadius değişkenini ayarlayarak yuvarlama kuvvetini belirleyebilirsiniz . Varsayılan değer 100x100 (görüntü alanı) koordinat sistemi için 3'tür, ancak SVG'nizin boyutuna bağlı olarak bunu ayarlamanız gerekebilir.


1
Bu matematik harika. Bunu anladım ve çokgenlerin yuvarlak köşesi olmasını sağlamak için android'de uyguladım.
Adil Soomro

Daha zarif olduğunu düşündüğüm daha küçük ve basitleştirilmiş bir stackoverflow.com/a/65186378/4655042 sürümü yaptım.
janispritzkau

5

Bu soru, Googling "svg yuvarlak köşeler yolu" için ilk sonuçtur. Phrogz'un kullanım önerisinin strokebazı sınırlamaları vardır (yani, stroku başka amaçlar için kullanamam ve boyutların strok genişliğine göre düzeltilmesi gerekir).

Bir eğri kullanma önerisi daha iyidir, ancak çok somut değildir. Yuvarlak köşeler çizmek için ikinci dereceden Bézier eğrilerini kullandım. Mavi bir nokta ve bitişik kenarlarda iki kırmızı nokta ile işaretlenmiş şu köşenin resmini düşünün:

bitişik kenarlarda iki nokta ile mavi ile işaretlenmiş bir şeklin köşesi

LKomut ile iki satır yapılabilir . Bu keskin köşeyi yuvarlak bir köşeye çevirmek için sol kırmızı noktadan bir eğri çizmeye başlayın ( M x,yo noktaya gitmek için kullanın ). Şimdi, ikinci dereceden Bézier eğrisinin mavi noktada ayarlamanız gereken tek bir kontrol noktası vardır. Eğrinin sonunu sağ kırmızı noktada ayarlayın. İki kırmızı noktadaki teğet önceki doğruların yönünde olduğundan, akıcı bir geçiş, "yuvarlak köşeler" göreceksiniz.

Şimdi yuvarlatılmış köşeden sonra şekle devam etmek için, iki köşe arasındaki çizgi arasındaki kontrol noktasını ayarlayarak Bézier eğrisinde düz bir çizgi elde edilebilir.

Yolu belirlememe yardımcı olmak için, kenarları ve yarıçapı kabul eden bu Python betiğini yazdım. Vektör matematiği bunu gerçekten çok kolaylaştırır. Çıktıdan elde edilen görüntü:

komut çıktısından oluşturulan şekil

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

Sekmeler için bazı yollar şunlardır:

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>

Diğer cevaplar mekaniği açıkladı. Özellikle hossein-maktoobian'ın cevabını beğendim.

Kalemdeki yollar işin yükünü oluşturur, değerler istenen boyutlara uyacak şekilde değiştirilebilir.


1

Bir çözüm buldum ama biraz hilekar, bu yüzden her zaman işe yaramayabilir. Gerçekten küçük değerlere sahip bir yayınız (A veya a) varsa, onu bir noktada bir eğri oluşturmaya zorladığını ve böylece yuvarlak bir köşe oluşturduğunu buldum ...

<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

@ Hmak.me yanıtını uygulamayı basitleştirmek için, yuvarlatılmış dikdörtgenler oluşturmak için yorumlanmış bir React kodu parçası burada.

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

Jsfiddle bağlantısı.


0

Bu temelde Mvins'in cevabıyla aynı şeyi yapar , ancak daha sıkıştırılmış ve basitleştirilmiş bir versiyondur. Köşeye bitişik çizgilerin yarıçapının mesafesini geri giderek ve her iki ucu kontrol noktası orijinal köşe noktasında olan bir bezier eğrisiyle birleştirerek çalışır.

function createRoundedPath(coords, radius, close) {
  let path = ""
  const length = coords.length + (close ? 1 : -1)
  for (let i = 0; i < length; i++) {
    const a = coords[i % coords.length]
    const b = coords[(i + 1) % coords.length]
    const t = Math.min(radius / Math.hypot(b.x - a.x, b.y - a.y), 0.5)

    if (i > 0) path += `Q${a.x},${a.y} ${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`

    if (!close && i == 0) path += `M${a.x},${a.y}`
    else if (i == 0) path += `M${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`

    if (!close && i == length - 1) path += `L${b.x},${b.y}`
    else if (i < length - 1) path += `L${a.x * t + b.x * (1 - t)},${a.y * t + b.y * (1 - t)}`
  }
  if (close) path += "Z"
  return path
}

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

-4

Bir yol öğesi kullanıyorsunuz, neden yola bir eğri vermiyorsunuz? Yol öğelerini kullanarak nasıl eğriler oluşturacağınızı öğrenmek için buraya bakın: http://www.w3.org/TR/SVG/paths.html#PathDataCurveCommands


Cevaplarınız için teşekkürler. Gerçekten yardımcı oluyorlar, ancak sorun şu ki KendoUI çizelgeleri kullanıyorum ve yollar dinamik olarak oluşturuluyor. Phrogz'u sunan yöntemle onları değiştirmeye çalıştım, ancak border-radius = 10px efekti elde ediyorum, ancak border-top- yalnızca sol yarıçap = 10 piksel ve sınır-sol alt yarıçap = 10 piksel. SVG'de gerçekten yeniyim, bu yüzden ikinci yöntem benim için değil. Benim için yol koordinatlarını yazabilir misin? Şimdiden teşekkürler
Danis

Bunu sizin için yapmayı çok sevsem de, matematik / koordinat konumundan geçecek vaktim yok. Bağlantıda eliptik yay komutlarını kullanırsanız çok zor olmamalıdır.
RestingRobot
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.