文章目录
- 一、在 Canvas 画布中绘制箭头图形 - 要点分析
- 1、数据准备
- 2、绘制直线
- 3、绘制箭头尾翼
- 二、代码示例
一、在 Canvas 画布中绘制箭头图形 - 要点分析
1、数据准备
绘制箭头时 , 先设置一条直线的起始点和终止点 , 箭头绘制在该线段上 ;
/*** 起始点 X, Y 坐标* 终止点 X, Y 坐标*/private int startX, startY, endX, endY;
为箭头指定一个长度 , 该长度的末尾是 箭头终点 , 在直线上确定箭头终点 , 该终点延伸出两个尾翼 , 尾翼也指定一个长度 ;
/*** 箭头 左右两个尾翼 长度*/private int arrowWingLength = 20;/*** 箭头终点在直线的位置*/private float arrowEndRatio = 0.5F;/*** 箭头长度*/private int arrowLength;
2、绘制直线
先把箭头附着的直线 , 绘制出来 ;
// 绘制直线g.drawLine(startX, startY, endX, endY);
3、绘制箭头尾翼
首先 , 确定起始点和终止点 , 在 x , y 轴上的差值 ;
// 计算起始点和终止点在 x, y 方向的差值int deltaX = endX - startX;int deltaY = endY - startY;
然后 , 计算出起始点到终止点的角度 , deltaY / deltaX 是该角度的正切 , 已知正切值 , 计算角度 , 使用 Math.atan2 函数即可 , 最终计算的角度是 该直线 与 x 轴夹角 ;
// 计算 直线的角度double angle = Math.atan2(deltaY, deltaX);
再后 , 使用勾股定理计算直线的长度 ;
// 计算直线的长度int len = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
再后 , 根据比例计算出箭头的长度 , 根据该长度 , 确定箭头终点的坐标 ; 下图中蓝色的箭头 , 就是计算出的箭头尾部相对于起始点的增量 ;
// 设置箭头终点在直线的位置 , 根据比例计算出箭头长度arrowLength = (int) (len * arrowEndRatio);// 箭头终点坐标int arrowEndX = (int) (startX + arrowLength * Math.cos(angle));int arrowEndY = (int) (startY + arrowLength * Math.sin(angle));
最后 , 绘制箭头的两个尾翼 , 箭头的位置 ; 尾翼的起始点 arrowEndX, arrowEndY , 终止点需要根据角度计算出来 ;
// 绘制箭头 尾翼 线段 , 直线的角度 增减 45 度 , 即可获得尾翼的角度g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle + Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle + Math.PI / 4)));g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle - Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle - Math.PI / 4)));
完整代码示例 :
// 绘制箭头private void drawArrow(Graphics g, int startX, int startY, int endX, int endY) {// 计算起始点和终止点在 x, y 方向的差值int deltaX = endX - startX;int deltaY = endY - startY;// 计算 直线的角度double angle = Math.atan2(deltaY, deltaX);// 计算直线的长度int len = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);// 设置箭头终点在直线的位置 , 根据比例计算出箭头长度arrowLength = (int) (len * arrowEndRatio);// 箭头终点坐标int arrowEndX = (int) (endX - arrowLength * Math.cos(angle));int arrowEndY = (int) (endY - arrowLength * Math.sin(angle));// 绘制箭头 尾翼 线段 , 直线的角度 增减 45 度 , 即可获得尾翼的角度g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle + Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle + Math.PI / 4)));g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle - Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle - Math.PI / 4)));}
二、代码示例
代码示例 :
import java.awt.*;public class ArrowCanvas extends Canvas {/*** 起始点 X, Y 坐标* 终止点 X, Y 坐标*/private int startX, startY, endX, endY;/*** 箭头 左右两个尾翼 长度*/private int arrowWingLength = 20;/*** 箭头终点在直线的位置*/private float arrowEndRatio = 0.5F;/*** 箭头长度*/private int arrowLength;public ArrowCanvas(int startX, int startY, int endX, int endY) {this.startX = startX;this.startY = startY;this.endX = endX;this.endY = endY;// 设置画布大小setSize(400, 400);}public void paint(Graphics g) {// 绘制直线g.drawLine(startX, startY, endX, endY);// 绘制箭头drawArrow(g, startX, startY, endX, endY);}// 绘制箭头private void drawArrow(Graphics g, int startX, int startY, int endX, int endY) {// 计算起始点和终止点在 x, y 方向的差值int deltaX = endX - startX;int deltaY = endY - startY;// 计算 直线的角度// 返回的是 这条直线 与 x 轴的夹角// deltaY / deltaX 是该角度的正切// 已知正切值 , 计算角度 , 使用 Math.atan2 函数即可// 最终计算的角度是 该直线 与 x 轴夹角double angle = Math.atan2(deltaY, deltaX);// 计算直线的长度int len = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);// 设置箭头终点在直线的位置 , 根据比例计算出箭头长度arrowLength = (int) (len * arrowEndRatio);// 箭头终点坐标int arrowEndX = (int) (startX + arrowLength * Math.cos(angle));int arrowEndY = (int) (startY + arrowLength * Math.sin(angle));// 绘制箭头 尾翼 线段 , 直线的角度 增减 45 度 , 即可获得尾翼的角度g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle + Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle + Math.PI / 4)));g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle - Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle - Math.PI / 4)));}public static void main(String[] args) {// 创建窗口并添加 ArrowCanvas 组件Frame f = new Frame("ArrowCanvas Example");ArrowCanvas ac = new ArrowCanvas(50, 50, 200, 200);f.add(ac);// 设置窗口大小并可见f.setSize(400, 400);f.setVisible(true);}
}
执行结果 :