You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在D3.js饼图中实现特殊纹理、渐变及圆角效果?

D3.js饼图:圆角边缘、渐变填充与纹理图案实现方案

1. 饼图边缘圆角实现

直接通过D3的d3.arc()生成器的cornerRadius()参数设置圆角半径即可,无需额外复杂处理:

// 初始化弧生成器
const arc = d3.arc()
  .innerRadius(0) // 内半径设为0即为实心饼图
  .outerRadius(radius)
  .cornerRadius(8); // 圆角大小按需调整,数值越大圆角越明显

// 绘制饼图分段
svg.selectAll('path')
  .data(pie(data))
  .enter()
  .append('path')
  .attr('d', arc)
  .attr('fill', d => color(d.data.category));

2. 渐变填充实现

需要在SVG的<defs>容器中定义渐变(线性或径向均可),然后让饼图分段的fill属性引用渐变ID。如果需要每个分段使用不同渐变,可循环生成对应ID的渐变规则:

// 添加defs容器用于存储渐变、图案等资源
const defs = svg.append('defs');

// 为每个数据项生成独立渐变
data.forEach((d, i) => {
  const grad = defs.append('linearGradient')
    .attr('id', `grad-${i}`)
    .attr('x1', '0%')
    .attr('y1', '0%')
    .attr('x2', '100%')
    .attr('y2', '100%');
  
  // 渐变起始色
  grad.append('stop')
    .attr('offset', '0%')
    .attr('stop-color', color(d.category))
    .attr('stop-opacity', 1);
  
  // 渐变结束色(基于起始色加深)
  grad.append('stop')
    .attr('offset', '100%')
    .attr('stop-color', d3.color(color(d.category)).darker(0.5))
    .attr('stop-opacity', 1);
});

// 绘制饼图时引用对应渐变
svg.selectAll('path')
  .data(pie(data))
  .enter()
  .append('path')
  .attr('d', arc)
  .attr('fill', (d, i) => `url(#grad-${i})`);

3. 大小点镶嵌纹理实现

同样在<defs>中定义SVG图案(<pattern>),将不同大小的圆点按规则排列,再让饼图分段的fill引用图案ID。若要同时保留渐变背景,可在图案中先添加渐变填充的矩形,再叠加圆点:

// 为每个数据项生成带渐变背景的纹理图案
data.forEach((d, i) => {
  const pattern = defs.append('pattern')
    .attr('id', `pattern-${i}`)
    .attr('width', 20) // 图案单元宽度
    .attr('height', 20) // 图案单元高度
    .attr('patternUnits', 'userSpaceOnUse');

  // 添加渐变背景矩形
  pattern.append('rect')
    .attr('width', 20)
    .attr('height', 20)
    .attr('fill', `url(#grad-${i})`);

  // 添加大圆点
  pattern.append('circle')
    .attr('cx', 10)
    .attr('cy', 10)
    .attr('r', 4)
    .attr('fill', '#fff')
    .attr('opacity', 0.6);

  // 添加小圆点(对角排列)
  pattern.append('circle')
    .attr('cx', 0)
    .attr('cy', 0)
    .attr('r', 2)
    .attr('fill', '#fff')
    .attr('opacity', 0.8);

  pattern.append('circle')
    .attr('cx', 20)
    .attr('cy', 20)
    .attr('r', 2)
    .attr('fill', '#fff')
    .attr('opacity', 0.8);
});

// 绘制饼图时引用纹理图案
svg.selectAll('path')
  .data(pie(data))
  .enter()
  .append('path')
  .attr('d', arc)
  .attr('fill', (d, i) => `url(#pattern-${i})`);

完整组合效果示例

将圆角、渐变、纹理三个效果整合的完整代码:

const width = 400;
const height = 400;
const radius = Math.min(width, height) / 2;

const svg = d3.select('body')
  .append('svg')
  .attr('width', width)
  .attr('height', height)
  .append('g')
  .attr('transform', `translate(${width/2}, ${height/2})`);

const data = [
  {category: 'A', value: 30},
  {category: 'B', value: 50},
  {category: 'C', value: 20}
];

const color = d3.scaleOrdinal()
  .domain(data.map(d => d.category))
  .range(['#ff7f0e', '#1f77b4', '#2ca02c']);

const pie = d3.pie()
  .value(d => d.value);

const arc = d3.arc()
  .innerRadius(0)
  .outerRadius(radius)
  .cornerRadius(8);

const defs = svg.append('defs');

// 生成每个分段的渐变+纹理组合资源
data.forEach((d, i) => {
  // 创建渐变
  const grad = defs.append('linearGradient')
    .attr('id', `grad-${i}`)
    .attr('x1', '0%')
    .attr('y1', '0%')
    .attr('x2', '100%')
    .attr('y2', '100%');
  grad.append('stop').attr('offset', '0%').attr('stop-color', color(d.category)).attr('stop-opacity', 1);
  grad.append('stop').attr('offset', '100%').attr('stop-color', d3.color(color(d.category)).darker(0.5)).attr('stop-opacity', 1);

  // 创建带渐变背景的纹理图案
  const pattern = defs.append('pattern')
    .attr('id', `pattern-${i}`)
    .attr('width', 20)
    .attr('height', 20)
    .attr('patternUnits', 'userSpaceOnUse');
  pattern.append('rect').attr('width', 20).attr('height', 20).attr('fill', `url(#grad-${i})`);
  pattern.append('circle').attr('cx',10).attr('cy',10).attr('r',4).attr('fill','#fff').attr('opacity',0.6);
  pattern.append('circle').attr('cx',0).attr('cy',0).attr('r',2).attr('fill','#fff').attr('opacity',0.8);
  pattern.append('circle').attr('cx',20).attr('cy',20).attr('r',2).attr('fill','#fff').attr('opacity',0.8);
});

// 绘制饼图
svg.selectAll('path')
  .data(pie(data))
  .enter()
  .append('path')
  .attr('d', arc)
  .attr('fill', (d, i) => `url(#pattern-${i})`);

内容的提问来源于stack exchange,提问作者The Old County

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:47:06