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

如何在GoJS中实现节点外围的环形图(Donut Chart)?

实现GoJS节点环形图(Donut Chart)模板的解决方案

我帮你梳理下当前的问题并给出可行的实现方案——你想要给GoJS节点添加环形甜甜圈图,参考了饼图和Ring Shape示例后修改了makeGeo函数,但效果没达到预期。核心问题出在路径闭合的处理上,我们来修正它:

修正后的makeGeo函数

你的原始代码里,绘制内层圆弧后没有正确连接路径的起点和终点,导致图形填充可能异常。下面是修正后的版本,确保每个环形分段是闭合的几何形状:

function makeGeo(data) {
  const start = data.start;
  const sweep = data.sweep;
  const end = start + sweep;
  const ringThickness = 8; // 可自定义环形厚度
  const size = 100; // 环形整体尺寸
  const outerRadius = size / 2;
  const innerRadius = Math.max(outerRadius - ringThickness, 0);

  const geo = new go.Geometry();
  // 外层圆弧的起点坐标(角度转弧度计算)
  const outerStartX = outerRadius + outerRadius * Math.cos(start * Math.PI / 180);
  const outerStartY = outerRadius + outerRadius * Math.sin(start * Math.PI / 180);
  
  const fig = new go.PathFigure(outerStartX, outerStartY, true); // 起点标记为自动闭合
  // 添加外层顺时针圆弧
  fig.add(new go.PathSegment(go.PathSegment.Arc, start, sweep, outerRadius, outerRadius, outerRadius, outerRadius));
  // 从外层圆弧终点连接到内层圆弧终点
  const innerEndX = outerRadius + innerRadius * Math.cos(end * Math.PI / 180);
  const innerEndY = outerRadius + innerRadius * Math.sin(end * Math.PI / 180);
  fig.add(new go.PathSegment(go.PathSegment.Line, innerEndX, innerEndY));
  // 添加内层逆时针圆弧
  fig.add(new go.PathSegment(go.PathSegment.Arc, end, -sweep, outerRadius, outerRadius, innerRadius, innerRadius));
  // 从内层圆弧起点连接回外层圆弧起点(PathFigure的true参数会自动闭合,这里也可省略)
  fig.add(new go.PathSegment(go.PathSegment.Line, outerStartX, outerStartY));

  geo.add(fig);
  geo.defaultStretch = go.GraphObject.Uniform;
  return geo;
}

完整节点模板实现

接下来把这个几何形状整合到节点模板中,让每个数据属性对应一个环形分段:

myDiagram.nodeTemplate =
  new go.Node("Auto")
    .add(
      new go.Panel("Spot")
        // 环形图容器:用Position面板承载多个分段Shape
        .add(
          new go.Panel("Position")
            .bind("itemArray", "segments") // 绑定节点数据中的segments数组
            .itemTemplate(
              new go.Shape({ stroke: null })
                .bind("fill", "color") // 绑定分段颜色
                .bind("geometry", "", (data) => {
                  // 计算总占比,得出当前分段的起始角度和扫过角度
                  const total = data.parent.segments.reduce((sum, seg) => sum + seg.value, 0);
                  const segmentSweep = (data.value / total) * 360;
                  let segmentStart = 0;
                  // 累计前面所有分段的角度,得到当前分段的起始角度
                  data.parent.segments.forEach((s, idx) => {
                    if (idx < data.parent.segments.indexOf(data)) {
                      segmentStart += (s.value / total) * 360;
                    }
                  });
                  return makeGeo({ start: segmentStart, sweep: segmentSweep });
                })
            )
        )
        // 添加节点中心内容,比如文本
        .add(
          new go.TextBlock({
            font: "bold 16px sans-serif",
            stroke: "#333",
            margin: 8
          })
            .bind("text", "name")
        )
    );

示例节点数据

你需要给节点提供包含5个属性的数组,示例数据如下:

const nodeDataArray = [
  {
    name: "Node A",
    segments: [
      { value: 25, color: "#ff4757" },
      { value: 20, color: "#ffa502" },
      { value: 15, color: "#2ed573" },
      { value: 30, color: "#1e90ff" },
      { value: 10, color: "#a55eea" }
    ]
  }
];

关键细节说明

  • 路径闭合:每个环形分段必须是闭合的几何图形,通过Line段连接内外圆弧的端点,确保颜色填充完整无缺口。
  • 角度计算:将角度转换为弧度计算坐标,避免绘制偏差;累计前面分段的角度保证环形分段连续无重叠。
  • 自定义参数:你可以通过调整ringThickness和size来改变环形的厚度和整体大小,适配不同的节点需求。

这样修改后,就能实现你想要的环形图节点效果,每个分段对应数据中的属性值和颜色。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:49:52