web-dev-qa-db-fra.com

SVG coins arrondis

J'ai le SVG suivant:

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

Je souhaite obtenir un effet de type border-top-right-radius et border-top-bottom-radius de type CSS.

Comment puis-je obtenir cet effet de coin arrondi?

51
Danis

Je sais qu'il est tard pour répondre à cette question, mais pour SO, voici comment créer un rectangle plus arrondi avec le chemin 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" />

Explication:

m100,100: déplacez vers le point (100,100)

h200: trace une ligne horizontale de 200 pixels de notre position actuelle

a20,20 0 0 1 20,20: trace un arc avec un rayon X de 20px, un rayon Y de 20px, dans le sens des aiguilles d'une montre, jusqu'à un point avec une différence de 20px entre les axes X et Y

v200: trace une ligne verticale de 200px d'où nous sommes

a20,20 0 0 1 -20,20: trace un arc de rayon 20px X et Y, dans le sens des aiguilles d'une montre, jusqu'à un point avec une différence de -20px en différence X et de 20px en axe Y

h-200: trace une ligne horizontale de -200px d'où nous sommes

a20,20 0 0 1 -20, -20: trace un arc de rayon 20px X et Y, dans le sens des aiguilles d'une montre, jusqu'à un point avec une différence de -20px en différence X et -20px en ordonnée

v-200: trace une ligne verticale de -200px d'où nous sommes

a20,20 0 0 1 20, -20: trace un arc de rayon 20px X et Y, dans le sens des aiguilles d'une montre, jusqu'à un point avec une différence de 20px dans la différence X et une différence de -20px dans l'axe Y

z: ferme le chemin

<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

Vous ne savez pas pourquoi personne n'a posté de réponse SVG. Voici un rectangle SVG avec des coins arrondis (rayon 3) sur le dessus:

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

Il s'agit d'un déplacement vers (M), ligne vers (L), arc vers (A), ligne vers (L), arc vers (A), ligne vers (L), chemin étroit (Z).

Les nombres délimités par des virgules sont des coordonnées absolues. Les arcs sont définis avec des paramètres supplémentaires spécifiant le rayon et le type d'arc. Cela pourrait également être accompli avec des coordonnées relatives (utilisez des lettres minuscules pour L et A).

La référence complète de ces commandes se trouve sur la page W3C SVG Paths , et des références supplémentaires sur les chemins SVG sont disponibles dans cet article .

44
vallismortis

Comme indiqué dans ma réponse à Application de coins arrondis à des chemins/polygones , j'ai écrit une routine en javascript pour arrondir génériquement les coins de chemins SVG, avec des exemples, ici: http://plnkr.co/edit/ kGnGGyoOCKil02k04snu .

Cela fonctionnera indépendamment de tout effet de course que vous pourriez avoir. Pour l'utiliser, incluez le fichier rounding.js à partir de la Plnkr et appelez la fonction comme suit:

roundPathCorners(pathString, radius, useFractionalRadius)

Le résultat sera le chemin arrondi.

Les résultats ressemblent à ceci:

SVG Path Rounding Examples

34
Yona Appletree

Vous avez explicitement défini votre stroke-linejoin sur round mais votre stroke-width sur 0, donc bien sûr vous n'allez pas voir les coins arrondis si vous n'avez pas de trait à arrondir.

Voici un exemple modifié avec des coins arrondis réalisés par coups:
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" />

Sinon, si vous avez besoin d'un remplissage de forme arrondie réelle et pas simplement d'un trait gras arrondi, vous devez faire ce que @Jlange dit et créer une forme arrondie réelle.

24
Phrogz

J'envisagerais également d'utiliser un ancien <rect> qui fournit les attributs rx et ry

Documentation MDN SVG <- notez le deuxième élément rect tiré

18
Joshua

Cette question est le premier résultat pour Googling "svg rounded corners path". La suggestion de Phrogz d'utiliser stroke a certaines limites (notamment le fait que je ne peux pas utiliser le trait à d'autres fins et que les dimensions doivent être corrigées en fonction de la largeur du trait).

Il est préférable d’utiliser une courbe, mais pas très concret. J'ai fini par utiliser des courbes de Bézier quadratiques pour dessiner des angles arrondis. Considérez cette image d'un coin marqué d'un point bleu et de deux points rouges sur les bords adjacents:

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

Les deux lignes peuvent être créées avec la commande L. Pour transformer ce coin pointu en coin arrondi, commencez par tracer une courbe à partir du point rouge de gauche (utilisez M x,y pour vous déplacer à ce point). Une courbe de Bézier quadratique ne contient plus qu'un seul point de contrôle que vous devez définir sur le point bleu. Placez la fin de la courbe au bon point rouge. Comme la tangente aux deux points rouges est dans la direction des lignes précédentes, vous verrez une transition fluide, "coins arrondis".

Maintenant, pour continuer la forme après le coin arrondi, une ligne droite dans une courbe de Bézier peut être obtenue en définissant le point de contrôle entre les deux coins.

Pour m'aider à déterminer le chemin, j'ai écrit ce script Python qui accepte les arêtes et les rayons. Les mathématiques vectorielles rendent cela très facile. L'image résultante de la sortie:

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

J'ai moi-même rencontré ce problème aujourd'hui et j'ai réussi à le résoudre en écrivant une petite fonction JavaScript.

D'après ce que je peux dire, il n'y a pas de moyen facile de donner un élément de chemin dans un svg arrondi coins sauf si vous avez seulement besoin que les bordures soient arrondies, auquel cas les attributs (CSS) coup, largeur de trait et surtout ligne-trait = "round" sont parfaitement suffisants.

Cependant, dans mon cas, j’ai utilisé un objet chemin pour créer des formes personnalisées avec des angles n remplis d’une certaine couleur et n’ayant pas de bordures visibles, à peu près comme ceci:

 enter image description here

J'ai réussi à écrire une fonction rapide qui prend un tableau de coordonnées pour un chemin d'accès svg et renvoie la chaîne de chemin d'accès terminée à placer dans l'attribut d de l'élément html du chemin d'accès. La forme résultante ressemblera alors à ceci:

 enter image description here

Voici la fonction:

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

Vous pouvez déterminer la force d'arrondi en définissant la variable curveRadius en haut. La valeur par défaut est 3 pour un système de coordonnées 100x100 (fenêtre), mais en fonction de la taille de votre svg, vous devrez peut-être régler cela.

1
Mvin

Voici quelques chemins pour les onglets:

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>

Les autres réponses ont expliqué la mécanique. J'ai particulièrement aimé la réponse de hossein-maktoobian.

Les chemins dans la plume font le plus gros du travail, les valeurs peuvent être modifiées pour s'adapter à toutes les dimensions souhaitées.

0
Jackie