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

在ReactNative中用victory-native实现圆角饼图/环形图切片

在Victory-Native中实现饼图切片圆角(无需自定义Path)

由于Victory-Native的VictoryPie组件确实没有直接设置切片圆角的属性,你可以通过叠加同色小圆点覆盖尖角的方式实现视觉上的圆角效果,完全不需要自定义Path或复杂的角度计算(仅需简单的坐标推导)。

实现思路

饼图切片的尖角位于圆弧与直边的连接处,我们只需要在这些尖角位置绘制与切片同色的小圆,就能模拟出圆角效果。具体步骤:

  • 计算每个饼图切片的起始/结束角度
  • 根据角度和饼图半径,算出每个尖角的坐标
  • 使用VictoryScatter组件在这些坐标上绘制同色小圆

代码示例

import React from 'react';
import { View } from 'react-native';
import { VictoryPie, VictoryScatter } from 'victory-native';
import { pie } from 'd3-array';

// 示例数据
const chartData = [
  { x: '项目A', y: 35 },
  { x: '项目B', y: 25 },
  { x: '项目C', y: 40 },
];

// 配置参数
const PIE_RADIUS = 120;
const CORNER_RADIUS = 10; // 圆角大小(对应小圆直径的一半)
const CHART_CENTER = { x: 0, y: 0 };

// 用d3计算每个切片的角度信息
const pieCalculations = pie().value(d => d.y)(chartData);

// 生成需要绘制的圆角点数据
const cornerPoints = pieCalculations.flatMap((slice, idx) => {
  // 转换Victory的角度坐标系(Victory默认0度向上,转为数学坐标系0度向右)
  const startAngle = slice.startAngle - Math.PI / 2;
  const endAngle = slice.endAngle - Math.PI / 2;
  
  // 自定义颜色(也可直接用Victory的colorScale)
  const sliceColor = ['#FF6B6B', '#4ECDC4', '#FFE66D'][idx];

  return [
    // 切片起始位置的圆角点
    {
      x: CHART_CENTER.x + PIE_RADIUS * Math.cos(startAngle),
      y: CHART_CENTER.y + PIE_RADIUS * Math.sin(startAngle),
      fill: sliceColor,
    },
    // 切片结束位置的圆角点
    {
      x: CHART_CENTER.x + PIE_RADIUS * Math.cos(endAngle),
      y: CHART_CENTER.y + PIE_RADIUS * Math.sin(endAngle),
      fill: sliceColor,
    },
  ];
});

export default function RoundedPie() {
  return (
    <View style={{ alignItems: 'center', justifyContent: 'center' }}>
      {/* 基础饼图 */}
      <VictoryPie
        data={chartData}
        radius={PIE_RADIUS}
        colorScale={['#FF6B6B', '#4ECDC4', '#FFE66D']}
        standalone={false}
      />
      {/* 叠加圆角点 */}
      <VictoryScatter
        data={cornerPoints}
        size={CORNER_RADIUS * 2} // size是圆点直径,所以乘以2
        style={{ data: { fill: d => d.fill } }}
        standalone={false} // 与饼图共享坐标系,确保位置准确
      />
    </View>
  );
}

适配环形饼图(innerRadius > 0)

如果是环形饼图,只需要额外计算内圈的尖角坐标,再添加一组散点即可:

// 新增内圈半径配置
const INNER_RADIUS = 60;

// 在cornerPoints中追加内圈点
const innerCornerPoints = pieCalculations.flatMap((slice, idx) => {
  const startAngle = slice.startAngle - Math.PI / 2;
  const endAngle = slice.endAngle - Math.PI / 2;
  const sliceColor = ['#FF6B6B', '#4ECDC4', '#FFE66D'][idx];

  return [
    {
      x: CHART_CENTER.x + INNER_RADIUS * Math.cos(startAngle),
      y: CHART_CENTER.y + INNER_RADIUS * Math.sin(startAngle),
      fill: sliceColor,
    },
    {
      x: CHART_CENTER.x + INNER_RADIUS * Math.cos(endAngle),
      y: CHART_CENTER.y + INNER_RADIUS * Math.sin(endAngle),
      fill: sliceColor,
    },
  ];
});

// 然后在VictoryScatter中合并数据
<VictoryScatter
  data={[...cornerPoints, ...innerCornerPoints]}
  // 其他属性不变
/>

这种方法完全依赖Victory原生组件,不需要手动编写SVG Path,且效果和原生圆角几乎一致。

内容的提问来源于stack exchange,提问作者Filip Savic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 02:43:13