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.
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>