Reputation: 25
I am trying to represent a pie chart with d3 library. I tried to make pie chart but I have problem in making lines around pie chart with arrows.
const data = [10, 10, 10, 10, 10, 10];
import React, { useEffect, useRef } from "react";
import * as d3 from "d3";
const PieChart = ({ data }) => {
const svgRef = useRef();
useEffect(() => {
createWheel();
}, [data]);
const createWheel = () => {
const width = 200;
const height = 200;
const outerRadius = 100;
const innerRadius = 0;
const borderWidth = 1;
const spaceBetweenSlices = 10;
const arrowSize = 30;
const padding = 20;
const svg = d3
.select(svgRef.current)
.attr("width", width + padding * 2)
.attr("height", height + padding * 2)
.append("g")
.attr(
"transform",
`translate(${width / 2 + padding},${height / 2 + padding})`
);
const pie = d3.pie();
const pieData = pie(data);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcs = svg
.selectAll("arc")
.data(pieData)
.enter()
.append("g")
.attr("class", "arc");
arcs
.append("path")
.attr("d", arc)
.attr("fill", (d, i) => d3.schemeCategory10[i]);
const borderArc = d3
.arc()
.innerRadius(outerRadius + spaceBetweenSlices)
.outerRadius(outerRadius + borderWidth + spaceBetweenSlices);
arcs
.append("path")
.attr("d", borderArc)
.attr("fill", "none")
.attr("stroke", (d, i) => d3.schemeCategory10[i])
.attr("stroke-width", borderWidth);
// Add greater-than signs at the end of each border
arcs
.append("text")
.attr("x", (d) => borderArc.centroid(d)[0])
.attr("y", (d) => borderArc.centroid(d)[1])
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.attr("font-size", arrowSize)
.attr("fill", (d, i) => d3.schemeCategory10[i])
.text(">");
};
return <svg ref={svgRef}></svg>;
};
export default PieChart;
Added padding to the SVG element by adjusting the position of the pie chart within the SVG container.
At the end of each pie slice border, can we arrow symbol? - sample design image added
Code-sandbox Link: https://codesandbox.io/s/condescending-banach-hzc6q8
Upvotes: 1
Views: 160
Reputation: 108567
The canoical way to do would be to use marker-end
. For your use case, though, I think it would be easier just to draw the arrow heads at the correct positions with correct rotation:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.js"></script>
</head>
<body>
<svg></svg>
<script>
const createWheel = () => {
const width = 200;
const height = 200;
const outerRadius = 100;
const innerRadius = 0;
const borderWidth = 1;
const spaceBetweenSlices = 10;
const arrowSize = 30;
const padding = 20;
const svg = d3
.select('svg')
.attr('width', width + padding * 2)
.attr('height', height + padding * 2)
.append('g')
.attr(
'transform',
`translate(${width / 2 + padding},${height / 2 + padding})`
);
const pie = d3.pie();
const data = [Math.random() * 10, Math.random() * 10, Math.random() * 10, Math.random() * 10, Math.random() * 10, Math.random() * 10];
const pieData = pie(data);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcs = svg.selectAll('arc').data(pieData).enter()
.append("g")
.attr("class", "arc");
arcs
.append('path')
.attr('d', arc)
.attr('fill', (d, i) => d3.schemeCategory10[i]);
const borderArc = d3
.arc()
.innerRadius(outerRadius + spaceBetweenSlices)
.outerRadius(outerRadius + borderWidth + spaceBetweenSlices);
arcs
.append('path')
.attr('d', borderArc)
.attr('fill', 'none')
.attr('stroke', (d, i) => d3.schemeCategory10[i])
.attr('stroke-width', borderWidth);
// Add greater-than signs at the end of each border
arcs
.append('path')
.attr('d', 'M-10,-10 L0,0 L10,-10')
.attr('transform', (d, i, j) => {
let x =
(outerRadius + spaceBetweenSlices) *
Math.cos(d.endAngle - Math.PI/2);
let y =
(outerRadius + spaceBetweenSlices) *
Math.sin(d.endAngle - Math.PI/2);
return 'translate(' + x + ',' + y + '), rotate(' + ((d.endAngle * 180/Math.PI) - 90) + ')';
})
.attr('fill', 'none')
.attr('stroke', (d, i) => d3.schemeCategory10[i])
.attr('stroke-width', borderWidth * 2);
};
createWheel();
</script>
</body>
</html>
Upvotes: 2