D3.js饼图扇区拆分问题:小扇区与大扇区间距重叠
饼图子扇区与父扇区padding重叠问题
我有5个饼图扇区,需要将每个扇区拆分为更小的子扇区,且子扇区间保持1px间距(如示意图中第5个扇区的红色线条所示)。但实现时,子扇区会与父扇区之间的padding发生重叠。
以下是我的代码:
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Indicator test</title> <script src="https://d3js.org/d3.v7.min.js"></script> <style> body, html { margin: 0px; height: 0px; font-family: sans-serif; } .parent { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: center; height: 100vh; } .child { border: 1px solid red } div.tooltip { position: absolute; text-align: center; padding: 2px; background: lightsteelblue; border: 0px; border-radius: 8px; } .highlight { fill: steelblue; } .hover { fill: #69c !important; stroke: #333 !important; stroke-width: 2px !important; } .d3map { border: 1px solid red; } .map-title { font-size: 30px } .map-text { text-align: center; } .map-text-container { display: flex; flex-direction: column; font-size: 14px; line-height: 1; align-items: center; max-width: 155px; } </style> </head> <body> <div id="main"> <div class="parent"> <div id="d3map" class="child" style="width:100%; height:100%; "></div> </div> </div> <script> createMap("d3map") function createMap(divId) { const mainData = { cities: [] } const svgDiv = document.getElementById(divId).getBoundingClientRect(); let width = 600; let height = 600; const radius = width / 2 const svg = d3 .select("#" + divId) .append("svg") .attr("viewBox", `0 0 ${width} ${height}`) ready(null, randomData()) async function ready(error, data) { const numberOfPies = 5 console.log("123", numberOfPies); svg.append("circle") .style("stroke", "rgba(0,0,0,0.2)") .style("stroke-width", "1") .style("fill", "rgba(0,0,0,0)") .attr("r", radius - 1) .attr("cx", width / 2) .attr("cy", height / 2); const sectors = [...Array(numberOfPies)].map((i, key) => { return { name: key, size: 10, } }); console.log('pie(sectors): ', sectors); const arc = (offset = 5) => { return d3.arc() .outerRadius(radius - offset) .innerRadius(radius) } const labelArc = d3.arc() .innerRadius(150) .outerRadius(radius) const pie = d3.pie() .startAngle(-90 * Math.PI / 180) .endAngle(-90 * Math.PI / 180 + 2 * Math.PI) .value(1) .padAngle(.05) // space between pies .sort(null); const lineFunc = d3.line() .x(function (d) { return d.x }) .y(function (d) { return d.y }) const labels = svg.append('g') .attr("class", "labels") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); labels.selectAll('.pies') .data(pie(sectors)) .enter() .append('path') .attr('d', labelArc) .attr('class', "pies") .attr("stroke", "none") .attr("fill", d => "gray") .style("stroke-width", "1px") .style("opacity", d => { return d.data.skipThisSector ? 0 : 1 }) labels.selectAll('.lines') .data(pie(sectors)) .enter() .append('path') .attr('d', d => { console.log('d: ', d); const pies = d3.pie() .startAngle(d.startAngle) .endAngle(d.endAngle) .value(1) .padAngle(.01) // space between pies .sort(null); labels.selectAll('.piesss') .data(pies(randomData())) .enter() .append('path') .attr('d', labelArc) .attr('class', "pies") .attr("stroke", "none") .attr("fill", d => "red") .style("stroke-width", "1px") .style("opacity", "0.4") }) labels.selectAll(".labelsText") .data(pie(sectors)) .enter() .append("text") .attr("dx", d => { const [x, y] = labelArc.centroid(d) return x }) .attr("dy", d => { const [x, y] = labelArc.centroid(d) return y + 5 }) .text(function (d) { if (!d.data.skipThisSector) { return d.data.name } else { return } }) .style("font-size", "8px") .style("text-anchor", "middle") .attr("transform", function (d) { var locationData = this.getBBox(); var x = locationData.x + (locationData.width / 2); var y = locationData.y + (locationData.height / 2); let angle = (Math.atan2(y, x) * 180) / Math.PI; if (angle > 90) angle = 180 + angle if (angle < -90 && angle > -180) angle = 180 + angle var result = 'translate(' + x + ',' + y + ')'; result += `rotate(${angle})`; result += 'translate(' + (-x) + ',' + (-y) + ')'; return result; }) .style("text-anchor", function (d) { var locationData = this.getBBox(); var x = locationData.x + (locationData.width / 2); var y = locationData.y + (locationData.height / 2); let angle = (Math.atan2(y, x) * 180) / Math.PI; if (angle > 90) return "end" if (angle < -90 && angle > -180) return "end" return "start" }) .attr("fill", d => { return "white" }) } } function randomData() { return [...Array(Math.floor(Math.random() * 11))].map((i, key) => { return { name: key, size: 10, } }); } const delay = ms => new Promise(res => setTimeout(res, ms)); </script> </body> </html>
效果示意图:
内容的提问来源于stack exchange,提问作者SERG
相关产品推荐
相关产品推荐

