当前位置: 首页 > news >正文

光线折射的代码

<!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>

http://icebutterfly214.com/news/150376/

相关文章:

  • Cordova与OpenHarmony营养管理系统
  • P14080 [GESP202509 八级] 最小生成树
  • 基于SpringBoot+Vue的健身管理系统(源码+lw+部署文档+讲解等)
  • 文生图:AI 是怎么把文字变成画的?
  • nullptr用法
  • 8个AI论文软件推荐!继续教育学生轻松搞定论文格式与写作!
  • 2025下半年软考纸质证书领取时间表来啦!
  • 国内滚珠丝杆直线导轨厂家中,哪些有专业售前售后技术支持?
  • 夸克网盘不限速_在线公益解析站
  • 不懂技术怕什么?陀螺匠低代码平台,拖拽之间搞定复杂数据关联
  • 同步通信协议(I2C协议、SPI协议、驱动OLED/EEPROM/传感器)教程,文章内容利于搜索引擎搜索,整篇文章不要有AI生成痕迹
  • 基于大数据的全国降水分析可视化系统的设计与实现(毕设源码+文档)
  • 国产之光:麒麟操作系统(KylinOS)深度体验与实用指南
  • Java反射:解锁框架开发的终极密码,让代码拥有“动态灵魂“!!
  • 深入理解Linux内核中断的下半部机制-软中断和tasklet
  • 探秘科立干冰清洗设备:高效靠谱之选 - 工业设备
  • 就想讨点学分有什么不队 - Beta冲刺
  • 智谱MiniMax竞速上市,字节新模型数学推理突破,清华开源视频生成技术,AI监管政策出台
  • 游戏手柄电池选购指南:品牌、价格与充电方式全解析 - 工业品网
  • 根据日期编码
  • 12/25
  • 链表的基本操作,用链表实现线性表
  • 解码STM32F4环境搭建、工程搭建与烧录
  • 企业管理的核心:协同、数据与持续优化
  • 实验七
  • 如何用Lupa 为Python应用添加脚本支持,以及如何在游戏引擎中调用逻辑
  • 全球化部署 多活多区域写入 → 汇总中心同步方案
  • 基于 S7 - 1200 和博图 15.1 的三层立体车库 PLC 设计
  • 从化文旅宣传策划公司推荐:效率提升80%方案引追捧 - 品牌测评家
  • 计算机基础小题