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>
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With