Adding Arrowhead to SVG Line After Initializing

时间:2018-02-01 18:41:04

标签: javascript html svg

So I am trying to write an html file based off of JavaScript. I have this code completed that calculates where my lines need to be drawn, and the lines draw the way I would like. However, I cannot figure out how to add arrowheads to the end of my lines. They are SVG lines that vary in size depending on my calculations. Every website and question I have checked so far has added the arrowhead by writing a <def> for the <marker> arrowhead and then adding that piece when they initialize the line like in this example.

<svg width="600px" height="100px">
<defs>
     <marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" 
       orient="auto" markerUnits="strokeWidth">
       <path d="M0,0 L0,6 L9,3 z" fill="#f00" />
     </marker>
</defs>

<line x1="50" y1="50" x2="250" y2="50" stroke="#000" stroke-width="5" 
 marker-end="url(#arrow)" />
</svg>

But none of these statements have semicolons on the ends of them, and every time I try to implement them into my html code it crashes.

Is there a way for me to add arrowheads to an already created line? And if so, how would I fit that into my code?

This is the function in question. It handles all of the line creation and then just appends the line into the SVG to show up on a grid that I have drawn elsewhere.

The x and y inputs correspond to the pixel the user clicked on.

function createFieldLine(x, y) {

            //The routine you will write to create an electric field line.  
            var d = 0.4; // d is the step size
            var x1; //plot line segment from (x1,y1) to (x2,y2)
            var y1;
            var x2;
            var y2;
            var cx;
            var cy;
            var eX = 0;
            var eY = 0;
            //var line;  //A variable needed below to create a line in the 
                     svg
            var g = document.createElementNS(svgNS, "g"); //Create a group 
                    in which to place the field line
            fieldLineGroup.appendChild(g);  //Append group to the svg

            var eMag = 0;

            for (i = 0; i < charges.length; i++) {
                x1 = x;
                y1 = y;
                cx = charges[i][0];
                cy = charges[i][1];
                charge = charges[i][2];

                eX = eX + ((9 * Math.pow(10, 9)) * (charge / Math.pow(10, 
                      9)) * (x1 - cx) / Math.pow(Math.sqrt(Math.pow(x1 - cx, 
                       2) + Math.pow(y1 - cy, 2)), 3));
                eY = eY + ((9 * Math.pow(10, 9)) * (charge / Math.pow(10, 
                        9)) * (y1 - cy) / Math.pow(Math.sqrt(Math.pow(x1 - 
                        cx, 2) + Math.pow(y1 - cy, 2)), 3));

                eMag = Math.abs(eMag + Math.sqrt(Math.pow(eX, 2) + 
                       Math.pow(eY, 2)));

                console.log(eX + "is an x component");
                console.log(eY + "is a y component");
                console.log(eMag + "is the magnitude of the field from " + 
               (i + 1) + "charges.");
            }

            x2 = x1 + eX * 1000;
            y2 = y1 + eY * 1000;

            line = document.createElementNS(svgNS, "line");
            line.setAttributeNS(null, "style", 
                       "fill:none;stroke:#000000;stroke-miterlimit:10;");
            line.setAttributeNS(null, "x1", xTranslated(x1));
            line.setAttributeNS(null, "y1", yTranslated(y1));
            line.setAttributeNS(null, "x2", xTranslated(x2));
            line.setAttributeNS(null, "y2", yTranslated(y2));
            line.style.strokeWidth = "2";
            g.appendChild(line);
 }

I should think that a possible fix would go into this function. But here is the entirety of my file if it is necessary

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style>
        </style>
    </head>
    <body>
        <svg version="1.1" id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	    width="510px" height="410px" viewBox="0 0 510 410" style="enable-background:new 0 0 500 400;" xml:space="preserve" onmouseup="mouseUp(evt)">
            <g id="gridLineGroup"></g>
            <g id="fieldLineGroup"></g>
            <g id="chargesGroup"></g>
        </svg>

        <script>
            var svgNS = "http://www.w3.org/2000/svg";
            var origin = { x: 5, y: 5 };  //Sets the location of the coordinate system origin
            var scale = { x: 1, y: 1 };  //Sets the scale of the coordinate system
            var width = 500;  //Sets the width of the grid
            var height = 400;  //Sets the height of the grid
            var chargeRadius = 10;  //Radius of the charges
            var charges = [[125, 250, 6], [175, 250, -3]];  //[x,y,q] coordinates and the size of each charge.  

            //Variables that point to various svg groups.
            svg = document.getElementById("svg");
            gridLineGroup = document.getElementById("gridLineGroup");
            chargeGroup = document.getElementById("chargesGroup");
            fieldLineGroup = document.getElementById("fieldLineGroup");
            createGrid(width, height);
            for (var chargeNum = 0; chargeNum < charges.length; chargeNum++) {
                createCharge(charges[chargeNum]);
            }

            function mouseUp(evt) {
                //Called whenever the svg is clicked.  
                var bound = svg.getBoundingClientRect();

                var x = evt.clientX - bound.left - svg.clientLeft - origin.x;
                var y = evt.clientY - bound.top - svg.clientTop - origin.y;

                console.log("x=" + x + " y=" + y);
                createFieldLine(x, y);  //Calls the routine to create a field line and passes the (x,y) coordinates of the mouse click.
            }

            function createFieldLine(x, y) {
                
                //The routine you will write to create an electric field line.  T
                var d = 0.4; // d is the step size
                var x1; //plot line segment from (x1,y1) to (x2,y2)
                var y1;
                var x2;
                var y2;
                var cx;
                var cy;
                var eX = 0;
                var eY = 0;
                //var line;  //A variable needed below to create a line in the svg
                var g = document.createElementNS(svgNS, "g"); //Create a group in which to place the field line
                fieldLineGroup.appendChild(g);  //Append group to the svg

                var eMag = 0;

                for (i = 0; i < charges.length; i++) {
                    x1 = x;
                    y1 = y;
                    cx = charges[i][0];
                    cy = charges[i][1];
                    charge = charges[i][2];

                    eX = eX + ((9 * Math.pow(10, 9)) * (charge / Math.pow(10, 9)) * (x1 - cx) / Math.pow(Math.sqrt(Math.pow(x1 - cx, 2) + Math.pow(y1 - cy, 2)), 3));
                    eY = eY + ((9 * Math.pow(10, 9)) * (charge / Math.pow(10, 9)) * (y1 - cy) / Math.pow(Math.sqrt(Math.pow(x1 - cx, 2) + Math.pow(y1 - cy, 2)), 3));

                    eMag = Math.abs(eMag + Math.sqrt(Math.pow(eX, 2) + Math.pow(eY, 2)));

                    console.log(eX + "is an x component");
                    console.log(eY + "is a y component");
                    console.log(eMag + "is the magnitude of the field from " + (i + 1) + "charges.");
                }

                x2 = x1 + eX * 1000;
                y2 = y1 + eY * 1000;

                /* Include the following code to create a line segment from (x1,y1) to (x2,y2).  You will have to calculate (x1,y1) and (x2,y2) */
                line = document.createElementNS(svgNS, "line");
                line.setAttributeNS(null, "style", "fill:none;stroke:#000000;stroke-miterlimit:10;");
                line.setAttributeNS(null, "x1", xTranslated(x1));
                line.setAttributeNS(null, "y1", yTranslated(y1));
                line.setAttributeNS(null, "x2", xTranslated(x2));
                line.setAttributeNS(null, "y2", yTranslated(y2));
                line.style.strokeWidth = "2";
                g.appendChild(line);
                /**/

            }


            function createCharge(charge) {
                //Creates a charge.
                //Each charge consists of a filled circle with the size of the charge printed inside.  The circle and label are placed inside a group.
                var x = charge[0];
                var y = charge[1];
                var q = charge[2];
                var g = document.createElementNS(svgNS, "g");
                chargeGroup.appendChild(g);
                var circle = document.createElementNS(svgNS, "circle");
                //Color the circle differently if it is positive or negative
                if (q > 0) {
                    circle.setAttributeNS(null, "style", "fill:#AAFFFF;stroke:#000000;stroke-miterlimit:10;");
                } else {
                    circle.setAttributeNS(null, "style", "fill:#FFAAAA;stroke:#000000;stroke-miterlimit:10;");
                }
                circle.setAttributeNS(null, "cx", xTranslated(x));
                circle.setAttributeNS(null, "cy", xTranslated(y));
                circle.setAttributeNS(null, "r", chargeRadius);
                g.appendChild(circle);
                var text = document.createElementNS(svgNS, "text");
                text.setAttributeNS(null, "transform", "matrix(1 0 0 1 " + xTranslated(x - 7) + " " + yTranslated(y + 2) + ")");
                text.setAttributeNS(null, "style", "font-size:6pt");
                if (q > 0) {
                    text.textContent = "+" + q + "C";
                } else {
                    text.textContent = q + "C";
                }
                g.appendChild(text);
            }

            function createGrid(width, height) {
                var line;
                //The horizontal lines
                for (var y = 0; y <= height; y += 25) {
                    line = document.createElementNS(svgNS, "line");
                    line.setAttributeNS(null, "style", "fill:none;stroke:#FFCC00;stroke-miterlimit:10;");
                    line.setAttributeNS(null, "x1", origin.x);
                    line.setAttributeNS(null, "y1", yTranslated(y));
                    line.setAttributeNS(null, "x2", origin.x + scale.x * width);
                    line.setAttributeNS(null, "y2", yTranslated(y));
                    gridLineGroup.appendChild(line);
                }
                //The vertical lines
                for (var x = 0; x <= width; x += 25) {
                    line = document.createElementNS(svgNS, "line");
                    line.setAttributeNS(null, "style", "fill:none;stroke:#FFCC00;stroke-miterlimit:10;")
                    line.setAttributeNS(null, "x1", xTranslated(x));
                    line.setAttributeNS(null, "y1", origin.y);
                    line.setAttributeNS(null, "x2", xTranslated(x));
                    line.setAttributeNS(null, "y2", origin.y + scale.y * height);
                    gridLineGroup.appendChild(line);
                }
            }

            function xTranslated(x) {
                //Allows the horizontal origin and scale of the svg to be easily changed if needed in the future.
                return origin.x + scale.x * x;
            }

            function yTranslated(y) {
                //Allows the vertical origin and scale of the svg to be easily changed if needed in the future.
                return origin.y + scale.y * y;
            }
        </script>
    </body>
</html>

2 个答案:

答案 0 :(得分:0)

marker-end是一个所谓的presentation attribute,这意味着它既可以作为属性也可以作为样式属性编写。因此,使用箭头编写行的最简单方法是定义样式类:

var svgNS = "http://www.w3.org/2000/svg";

var line = document.createElementNS(svgNS, "line");
line.setAttribute("class", "arrow");
line.setAttribute("x1", 50); //Namespacing is only needed for creating the element
line.setAttribute("y1", 05);
line.setAttribute("x2", 250);
line.setAttribute("y2", 05);

var svg = document.getElementById("svg");
svg.appendChild(line);
.arrow {
    stroke: #000000;
    stroke-width: 2;
    marker-end: url(#arrow);
}
<svg width="600px" height="200px" id="svg">
<defs>
     <marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" 
       orient="auto" markerUnits="strokeWidth">
       <path d="M0,0 L0,6 L9,3 z" fill="#f00" />
     </marker>
</defs>
</svg>

答案 1 :(得分:0)

只需使用def参考值

调用set属性

&#13;
&#13;
function change () {

    var line2 = document.getElementById("line2");

    line2.setAttribute("marker-end", "url(#arrow)");
}
&#13;
<svg width="600px" height="100px">
<defs>
     <marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
       <path d="M0,0 L0,6 L9,3 z" fill="#f00"></path>
     </marker>
</defs>

<line id="line1" x1="50" y1="30" x2="250" y2="30" stroke="#000" stroke-width="5" marker-end="url(#arrow)"></line>
<line id="line2" x1="50" y1="70" x2="250" y2="70" stroke="red" stroke-width="5"></line>
</svg>
<button onclick="change()">change</button>
&#13;
&#13;
&#13;