SVG标记无法渲染

时间:2015-10-01 10:01:34

标签: svg marker

在以下示例中,有人可以帮我理解如何在路径上渲染标记吗?

    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>

1 个答案:

答案 0 :(得分:2)

您无法使用document.createElement创建SVG元素,您必须使用document.createElementNS并提供SVG名称空间。

我确定如果你使用Chrome的devtools检查rect和path元素,它会告诉你元素是html元素(在html命名空间中)而不是SVG元素。

我已经纠正了以下示例:

&#13;
&#13;
    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("")
        }
    };
&#13;
        body{margin:0; position: relative}
        svg{outline:solid 1px #ccc;
            overflow: visible;
        }
&#13;
<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>
&#13;
&#13;
&#13;