news 2026/4/16 11:03:20

光的折射模拟器(斯涅尔定律演示)

作者头像

张小明

前端开发工程师

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 {

font-family: 'Microsoft YaHei', sans-serif;

display: flex;

flex-direction: column;

align-items: center;

padding: 20px;

background-color: #f4f6f9;

margin: 0;

}

h1 {

color: #2c3e50;

text-align: center;

}

.container {

width: 90%;

max-width: 800px;

display: flex;

flex-direction: column;

gap: 15px;

}

.controls {

display: grid;

grid-template-columns: 1fr 1fr;

gap: 15px;

background-color: #ecf0f1;

padding: 15px;

border-radius: 8px;

}

label {

font-weight: bold;

color: #34495e;

}

input[type="range"],

input[type="number"],

select {

width: 100%;

padding: 8px;

border-radius: 5px;

border: 1px solid #bdc3c7;

font-size: 14px;

}

canvas {

border: 1px solid #ccc;

background-color: #ffffff;

margin-top: 10px;

box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);

border-radius: 4px;

}

.info {

margin-top: 15px;

padding: 12px;

background-color: #d5f5e3;

border-left: 5px solid #2ecc71;

font-size: 15px;

color: #27ae60;

white-space: pre-line;

}

</style>

</head>

<body>

<h1>✨ 光的折射模拟器(斯涅尔定律演示)</h1>

<div class="container">

<div class="controls">

<div>

<label>入射角 θ₁ (度):</label>

<input type="range" id="angleSlider" min="0" max="90" value="30" step="0.1" />

<span id="angleValue">30.0°</span>

</div>

<div>

<label>介质1折射率 n₁:</label>

<input type="number" id="n1Input" step="0.01" min="1.00" max="2.50" value="1.00" />

</div>

<div>

<label>介质2折射率 n₂:</label>

<input type="number" id="n2Input" step="0.01" min="1.00" max="2.50" value="1.50" />

</div>

<div>

<label>光线颜色:</label>

<select id="colorSelect">

<option value="red">🔴 红色</option>

<option value="green">🟢 绿色</option>

<option value="blue">🔵 蓝色</option>

<option value="yellow">🟡 黄色</option>

<option value="magenta">🟣 品红</option>

</select>

</div>

</div>

<canvas id="refractionCanvas" width="800" height="500"></canvas>

<div class="info" id="angleDisplay">

入射角 θ₁ = 30.0°

折射角 θ₂ = 19.5°

验证斯涅尔定律:n₁·sinθ₁ ≈ n₂·sinθ₂

</div>

</div>

<!-- 使用国内 CDN 加载 jQuery -->

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<script>

$(function () {

const canvas = document.getElementById('refractionCanvas');

const ctx = canvas.getContext('2d');

const width = canvas.width;

const height = canvas.height;

// 中间分界线 y 坐标

const boundaryY = height / 2;

function draw() {

const theta1Deg = parseFloat($('#angleSlider').val());

const n1 = parseFloat($('#n1Input').val());

const n2 = parseFloat($('#n2Input').val());

const color = $('#colorSelect').val();

const theta1Rad = (theta1Deg * Math.PI) / 180;

let theta2Rad = 0;

let theta2Deg = 0;

// 斯涅尔定律:n1*sin(θ1) = n2*sin(θ2)

const sinTheta2 = (n1 * Math.sin(theta1Rad)) / n2;

// 判断是否全反射

if (Math.abs(sinTheta2) <= 1) {

theta2Rad = Math.asin(sinTheta2);

theta2Deg = (theta2Rad * 180) / Math.PI;

} else {

theta2Deg = "全反射";

}

// 更新显示角度和公式

$('#angleValue').text(`${theta1Deg.toFixed(1)}°`);

$('#angleDisplay').text(

`入射角 θ₁ = ${theta1Deg.toFixed(1)}°\n` +

`折射角 θ₂ = ${typeof theta2Deg === 'number' ? theta2Deg.toFixed(1) : theta2Deg}°\n` +

`验证斯涅尔定律:n₁·sinθ₁ = n₂·sinθ₂?\n` +

(typeof theta2Deg === 'number'

? `→ ${n1.toFixed(2)} × sin(${theta1Deg.toFixed(1)}°) ≈ ${(n1 * Math.sin(theta1Rad)).toFixed(4)}\n → ${n2.toFixed(2)} × sin(${theta2Deg.toFixed(1)}°) ≈ ${(n2 * Math.sin(theta2Rad)).toFixed(4)}`

: `→ |sin(θ₂)| > 1,发生全反射`)

);

// 清空画布

ctx.clearRect(0, 0, width, height);

// 绘制上下区域

ctx.fillStyle = '#e3f2fd'; // 介质1:浅蓝

ctx.fillRect(0, 0, width, boundaryY);

ctx.fillStyle = '#f3e5f5'; // 介质2:浅紫

ctx.fillRect(0, boundaryY, width, boundaryY);

// 绘制分界线

ctx.beginPath();

ctx.moveTo(0, boundaryY);

ctx.lineTo(width, boundaryY);

ctx.strokeStyle = '#333';

ctx.lineWidth = 2;

ctx.stroke();

// 绘制法线(虚线)

ctx.setLineDash([6, 4]);

ctx.beginPath();

ctx.moveTo(width / 2, 0);

ctx.lineTo(width / 2, height);

ctx.strokeStyle = '#555';

ctx.lineWidth = 1.5;

ctx.stroke();

ctx.setLineDash([]);

// 设置光源位置(在画布左侧上方)

const originX = width / 2;

const originY = boundaryY;

// 绘制入射光线

const incidentLength = 140;

const incidentX = originX - incidentLength * Math.sin(theta1Rad);

const incidentY = originY - incidentLength * Math.cos(theta1Rad);

drawArrow(ctx, incidentX, incidentY, originX, originY, color, 3);

// 如果没有全反射,绘制折射光线;否则绘制反射光线

if (typeof theta2Deg === 'number') {

const refractedLength = 140;

const refractedX = originX + refractedLength * Math.sin(theta2Rad);

const refractedY = originY + refractedLength * Math.cos(theta2Rad);

drawArrow(ctx, originX, originY, refractedX, refractedY, color, 3);

} else {

// 全反射:向上反射

const reflectedLength = 140;

const reflectedX = originX + reflectedLength * Math.sin(theta1Rad);

const reflectedY = originY - reflectedLength * Math.cos(theta1Rad);

drawArrow(ctx, originX, originY, reflectedX, reflectedY, color, 3, true);

}

}

// 绘制带箭头的线段

function drawArrow(context, fromX, fromY, toX, toY, color, lineWidth, isReflection = false) {

context.strokeStyle = color;

context.fillStyle = color;

context.lineWidth = lineWidth;

context.beginPath();

context.moveTo(fromX, fromY);

context.lineTo(toX, toY);

context.stroke();

// 绘制箭头

const headLen = 10;

const angle = Math.atan2(toY - fromY, toX - fromX);

context.beginPath();

context.moveTo(toX, toY);

context.lineTo(

toX - headLen * Math.cos(angle - Math.PI / 6),

toY - headLen * Math.sin(angle - Math.PI / 6)

);

context.lineTo(

toX - headLen * Math.cos(angle + Math.PI / 6),

toY - headLen * Math.sin(angle + Math.PI / 6)

);

context.closePath();

context.fill();

// 反射标记

if (isReflection) {

context.font = '14px Microsoft YaHei';

context.fillStyle = 'red';

context.fillText('反射!', toX + 12, toY - 10);

}

}

// 初始化绘制

draw();

// 绑定所有控件事件

$('#angleSlider, #n1Input, #n2Input, #colorSelect')

.on('input change', draw);

});

</script>

</body>

</html>

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

Requestium - 将Requests和Selenium合并在一起的自动化测试工具

Requests 是 Python 的第三方库&#xff0c;主要用于发送 http 请求&#xff0c;常用于接口自动化测试等。 Selenium 是一个用于 Web 应用程序的自动化测试工具。Selenium 测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。 本篇介绍一款将 Requests 和 Seleniu…

作者头像 李华
网站建设 2026/4/12 15:29:58

AI 助力编程:三大算法题的代码生成与测试全流程记录

问题 1&#xff1a;汉诺塔python运行def hanoi(n, start, helper, target):if n 1:print(f"移动圆盘1从柱子{start}到柱子{target}")returnhanoi(n-1, start, target, helper)print(f"移动圆盘{n}从柱子{start}到柱子{target}")hanoi(n-1, helper, start,…

作者头像 李华
网站建设 2026/4/15 4:09:41

【课程设计/毕业设计】基于java的个人健康管理系统的设计与实现健康建议和健康管理建议【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/12 16:33:18

告别大模型幻觉!RAG检索增强生成技术全解析,程序员必看,建议收藏

RAG&#xff08;检索增强生成&#xff09;技术通过先检索私有知识库再生成答案的方式&#xff0c;解决了大模型不了解私有数据和产生幻觉的问题。文章详细介绍了RAG的完整流程&#xff1a;文档整理、数据切片、向量化、存储、检索、重排和生成&#xff0c;并通过智能客服实例提…

作者头像 李华