根据8楼董老师的建议,进行了改进这样好多了!
.container {
display: flex;
align-items: flex-start;
gap: 20px;
}
canvas {
border: 1px solid #ccc;
background: #fff;
}
.controls {
display: flex;
flex-direction: column;
gap: 10px;
}
.angle-display {
margin-top: 10px;
}
<div class="container">
<div class="controls">
入射角调整:
<div class="angle-display">
当前入射角:<span>30</span>°
</div>
</div>
</div>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const slider = document.getElementById('angleSlider');
const angleValue = document.getElementById('angleValue');
// 介质参数
const n1 = 1.0; // 空气折射率
const n2 = 1.33; // 水折射率
const interfaceY = 300; // 界面位置
const rayLength = 150; // 光线长度
const normalX = 300; // 法线X坐标
function drawArrow(x1, y1, x2, y2, label, color) {
// 画光线
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.stroke();
// 画箭头
const angle = Math.atan2(y2 - y1, x2 - x1);
ctx.beginPath();
ctx.moveTo(x2, y2);
ctx.lineTo(x2 - 10 * Math.cos(angle - Math.PI/6), y2 - 10 * Math.sin(angle - Math.PI/6));
ctx.lineTo(x2 - 10 * Math.cos(angle + Math.PI/6), y2 - 10 * Math.sin(angle + Math.PI/6));
ctx.fillStyle = color;
ctx.fill();
// 写标签(沿光线方向偏移)
ctx.fillStyle = color;
ctx.font = "14px Arial";
const labelX = (x1 + x2)/2 + 15 * Math.cos(angle);
const labelY = (y1 + y2)/2 + 15 * Math.sin(angle);
ctx.fillText(label, labelX, labelY);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 填充水介质区域(淡蓝色)
ctx.fillStyle = 'rgba(173, 216, 230, 0.2)';
ctx.fillRect(0, interfaceY, canvas.width, canvas.height - interfaceY);
// 画界面
ctx.beginPath();
ctx.moveTo(0, interfaceY);
ctx.lineTo(canvas.width, interfaceY);
ctx.setLineDash([5, 5]);
ctx.strokeStyle = "#666";
ctx.stroke();
ctx.setLineDash([]);
// 画法线
ctx.beginPath();
ctx.moveTo(normalX, interfaceY - 100);
ctx.lineTo(normalX, interfaceY + 100);
ctx.strokeStyle = "#999";
ctx.stroke();
ctx.fillStyle = "#666";
ctx.fillText("法线", normalX + 10, interfaceY - 50);
const theta = slider.value * Math.PI / 180;
const endpointX = normalX; // 入射点X坐标
const endpointY = interfaceY; // 入射点Y坐标
// 入射光线(法线左侧)
const startX = endpointX - rayLength * Math.sin(theta);
const startY = endpointY - rayLength * Math.cos(theta);
drawArrow(startX, startY, endpointX, endpointY, "入射光线", "red");
// 反射光线(法线右侧)
const reflectX = endpointX + rayLength * Math.sin(theta);
const reflectY = endpointY - rayLength * Math.cos(theta);
drawArrow(endpointX, endpointY, reflectX, reflectY, "反射光线", "blue");
// 折射光线(法线右侧下方)
const sinTheta2 = (n1/n2) * Math.sin(theta);
if (sinTheta2 {
angleValue.textContent = slider.value;
draw();
});
draw(); // 初始绘制
