2011-09-13 9 views
12

Tengo este simple archivo ficticio que estoy usando para hacer algunas pruebas. El resultado previsto es arrastrar el círculo rojo a lo largo de la ruta. La cuestión es que no puedo entender cómo asociar ambas formas.Cómo arrastrar una forma a lo largo de una ruta determinada

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

La idea principal es conseguir algo similar a animateAlong pero arrastrando en lugar de animar. – Guillermo

+2

Aquí hay un jsFiddle para que la gente lo use: http://jsfiddle.net/8T9NQ/ – Joe

+0

En general, debe proyectar la posición del cursor en la ruta, encontrando el punto más cercano en la ruta. Es muy posible que haya dos (o más, o infinitos) puntos en el camino más cercano al cursor, por lo que deberá desambiguar para elegir el mejor. – Phrogz

Respuesta

1

Un objeto circular tiene una coordenada x, y para su centro y un radio. Para asegurarse de que el círculo permanezca en la línea, simplemente encuentre la intersección del centro del círculo y la línea misma.

Para hacer esto, deberá almacenar las coordenadas de inicio y fin de su línea. Luego, usando la ecuación de una línea: y = mx + b, puedes encontrar la pendiente y la intersección con el eje y. Una vez que tienes una función para la línea, puedes generar nuevas coordenadas para el círculo insertando diferentes valores de x.

Además, al insertar las coordenadas x, y del círculo en su función, puede verificar si el círculo está en la línea.

27

No especificó exactamente cómo desea que funcione la interacción, por lo que utilicé lo que me parece más natural.

Podemos suponer que el punto debe permanecer en el camino, por lo que su posición debe ser dada por

p.getPointAtLength(l); 

por alguna l. Para encontrar l podemos buscar el local mínimo de la distancia entre la curva y la posición del cursor. Inicializamos la búsqueda con l0 donde l0 es el valor de lactualmente que define la ubicación del punto.

Véase el jsFiddle aquí un ejemplo de trabajo:

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

Aquí está el código:

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

Muy bien hecho. ¡Esto debería ser aceptado como la respuesta correcta! –

+0

Fuzic si quiero crear un gráfico circular algo como [enlace] http://www.shodor.org/interactivate/activities/PieChart/ [link] es posible usando la biblioteca raphael js? –

+0

@fuzic - ¿Puedes explicarnos cómo funciona gradSearch? Ver: http://stackoverflow.com/questions/23812322/snap-svg-determine-drag-distance-along-a-path – Inator

Cuestiones relacionadas