news 2026/1/3 8:05:14

光线折射的代码

作者头像

张小明

前端开发工程师

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进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/25 22:58:48

基于SpringBoot的酒店客房管理系统的设计与实现毕业设计项目源码

题目简介本课题以 SpringBoot 框架为核心技术支撑&#xff0c;研发一套高效、易用的酒店客房管理系统&#xff0c;旨在解决传统酒店客房管理中人工登记效率低、房态更新不及时、数据统计困难等痛点问题。系统面向中中小型酒店的前厅、客房、财务等部门&#xff0c;覆盖客房预订…

作者头像 李华
网站建设 2025/12/25 22:56:56

程序员的职业生涯:从代码到架构师

程序员的职业生涯:从代码到架构师 关键词:程序员、职业生涯、代码、架构师、技术成长、职业规划、技能提升 摘要:本文深入探讨了程序员从专注于代码编写逐步成长为架构师的职业生涯发展路径。详细阐述了每个阶段所需的核心技能、知识体系和思维转变,通过对相关概念、算法原…

作者头像 李华
网站建设 2025/12/25 22:54:49

【mamba-ssm】cuda12.4|python3.12|torch2.6.0保姆级安装手册

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录环境下载安装插播广告环境 linux python3.12.3 torch2.6.0 cuda12.4 使用pip install xxx.whl 方式安装 安装成功的关键是版本对齐 下载 需要下载两个.whl 1、cau…

作者头像 李华
网站建设 2025/12/25 22:54:29

基于SpringBoot的物流管理系统的设计与实现毕业设计项目源码

项目简介本课题以 SpringBoot 框架为核心技术支撑&#xff0c;研发一套适配中小物流企业的全流程物流管理系统&#xff0c;旨在解决传统物流运营中订单处理效率低、货物轨迹不可控、仓储与配送衔接不畅、财务结算繁琐等痛点&#xff0c;实现物流订单、仓储、运输、结算全环节的…

作者头像 李华
网站建设 2025/12/25 22:53:40

PI-36双麦降噪拾音模块:高清拾音,嘈杂环境克星

核心优势&#xff1a;四大亮点&#xff0c;赋能优质体验1. 双核DSP强效降噪&#xff0c;全场景噪音压制内置双核DSP芯片与定制算法&#xff0c;36dB高降噪指标&#xff0c;精准压制稳态与非稳态噪音。配合16KHZ高采样率&#xff0c;清晰萃取人声&#xff0c;大幅提升信噪比&…

作者头像 李华
网站建设 2025/12/25 22:53:08

基本设置模块 Cordova 与 OpenHarmony 混合开发实战

欢迎大家加入开源鸿蒙跨平台开发者社区&#xff0c;一起共建开源鸿蒙跨平台生态。 &#x1f4cc; 概述 基本设置模块为用户提供了配置应用全局行为的入口&#xff0c;包括应用语言、货币单位、默认排序方式、首页展示内容等。模块同时打通了 Web 层配置面板与 OpenHarmony 原生…

作者头像 李华