2011-09-13 2 views
12

Ho questo semplice file fittizio che sto usando per fare dei test. Il risultato voluto è trascinare il cerchio rosso lungo il percorso. Il fatto è che non riesco a capire come associare entrambe le forme.Come trascinare una forma lungo un determinato percorso

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8" />  
    <script src="raphael-min.js"></script>  
</head> 
<body>  
<script type="text/javascript">  
// Creates canvas 320 × 200 at 10, 50 
var r = Raphael(10, 50, 320, 200); 

var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}), 
    e = r.ellipse(104, 100, 4, 4).attr({stroke: "none", fill: "#f00"}), 


/*var c = r.circle(100, 100, 50).attr({ 
    fill: "hsb(.8, 1, 1)", 
    stroke: "none", 
    opacity: .5 
});*/ 


var start = function() { 
    // storing original coordinates 
    this.ox = this.attr("cx"); 
    this.oy = this.attr("cy"); 
    this.attr({opacity: 1}); 
}, 
move = function (dx, dy) { 
    // move will be called with dx and dy 
    this.attr({cx: this.ox + dx, cy: this.oy + dy}); 
}, 
up = function() { 
    // restoring state 
    this.attr({opacity: 1}); 
}; 
e.drag(move, start, up);  
</script> 
</body> 
</html> 
+0

L'idea principale è quello di ottenere qualcosa di simile a animateAlong ma trascinando al posto di animazione. – Guillermo

+2

Ecco un jsFiddle per le persone da utilizzare: http://jsfiddle.net/8T9NQ/ – Joe

+0

In generale, è necessario proiettare la posizione del cursore sul percorso, individuando il punto più vicino sul percorso. È del tutto possibile che possano esserci due (o più o infiniti) punti sul percorso più vicino al cursore, quindi sarà necessario disambiguare per scegliere il migliore. – Phrogz

risposta

1

Un oggetto cerchio ha una x, y coordinate per il suo centro, e un raggio. Per assicurarsi che il cerchio rimanga sulla linea, trova semplicemente l'intersezione tra il centro del cerchio e la linea stessa.

Per fare ciò, è necessario memorizzare le coordinate di inizio e fine della linea. Quindi usando l'equazione di una linea: y = mx + b, puoi trovare la pendenza e l'intercetta y. Una volta che hai una funzione per la linea, puoi generare nuove coordinate per il cerchio inserendo diversi valori di x.

Inoltre, collegando le coordinate x, y del cerchio alla funzione, è possibile verificare se il cerchio si trova sulla linea.

27

Non hai specificato esattamente come vuoi che l'interazione funzioni, quindi ho usato quello che mi sembra più naturale.

Possiamo ipotizzare il punto deve rimanere sul percorso, quindi la sua posizione deve essere dato da

p.getPointAtLength(l); 

per qualche l. Per trovare l possiamo cercare il locale minimo della distanza tra la curva e la posizione del cursore. Inizializziamo la ricerca con l0 dove l0 è il valore di lattualmente che definisce la posizione del punto.

Vedi l'JSfiddle qui per un esempio di lavoro:

http://jsfiddle.net/fuzic/kKLtH/

Ecco il codice:

var searchDl = 1; 
var l = 0; 

// Creates canvas 320 × 200 at 10, 50 
var r = Raphael(10, 50, 320, 200); 

var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}), 
    pt = p.getPointAtLength(l); 
    e = r.ellipse(pt.x, pt.y, 4, 4).attr({stroke: "none", fill: "#f00"}), 
    totLen = p.getTotalLength(), 


start = function() { 
    // storing original coordinates 
    this.ox = this.attr("cx"); 
    this.oy = this.attr("cy"); 
    this.attr({opacity: 1}); 
}, 
move = function (dx, dy) { 
    var tmpPt = { 
     x : this.ox + dx, 
     y : this.oy + dy 
    }; 
    l = gradSearch(l, tmpPt); 
    pt = p.getPointAtLength(l); 
    this.attr({cx: pt.x, cy: pt.y}); 
}, 
up = function() { 
    this.attr({opacity: 1}); 
}, 
gradSearch = function (l0, pt) { 
    l0 = l0 + totLen; 
    var l1 = l0, 
     dist0 = dist(p.getPointAtLength(l0 % totLen), pt), 
     dist1, 
     searchDir; 

    if (dist(p.getPointAtLength((l0 - searchDl) % totLen), pt) > 
     dist(p.getPointAtLength((l0 + searchDl) % totLen), pt)) { 
     searchDir = searchDl; 
    } else { 
     searchDir = -searchDl; 
    } 

    l1 += searchDir; 
    dist1 = dist(p.getPointAtLength(l1 % totLen), pt); 
    while (dist1 < dist0) { 
     dist0 = dist1; 
     l1 += searchDir; 
     dist1 = dist(p.getPointAtLength(l1 % totLen), pt); 
    } 
    l1 -= searchDir; 

    return (l1 % totLen); 
}, 
dist = function (pt1, pt2) { 
    var dx = pt1.x - pt2.x; 
    var dy = pt1.y - pt2.y; 
    return Math.sqrt(dx * dx + dy * dy); 
}; 
e.drag(move, start, up);​ 
+0

Molto ben fatto. Questo dovrebbe essere accettato come risposta corretta !! –

+0

Fuzic se voglio creare un grafico a torta qualcosa come [link] http://www.shodor.org/interactivate/activities/PieChart/ [link] è possibile usando la libreria js Raphael? –

+0

@fuzic - Puoi spiegare come funziona gradSearch? Vedi: http://stackoverflow.com/questions/23812322/snap-svg-determine-drag-distance-along-a-path – Inator