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

