Home > Enterprise >  How to make the patterns of a pie chart parallel to the center line of sectors in d3.js?
How to make the patterns of a pie chart parallel to the center line of sectors in d3.js?

Time:05-29

I created a pie chart filled with patterns. I want to make the pattern parallel to the center line of the sector it is in. I tried to change the patternTransform parameter to rotate the pattern, but I do not know how to get the correct degree.

How could I achieve this? Here is the diagram of the result I want.

My current code:

<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="300" height="200"> </svg>
<svg>
    
    <defs>
        <pattern id="pattern0"
                 x="0" y="0" width="20" height="20"
                 patternUnits="userSpaceOnUse" patternTransform="rotate(0)">
      
          <rect id="rotateRect" x="5" y = "5" width = "10" height = "10" fill = "   #87CEFA "/>
      
        </pattern>
      </defs>
    
      <defs>
        <pattern id="pattern1"
                 x="0" y="0" width="20" height="20"
                 patternUnits="userSpaceOnUse" patternTransform="rotate(0)">
      
            <rect id="rotateRect" x="5" y = "5" width = "10" height = "10" fill = " #4169E1 "/>
      
        </pattern>
      </defs>
    
      <defs>
        <pattern id="pattern2"
                 x="0" y="0" width="20" height="20"
                 patternUnits="userSpaceOnUse" patternTransform="rotate(0)">
      
            <rect id="rotateRect" x="5" y = "5" width = "10" height = "10" fill = " #000080 "/>
      
        </pattern>
      </defs>
    
        <rect x="0" y="0" width="100" height="100"
        style="stroke: #000000; fill: url(#pattern0);" />   
    <rect x="100" y="0" width="100" height="100"
        style="stroke: #000000; fill: url(#pattern1);" />   
        <rect x="200" y="0" width="100" height="100"
        style="stroke: #000000; fill: url(#pattern2);" />   
</svg>

<script>
    var data = [{ year: '2001', value:10 },
            { year: '2002', value:30 },
            { year: '2003', value:60 },
           ]

    var svg = d3.select("svg"),
        width = svg.attr("width"),
        height = svg.attr("height"),
        radius = Math.min(width, height) / 2,
        g = svg.append("g").attr("transform", "translate("   width / 2   ","   height / 2   ")");

    var color = d3.scaleOrdinal(['#4daf4a','#377eb8','#ff7f00','#984ea3','#e41a1c']);

    // Generate the pie
    var pie = d3.pie().value(function(d) { 
    return d.value;});

    // Generate the arcs
    var arc = d3.arc()
                .innerRadius(0)
                .outerRadius(radius);

    //Generate groups
    var arcs = g.selectAll("arc")
                .data(pie(data))
                .enter()
                .append("g")
                .attr("class", "arc")

    //Draw arc paths
    arcs.append("path")
        .attr("d", arc)
  .attr('stroke', "black")
            .attr('stroke-width', '1')
            .attr("fill", function(d,i) { return  "url(#pattern"   i  ")"});
</script>
</script>

Thank you in advance.

CodePudding user response:

As the patternTransform attribute is defined on the pattern, you need to create the <pattern> elements dynamically at runtime.

d3.pie(data) returns an array of objects that have, among others the properties startAngle and endAngle. You can use them to compute the needed rotation:

averageAngle = (d.startAngle   d.endAngle) * 90 / Math.PI

I would have hoped to define the pattern geometry only once, and then re-use that as a template, but unfortunately at least Firefox does not implement style inheritance via the shadow tree model. Thus, if I do something like this...

 <pattern id="patternTemplate"
          x="0" y="0" width="20" height="20"
          patternUnits="userSpaceOnUse" patternTransform="rotate(0)">
  
     <rect id="rotateRect" x="5" y = "5" width = "10" height = "10" />
 </pattern>

 <pattern id="pattern0" href="#patternTemplate" fill="#4daf4a" />

...the fill color used in the pattern remains black.

<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<svg id="pie" width="300" height="200"> </svg>
<svg id="legend">
    
        <rect x="0" y="0" width="100" height="100"
        style="stroke: #000000; fill: url(#pattern0);" />   
    <rect x="100" y="0" width="100" height="100"
        style="stroke: #000000; fill: url(#pattern1);" />   
        <rect x="200" y="0" width="100" height="100"
        style="stroke: #000000; fill: url(#pattern2);" />   
</svg>

<script>
    var data = [{ year: '2001', value:10 },
            { year: '2002', value:30 },
            { year: '2003', value:60 },
           ]

    var svg = d3.select("svg#pie"),
        width = svg.attr("width"),
        height = svg.attr("height"),
        radius = Math.min(width, height) / 2,
        g = svg.append("g").attr("transform", "translate("   width / 2   ","   height / 2   ")");

    var color = d3.scaleOrdinal(['#4daf4a','#377eb8','#ff7f00','#984ea3','#e41a1c']);

    // Generate the pie
    var pie = d3.pie().value(function(d) { 
    return d.value;})(data);

    // Generate the patterns
    var legend = d3.select("svg#legend"),
        defs = legend.append("defs");
    defs.selectAll("pattern")
        .data(pie)
        .enter()
        .append("pattern")
        .attr("id", (d, i) => "pattern"   i)
        .attr("patternUnits", "userSpaceOnUse")
        .attr("width", 20)
        .attr("height", 20)
        .attr("patternTransform", (d) => `rotate(${(d.startAngle   d.endAngle) * 90 / Math.PI})`)
        .style("fill", (d, i) => color(i))
             .append("rect")
             .attr("x", 5)
             .attr("y", 5)
             .attr("width", 10)
             .attr("height", 10)

    // Generate the arcs
    var arc = d3.arc()
                .innerRadius(0)
                .outerRadius(radius);

    //Generate groups
    var arcs = g.selectAll("arc")
                .data(pie)
                .enter()
                .append("g")
                .attr("class", "arc")

    //Draw arc paths
    arcs.append("path")
        .attr("d", arc)
  .attr('stroke', "black")
            .attr('stroke-width', '1')
            .attr("fill", function(d,i) { return  "url(#pattern"   i  ")"});
</script>
</script>

  • Related