使用D3我想检测我的动画线何时改变方向(或到达某个点),并在此时间点附加一个圆圈。因此,一个圆圈将一次追加而不是全部追加,这就是目前正在发生的事情。
var points = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
var path = svg.append("path")
.data([points])
.attr("d", d3.svg.line()
.tension(0) ); //); // Catmull–Rom
//.interpolate("cardinal-closed"));
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(10000)
.ease("linear")
.attr("stroke-dashoffset", 0);
svg.selectAll(".point", function(d,i){
console.log(d,i)
})
.data(points)
.enter().append("circle")
.transition()
.duration(2000)
.ease("linear")
.style("fill", "url(#image)")
.attr("r", 20)
.attr("transform", function(d) { return "translate(" + d + ")"; })
我尝试测量前一个x和y的前一个x和y,但是如果它们继续向正方向或负方向移动,则不会轻易注意到差异。我还需要测量坡度变化。我希望有一个更聪明的方法?
我试过测量一下,看看newX和oldX之间的区别是否保持不变,但它不起作用:( https://jsfiddle.net/hs5a9z5a/3/
答案 0 :(得分:3)
看看下面的代码是基于你的小提琴。
slope
是一个数组,它是x和y的向量。
它是通过减去p.x
和最后一个x坐标并将其除以时差来计算的。如果它高于threshold
,则会向控制台写入一条消息。
var points = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
var path = svg.append("path")
.data([points])
.attr("d", d3.svg.line()
.tension(0) ); //); // Catmull–Rom
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(10000)
.ease("linear")
.attr("stroke-dashoffset", 0);
svg.selectAll(".point", function(d,i){})
.data(points)
.enter().append("circle")
.transition()
.duration(2000)
.ease("linear")
.style("fill", "url(#image)")
.attr("r", 20)
.attr("transform", function(d) { return "translate(" + d + ")"; })
var circle = svg.append("circle")
.attr("r", 13)
.attr("transform", "translate(" + points[0] + ")");
transition();
function transition() {
circle.transition()
.duration(10000)
.attrTween("transform", translateAlong(path.node()))
.each("end");
}
// Returns an attrTween for translating along the specified path element.
var newX = 0, diffX = 0, prevdiffX=0, oldX=0;
var newY = 0;
var newT = 0;
function translateAlong(path) {
var l = path.getTotalLength();
var slope = [];
slope.push('-1');
slope.push('-1');
var threshold = 0.1;
return function(d, i, a) {
return function(t) {
var p = path.getPointAtLength(t * l);
if ((1 - Math.abs(slope[0]/((p.x - newX) / (t - newT) + 0.001))) > 0.1) {
console.log('slopeX changed');
} else if ((1 - Math.abs(slope[1]/((p.y - newY) / (t - newT) + 0.001))) > 0.1) {
console.log('slopeY changed');
}
slope = [];
slope.push((p.x - newX) / (t - newT) + 0.001);
slope.push((p.y - newY) / (t - newT) + 0.001);
newX = p.x;
newY = p.y;
newT = t;
return "translate(" + p.x + "," + p.y + ")";
};
};
}
path {
fill: none;
stroke: #000;
stroke-width: 3px;
}
circle {
fill: url('http://www.e-pint.com/epint.jpg');
fill: steelblue;
/stroke: #fff;
//stroke-width: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg id="mySvg" width="80" height="80">
<defs id="mdef">
<pattern id="image" x="0" y="0" height="40" width="40">
<image x="0" y="0" width="40" height="40" xlink:href="http://www.e-pint.com/epint.jpg"></image>
</pattern>
</defs>
</svg>
<div id="line"></div>
答案 1 :(得分:3)
要知道线路何时更改方向(即命中数据点),您需要控制stroke-dashoffset
上的过渡功能。我就是这样做的(我试着好好评论一下,如果你有任何问题,请告诉我):
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(10000)
.ease("linear")
.tween("myTween", function() {
var i = d3.interpolate(totalLength, 0);
var self = d3.select(this);
return function(t) {
// current position of stroke-dashoffset
var len = i(t),
// current position with respect to line length of stroke-dashoffset
per = (1 - len / totalLength) * totalLength,
// pixel position of stroke-dashoffset
p = self.node().getPointAtLength(per);
// loop our points and look for hit detection
points.forEach(function(d) {
// are we one a point?
if (Math.abs(p.x - d[0]) < 1 && Math.abs(p.y - d[1]) < 1) {
console.log("point hit");
}
});
// apply stroke-dashoffset
self.attr("stroke-dashoffset", len);
};
});
运行样本:
var points = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
var path = svg.append("path")
.data([points])
.attr("d", d3.svg.line()
.tension(0)); //); // Catmull–Rom
//.interpolate("cardinal-closed"));
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(10000)
.ease("linear")
.tween("myTween", function() {
var i = d3.interpolate(totalLength, 0);
var self = d3.select(this);
return function(t) {
var len = i(t),
per = (1 - len / totalLength) * totalLength,
p = self.node().getPointAtLength(per);
points.forEach(function(d) {
if (Math.abs(p.x - d[0]) < 1 && Math.abs(p.y - d[1]) < 1) {
console.log("point hit");
}
});
self.attr("stroke-dashoffset", i(t));
};
});
/*
svg.selectAll(".point", function(d,i){
//console.log(d,i)
})
.data(points)
.enter().append("circle")
.transition()
.duration(2000)
.ease("linear")
.style("fill", "url(#image)")
.attr("r", 20)
.attr("transform", function(d) { return "translate(" + d + ")"; })
var circle = svg.append("circle")
.attr("r", 13)
.attr("transform", "translate(" + points[0] + ")");
transition();
function transition() {
circle.transition()
.duration(10000)
.attrTween("transform", translateAlong(path.node()))
//.each("end", transition);
.each("end");
}
// Returns an attrTween for translating along the specified path element.
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
};
};
}
*/
path {
fill: none;
stroke: #000;
stroke-width: 3px;
}
circle {
fill: url('http://www.e-pint.com/epint.jpg');
fill: steelblue;
/stroke: #fff;
//stroke-width: 3px;
}
<script src="http://d3js.org/d3.v3.js"></script>
<svg id="mySvg" width="80" height="80">
<defs id="mdef">
<pattern id="image" x="0" y="0" height="40" width="40">
<image x="0" y="0" width="40" height="40" xlink:href="http://www.e-pint.com/epint.jpg"></image>
</pattern>
</defs>
</svg>
<div id="line"></div>