Pie Graph
(data, {colors, width = 480, height = 315} = {})
| 949 | }, |
| 950 | /**Pie Graph */ |
| 951 | pie(data, {colors, width = 480, height = 315} = {}) { |
| 952 | //Generate SVG |
| 953 | const radius = Math.min(width, height) / 2 |
| 954 | const d3n = new D3node() |
| 955 | const svg = d3n.createSVG(width, height) |
| 956 | |
| 957 | //Data |
| 958 | const K = Object.keys(data) |
| 959 | const V = Object.values(data) |
| 960 | const I = d3.range(K.length).filter(i => !Number.isNaN(V[i])) |
| 961 | |
| 962 | //Colors |
| 963 | const spectral = [...d3.schemeSpectral] |
| 964 | spectral[0] = ["#000000"] |
| 965 | spectral[1] = spectral[3].slice(0, 1) |
| 966 | spectral[2] = spectral[3].slice(0, 2) |
| 967 | |
| 968 | //Construct arcs |
| 969 | const color = d3.scaleOrdinal(K, spectral[K.length]) |
| 970 | const arcs = d3.pie().padAngle(1 / radius).sort(null).value(i => V[i])(I) |
| 971 | const arc = d3.arc().innerRadius(0).outerRadius(radius) |
| 972 | const labels = d3.arc().innerRadius(radius / 2).outerRadius(radius / 2) |
| 973 | |
| 974 | svg.append("g") |
| 975 | .attr("transform", `translate(${width / 2},${height / 2})`) |
| 976 | .attr("stroke", "white") |
| 977 | .attr("stroke-width", 1) |
| 978 | .attr("stroke-linejoin", "round") |
| 979 | .selectAll("path") |
| 980 | .data(arcs) |
| 981 | .join("path") |
| 982 | .attr("fill", d => colors?.[K[d.data]] ?? color(K[d.data])) |
| 983 | .attr("d", arc) |
| 984 | .append("title") |
| 985 | .text(d => `${K[d.data]}\n${V[d.data]}`) |
| 986 | |
| 987 | svg.append("g") |
| 988 | .attr("transform", `translate(${width / 2},${height / 2})`) |
| 989 | .attr("font-family", "sans-serif") |
| 990 | .attr("font-size", 12) |
| 991 | .attr("text-anchor", "middle") |
| 992 | .attr("fill", "white") |
| 993 | .attr("stroke", "rbga(0,0,0,.9)") |
| 994 | .attr("paint-order", "stroke fill") |
| 995 | .selectAll("text") |
| 996 | .data(arcs) |
| 997 | .join("text") |
| 998 | .attr("transform", d => `translate(${labels.centroid(d)})`) |
| 999 | .selectAll("tspan") |
| 1000 | .data(d => { |
| 1001 | const lines = `${K[d.data]}\n${V[d.data]}`.split(/\n/) |
| 1002 | return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1) |
| 1003 | }) |
| 1004 | .join("tspan") |
| 1005 | .attr("x", 0) |
| 1006 | .attr("y", (_, i) => `${i * 1.1}em`) |
| 1007 | .attr("font-weight", (_, i) => i ? null : "bold") |
| 1008 | .text(d => d) |