我需要创建一个圆,并在发生mousedown事件时将其移动到SVG路径中的最近点。
动画在一个路径中正常工作,但是在添加其他路径时,圆会停止移动。
检查:http://jsfiddle.net/grf15mqv/
我试图在一个变量中创建路径,但这不起作用。
代码:
var points = [[180,300],[234,335],[288,310],[350,290],[405,300],[430,305],[475,310],[513,300],[550,280]];
var pointss = [[246,333],[300,370],[350,400]];
var pointsss = [[400,150],[430,305],[500,433]];
var width = 1000,height = 600;
var line = d3.svg.line().interpolate("cardinal");
var svg = d3.select("#Con").append("svg").attr("width", width).attr("height", height).attr("id", "svgs");
var path = svg.append("path").datum(points).attr("d", line) //+ svg.append("path").datum(pointss).attr("d", line) + svg.append("path").datum(pointsss).attr("d", line);
var line = svg.append("line");
var circle = svg.append("circle").attr("cx", -10).attr("cy", -10).attr("r", 3.5).attr("id", "pointm");
circle.attr("cx", 180).attr("cy", 300);
svg.append("rect").attr("width", width).attr("height", height).on("mousedown", mouseclick);
var lastIndex = 0;
function mouseclick() {
let m = d3.mouse(this);
let p = closestPoint(path.node(), m);
let forward = true;
let currentPoint = path.node().getPointAtLength(lastIndex);
if (p[0] < currentPoint.x) {
forward = false;
}
let pathLength = path.node().getTotalLength();
getAnimate(pathLength, path, lastIndex, p[0], forward)();
}
let timer;
function getAnimate(pLength, path, currentIndex, finishPos, forward) {
let animate = function() {
clearTimeout(timer);
let scan = path.node().getPointAtLength(currentIndex);
if (scan.x < finishPos || !forward && scan.x > finishPos) {
circle.attr("cx", scan.x).attr("cy", scan.y);
}
if (forward) {
currentIndex += 1;
lastIndex = currentIndex;
if (scan.x < finishPos) {
timer = setTimeout(animate, 10);
}
} else {
currentIndex -= 1;
lastIndex = currentIndex;
if (scan.x > finishPos) {
timer = setTimeout(animate, 10);
}
}
}
return animate;
}
function closestPoint(pathNode, point) {
var pathLength = pathNode.getTotalLength(),precision = 8,best, bestLength, bestDistance = Infinity;
for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
best = scan, bestLength = scanLength, bestDistance = scanDistance;
}
}
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;
}
}
* {
margin: 0;
padding: 0;
}
#Con {
border: 1px solid black;
margin: auto;
width: 1000px;
height: 600px;
}
path {
z-index: 1000;
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
line {
fill: none;
stroke: red;
stroke-width: 1.5px;
}
circle {
fill: red;
}
rect {
fill: none;
pointer-events: all;
}
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.5.0"></script>
<div id="Con">
<span>Remove the"//" comment to see the three paths</span>
</div>
谢谢。