在SVG多路径(d3.js)中移动到鼠标单击

时间:2019-04-18 19:18:57

标签: javascript html d3.js svg

我需要创建一个圆,并在发生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>

谢谢。

0 个答案:

没有答案