d3.js自定义样式区域饼图实现咨询:替代传统老旧饼图
D3.js 实现曲线分区饼图方案
你要的这种类《Land of colors》的可视化效果,核心是把传统饼图指向圆心的直线边替换为向内凹陷的贝塞尔曲线,无需严格遵循Moser圆的数学规则,实现难度很低,完整实现逻辑如下:
前置依赖
引入D3.js v7版本即可,无其他额外依赖。
步骤1:数据格式化
先把你提供的KV结构原始数据,转换为带弧度映射的结构化数据:
// 你的原始数据 const rawData = {a: 9, b: 20, c:30, d:8, e:12}; // 转换为数组并计算各分类对应的圆周弧度 const dataArr = Object.entries(rawData).map(([key, value]) => ({name: key, value})); const totalValue = d3.sum(dataArr, d => d.value); // 用d3自带的pie生成器计算各分类的起始/结束弧度,和普通饼图逻辑一致 const pieData = d3.pie() .value(d => d.value) .sort(null) // 保持原始数据顺序,不需要按数值排序可以去掉这行 (dataArr);
步骤2:自定义曲线路径生成
替换传统饼图的d3.arc()生成器,自己写路径逻辑,用二次贝塞尔曲线生成向内凹陷的分区边:
// 画布和半径配置 const width = 600, height = 600; const outerRadius = Math.min(width, height) / 2 * 0.85; const innerControlRatio = 0.3; // 曲线内凹比例,0=完全贴合圆心(和传统饼图一致),1=完全贴合圆周(没有内凹),可自行调整 // 自定义分区路径生成函数 function generateCurveArc(d) { // 计算外弧两个端点的坐标 const [x1, y1] = [ outerRadius * Math.cos(d.startAngle - Math.PI / 2), outerRadius * Math.sin(d.startAngle - Math.PI / 2) ]; const [x2, y2] = [ outerRadius * Math.cos(d.endAngle - Math.PI / 2), outerRadius * Math.sin(d.endAngle - Math.PI / 2) ]; // 计算贝塞尔曲线的控制点(弧中点往圆心偏移对应比例) const midAngle = (d.startAngle + d.endAngle) / 2; const controlRadius = outerRadius * innerControlRatio; const [cx, cy] = [ controlRadius * Math.cos(midAngle - Math.PI / 2), controlRadius * Math.sin(midAngle - Math.PI / 2) ]; // 拼接SVG路径 return `M ${x1} ${y1} A ${outerRadius} ${outerRadius} 0 ${d.endAngle - d.startAngle > Math.PI ? 1 : 0} 1 ${x2} ${y2} Q ${cx} ${cy} ${x1} ${y1} Z`; }
步骤3:渲染到页面
// 创建SVG画布 const svg = d3.select('body').append('svg') .attr('width', width) .attr('height', height) .append('g') .attr('transform', `translate(${width / 2}, ${height / 2})`); // 配色方案,可自行替换 const colorScale = d3.scaleOrdinal(d3.schemeSet3); // 渲染分区 svg.selectAll('.curve-arc') .data(pieData) .enter() .append('path') .attr('class', 'curve-arc') .attr('d', generateCurveArc) .attr('fill', (d, i) => colorScale(i)) .attr('stroke', '#fff') .attr('stroke-width', 2) .attr('opacity', 0.8); // 半透明叠加更接近参考效果的通透质感
效果调整技巧
- 改
innerControlRatio的数值就能调整曲线的凹陷程度,想要更夸张的效果可以调到0.1,想要更饱满的分区调到0.5即可 - 如果需要加参考效果里的内部交叉连线,额外遍历所有弧的端点,按需求配对渲染直线即可,不需要计算复杂的交点
- 标签、悬停高亮等交互逻辑和普通饼图完全一致,直接复用常规饼图的交互代码就行
你要的参考效果如下:
内容的提问来源于stack exchange,提问作者costargc
相关产品推荐
相关产品推荐

