news 2026/4/16 17:44:21

光线折射的代码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
光线折射的代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>光的折射控制器</title>
<style>
body {
padding: 20px;
background-color: #f5f5f5;
font-family: "Microsoft YaHei", Arial, sans-serif;
}
#canvas-container {
position: relative;
width: 800px;
height: 600px;
margin: 20px auto;
border: 2px solid #333;
background-color: #fff;
/* 确保容器可见 */
display: block;
}
#refraction-canvas {
width: 100%;
height: 100%;
/* 修复canvas渲染模糊 */
image-rendering: -webkit-optimize-contrast;
}
.controls {
width: 800px;
margin: 0 auto;
padding: 15px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
margin-bottom: 10px;
}
.control-group {
margin-bottom: 15px;
line-height: 30px;
}
label {
display: inline-block;
width: 150px;
font-weight: bold;
}
.angle-label {
margin-left: 10px;
color: #666;
}
/* 成果展示框样式 */
.result-box {
width: 800px;
margin: 10px auto;
padding: 20px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
line-height: 1.8;
}
.result-box h4 {
margin-top: 0;
color: #2c3e50;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
}
.result-item {
margin: 8px 0;
}
.result-key {
font-weight: bold;
color: #3498db;
display: inline-block;
width: 180px;
}
.result-value {
color: #27ae60;
}
.warning {
color: #e74c3c;
font-weight: bold;
}
/* 兼容IE的滑块样式 */
input[type="range"] {
width: 200px;
height: 20px;
}
</style>
</head>
<body>
<div class="controls">
<div class="control-group">
<label for="angle">入射角(θ₁):</label>
<input type="range" id="angle" min="0" max="90" value="30" step="1">
<span id="angle-value" class="angle-label">30°</span>
</div>
<div class="control-group">
<label for="n1">介质1折射率(n₁):</label>
<input type="range" id="n1" min="1.0" max="2.0" value="1.0" step="0.1">
<span id="n1-value" class="angle-label">1.0</span>
</div>
<div class="control-group">
<label for="n2">介质2折射率(n₂):</label>
<input type="range" id="n2" min="1.0" max="2.0" value="1.5" step="0.1">
<span id="n2-value" class="angle-label">1.5</span>
</div>
<div class="control-group">
<label for="color">光线颜色:</label>
<input type="color" id="color" value="#ff0000">
</div>
</div>

<div id="canvas-container">
<canvas id="refraction-canvas"></canvas>
</div>

<!-- 成果展示框 -->
<div class="result-box">
<h4>光的折射计算成果</h4>
<div class="result-item">
<span class="result-key">入射角度(θ₁):</span>
<span id="res-incident-angle" class="result-value">30.0°</span>
</div>
<div class="result-item">
<span class="result-key">介质1折射率(n₁):</span>
<span id="res-n1" class="result-value">1.0</span>
</div>
<div class="result-item">
<span class="result-key">介质2折射率(n₂):</span>
<span id="res-n2" class="result-value">1.5</span>
</div>
<div class="result-item">
<span class="result-key">折射角度(θ₂):</span>
<span id="res-refraction-angle" class="result-value">19.47°</span>
</div>
<div class="result-item">
<span class="result-key">现象说明:</span>
<span id="res-phenomenon" class="result-value">正常折射</span>
</div>
<div class="result-item">
<span class="result-key">斯涅尔定律验证:</span>
<span id="res-snell" class="result-value">n₁sinθ₁ = 0.500,n₂sinθ₂ = 0.500(相等)</span>
</div>
</div>

<script>
// 全局变量初始化
var canvas, ctx, container;
var angleInput, n1Input, n2Input, colorInput;
var angleValue, n1Value, n2Value;
var resIncidentAngle, resN1, resN2, resRefractionAngle, resPhenomenon, resSnell;

// 页面加载完成后初始化
window.onload = function() {
// 获取DOM元素
canvas = document.getElementById('refraction-canvas');
ctx = canvas.getContext('2d');
container = document.getElementById('canvas-container');

// 成果展示框元素
resIncidentAngle = document.getElementById('res-incident-angle');
resN1 = document.getElementById('res-n1');
resN2 = document.getElementById('res-n2');
resRefractionAngle = document.getElementById('res-refraction-angle');
resPhenomenon = document.getElementById('res-phenomenon');
resSnell = document.getElementById('res-snell');

// 控件元素
angleInput = document.getElementById('angle');
n1Input = document.getElementById('n1');
n2Input = document.getElementById('n2');
colorInput = document.getElementById('color');
angleValue = document.getElementById('angle-value');
n1Value = document.getElementById('n1-value');
n2Value = document.getElementById('n2-value');

// 绑定事件(兼容所有浏览器)
angleInput.addEventListener('input', updateAndDraw);
n1Input.addEventListener('input', updateAndDraw);
n2Input.addEventListener('input', updateAndDraw);
colorInput.addEventListener('input', drawRefraction);

// 监听窗口大小变化
window.addEventListener('resize', resizeCanvas);

// 初始化画布和绘制
resizeCanvas();
drawRefraction();
};

// 设置canvas实际分辨率(修复模糊+空白问题)
function resizeCanvas() {
// 强制设置canvas的实际宽高(与容器一致)
canvas.width = container.offsetWidth;
canvas.height = container.offsetHeight;
}

// 更新控件显示并绘制
function updateAndDraw() {
// 更新控件显示值
angleValue.textContent = angleInput.value + "°";
n1Value.textContent = n1Input.value;
n2Value.textContent = n2Input.value;
// 绘制折射效果
drawRefraction();
}

// 核心绘制函数
function drawRefraction() {
// 清空画布(必做,防止重绘重叠)
ctx.clearRect(0, 0, canvas.width, canvas.height);

// 获取参数
var width = canvas.width;
var height = canvas.height;
var centerX = width / 2;
var mediumLineY = height / 2; // 介质分界线
var incidentAngleDeg = parseFloat(angleInput.value); // 入射角(角度)
var incidentAngle = incidentAngleDeg * Math.PI / 180; // 转弧度
var n1 = parseFloat(n1Input.value);
var n2 = parseFloat(n2Input.value);
var lightColor = colorInput.value;

// 1. 绘制介质背景
// 介质1(上半部分)
ctx.fillStyle = 'rgba(173, 216, 230, 0.5)';
ctx.fillRect(0, 0, width, mediumLineY);
// 介质2(下半部分)
ctx.fillStyle = 'rgba(255, 228, 196, 0.5)';
ctx.fillRect(0, mediumLineY, width, height);
// 介质分界线
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(0, mediumLineY);
ctx.lineTo(width, mediumLineY);
ctx.stroke();

// 2. 绘制法线(垂直虚线)
ctx.strokeStyle = '#888';
ctx.lineWidth = 1;
ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.moveTo(centerX, 0);
ctx.lineTo(centerX, height);
ctx.stroke();
ctx.setLineDash([]); // 恢复实线

// 3. 计算入射光线坐标
var incidentLineLength = 200;
var incidentStartX = centerX - incidentLineLength * Math.sin(incidentAngle);
var incidentStartY = mediumLineY - incidentLineLength * Math.cos(incidentAngle);
var incidentEndX = centerX;
var incidentEndY = mediumLineY;

// 4. 斯涅尔定律计算折射角
var refractionAngle = 0;
var refractionAngleDeg = 0;
var hasRefraction = true;
var phenomenon = "正常折射";
var sinTheta1 = Math.sin(incidentAngle);
var sinTheta2 = (n1 / n2) * sinTheta1;

// 全反射判断
if (sinTheta2 > 1) {
refractionAngle = Math.PI - incidentAngle; // 反射角=入射角
refractionAngleDeg = incidentAngleDeg;
hasRefraction = false;
phenomenon = "<span class='warning'>全反射(无折射光线)</span>";
} else {
refractionAngle = Math.asin(sinTheta2);
refractionAngleDeg = refractionAngle * 180 / Math.PI;
}

// 5. 计算折射/反射光线坐标
var refractionLineLength = 200;
var refractionEndX = centerX + refractionLineLength * Math.sin(refractionAngle);
var refractionEndY;
if (hasRefraction) {
refractionEndY = mediumLineY + refractionLineLength * Math.cos(refractionAngle);
} else {
refractionEndY = mediumLineY - refractionLineLength * Math.cos(refractionAngle);
}

// 6. 绘制入射光线
ctx.strokeStyle = lightColor;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(incidentStartX, incidentStartY);
ctx.lineTo(incidentEndX, incidentEndY);
drawArrowhead(ctx, incidentEndX, incidentEndY, incidentStartX, incidentStartY, 10);
ctx.stroke();

// 7. 绘制折射/反射光线
ctx.beginPath();
ctx.moveTo(incidentEndX, incidentEndY);
ctx.lineTo(refractionEndX, refractionEndY);
drawArrowhead(ctx, refractionEndX, refractionEndY, incidentEndX, incidentEndY, 10);
ctx.stroke();

// 8. 标注入射角和折射角
drawAngleLabel(ctx, centerX, mediumLineY, incidentAngle, 'θ₁', -incidentLineLength/2);
var refractionLabel = hasRefraction ? 'θ₂' : '全反射';
drawAngleLabel(ctx, centerX, mediumLineY, refractionAngle, refractionLabel, refractionLineLength/2, !hasRefraction);

// 9. 更新成果展示框
resIncidentAngle.textContent = incidentAngleDeg.toFixed(1) + "°";
resN1.textContent = n1.toFixed(1);
resN2.textContent = n2.toFixed(1);

if (hasRefraction) {
resRefractionAngle.textContent = refractionAngleDeg.toFixed(2) + "°";
} else {
resRefractionAngle.innerHTML = "<span class='warning'>-" + incidentAngleDeg.toFixed(1) + "°(反射角)</span>";
}

resPhenomenon.innerHTML = phenomenon;

var n1Sin1 = (n1 * sinTheta1).toFixed(3);
var n2Sin2 = hasRefraction ? (n2 * sinTheta2).toFixed(3) : "无(全反射)";
var snellText;
if (hasRefraction) {
snellText = "n₁sinθ₁ = " + n1Sin1 + ",n₂sinθ₂ = " + n2Sin2 + "(相等)";
} else {
snellText = "n₁sinθ₁ = " + n1Sin1 + " > n₂(满足全反射条件)";
}
resSnell.innerHTML = snellText;
}

// 绘制箭头(辅助函数)
function drawArrowhead(ctx, fromX, fromY, toX, toY, size) {
var angle = Math.atan2(fromY - toY, fromX - toX);
ctx.moveTo(toX, toY);
ctx.lineTo(
toX + size * Math.cos(angle - Math.PI/6),
toY + size * Math.sin(angle - Math.PI/6)
);
ctx.lineTo(
toX + size * Math.cos(angle + Math.PI/6),
toY + size * Math.sin(angle + Math.PI/6)
);
ctx.lineTo(toX, toY);
}

// 绘制角度标注(辅助函数)
function drawAngleLabel(ctx, x, y, angle, label, radius, isReflection) {
if (isReflection === undefined) {
isReflection = false;
}
ctx.fillStyle = '#333';
ctx.font = '16px "Microsoft YaHei", Arial';
var startAngle = isReflection ? Math.PI/2 + angle : Math.PI/2 - angle;
var endAngle = Math.PI/2;

// 绘制角度弧线
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle, isReflection);
ctx.stroke();

// 绘制标签
var labelX = x + (radius + 20) * Math.cos((startAngle + endAngle)/2);
var labelY = y + (radius + 20) * Math.sin((startAngle + endAngle)/2);
ctx.fillText(label, labelX, labelY);
}
</script>
</body>
</html>

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 7:43:34

JavaScript 变量:let 和 const 该用谁?

JavaScript 变量&#xff1a;let 和 const 该用谁&#xff1f;生活中的例子 01游戏得分&#xff1a;分数会一直变&#xff0c;所以用 let。生活中的例子 02圆周率 (π)&#xff1a;数学常数永远是 3.14...&#xff0c;所以用 const。生活中的例子 03用户的出生年份&#xff1a;…

作者头像 李华
网站建设 2026/4/15 17:33:47

基于GD32的直流无刷电机控制算法实现和验证

目录 1 项目概述 1.1 项目背景 1.2 系统功能介绍 1.3 系统使用的技术要点 2 系统硬件框架结构 2.1 电机PWM接口 2.2 电流采样接口 2.3 编码器接口 3 驱动程序实现 3.1 PWM 功能实现 3.1.1 PWM接口配置 3.1.2 验证PWM输出波形 3.2 AS5600的驱动 3.2.1 AS5600与MCU之…

作者头像 李华
网站建设 2026/4/16 13:28:58

Win10 系统备份与还原实用指南:3 种方法筑牢数据安全防线

在数字化时代&#xff0c;电脑里的系统文件、工作文档、个人资料等都是核心资产&#xff0c;一旦遭遇硬件故障、病毒攻击或误操作&#xff0c;数据丢失可能造成不小损失。Windows 10 自带了实用的备份还原工具&#xff0c;同时也有更高效的第三方方案&#xff0c;下面就为大家精…

作者头像 李华
网站建设 2026/4/13 10:37:14

EHR+AI助手:远程办公模式下HR与IT的合规协同方案

摘要&#xff1a;随着数字经济的深度发展&#xff0c;远程办公已从应急选项升级为企业运营的战略配置&#xff0c;但其带来的跨地域用工、数据流转、流程管控等问题&#xff0c;对HR与IT部门的协同合规提出了严峻挑战。EHR系统作为人力资源数字化的核心载体&#xff0c;与AI助手…

作者头像 李华
网站建设 2026/4/13 22:07:50

《jQuery UI API 文档》

《jQuery UI API 文档》 引言 jQuery UI 是一个基于 jQuery 的用户界面库,它提供了丰富的交互组件和效果,帮助开发者快速构建出具有丰富交互体验的网页应用。本文档将详细介绍 jQuery UI 的 API,包括其组件、方法和事件,旨在帮助开发者更好地理解和运用 jQuery UI。 一、…

作者头像 李华