2015-08-04 18 views
22

Voglio connettere due punti SVG (ad esempio i centri di due cerchi) utilizzando gli archi. Se c'è una sola connessione, la linea (<path>) sarà diritta. Se ci sono due connessioni, entrambi saranno arrotondati e sarà simmetrico, in questo modo:Creare archi svg tra due punti

Così, infatti, ci sono poche regole:

  1. Tutto dovrebbe essere simmetrica per la linea immaginaria che collega i due punti.
  2. Da 1, è ovvio che se il numero di connessioni è:

    • strano: non visualizziamo la linea retta
    • anche: visualizziamo la retta
  3. Ci dovrebbe essere un valore k che definisce la distanza tra due connessioni tra gli stessi punti.

  4. La tangente che attraversa il centro dell'arco ellittico deve essere parallela alla linea retta che collega i due punti. E ovviamente, il centro della linea sarà perpendicolare alla tangente.

che sto lottando per ottenere una formula per calcolare i parametri A nell'elemento <path>.

Quello che ho fatto fino ad ora è:

<path d="M100 100, A50,20 0 1,0 300,100" stroke="black" fill="transparent"/> 
  • M100 100 è chiaro: questo è il punto di partenza (mossa a 100,100)
  • ultimi due numeri sono anche chiaro. Il percorso termina in 300,100
  • Ho anche visto che se inserisco 0 anziché 20, ottengo una linea retta.
  • Se sostituisco 1,0 con 1,1, il percorso viene capovolto.

Quello che non so è come calcolare i parametri A. Ho letto the docs, ma l'immagine non mi è ancora chiara. Come calcolare questi valori?

svg { 
 
    width: 100%; 
 
    height: 100%; 
 
    position: absolute; 
 
}
<!DOCTYPE html> 
 
<html> 
 

 
<head> 
 
    <meta charset="utf-8"> 
 
    <title>JS Bin</title> 
 
</head> 
 

 
<body> 
 
    <?xml version="1.0" standalone="no" ?> 
 

 
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> 
 
     <!-- Connect A(100,100) with B(300, 100) --> 
 
     <path d="M100 100, A50,0 0 1,0 300,100" stroke="black" fill="transparent" /> 
 
     <path d="M100 100, A50,20 0 1,0 300,100" stroke="black" fill="transparent" /> 
 
     <path d="M100 100, A50,20 0 1,1 300,100" stroke="black" fill="transparent" /> 
 
     <path d="M100 100, A50,30 0 1,0 300,100" stroke="black" fill="transparent" /> 
 
     <path d="M100 100, A50,30 0 1,1 300,100" stroke="black" fill="transparent" /> 
 
     
 
     <!-- A(100, 100) B(300, 400) --> 
 
     <path d="M100 100, A50,0 57 1,0 300,400" stroke="black" fill="transparent" /> 
 
     <path d="M100 100, A50,20 57 1,0 300,400" stroke="black" fill="transparent" /> 
 
     <path d="M100 100, A50,20 57 1,1 300,400" stroke="black" fill="transparent" /> 
 
    </svg> 
 
</body> 
 

 
</html>

sto usando svg.js per creare i percorsi.

+0

Nota che il "numero pari di connessioni" linee, omettendo la linea centrale, comporta la spaziatura tra gli archi del doppio della distanza degli altri archi, nella vostra immagine del campione. Forse è quello che vuoi, ma mi sembra strano. – Victoria

risposta

16

Stai rendendo la vita molto difficile per te stesso richiedendo archi circolari.

Se si utilizzano invece le curve quadratiche, la geometria diventa molto semplice: basta spostare la coordinata X centrale della metà della differenza delle coordinate Y e viceversa.

function arc_links(dwg,x1,y1,x2,y2,n,k) { 
 
    var cx = (x1+x2)/2; 
 
    var cy = (y1+y2)/2; 
 
    var dx = (x2-x1)/2; 
 
    var dy = (y2-y1)/2; 
 
    var i; 
 
    for (i=0; i<n; i++) { 
 
    if (i==(n-1)/2) { 
 
     dwg.line(x1,y1,x2,y2).stroke({width:1}).fill('none'); 
 
    } 
 
    else { 
 
     dd = Math.sqrt(dx*dx+dy*dy); 
 
     ex = cx + dy/dd * k * (i-(n-1)/2); 
 
     ey = cy - dx/dd * k * (i-(n-1)/2); 
 
     dwg.path("M"+x1+" "+y1+"Q"+ex+" "+ey+" "+x2+" "+y2).stroke({width:1}).fill('none'); 
 
    } 
 
    } 
 
} 
 

 
function create_svg() { 
 
    var draw = SVG('drawing').size(300, 300); 
 
    arc_links(draw,50,50,250,50,2,40); 
 
    arc_links(draw,250,50,250,250,3,40); 
 
    arc_links(draw,250,250,50,250,4,40); 
 
    arc_links(draw,50,250,50,50,5,40); 
 
    draw.circle(50).move(25,25).fill('#fff').stroke({width:1}); 
 
    draw.circle(50).move(225,25).fill('#fff').stroke({width:1}); 
 
    draw.circle(50).move(225,225).fill('#fff').stroke({width:1}); 
 
    draw.circle(50).move(25,225).fill('#fff').stroke({width:1}); 
 
} 
 

 
create_svg();
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.3.2/svg.min.js"></script> 
 
<div id="drawing"></div>

+0

Grazie mille! Davvero, sei fantastico! –

+1

È necessario aggiornare i file js esterni poiché non funziona più. – jnowland

+0

Come ha detto jnowland ... questo frammento non funziona più. – Victoria

3

Ecco una soluzione che utilizza gli archi, come richiesto, piuttosto che le curve di secondo grado.

// Internal function 
function connectInternal(x1,y1,x2,y2,con){ 
var dx=x2-x1 
var dy=y2-y1 
var dist=Math.sqrt(dx*dx+dy*dy) 
if(dist==0 || con==0){ 
    return "M"+x1+","+y1+"L"+x2+","+y2 
} 
var xRadius=dist*0.75 
var yRadius=dist*0.3*(con*0.75) 
var normdx=dx/dist 
if(normdx<-1)normdx=-1 
if(normdx>1)normdx=1 
var angle=Math.acos(normdx)*180/Math.PI 
if(x1>x2){ 
    angle=-angle 
} 
return "M"+x1+","+y1+"A"+xRadius+","+yRadius+","+ 
    angle+",00"+x2+","+y2+ 
    "M"+x1+","+y1+"A"+xRadius+","+yRadius+","+ 
    angle+",01"+x2+","+y2 
} 

// Returns an SVG path that represents 
// "n" connections between two points. 
function connect(x1,y1,x2,y2,n){ 
var ret="" 
var con=n 
if(con%2==1){ 
    ret+=connectInternal(x1,y1,x2,y2,con) 
    con-=1 
} 
for(var i=2;i<=con;i+=2){ 
    ret+=connectInternal(x1,y1,x2,y2,i) 
} 
return ret 
} 
+1

Questa soluzione non soddisfa il requisito di una separazione dell'arco uniformemente distanziata. – Victoria

Problemi correlati