javascript - 在 svg 路径中​​动态绘制箭头不起作用

标签 javascript jquery svg

var Belay = (function () {
    var settings = {
        strokeColor: '#fff',
        strokeWidth: 2,
        opacity: 1,
        fill: 'none',
        animate: true,
        animationDirection: 'right',
        animationDuration: .75
    };
    var me = {};

    me.init = function (initObj) {
        if (initObj) {
            $.each(initObj, function (index, value) {
                //TODO validation on settings
                settings[index] = value;
            });
        }
    }

    me.set = function (prop, val) {
        //TODO validate
        settings[prop] = val;
    }

    me.on = function (el1, el2) {
        var $el1 = $(el1);
        var $el2 = $(el2);
        if ($el1.length && $el2.length) {
            var svgheight, p, svgleft, svgtop, svgwidth

            var el1pos = $(el1).offset();
            var el2pos = $(el2).offset();

            var el1H = $(el1).outerHeight();
            var el1W = $(el1).outerWidth();

            var el2H = $(el2).outerHeight();
            var el2W = $(el2).outerWidth();

            var node1X = Math.round(el1pos.left + el1W);
            var node2X = Math.round(el2pos.left);
            var overlapping = node1X >= node2X;
            
            var svgwidth = Math.abs(node2X - node1X);
            var svgleft = Math.min(node1X, node2X);

            var node1Y = Math.round(el1pos.top + el1H / 2);
            var node2Y = Math.round(el2pos.top + el1H / 2);
            
            var svgheight = Math.abs(node1Y - node2Y);
            var svgtop = Math.min(node1Y, node2Y);

            var pt1x = node1X - svgleft;
            var pt1y = node1Y - svgtop + settings.strokeWidth;
            var pt2x = node2X - svgleft;
            var pt2y = node2Y - svgtop + settings.strokeWidth;

            // cpt is the length of the control point vector
            // variew with distance netween boxes
            var cpt = Math.round(svgwidth * Math.min(svgheight / 300, 1));

            if (overlapping) {
                // Need to widen the svg because otherwise the bezier control
                // points (and hence the curve) will extend outside it.
                svgleft -= cpt;
                svgwidth += 2 * cpt;
                pt1x += cpt;
                pt2x += cpt;
            }

            // Build the path decription
            p = "M" + pt1x + "," + pt1y +
            " L" + (pt1x + pt2x) / 8 + "," + pt1y +
            " L" + (pt1x + pt2x) / 8 + "," + pt2y //+
            " L" + (pt2x) / 1.03 + "," + pt2y +
            " L" + (pt2x) / 1.03 + "," + (pt2y - 5) +
            " L" + pt2x + "," + pt2y +
            " L" + (pt2x) / 1.03 + "," + (pt2y + 5) +
            " L" + (pt2x) / 1.03 + "," + pt2y;

            //ugly one-liner
            $ropebag = $('#ropebag').length ? $('#ropebag') : $('body').append($("<div id='ropebag' />")).find('#ropebag');

            var svgnode = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            var defs = document.createElementNS('http://www.w3.org/2000/svg', "defs");
            var marker = document.createElementNS('http://www.w3.org/2000/svg', "marker");
            var path = document.createElementNS('http://www.w3.org/2000/svg', "path");

            marker.setAttributeNS(null,"id","arrow");
            marker.setAttributeNS(null,"markerWidth","13");
            marker.setAttributeNS(null,"markerHeight","13");
            marker.setAttributeNS(null,"refX","2");
            marker.setAttributeNS(null,"refY","7");
            marker.setAttributeNS(null,"markerUnits","userSpaceOnUse");
            path.setAttributeNS(null,"d","M2,2 L2,13 L8,7 L2,2");

						marker.appendChild(path);
            defs.appendChild(marker);

            var newpath = document.createElementNS('http://www.w3.org/2000/svg', "path");
            newpath.setAttributeNS(null, "d", p);
            newpath.setAttributeNS(null, "stroke", settings.strokeColor);
            newpath.setAttributeNS(null, "stroke-width", settings.strokeWidth);
            newpath.setAttributeNS(null, "opacity", settings.opacity);
            newpath.setAttributeNS(null, "fill", settings.fill);
            newpath.setAttributeNS(null, "marker-end", "url(#arrow)");

           svgnode.appendChild(newpath);
           svgnode.appendChild(defs);
          
            $(svgnode).css({
                left: svgleft,
                top: svgtop - settings.strokeWidth,
                position: 'absolute',
                width: svgwidth,
                height: svgheight + settings.strokeWidth * 2,
                minHeight: '20px',
                'pointer-events': 'none'
            });
            $ropebag.append(svgnode);
            if (settings.animate) {
                // THANKS to http://jakearchibald.com/2013/animated-line-drawing-svg/
                var pl = newpath.getTotalLength();
                // Set up the starting positions
                newpath.style.strokeDasharray = pl + ' ' + pl;

                if (settings.animationDirection == 'right') {
                    newpath.style.strokeDashoffset = pl;
                } else {
                    newpath.style.strokeDashoffset = -pl;
                }

                // Trigger a layout so styles are calculated & the browser
                // picks up the starting position before animating
                // WON'T WORK IN IE. If you want that, use requestAnimationFrame to update instead of CSS animation
                newpath.getBoundingClientRect();
                newpath.style.transition = newpath.style.WebkitTransition = 'stroke-dashoffset ' + settings.animationDuration + 's ease-in-out';
                // Go!
                newpath.style.strokeDashoffset = '0';
            }
        }
    }

    me.off = function () {
        $("#ropebag").empty();
    }

    return me;
}());


/***********************  Custom JavaScript **********************************/


$(document).ready(function () {


    $(".draggable").draggable({
        drag: function (event, ui) {
            Belay.off();
            drawConnectors();
        }
    });



    function drawConnectors() {
        $(".parent").each(function () {
            var theID = this.id;
            $("." + theID).each(function (i, e) {
                var rand = Math.random() * .7 + .3;
                Belay.set('animationDuration', rand)
                Belay.on($("#" + theID), e)
            });
        })
    }

    $(window).resize(function () {
        Belay.off();
        drawConnectors();
    });

    Belay.init({
        strokeWidth: 1
    });
    Belay.set('strokeColor', '#999');
    drawConnectors();
});
.row{
margin-top:2in;
}

.box{
    border:1px solid #ccc;
    padding:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>

<body>
    <div class="row">
        <div class="col-md-4">
            <div class="pull-left ">
                <div class="parent draggable box" id="parent1">Left drag</div>
            </div>

            <div class="pull-right">
                <div class="child parent1 draggable box">Right drag</div>
            </div>
        </div>
    </div>
</body>

嗨,按照这个例子 how-to-change-the-lines-between-two-points-from-curved-to-straight-lines-with-on如何动态地在路径末尾绘制箭头

有人可以告诉我在代码中添加标记结尾有什么问题

var Belay = (function () 
{
    var settings = {
        strokeColor: 'red',
        strokeWidth: 2,
        opacity: 1,
        fill: 'none',
        animate: true,
        animationDirection: 'right',
        animationDuration: .75
    };
    var me = {};

    me.init = function (initObj) {
        if (initObj) {
            $.each(initObj, function (index, value) {
                //TODO validation on settings
                settings[index] = value;
            });
        }
    }

    me.set = function (prop, val) {
        //TODO validate
        settings[prop] = val;
    }

    me.on = function (el1, el2) {
        var $el1 = $(el1);
        var $el2 = $(el2);
        if ($el1.length && $el2.length) {
            var svgheight, p, svgleft, svgtop, svgwidth

            var el1pos = $(el1).offset();
            var el2pos = $(el2).offset();

            var el1H = $(el1).outerHeight();
            var el1W = $(el1).outerWidth();

            var el2H = $(el2).outerHeight();
            var el2W = $(el2).outerWidth();

            var node1X = Math.round(el1pos.left + el1W);
            var node2X = Math.round(el2pos.left);
            var overlapping = node1X >= node2X;

            var svgwidth = Math.abs(node2X - node1X);
            var svgleft = Math.min(node1X, node2X);

            var node1Y = Math.round(el1pos.top + el1H / 2);
            var node2Y = Math.round(el2pos.top + el1H / 2);

            var svgheight = Math.abs(node1Y - node2Y);
            var svgtop = Math.min(node1Y, node2Y);

            var pt1x = node1X - svgleft;
            var pt1y = node1Y - svgtop + settings.strokeWidth;
            var pt2x = node2X - svgleft;
            var pt2y = node2Y - svgtop + settings.strokeWidth;

            // cpt is the length of the control point vector
            // variew with distance netween boxes
            var cpt = Math.round(svgwidth * Math.min(svgheight / 300, 1));

            if (overlapping) {
                // Need to widen the svg because otherwise the bezier control
                // points (and hence the curve) will extend outside it.
                svgleft -= cpt;
                svgwidth += 2 * cpt;
                pt1x += cpt;
                pt2x += cpt;
            }

            p = "M" + pt1x + "," + pt1y +
            " L" + (pt1x + pt2x) / 8 + "," + pt1y +
            " L" + (pt1x + pt2x) / 8 + "," + pt2y +
            " L" + (pt2x) / 1.03 + "," + pt2y +
            " L" + (pt2x) / 1.03 + "," + (pt2y - 5) +
            " L" + pt2x + "," + pt2y +
            " L" + (pt2x) / 1.03 + "," + (pt2y + 5) +
            " L" + (pt2x) / 1.03 + "," + pt2y;

            //ugly one-liner
            $ropebag = $('#ropebag').length ? $('#ropebag') : $('body').append($("<div id='ropebag' />")).find('#ropebag');

            var svgnode = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

            //try
            var defs = document.createElementNS('http://www.w3.org/2000/svg', "defs");
            var marker = document.createElementNS('http://www.w3.org/2000/svg', "marker");
            var path = document.createElementNS('http://www.w3.org/2000/svg', "path");

            marker.setAttributeNS(null,"id","arrow");
            marker.setAttributeNS(null,"markerWidth",10);
            marker.setAttributeNS(null,"markerHeight",10);
            marker.setAttributeNS(null,"refX",0);
            marker.setAttributeNS(null,"refY",5);
            marker.setAttributeNS(null,"viewbox","0 0 10 10");
            marker.setAttributeNS(null,"orient","auto");
            marker.setAttributeNS(null,"markerUnits","strokeWidth");
            
            path.setAttributeNS(null,"d","M 0 0 L 10 5 L 0 10");
            ////try
            marker.appendChild(path);
            defs.appendChild(marker);

            var newpath = document.createElementNS('http://www.w3.org/2000/svg', "path");
            newpath.setAttributeNS(null, "d", p);
            newpath.setAttributeNS(null, "stroke", settings.strokeColor);
            newpath.setAttributeNS(null, "stroke-width", settings.strokeWidth);
            newpath.setAttributeNS(null, "opacity", settings.opacity);
            newpath.setAttributeNS(null, "fill", settings.fill);
            newpath.setAttributeNS(null, "marker-end", "url(#arrow)");

            newpath.appendChild(defs);


            svgnode.appendChild(newpath);
            //for some reason, adding a min-height to the svg div makes the lines appear more correctly.
            $(svgnode).css({
                left: svgleft,
                top: svgtop - settings.strokeWidth,
                position: 'absolute',
                width: svgwidth,
                height: svgheight + settings.strokeWidth * 2,
                minHeight: '20px',
                'pointer-events': 'none'
            });
            $ropebag.append(svgnode);
            if (settings.animate) {
                // THANKS to http://jakearchibald.com/2013/animated-line-drawing-svg/
                var pl = newpath.getTotalLength();
                // Set up the starting positions
                newpath.style.strokeDasharray = pl + ' ' + pl;

                if (settings.animationDirection == 'right') {
                    newpath.style.strokeDashoffset = pl;
                } else {
                    newpath.style.strokeDashoffset = -pl;
                }

                // Trigger a layout so styles are calculated & the browser
                // picks up the starting position before animating
                // WON'T WORK IN IE. If you want that, use requestAnimationFrame to update instead of CSS animation
                newpath.getBoundingClientRect();
                newpath.style.transition = newpath.style.WebkitTransition = 'stroke-dashoffset ' + settings.animationDuration + 's ease-in-out';
                // Go!
                newpath.style.strokeDashoffset = '0';
            }
        }
    }

    me.off = function () 
	{
        $("#ropebag").empty();
    }

    return me;
} ());

function drawConnectors() 
{
    
}

最佳答案

您似乎没有将 newpath 附加到任何内容。

此外,您还将 defs 附加到 newpath。我不确定这是否有效(我从未尝试过)。你应该避免这样做。将 defs 附加到 SVG。

关于javascript - 在 svg 路径中​​动态绘制箭头不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44195693/

相关文章:

javascript - 使用 ng-file-upload 和 angularjs 进行内容处理

javascript - 如何将传递到 function() 的动态参数中继到 function() 中调用的 function()

javascript - 是否可以在不重新加载的情况下运行注入(inject)的脚本?

css - SVG 使用 css 或 xml 从其中心点在一个圆圈中制作动画

javascript - 从由独立线创建的形状创建多边形

javascript - 仅在屏幕媒体上运行 javascript/jquery,而不是打印

javascript - 如何在 wp7 和 wp8 上运行 Jurassic(js 引擎)

javascript - Highcharts 堆积区 : legend hover event

javascript - 如何访问当前表格行特定单元格?

javascript - 旋转标签 nvd3 折线图