如何在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
相关产品推荐
相关产品推荐

