Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG markers not rendering

Tags:

svg

marker

Can anybody help me to understand how to get the markers to render on the path in the following example?

    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>

If I manually edit the marker elements in chrome devtools for example, and delete the viewBox attribute, the markers render. Then if I remove the viewBox attribute from the code and try again, the markers are still not rendered. Then if I manually add the viewBox, the markers render.

I tried adding the markers in a timer callback in case it was a timing issue but no change.

The rendered HTML looks like this...

<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>
like image 740
Cool Blue Avatar asked May 12 '26 06:05

Cool Blue


1 Answers

You can't create SVG elements with document.createElement you must use document.createElementNS and provide the SVG namespace.

I'm sure if you check out the rect and path elements using Chrome's devtools it will tell you that the elements are html elements (in the html namespace) rather than SVG elements.

I've corrected your example below:

    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>
like image 189
Robert Longson Avatar answered May 19 '26 03:05

Robert Longson