medievalmatt medievalmatt - 3 months ago 35
Javascript Question

translate SVG striped pattern into d3

I have a chart I'm constructing in d3, and I'd like to include a striped bar in spots. I have a test version of the bar working in SVG:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64 64">
<defs>
<pattern id="diagonalStripes" x="0" y="0" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<rect x="0" y="0" width="2" height="15" style="stroke:none; fill:purple;" />
<rect x="2" y="0" width="2" height="15" style="stroke:none; fill:green;" />
<rect x="4" y="0" width="2" height="15" style="stroke:none; fill:red;" />
<rect x="6" y="0" width="2" height="15" style="stroke:none; fill:yellow;" />
</pattern>
</defs>

<rect x="0" y="0" width="5" height="15" style="fill:url(#diagonalStripes);"></rect>
</svg>


But when I attempt to translate the information between the tags into d3 only the first bar (the purple one) shows up:

svg.append('defs')
.append('pattern')
.attr('id', 'diagonalStripes')
.attr('patternUnits', 'userSpaceOnUse')
.attr('patternTransform', 'rotate(45)')
.attr('width', 8)
.attr('height', 8)
.append('rect')
.attr("x",0)
.attr("y",0)
.attr('width', 2)
.attr('height', 15)
.attr('style',"stroke:none; fill:purple;")
.append('rect')
.attr("x",2)
.attr("y",0)
.attr('width', 2)
.attr('height', 15)
.attr('style',"stroke:none; fill:yellow;")
.append('rect')
.attr("x",4)
.attr("y",0)
.attr('width', 2)
.attr('height', 15)
.attr('style',"stroke:none; fill:red;")
.append('rect')
.attr("x",6)
.attr("y",0)
.attr('width', 2)
.attr('height', 15)
.attr('style',"stroke:none; fill:green;");

svg.append("rect")
.attr("x", 10)
.attr("width", 10)
.attr("height", 10)
.attr('fill', 'url(#diagonalStripes)')


Obviously d3 doesn't handle appending multiple rectangles to a single pattern, but how should I format that first section correctly in order to get the striped bar I expect?

Answer

Instead of doing:

svg.append('defs')
  .append('pattern')
    .attr('id', 'diagonalStripes')
    .attr('patternUnits', 'userSpaceOnUse')
    .attr('patternTransform', 'rotate(45)')
    .attr('width', 8)
    .attr('height', 8)
    .append('rect')
    .attr("x",0)
    .attr("y",0)
    .attr('width', 2)
    .attr('height', 15)
    .attr('style',"stroke:none; fill:purple;")
    .append('rect')
    .attr("x",2)
    .attr("y",0)
    .attr('width', 2)
    .attr('height', 15)
    .attr('style',"stroke:none; fill:yellow;")
    .append('rect')
    .attr("x",4)
    .attr("y",0)
    .attr('width', 2)
    .attr('height', 15)
    .attr('style',"stroke:none; fill:red;") 
    .append('rect') 
    .attr("x",6)
    .attr("y",0)
    .attr('width', 2)
    .attr('height', 15)
    .attr('style',"stroke:none; fill:green;"); 

Do it this way:

 var defs = svg.append('defs')
   .append('pattern')
   .attr('id', 'diagonalStripes')
   .attr('patternUnits', 'userSpaceOnUse')
   .attr('patternTransform', 'rotate(45)')
   .attr('width', 8)
   .attr('height', 8);
 //to def add rect.
 defs
   .append('rect')
   .attr("x", 0)
   .attr("y", 0)
   .attr('width', 2)
   .attr('height', 15)
   .attr('style', "stroke:none; fill:purple;");
 defs
   .append('rect')
   .attr("x", 2)
   .attr("y", 0)
   .attr('width', 2)
   .attr('height', 15)
   .attr('style', "stroke:none; fill:yellow;");


 defs
   .append('rect')
   .attr("x", 4)
   .attr("y", 0)
   .attr('width', 2)
   .attr('height', 15)
   .attr('style', "stroke:none; fill:red;");

 defs.append('rect')
   .attr("x", 6)
   .attr("y", 0)
   .attr('width', 2)
   .attr('height', 15)
   .attr('style', "stroke:none; fill:green;");

working code here

The problem with your approach is that you are appending a rectangle DOM inside another rectangle. Like first you make a pattern then you add a rect DOM inside the pattern DOM. Later you add the next rect DOM inside the first created rect DOM so on.