2016-07-07 98 views
0

使用d3和React我繪製了一條路徑。在這條道路上,我有多個只能沿着該路徑拖動的圓圈。但是,我目前的實現(有點)只有在該路徑上有一個圓圈時才起作用。在d3中沿路徑拖動

(在dragStart上它移動到路徑上的長度爲0,而不管位置如何,每當我拖動第二個圓時,它就會從前一個圓的位置開始)。

我的問題是:如何在d3中沿着路徑拖動多個圓圈(或w.e)?有沒有辦法根據當前圈的cx和cy獲取當前路徑的位置?

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

事情與此類似,只是拖動和多圈: http://bl.ocks.org/mbostock/1705868

+0

你可以用這段代碼創建一個JS小提琴嗎?調試這些代碼很難,而不會在實際中看到它。 我看到的一個問題是,您沒有將「移動」綁定到您的班級,因此指定this.cy/this.cx可能不起作用 –

回答

1

這裏有一個快速修改this example,這使得圓圈拖動:

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

您是救生員先生。謝謝! – mrlarssen