【发布时间】:2020-07-09 10:44:16
【问题描述】:
我想让多个圆圈沿着路径移动。我参考here
var w = $(window).innerWidth();
var h = $(window).innerHeight();
var svg = d3
.select('.container')
.append('svg')
.attr('width', w)
.attr('height', h);
// FIRST (START) POINT & SECOND (FINISH) POINT ARRAY
var points = [{
x: 0,
y: 0,
r: 5
}, {
x: 700,
y: 100,
r: 5
}];
// ADD GROUP 'G'
var group = svg
.append('g')
.attr('transform', 'translate(20,20)');
// ADD CIRCLE AT START & FINISH AS AN VISUAL ANCHOR
group.selectAll("circle")
.data(points)
.enter()
.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.r;
});
// DETERMINED THE SUBPATH FOR THE CURVE
var cpx = ((points[1].x - points[0].x)),
cpy = ((points[1].y - points[0].y)) ;
// EMPTY ARRAY
var linesArray = [];
//POPULATE ARRAY WITH RANDOM CURVE SVG
for (let i = 0; i <= 10; i++) { // FOR LOOP UNTUK ISI ARRAY DENGAN KORDINAT GARIS MELENGKUNG
var path = d3.path();
path.moveTo(points[0].x, points[0].y);
path.quadraticCurveTo(Math.random(1) * cpx + points[0].x, Math.random() * cpy + points[0].y, points[1].x, points[1].y);
var l = path.toString();
linesArray.push({
d: l
})
}
// DRAW THE PATH
var mypath = group
.selectAll('path')
.data(linesArray)
.enter()
.append("path")
.attr("d", d => d.d)
.attr("stroke", "firebrick")
.attr("stroke-width", 2)
.attr("fill", "none");
// DRAW THE CIRCLE I WILL ANIMATE
var circle = group
.selectAll('circle')
.data(linesArray)
.enter()
.append("circle")
.attr('id','travel')
.attr("r", 8)
.style("fill", 'steelblue')
.style('opacity', 0.5)
.attr("transform", "translate(" + points[0].x + ","+points[0].y+" )");
// ANIMATE ALONG PATH FUNCTION
function translateAlong(mypath) {
var length = mypath.getTotalLength();
return () => {
return x => {
var p = mypath.getPointAtLength(x * length);
return "translate("+p.x+","+p.y+")";
}
}
}
// ANIMATE THE CIRCLE ALONG PATH
setTimeout(() => {
circle
.each(() => {
d3
.selectAll('#travel')
.transition()
.duration(10000)
.style('fill', 'red')
.attrTween('transform', translateAlong(mypath.node()))
.remove();
})
},0)
<div class='container'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
圆圈仅沿 1 条路径一起动画,而不是在我制作的其他路径中动画。
我已经阅读了答案here,并附上了示例here,但是当我像示例一样添加index 属性时我很困惑,我收到一条错误消息Cannot read property 'getTotalLength' of undefined
这是带有index 属性的编辑部分,我在setTimeout 中作为函数进行了转换
// this part are modified based on reference below
// https://bl.ocks.org/anonymous/f54345ed04e1a66b7cff3ebeef271428/76fc9fbaeed5dfa867fdd57b24c6451346852568
function transitionCircle(pathItem, index) {
circle
.each(() => {
d3
.selectAll('#travel')
.transition()
.duration(10000)
.style('fill', 'red')
.attrTween('transform', translateAlong(mypath.node()[index], index))
.remove();
}) // end each
} // end transitionCircle
setTimeout(() => {
transitionCircle();
},0)// end timeout
function translateAlong(mypath, offset) { //mypath value supposed to be mypath.node()[index] right?
var length = mypath.getTotalLength();
return () => {
return x => {
var p = mypath.getPointAtLength(x * length);
return "translate("+p.x+","+p.y+")";
}
}
} //end function translateAlong()
参考https://bl.ocks.org/mbostock/1705868
更新:
我把node()改成nodes(),就可以在console.log(mypath.nodes()[0])工作了。
代码.attrTween('transform', translateAlong(mypath.node()[0], index)) 也可以工作,但仍然只在第一条路径中设置动画。当我将[0] 改回[index] 时,它再次返回Cannot read property 'getTotalLength' of undefined
【问题讨论】:
标签: javascript d3.js