<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>光的折射控制器</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
background: #f0f0f0;
font-family: Arial, sans-serif;
}
#container {
position: relative;
width: 600px;
height: 400px;
border: 2px solid #333;
margin: 20px 0;
overflow: hidden;
}
#medium1 {
position: absolute;
top: 0;
width: 100%;
height: 50%;
background: #e0f7fa;
}
#medium2 {
position: absolute;
bottom: 0;
width: 100%;
height: 50%;
background: #bbdefb;
}
#normal {
position: absolute;
left: 300px;
top: 0;
width: 1px;
height: 400px;
background: #f00;
}
#ray {
position: absolute;
left: 300px;
top: 0;
width: 200px;
height: 2px;
background: #000;
transform-origin: left center;
}
#ray::after {
content: '';
position: absolute;
right: 0;
top: -5px;
border: 6px solid transparent;
border-left-color: inherit;
}
.control {
margin: 10px 0;
}
</style>
</head>
<body>
<h1>光的折射控制器</h1>
<div id="container">
<div id="medium1" title="介质1"></div>
<div id="medium2" title="介质2"></div>
<div id="normal" title="法线"></div>
<div id="ray" title="光线"></div>
</div>
<div class="control">
<label>入射角:<span id="iAngle">45</span>°</label>
<input type="range" id="iSlider" min="0" max="89" value="45">
</div>
<div class="control">
<label>介质1折射率:<span id="n1Val">1.0</span></label>
<input type="range" id="n1Slider" min="1.0" max="2.0" step="0.1" value="1.0">
</div>
<div class="control">
<label>介质2折射率:<span id="n2Val">1.5</span></label>
<input type="range" id="n2Slider" min="1.0" max="2.0" step="0.1" value="1.5">
</div>
<div class="control">
<label>光线颜色:</label>
<input type="color" id="colorPicker" value="#000000">
</div>
<div class="control">
<label>折射角:<span id="rAngle">28</span>°</label>
</div>
<div class="control">
<label>斯涅尔定律:n₁sinθ₁ = n₂sinθ₂</label>
</div>
<script>
const ray = document.getElementById('ray');
const iAngleSpan = document.getElementById('iAngle');
const rAngleSpan = document.getElementById('rAngle');
const n1ValSpan = document.getElementById('n1Val');
const n2ValSpan = document.getElementById('n2Val');
const iSlider = document.getElementById('iSlider');
const n1Slider = document.getElementById('n1Slider');
const n2Slider = document.getElementById('n2Slider');
const colorPicker = document.getElementById('colorPicker');
function updateRay() {
const iAngle = parseFloat(iSlider.value);
const n1 = parseFloat(n1Slider.value);
const n2 = parseFloat(n2Slider.value);
// 计算折射角(斯涅尔定律)
const sinI = Math.sin(iAngle * Math.PI / 180);
const sinR = (n1 * sinI) / n2;
const rAngle = sinR > 1 ? 90 : Math.asin(sinR) * 180 / Math.PI;
// 更新显示
iAngleSpan.textContent = iAngle;
rAngleSpan.textContent = rAngle.toFixed(0);
n1ValSpan.textContent = n1;
n2ValSpan.textContent = n2;
// 绘制入射光线
ray.style.transform = `rotate(${iAngle}deg)`;
ray.style.width = '200px';
ray.style.top = '0';
ray.style.backgroundColor = colorPicker.value;
ray.style.borderLeftColor = colorPicker.value;
// 绘制折射光线
if (sinR <= 1) {
const refractedRay = document.getElementById('refractedRay') || document.createElement('div');
refractedRay.id = 'refractedRay';
refractedRay.style.position = 'absolute';
refractedRay.style.left = '300px';
refractedRay.style.top = '200px';
refractedRay.style.width = '200px';
refractedRay.style.height = '2px';
refractedRay.style.backgroundColor = colorPicker.value;
refractedRay.style.transformOrigin = 'left center';
refractedRay.style.transform = `rotate(${-rAngle}deg)`;
refractedRay.style.borderLeftColor = colorPicker.value;
refractedRay.innerHTML = '<div style="position:absolute;right:0;top:-5px;border:6px solid transparent;border-left-color:inherit;"></div>';
document.getElementById('container').appendChild(refractedRay);
} else {
document.getElementById('refractedRay')?.remove();
}
}
// 绑定事件
iSlider.addEventListener('input', updateRay);
n1Slider.addEventListener('input', updateRay);
n2Slider.addEventListener('input', updateRay);
colorPicker.addEventListener('input', updateRay);
// 初始化
updateRay();
</script>
</body>
</html>