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

如何使用D3 v4通过点数组绘制圆弧?

在D3.js中通过三点绘制圆弧的正确方法

你遇到的问题很典型:d3.curveBasis这类曲线生成器是用来创建平滑的贝塞尔拟合曲线的,它只是让路径看起来圆润,但并不是几何意义上的圆弧(圆弧是严格遵循圆周的一部分)。要实现真正的圆弧,我们需要先通过三个点计算出对应的圆参数(圆心、半径),再用D3的d3.arc()生成器来绘制。

步骤1:通过三点计算圆的参数

三个不共线的点可以确定唯一的圆,我们需要先计算出这个圆的圆心和半径。这里提供一个实用的计算函数:

function getCircleFromThreePoints(p1, p2, p3) {
  // 计算三条边的中点和垂线斜率
  const x1 = p1[0], y1 = p1[1];
  const x2 = p2[0], y2 = p2[1];
  const x3 = p3[0], y3 = p3[1];

  const midX12 = (x1 + x2) / 2;
  const midY12 = (y1 + y2) / 2;
  const slope12 = (y2 - y1) / (x2 - x1);
  const perpSlope12 = -1 / slope12;

  const midX23 = (x2 + x3) / 2;
  const midY23 = (y2 + y3) / 2;
  const slope23 = (y3 - y2) / (x3 - x2);
  const perpSlope23 = -1 / slope23;

  // 求解两条垂线的交点(圆心)
  const cx = (perpSlope12 * midX12 - perpSlope23 * midX23 + midY23 - midY12) / (perpSlope12 - perpSlope23);
  const cy = perpSlope12 * (cx - midX12) + midY12;

  // 计算半径
  const radius = Math.sqrt(Math.pow(cx - x1, 2) + Math.pow(cy - y1, 2));

  return { cx, cy, radius };
}

步骤2:计算圆弧的起始和结束角度

得到圆心后,我们需要计算三个点中首尾两点相对于圆心的角度,同时要确保圆弧经过中间点(需要判断圆弧的方向:顺时针或逆时针):

function getArcAngles(cx, cy, p1, p2, p3) {
  // 计算各点相对于圆心的角度(弧度制)
  const angle1 = Math.atan2(p1[1] - cy, p1[0] - cx);
  const angle2 = Math.atan2(p2[1] - cy, p2[0] - cx);
  const angle3 = Math.atan2(p3[1] - cy, p3[0] - cx);

  // 判断圆弧方向:确保中间点在起始和结束角度之间
  let startAngle, endAngle, counterClockwise;

  // 计算角度差,确定正确的圆弧走向
  const diff1 = (angle2 - angle1 + 2 * Math.PI) % (2 * Math.PI);
  const diff2 = (angle3 - angle2 + 2 * Math.PI) % (2 * Math.PI);
  counterClockwise = (diff1 + diff2) > Math.PI;

  startAngle = angle1;
  endAngle = angle3;

  return { startAngle, endAngle, counterClockwise };
}

步骤3:用D3绘制圆弧

现在把这些参数传入d3.arc()生成器,创建真正的圆弧路径:

// 你的点数据
var points = [ 
  [51.93326250000001, 21.4375], 
  [36.72733749999999, 40.603550000000002], 
  [21.527537500000008, 21.4144] 
];

// 计算圆参数
const { cx, cy, radius } = getCircleFromThreePoints(points[0], points[1], points[2]);

// 计算圆弧角度和方向
const { startAngle, endAngle, counterClockwise } = getArcAngles(cx, cy, points[0], points[1], points[2]);

// 创建圆弧生成器
const arcGenerator = d3.arc()
  .innerRadius(0) // 内半径设为0,绘制实心圆弧(如果要空心环可以调整)
  .outerRadius(radius)
  .startAngle(startAngle)
  .endAngle(endAngle)
  .cornerRadius(0) // 无圆角
  .counterClockwise(counterClockwise); // 设置圆弧走向

// 绘制圆弧(假设你已经有一个SVG容器node)
var arc = node.append('path')
  .attr("d", arcGenerator({})) // arcGenerator需要传入一个空对象(或包含角度的对象)
  .attr("transform", `translate(${cx}, ${cy})`) // 将圆弧的圆心移动到计算出的位置
  .attr("fill", "none")
  .attr("stroke", "black")
  .attr("stroke-width", 2);

关键说明

  • d3.arc()默认是以原点(0,0)为圆心绘制的,所以我们需要用transform将其平移到计算出的(cx, cy)位置。
  • 如果三个点共线,上面的计算函数会报错,实际使用时可以先添加共线判断逻辑。
  • counterClockwise参数确保圆弧经过中间点,避免绘制出另一段更短的圆弧。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:53:34