news 2026/6/10 13:55:47

光线折射的代码

作者头像

张小明

前端开发工程师

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/6/10 12:39:16

别只测功能:一套可落地的鸿蒙分布式压力测试方案

摘要 随着鸿蒙系统在多设备、多终端场景下的应用越来越多&#xff0c;分布式能力已经不再是“演示功能”&#xff0c;而是直接跑在真实业务里的核心能力。 但在实际开发中&#xff0c;很多项目在功能跑通之后&#xff0c;很少系统性地去验证&#xff1a; 当设备变多、调用变频繁…

作者头像 李华
网站建设 2026/6/10 12:38:02

“十五五”背景下的智慧农机治理,从作业感知到数据驱动的农业装备升级路径

在“十五五”时期国家持续推进农业农村现代化、加快农业强国建设的整体背景下&#xff0c;农业生产体系正在经历从“机械化普及”向“智能化深化”的关键跃迁。作为农业生产中最重要的基础装备&#xff0c;农机不仅承担着耕、种、管、收等核心作业任务&#xff0c;也逐渐成为农…

作者头像 李华
网站建设 2026/6/10 11:12:25

大数据与数字孪生:工业系统仿真优化

大数据驱动数字孪生:工业系统仿真优化的实践与未来 一、摘要/引言:当工业系统有了“会思考的虚拟镜像” 清晨8点,某汽车制造工厂的生产线准时启动。与以往不同的是,中控室的屏幕上不仅显示着实时产量,还有一个1:1的虚拟生产线——它同步着每台设备的温度、转速,甚至预测…

作者头像 李华
网站建设 2026/6/10 10:12:18

基于SpringBoot的消防安全知识竞赛系统毕业设计项目源码

项目简介本课题以 SpringBoot 框架为核心技术底座&#xff0c;研发一套面向企事业单位、学校及社区的消防安全知识竞赛系统&#xff0c;旨在解决传统消防安全知识普及形式单一、竞赛组织成本高、答题数据难统计、学习效果难评估等痛点&#xff0c;打造集题库管理、在线竞赛、自…

作者头像 李华
网站建设 2026/6/10 10:12:19

基于SpringBoot的校园传统文化交流系统毕业设计项目源码

项目简介本课题以 SpringBoot 框架为核心技术支撑&#xff0c;研发一套面向高校师生的校园传统文化交流系统&#xff0c;旨在解决校园内传统文化传播形式单一、交流场景分散、资源整合不足、互动参与度低等痛点&#xff0c;打造集文化资源分享、主题交流、活动组织、成果展示于…

作者头像 李华