558 lines
20 KiB
HTML
558 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>레인보우 - 볼링공 속도 계산기</title>
|
|
<style>
|
|
body {
|
|
font-family: 'Nanum Gothic', Arial, sans-serif;
|
|
background-color: #f5f5f5;
|
|
margin: 0;
|
|
padding: 20px;
|
|
color: #333;
|
|
}
|
|
.container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
background-color: #fff;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
}
|
|
h1 {
|
|
color: #2c3e50;
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
}
|
|
.description {
|
|
background-color: #eaf2f8;
|
|
padding: 15px;
|
|
border-radius: 5px;
|
|
margin-bottom: 20px;
|
|
line-height: 1.6;
|
|
}
|
|
.calculator {
|
|
background-color: #f9f9f9;
|
|
padding: 20px;
|
|
border-radius: 5px;
|
|
border: 1px solid #ddd;
|
|
}
|
|
.input-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
label {
|
|
display: inline-block;
|
|
margin-bottom: 5px;
|
|
font-weight: bold;
|
|
}
|
|
input[type="text"], input[type="number"] {
|
|
width: 100px;
|
|
padding: 6px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
box-sizing: border-box;
|
|
text-align: right;
|
|
}
|
|
|
|
.result-input {
|
|
width: 100px;
|
|
text-align: right;
|
|
}
|
|
|
|
.distance-container {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 20px;
|
|
}
|
|
|
|
.distance-half {
|
|
flex: 1;
|
|
}
|
|
.buttons {
|
|
margin: 20px 0;
|
|
text-align: center;
|
|
}
|
|
button {
|
|
background-color: #3498db;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
margin: 0 10px;
|
|
}
|
|
button:hover {
|
|
background-color: #2980b9;
|
|
}
|
|
.results {
|
|
margin-top: 20px;
|
|
background-color: #f0f8ff;
|
|
padding: 15px;
|
|
border-radius: 5px;
|
|
border: 1px solid #b3d8ff;
|
|
}
|
|
.result-item {
|
|
margin-bottom: 10px;
|
|
font-size: 16px;
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.result-item span:first-child {
|
|
min-width: 120px;
|
|
margin-right: 5px;
|
|
}
|
|
|
|
.result-item .unit {
|
|
min-width: 40px;
|
|
text-align: left;
|
|
margin-left: 5px;
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.result-item {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.result-item span:first-child {
|
|
min-width: 100px;
|
|
}
|
|
|
|
input[type="text"], input[type="number"], .result-input {
|
|
width: 90px;
|
|
}
|
|
}
|
|
|
|
.result-value {
|
|
font-weight: bold;
|
|
color: #2980b9;
|
|
margin-left: 10px;
|
|
}
|
|
footer {
|
|
margin-top: 30px;
|
|
text-align: center;
|
|
font-size: 14px;
|
|
color: #777;
|
|
}
|
|
.stopwatch {
|
|
background-color: #e8f4fc;
|
|
padding: 15px;
|
|
border-radius: 5px;
|
|
margin-bottom: 20px;
|
|
border: 1px solid #b3d8ff;
|
|
}
|
|
.stopwatch-display {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
margin: 10px 0;
|
|
color: #2c3e50;
|
|
font-family: monospace;
|
|
}
|
|
.stopwatch-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
.toggle-btn {
|
|
width: 120px;
|
|
height: 120px;
|
|
border-radius: 50%;
|
|
background-color: #27ae60;
|
|
font-size: 22px;
|
|
font-weight: bold;
|
|
margin-bottom: 15px;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
transition: all 0.3s ease;
|
|
}
|
|
.toggle-btn.running {
|
|
background-color: #e74c3c;
|
|
}
|
|
.toggle-btn:hover {
|
|
background-color: #219653;
|
|
transform: scale(1.05);
|
|
}
|
|
.toggle-btn.running:hover {
|
|
background-color: #c0392b;
|
|
}
|
|
.reset-btn {
|
|
background-color: #f39c12;
|
|
font-size: 16px;
|
|
padding: 8px 16px;
|
|
margin-top: 10px;
|
|
}
|
|
.reset-btn:hover {
|
|
background-color: #d35400;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>볼링공 속도 계산기</h1>
|
|
|
|
<div class="description">
|
|
<p>이 계산기는 볼링공이 파울라인에서 헤드핀까지 이동하는 속도를 계산합니다.</p>
|
|
<p>시간 입력 또는 원하는 속도 입력으로 양방향 계산이 가능합니다. 볼링 레인의 기본 거리는 60피트(18.288미터)입니다.</p>
|
|
</div>
|
|
|
|
<div class="stopwatch">
|
|
<h3>스톱워치</h3>
|
|
<p>볼링공이 파울라인을 지날 때 '시작'을 누르고, 헤드핀에 도달할 때 '정지'를 누르세요.</p>
|
|
<div class="stopwatch-display" id="stopwatch-display">00:00.000</div>
|
|
<div class="stopwatch-container">
|
|
<button class="toggle-btn" id="toggle-btn">시작</button>
|
|
<button class="reset-btn" id="reset-btn">초기화</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="calculator">
|
|
<div class="input-group">
|
|
<label for="time">볼링공 이동 시간:</label>
|
|
<input type="number" id="time" step="0.001" value="2.000" min="0.001"> 초
|
|
</div>
|
|
|
|
<div class="input-group distance-container">
|
|
<div class="distance-half">
|
|
<label for="distance-meters">거리 (미터):</label>
|
|
<input type="number" id="distance-meters" value="18.288" step="0.001" min="0.1" onchange="updateFeet()"> 미터
|
|
</div>
|
|
<div class="distance-half">
|
|
<label for="distance-feet">거리 (피트):</label>
|
|
<input type="number" id="distance-feet" value="60.00" step="0.01" min="1" onchange="updateMeters()"> 피트
|
|
</div>
|
|
</div>
|
|
|
|
<div class="buttons">
|
|
<button onclick="calculateSpeed()">계산하기</button>
|
|
<button onclick="resetValues()">초기화</button>
|
|
</div>
|
|
|
|
<div class="results" id="results">
|
|
<div class="result-item">
|
|
<span>시속 (킬로미터):</span>
|
|
<input type="number" class="result-input" id="kph" value="0" step="0.01" min="0" onchange="calculateTimeFromKPH()">
|
|
<span class="unit">KPH</span>
|
|
</div>
|
|
<div class="result-item">
|
|
<span>시속 (마일):</span>
|
|
<input type="number" class="result-input" id="mph" value="0" step="0.01" min="0" onchange="calculateTimeFromMPH()">
|
|
<span class="unit">MPH</span>
|
|
</div>
|
|
<div class="result-item">
|
|
<span>초속 (피트):</span>
|
|
<input type="number" class="result-input" id="fps" value="0" step="0.01" min="0" onchange="calculateTimeFromFPS()">
|
|
<span class="unit">FPS</span>
|
|
</div>
|
|
<div class="result-item">
|
|
<span>초속 (미터):</span>
|
|
<input type="number" class="result-input" id="mps" value="0" step="0.01" min="0" onchange="calculateTimeFromMPS()">
|
|
<span class="unit">MPS</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<footer>
|
|
<p> 2025 볼링공 속도 계산기 © <a href="https://lanebow.com" target="_blank">레인보우 - 볼링클럽 매니저</a></p>
|
|
</footer>
|
|
</div>
|
|
|
|
<script>
|
|
// 소수점 자릿수 반올림 함수
|
|
function perRound(num, precision) {
|
|
precision = precision || 3;
|
|
precision = parseInt(precision);
|
|
var result1 = num * Math.pow(10, precision);
|
|
var result2 = Math.round(result1);
|
|
var result3 = result2 / Math.pow(10, precision);
|
|
return zerosPad(result3, precision);
|
|
}
|
|
|
|
// 소수점 자릿수 0 채우기 함수
|
|
function zerosPad(rndVal, decPlaces) {
|
|
var valStrg = rndVal.toString();
|
|
var decLoc = valStrg.indexOf(".");
|
|
|
|
if (decLoc == -1) {
|
|
decPartLen = 0;
|
|
valStrg += decPlaces > 0 ? "." : "";
|
|
} else {
|
|
decPartLen = valStrg.length - decLoc - 1;
|
|
}
|
|
|
|
var totalPad = decPlaces - decPartLen;
|
|
if (totalPad > 0) {
|
|
for (var i = 1; i <= totalPad; i++) {
|
|
valStrg += "0";
|
|
}
|
|
}
|
|
return valStrg;
|
|
}
|
|
|
|
// 미터를 피트로 변환
|
|
function updateFeet() {
|
|
var meters = document.getElementById("distance-meters").value;
|
|
var feet = perRound(meters * 3.2808399, 2);
|
|
document.getElementById("distance-feet").value = feet;
|
|
}
|
|
|
|
// 피트를 미터로 변환
|
|
function updateMeters() {
|
|
var feet = document.getElementById("distance-feet").value;
|
|
var meters = perRound(feet * 0.3048, 3);
|
|
document.getElementById("distance-meters").value = meters;
|
|
}
|
|
|
|
// 속도 계산 함수
|
|
function calculateSpeed() {
|
|
var time = parseFloat(document.getElementById("time").value);
|
|
var distance = parseFloat(document.getElementById("distance-feet").value);
|
|
|
|
if (time <= 0) {
|
|
alert("시간은 0보다 커야 합니다.");
|
|
return;
|
|
}
|
|
|
|
if (distance <= 0) {
|
|
alert("거리는 0보다 커야 합니다.");
|
|
return;
|
|
}
|
|
|
|
// 속도 계산 (원본 코드의 공식 사용)
|
|
var mph = perRound((distance / time) * (3600 / 5280), 2);
|
|
var kph = perRound((distance / time) * (3600 * 0.0003048), 2);
|
|
var fps = perRound(distance / time, 2);
|
|
var mps = perRound((distance * 0.3048) / time, 2);
|
|
|
|
// 결과 표시 (입력 필드에 값 설정)
|
|
document.getElementById("mph").value = mph;
|
|
document.getElementById("kph").value = kph;
|
|
document.getElementById("fps").value = fps;
|
|
document.getElementById("mps").value = mps;
|
|
}
|
|
|
|
// 시속(KPH)에서 시간 계산
|
|
function calculateTimeFromKPH() {
|
|
var kph = parseFloat(document.getElementById("kph").value);
|
|
var distance = parseFloat(document.getElementById("distance-meters").value);
|
|
|
|
if (kph <= 0) {
|
|
alert("속도는 0보다 커야 합니다.");
|
|
return;
|
|
}
|
|
|
|
// KPH에서 시간(초) 계산: 거리(m) / 속도(m/s) = 시간(s)
|
|
// KPH를 m/s로 변환: kph * 1000 / 3600
|
|
var speedInMps = kph * 1000 / 3600;
|
|
var time = distance / speedInMps;
|
|
|
|
// 시간 설정 및 다른 속도 값 업데이트
|
|
document.getElementById("time").value = perRound(time, 3);
|
|
|
|
// 다른 속도 단위 계산
|
|
var distanceFeet = parseFloat(document.getElementById("distance-feet").value);
|
|
var mph = perRound((distanceFeet / time) * (3600 / 5280), 2);
|
|
var fps = perRound(distanceFeet / time, 2);
|
|
var mps = perRound(speedInMps, 2);
|
|
|
|
// 다른 속도 필드 업데이트 (무한 루프 방지를 위해 이벤트 발생 없이)
|
|
document.getElementById("mph").value = mph;
|
|
document.getElementById("fps").value = fps;
|
|
document.getElementById("mps").value = mps;
|
|
}
|
|
|
|
// 시속(MPH)에서 시간 계산
|
|
function calculateTimeFromMPH() {
|
|
var mph = parseFloat(document.getElementById("mph").value);
|
|
var distance = parseFloat(document.getElementById("distance-feet").value);
|
|
|
|
if (mph <= 0) {
|
|
alert("속도는 0보다 커야 합니다.");
|
|
return;
|
|
}
|
|
|
|
// MPH에서 시간(초) 계산: 거리(feet) / 속도(feet/s) = 시간(s)
|
|
// MPH를 feet/s로 변환: mph * 5280 / 3600
|
|
var speedInFps = mph * 5280 / 3600;
|
|
var time = distance / speedInFps;
|
|
|
|
// 시간 설정 및 다른 속도 값 업데이트
|
|
document.getElementById("time").value = perRound(time, 3);
|
|
|
|
// 다른 속도 단위 계산
|
|
var kph = perRound(mph * 1.60934, 2);
|
|
var fps = perRound(speedInFps, 2);
|
|
var mps = perRound(speedInFps * 0.3048, 2);
|
|
|
|
// 다른 속도 필드 업데이트
|
|
document.getElementById("kph").value = kph;
|
|
document.getElementById("fps").value = fps;
|
|
document.getElementById("mps").value = mps;
|
|
}
|
|
|
|
// 초속(FPS)에서 시간 계산
|
|
function calculateTimeFromFPS() {
|
|
var fps = parseFloat(document.getElementById("fps").value);
|
|
var distance = parseFloat(document.getElementById("distance-feet").value);
|
|
|
|
if (fps <= 0) {
|
|
alert("속도는 0보다 커야 합니다.");
|
|
return;
|
|
}
|
|
|
|
// FPS에서 시간(초) 계산: 거리(feet) / 속도(feet/s) = 시간(s)
|
|
var time = distance / fps;
|
|
|
|
// 시간 설정 및 다른 속도 값 업데이트
|
|
document.getElementById("time").value = perRound(time, 3);
|
|
|
|
// 다른 속도 단위 계산
|
|
var mph = perRound(fps * 3600 / 5280, 2);
|
|
var kph = perRound(fps * 0.3048 * 3.6, 2);
|
|
var mps = perRound(fps * 0.3048, 2);
|
|
|
|
// 다른 속도 필드 업데이트
|
|
document.getElementById("mph").value = mph;
|
|
document.getElementById("kph").value = kph;
|
|
document.getElementById("mps").value = mps;
|
|
}
|
|
|
|
// 초속(MPS)에서 시간 계산
|
|
function calculateTimeFromMPS() {
|
|
var mps = parseFloat(document.getElementById("mps").value);
|
|
var distance = parseFloat(document.getElementById("distance-meters").value);
|
|
|
|
if (mps <= 0) {
|
|
alert("속도는 0보다 커야 합니다.");
|
|
return;
|
|
}
|
|
|
|
// MPS에서 시간(초) 계산: 거리(m) / 속도(m/s) = 시간(s)
|
|
var time = distance / mps;
|
|
|
|
// 시간 설정 및 다른 속도 값 업데이트
|
|
document.getElementById("time").value = perRound(time, 3);
|
|
|
|
// 다른 속도 단위 계산
|
|
var distanceFeet = parseFloat(document.getElementById("distance-feet").value);
|
|
var fps = perRound(mps / 0.3048, 2);
|
|
var mph = perRound(mps * 2.23694, 2);
|
|
var kph = perRound(mps * 3.6, 2);
|
|
|
|
// 다른 속도 필드 업데이트
|
|
document.getElementById("mph").value = mph;
|
|
document.getElementById("kph").value = kph;
|
|
document.getElementById("fps").value = fps;
|
|
}
|
|
|
|
// 초기화 함수
|
|
function resetValues() {
|
|
document.getElementById("time").value = "2.000";
|
|
document.getElementById("distance-feet").value = "60.00";
|
|
document.getElementById("distance-meters").value = "18.288";
|
|
document.getElementById("mph").value = "0";
|
|
document.getElementById("kph").value = "0";
|
|
document.getElementById("fps").value = "0";
|
|
document.getElementById("mps").value = "0";
|
|
}
|
|
|
|
// 스톱워치 관련 변수
|
|
let stopwatchInterval;
|
|
let startTime;
|
|
let elapsedTime = 0;
|
|
let isRunning = false;
|
|
|
|
// 스톱워치 시작/정지 토글 함수
|
|
function toggleStopwatch() {
|
|
const toggleBtn = document.getElementById('toggle-btn');
|
|
|
|
if (!isRunning) {
|
|
// 시작
|
|
startTime = Date.now() - elapsedTime;
|
|
stopwatchInterval = setInterval(updateStopwatch, 10);
|
|
isRunning = true;
|
|
|
|
// 버튼 상태 변경
|
|
toggleBtn.textContent = '정지';
|
|
toggleBtn.classList.add('running');
|
|
} else {
|
|
// 정지
|
|
clearInterval(stopwatchInterval);
|
|
elapsedTime = Date.now() - startTime;
|
|
isRunning = false;
|
|
|
|
// 버튼 상태 변경
|
|
toggleBtn.textContent = '시작';
|
|
toggleBtn.classList.remove('running');
|
|
|
|
// 스톱워치 정지 시 정확한 시간 계산
|
|
updateStopwatchDisplay(); // 스톱워치 표시 갱신
|
|
|
|
// 스톱워치와 동일한 값을 입력 필드에 설정
|
|
const exactSeconds = Math.floor((elapsedTime % 60000) / 1000) + ((elapsedTime % 1000) / 1000);
|
|
document.getElementById('time').value = exactSeconds.toFixed(3);
|
|
|
|
calculateSpeed();
|
|
}
|
|
}
|
|
|
|
// 스톱워치 초기화 함수
|
|
function resetStopwatch() {
|
|
clearInterval(stopwatchInterval);
|
|
elapsedTime = 0;
|
|
isRunning = false;
|
|
updateStopwatchDisplay();
|
|
|
|
// 버튼 상태 변경
|
|
const toggleBtn = document.getElementById('toggle-btn');
|
|
toggleBtn.textContent = '시작';
|
|
toggleBtn.classList.remove('running');
|
|
}
|
|
|
|
// 스톱워치 표시 업데이트 함수
|
|
function updateStopwatch() {
|
|
elapsedTime = Date.now() - startTime;
|
|
updateStopwatchDisplay();
|
|
}
|
|
|
|
// 스톱워치 시간 표시 형식 변환 함수
|
|
function updateStopwatchDisplay() {
|
|
const minutes = Math.floor(elapsedTime / 60000);
|
|
const seconds = Math.floor((elapsedTime % 60000) / 1000);
|
|
const milliseconds = elapsedTime % 1000;
|
|
|
|
const display = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${milliseconds.toString().padStart(3, '0')}`;
|
|
document.getElementById('stopwatch-display').textContent = display;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 페이지 로드 시 초기 계산 및 이벤트 리스너 설정
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
calculateSpeed();
|
|
|
|
// 스톱워치 버튼에 이벤트 리스너 추가
|
|
const toggleBtn = document.getElementById('toggle-btn');
|
|
const resetBtn = document.getElementById('reset-btn');
|
|
|
|
// mousedown과 touchstart 이벤트를 모두 추가하여 모바일과 데스크톱 모두 지원
|
|
toggleBtn.addEventListener('mousedown', toggleStopwatch);
|
|
toggleBtn.addEventListener('touchstart', function(e) {
|
|
e.preventDefault(); // 화면 스크롤 방지
|
|
toggleStopwatch();
|
|
});
|
|
|
|
resetBtn.addEventListener('mousedown', resetStopwatch);
|
|
resetBtn.addEventListener('touchstart', function(e) {
|
|
e.preventDefault();
|
|
resetStopwatch();
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |