SVG 标记未呈现

SVG markers not rendering

任何人都可以帮助我了解如何在以下示例中让标记呈现在路径上吗?

    var size = {width: 500, height: 180},
        svg = d3.select("body").append("svg").attr(size),
        markers = Marker(svg, "red");

    var circles = svg.append("ellipse").datum({})
            .attr({
                class: "circle",
                'cx': size.width / 2,
                'cy': size.height / 2,
                'ry': 50,
                'rx': 100,
                "fill": "steelblue"
            }),
        shadePath = svg.append("path")
            .attr({
                class: "arrow",
                d: d3.svg.line()([[100,50], [400,150]]),
                stroke: "red"
            }).style({
                "marker-start": markers.start,
                "marker-end": markers.end
            });

    function Marker(svg, color){
        var id = "filter-marker", defs = svg.selectAll("defs").data([id]),
            idS = id + "-start", idE = id + "-end";

        defs.enter().append("defs");
        var markers = defs.selectAll("#"+id).data([
            {
                attr: {id: idS, viewBox: "0 0 7 7",
                    markerWidth: "7", markerHeight: "7",
                    refX: "4", refY: "4",orient: "auto"},
                symbol: {
                    type: "rect",
                    attr: {x: "1", y: "1", width: "5", height: "5", style: "stroke: none; fill: " + color + ";"}
                }
            },
            {
                attr: {id: idE, viewBox: "0 0 13 13",
                    markerWidth: "13", markerHeight: "13",
                    refX: "2", refY: "7", orient: "auto"},
                symbol: {
                    type: "path",
                    attr:{d: "M2,2 L2,13 L8,7 L2,2", style: "stroke: none; fill: " + color + ";"}
                }
            }
        ]);
        markers.enter().append("marker")
            .each(function(d){
                return d3.select(this).attr(d.attr)
            });
        var marker = markers.selectAll(".symbol").data(function(d){return [d.symbol]});
        marker.enter().append(function(d) {
            return document.createElement(d.type)
        })
            .each(function(d){
                return d3.select(this).attr(d.attr)
            });

        return {
            start: ["url(#", idS, ")"].join(""),
            end: ["url(#", idE, ")"].join("")
        }
    };
        body{margin:0; position: relative}
        svg{outline:solid 1px #ccc;
            overflow: visible;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.1.2/tinycolor.min.js"></script>

例如,如果我在 chrome devtools 中手动编辑标记元素,并删除 viewBox 属性,则标记会呈现。然后,如果我从代码中删除 viewBox 属性并重试,标记仍未呈现。然后,如果我手动添加 viewBox,则标记会呈现。

我尝试在计时器回调中添加标记,以防出现计时问题但没有任何变化。

渲染后的 HTML 看起来像这样...

<svg width="500" height="180">
    <defs>
        <marker id="filter-marker-start" viewBox="0 0 7 7" markerWidth="7"
                markerHeight="7" refX="4" refY="4"
                orient="auto">
            <rect x="1" y="1" width="5" height="5"
                  style="stroke: none; fill: red;"></rect>
        </marker>
        <marker id="filter-marker-end" viewBox="0 0 13 13" markerWidth="13"
                markerHeight="13" refX="2" refY="7"
                orient="auto">
            <path d="M2,2 L2,13 L8,7 L2,2" style="stroke: none; fill: red;"></path>
        </marker>
    </defs>
    <ellipse class="circle" cx="250" cy="90" ry="50" rx="100" fill="steelblue"></ellipse>
    <path class="arrow" d="M100,50L400,150" stroke="red"
          style="marker-start: url(#filter-marker-start); marker-end: url(#filter-marker-end);">
    </path>
</svg>

您不能使用 document.createElement 创建 SVG 元素,您必须使用 document.createElementNS 并提供 SVG 命名空间。

我敢肯定,如果您使用 Chrome 的开发工具检查矩形和路径元素,它会告诉您这些元素是 html 元素(在 html 命名空间中) 而不是 SVG 元素。

我已经在下面更正了您的示例:

    var size = {width: 500, height: 180},
        svg = d3.select("body").append("svg").attr(size),
        markers = Marker(svg, "red");

    var circles = svg.append("ellipse").datum({})
            .attr({
                class: "circle",
                'cx': size.width / 2,
                'cy': size.height / 2,
                'ry': 50,
                'rx': 100,
                "fill": "steelblue"
            }),
        shadePath = svg.append("path")
            .attr({
                class: "arrow",
                d: d3.svg.line()([[100,50], [400,150]]),
                stroke: "red"
            }).style({
                "marker-start": markers.start,
                "marker-end": markers.end
            });

    function Marker(svg, color){
        var id = "filter-marker", defs = svg.selectAll("defs").data([id]),
            idS = id + "-start", idE = id + "-end";

        defs.enter().append("defs");
        var markers = defs.selectAll("#"+id).data([
            {
                attr: {id: idS, viewBox: "0 0 7 7",
                    markerWidth: "7", markerHeight: "7",
                    refX: "4", refY: "4",orient: "auto"},
                symbol: {
                    type: "rect",
                    attr: {x: "1", y: "1", width: "5", height: "5", style: "stroke: none; fill: " + color + ";"}
                }
            },
            {
                attr: {id: idE, viewBox: "0 0 13 13",
                    markerWidth: "13", markerHeight: "13",
                    refX: "2", refY: "7", orient: "auto"},
                symbol: {
                    type: "path",
                    attr:{d: "M2,2 L2,13 L8,7 L2,2", style: "stroke: none; fill: " + color + ";"}
                }
            }
        ]);
        markers.enter().append("marker")
            .each(function(d){
                return d3.select(this).attr(d.attr)
            });
        var marker = markers.selectAll(".symbol").data(function(d){return [d.symbol]});
        marker.enter().append(function(d) {
            return document.createElementNS("http://www.w3.org/2000/svg", d.type)
        })
            .each(function(d){
                return d3.select(this).attr(d.attr)
            });

        return {
            start: ["url(#", idS, ")"].join(""),
            end: ["url(#", idE, ")"].join("")
        }
    };
        body{margin:0; position: relative}
        svg{outline:solid 1px #ccc;
            overflow: visible;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.1.2/tinycolor.min.js"></script>