Penggunaan fungsi ARCTO pada PHP

Saya memiliki SVG berikut:

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

Saya ingin mendapatkan efek border-top-right-radius dan border-top-bottom-radius seperti CSS.

Bagaimana saya bisa mencapai efek sudut bulat itu?

Saya tahu bahwa sudah terlambat untuk menjawab ini, tetapi demi SO, inilah cara Anda bisa membuat kotak bulat dengan 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" />

Penjelasan:

m100.100: pindah ke titik (100.100)

h200: gambar garis horizontal 200px dari tempat kita berada

a20,20 0 0 1 20,20: gambar busur dengan jari-jari 20px X, jari-jari 20px Y, searah jarum jam, ke titik dengan perbedaan 20px pada sumbu X dan Y

v200: gambar garis vertikal 200px dari tempat kita berada

a20,20 0 0 1 -20,20: gambar busur dengan jari-jari 20px X dan Y, searah jarum jam, ke titik dengan perbedaan -20px dalam X dan perbedaan 20px pada sumbu Y

h-200: gambar garis horizontal -200px dari tempat kita berada

a20,20 0 0 1 -20, -20: gambar busur dengan 20px X dan jari-jari Y, searah jarum jam, ke titik dengan perbedaan -20px dalam X dan -20px perbedaan dalam sumbu Y

v-200: gambar garis vertikal -200px dari tempat kita berada

a20,20 0 0 1 20, -20: gambar busur dengan jari-jari 20px X dan Y, searah jarum jam, ke titik dengan perbedaan 20px dalam X dan -20px perbedaan dalam sumbu Y

z: tutup jalur

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

Tidak yakin mengapa tidak ada yang mengirim jawaban SVG yang sebenarnya. Berikut adalah persegi panjang SVG dengan sudut bulat (jari-jari 3) di atas:

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

Ini adalah Move To (M), Line To (L), Arc To (A), Line To (L), Arc To (A), Line To (L), Close Path (Z).

Angka yang dibatasi koma adalah koordinat absolut. Busur didefinisikan dengan parameter tambahan yang menentukan jari-jari dan jenis busur. Ini juga dapat dilakukan dengan koordinat relatif (gunakan huruf kecil untuk L dan A).

Referensi lengkap untuk perintah-perintah itu ada di halaman W3C SVG Paths , dan bahan referensi tambahan pada path SVG dapat ditemukan di artikel ini .

Seperti yang dirujuk dalam jawaban saya ke Menerapkan sudut bulat ke jalur/poligon , saya telah menulis rutin dalam javascript untuk sudut pembulatan umum jalur SVG, dengan contoh, di sini: http://plnkr.co/edit/ kGnGGyoOCKil02k04snu .

Ini akan bekerja secara independen dari efek stroke yang Anda miliki. Untuk menggunakan, sertakan file rounding.js dari Plnkr dan panggil fungsi seperti ini:

roundPathCorners(pathString, radius, useFractionalRadius)

Hasilnya akan menjadi jalan bulat.

Hasilnya terlihat seperti ini:

Penggunaan fungsi ARCTO pada PHP

Anda telah menetapkan secara eksplisit stroke-linejoin Anda menjadi round tetapi stroke-width Anda menjadi 0, jadi tentu saja Anda tidak akan melihat sudut bundar jika Anda tidak memiliki ujung ke ujung.

Berikut adalah contoh yang dimodifikasi dengan sudut bulat yang dibuat melalui goresan:
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" />

Jika tidak — jika Anda membutuhkan bentuk bundar yang sebenarnya dan bukan hanya stroke lemak bulat — Anda harus melakukan apa yang dikatakan @Jlange dan membuat bentuk bundar yang sebenarnya.

Saya juga akan mempertimbangkan untuk menggunakan <rect> tua sederhana yang menyediakan atribut rx dan ry

MDN SVG docs <- perhatikan elemen rect yang ditarik kedua

Pertanyaan ini adalah hasil pertama untuk Googling "svg rounded cornerers corner". Saran Phrogz untuk menggunakan stroke memiliki beberapa batasan (yaitu, bahwa saya tidak dapat menggunakan stroke untuk tujuan lain, dan bahwa dimensi harus dikoreksi untuk lebar stroke).

Saran Jlange untuk menggunakan kurva lebih baik, tetapi tidak terlalu konkret. Saya akhirnya menggunakan kurva Bézier kuadrat untuk menggambar sudut bulat. Perhatikan gambar sudut yang ditandai dengan titik biru dan dua titik merah di tepi yang berdekatan:

Penggunaan fungsi ARCTO pada PHP

Dua baris dapat dibuat dengan perintah L. Untuk mengubah sudut tajam ini menjadi sudut bulat, mulailah menggambar kurva dari titik merah kiri (gunakan M x,y untuk pindah ke titik itu). Sekarang kurva Bézier kuadratik hanya memiliki satu titik kontrol yang harus Anda atur pada titik biru. Atur ujung kurva di titik merah kanan. Karena garis singgung pada dua titik merah mengarah ke garis sebelumnya, Anda akan melihat transisi yang lancar, "sudut membulat".

Sekarang untuk melanjutkan bentuk setelah sudut membulat, garis lurus dalam kurva Bézier dapat dicapai dengan mengatur titik kontrol antara pada garis di antara dua sudut.

Untuk membantu saya menentukan path, saya menulis skrip Python ini yang menerima edge dan radius. Vektor matematika membuat ini sebenarnya sangat mudah. Gambar yang dihasilkan dari output:

Penggunaan fungsi ARCTO pada PHP

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

Saya sendiri pernah mengalami masalah ini dan berhasil menyelesaikannya dengan menulis fungsi JavaScript kecil.

Dari apa yang saya tahu, tidak ada cara mudah untuk memberikan elemen path di sudut bulat svg kecuali jika Anda hanya perlu perbatasan untuk dibulatkan, dalam hal ini (CSS) atribut stroke, lebar-stroke dan yang terpenting stroke-linejoin = "round" cukup memadai.

Namun, dalam kasus saya, saya menggunakan objek jalur untuk membuat bentuk khusus dengan sudut n yang diisi dengan warna tertentu dan tidak memiliki batas yang terlihat, seperti ini:

 

Penggunaan fungsi ARCTO pada PHP

Saya berhasil menulis fungsi cepat yang mengambil array koordinat untuk path svg dan mengembalikan string path yang sudah selesai untuk dimasukkan ke atribut d dari elemen path html. Bentuk yang dihasilkan kemudian akan terlihat seperti ini:

 

Penggunaan fungsi ARCTO pada PHP

Inilah fungsinya:

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

Anda dapat menentukan kekuatan pembulatan dengan mengatur variabel curveRadius di bagian atas. Standarnya adalah 3 untuk sistem koordinat 100x100 (viewport), tetapi tergantung pada ukuran svg Anda, Anda mungkin perlu menyesuaikan ini.

Berikut ini beberapa jalur untuk 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>

Jawaban lain menjelaskan mekanika. Saya terutama menyukai jawaban hossein-maktoobian.

Jalur di pena melakukan pekerjaan paling berat, nilainya dapat dimodifikasi sesuai dengan dimensi apa pun yang diinginkan.