2016-07-07 3 views
0

En utilisant d3 et React, j'ai tracé un chemin. Sur ce chemin, j'ai plusieurs cercles qui ne peuvent être déplacés que le long de ce chemin. Cependant, mon implémentation actuelle (sorte de) fonctionne quand il y a un cercle sur ce chemin.Traîner le long de la trajectoire en d3

(Sur dragStart, il se déplace à la longueur 0 sur le chemin quelle que soit sa position, et chaque fois que je fais glisser un second cercle, il commence à la position du cercle précédent).

Ma question est: Comment puis-je faire glisser plusieurs cercles (ou w.e) le long d'un chemin dans d3? Est-il possible d'obtenir la position currentLength sur le chemin en fonction de cx et cy du cercle actuel?

var currentLength = 0; 
 

 
class MyComponent extends Component { 
 

 
    constructor(props) { 
 
    super(props) 
 
    currentLength = 0; 
 
    } 
 

 
    componentDidMount() { 
 
    var drag = d3.behavior.drag() 
 
     .on('drag', this.move); 
 

 
    var g = d3.select(this._base); 
 
    var circle = g.selectAll('circle').data(this.props.data); 
 
    var onEnter = circle.enter(); 
 

 
     onEnter.append('circle') 
 
     .attr({ 
 
     r: 10, 
 
     cx: (d) => d.x, 
 
     cy: (d) => d.y 
 
     }) 
 
     .style('fill', 'blue') 
 
     .call(drag); 
 
    } 
 

 
    move(d) { 
 
    currentLength += d3.event.dx + d3.event.dy 
 

 
    if (currentLength < 0) { 
 
     currentLength = 0 
 
    } 
 

 
    var pointAtCurrentLength = d3.select('#path').node().getPointAtLength(currentLength) 
 
    this.cx.baseVal.value = pointAtCurrentLength.x; 
 
    this.cy.baseVal.value = pointAtCurrentLength.y; 
 
    } 
 

 
    render() { 
 
    return <g ref={(c)=>this._base=c}></g> 
 
    } 
 
}

Quelque chose de semblable à cela, seuls les cercles draggable et multiples: http://bl.ocks.org/mbostock/1705868

+0

Pouvez-vous créer un violon JS avec cet extrait? Il est difficile de déboguer ce code sans le voir en action. Un problème que je vois est que vous ne liez pas 'move' à votre classe, alors assigner this.cy/this.cx ne fonctionnera probablement pas –

Répondre

1

est ici une modification rapide à this example, ce qui rend les cercles draggable:

<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<style> 
 

 
path { 
 
    fill: none; 
 
    stroke: #000; 
 
    stroke-width: 1.5px; 
 
} 
 

 
line { 
 
    fill: none; 
 
    stroke: red; 
 
    stroke-width: 1.5px; 
 
} 
 

 
circle { 
 
    fill: red; 
 
} 
 

 
</style> 
 
<body> 
 
<script src="//d3js.org/d3.v3.min.js"></script> 
 
<script> 
 

 
var points = [[600,276],[586,393],[378,388],[589,148],[346,227],[365,108]]; 
 

 
var width = 960, 
 
    height = 500; 
 

 
var line = d3.svg.line() 
 
    .interpolate("cardinal"); 
 
    
 
var drag = d3.behavior.drag() 
 
    .on("drag", dragged); 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", width) 
 
    .attr("height", height); 
 

 
var path = svg.append("path") 
 
    .datum(points) 
 
    .attr("d", line); 
 

 
var line = svg.append("line"); 
 

 
var circle = svg.append("circle") 
 
    .attr("transform", "translate(" + points[0] + ")") 
 
    .attr("r", 7) 
 
    .call(drag); 
 
    
 
svg.append("circle") 
 
    .attr("transform", "translate(" + points[5] + ")") 
 
    .attr("r", 7) 
 
    .call(drag); 
 

 
function dragged(d) { 
 
    var m = d3.mouse(svg.node()), 
 
    p = closestPoint(path.node(), m); 
 

 
    d3.select(this) 
 
    .attr("transform", "translate(" + p[0] + "," + p[1] + ")") 
 
} 
 

 
function closestPoint(pathNode, point) { 
 
    var pathLength = pathNode.getTotalLength(), 
 
     precision = 8, 
 
     best, 
 
     bestLength, 
 
     bestDistance = Infinity; 
 

 
    // linear scan for coarse approximation 
 
    for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { 
 
    if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) { 
 
     best = scan, bestLength = scanLength, bestDistance = scanDistance; 
 
    } 
 
    } 
 

 
    // binary search for precise estimate 
 
    precision /= 2; 
 
    while (precision > 0.5) { 
 
    var before, 
 
     after, 
 
     beforeLength, 
 
     afterLength, 
 
     beforeDistance, 
 
     afterDistance; 
 
    if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) { 
 
     best = before, bestLength = beforeLength, bestDistance = beforeDistance; 
 
    } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) { 
 
     best = after, bestLength = afterLength, bestDistance = afterDistance; 
 
    } else { 
 
     precision /= 2; 
 
    } 
 
    } 
 

 
    best = [best.x, best.y]; 
 
    best.distance = Math.sqrt(bestDistance); 
 
    return best; 
 

 
    function distance2(p) { 
 
    var dx = p.x - point[0], 
 
     dy = p.y - point[1]; 
 
    return dx * dx + dy * dy; 
 
    } 
 
} 
 

 
</script>

+0

Vous êtes un sauveur de vie monsieur. Je vous remercie! – mrlarssen