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

