2023-02-14 06:21:19 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
|
|
|
|
<head>
|
|
|
|
<title>Target scaler</title>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
body {
|
2023-02-14 07:18:26 +00:00
|
|
|
max-width: 50em;
|
|
|
|
margin: 1.5em auto;
|
2023-02-14 06:21:19 +00:00
|
|
|
}
|
2023-02-14 07:18:26 +00:00
|
|
|
|
2023-02-14 06:21:19 +00:00
|
|
|
input {
|
|
|
|
margin-left: 1em;
|
|
|
|
}
|
|
|
|
|
|
|
|
.complex-radio {
|
|
|
|
display: inline-block;
|
|
|
|
text-align: center;
|
|
|
|
vertical-align: top;
|
|
|
|
}
|
|
|
|
|
|
|
|
.complex-radio img {
|
|
|
|
width: 10em;
|
|
|
|
}
|
|
|
|
|
2023-02-14 07:18:26 +00:00
|
|
|
.vanish {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
#print [id^=caption-] {
|
|
|
|
text-align: center;
|
|
|
|
font-family: sans-serif;
|
|
|
|
}
|
|
|
|
|
2023-02-14 06:21:19 +00:00
|
|
|
#print {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
#print .target {
|
|
|
|
display: block;
|
|
|
|
margin-left: auto;
|
|
|
|
margin-right: auto;
|
|
|
|
}
|
|
|
|
|
|
|
|
@media screen {
|
|
|
|
#print {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@media print {
|
|
|
|
#ui {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body>
|
|
|
|
<div id="ui">
|
|
|
|
<h1>Dry Fire Target Maker</h1>
|
|
|
|
<p>
|
2023-02-14 06:33:28 +00:00
|
|
|
Scale the target by setting the simulated and actual distances to the target in any unit of length,
|
|
|
|
then click <em>Print</em>.
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
For example, if you want the target to appear as if it is 15m away when it is actually
|
|
|
|
only 3m away, set <em>Simulated distance</em> to 15 and <em>Actual distance</em>
|
2023-02-14 06:21:19 +00:00
|
|
|
to 3.
|
|
|
|
</p>
|
2023-02-14 06:33:28 +00:00
|
|
|
<p>
|
2023-02-14 07:18:26 +00:00
|
|
|
The target <strong>will not</strong> fit on US letter paper if <em>Actual distance</em> is more than ~35% of
|
|
|
|
<em>Simulated distance</em>.
|
2023-02-14 06:33:28 +00:00
|
|
|
</p>
|
|
|
|
<hr>
|
2023-02-14 06:21:19 +00:00
|
|
|
<p>
|
|
|
|
<label>Simulated distance<input id="simulated-range" type="number" value="40"></label>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<label>Actual distance<input id="actual-range" type="number" value="3"></label>
|
|
|
|
</p>
|
2023-02-14 07:18:26 +00:00
|
|
|
<fieldset id="caption-settings">
|
|
|
|
<legend>Caption</legend>
|
|
|
|
<label><input type="radio" name="caption-pos" value="none" checked>None</label>
|
|
|
|
<label><input type="radio" name="caption-pos" value="above">Above</label>
|
|
|
|
<label><input type="radio" name="caption-pos" value="below">Below</label>
|
|
|
|
<p><label>Text<input id="caption-input"></label></p>
|
|
|
|
</fieldset>
|
2023-02-14 06:21:19 +00:00
|
|
|
<fieldset role="radiogroup" id="target-styles">
|
|
|
|
<legend>Target style</legend>
|
|
|
|
|
|
|
|
<label><input type="radio" name="target-style" checked>
|
|
|
|
<div class="complex-radio">
|
|
|
|
<div>USPSA</div><img class="target" src="uspsa.svg">
|
|
|
|
</div>
|
|
|
|
</label>
|
|
|
|
<label><input type="radio" name="target-style">
|
|
|
|
<div class="complex-radio">
|
|
|
|
<div>IDPA</div><img class="target" src="idpa.svg">
|
|
|
|
</div>
|
|
|
|
</label>
|
|
|
|
<label><input type="radio" name="target-style">
|
|
|
|
<div class="complex-radio">
|
|
|
|
<div>IPSC</div><img class="target" src="ipsc.svg">
|
|
|
|
</div>
|
|
|
|
</label>
|
|
|
|
</fieldset>
|
|
|
|
<p>
|
|
|
|
<button id="print-button">Print</button>
|
|
|
|
</p>
|
|
|
|
</div>
|
2023-02-14 07:18:26 +00:00
|
|
|
|
2023-02-14 06:21:19 +00:00
|
|
|
<div id="print">
|
2023-02-14 07:18:26 +00:00
|
|
|
<h1 id="caption-above"></h1>
|
2023-02-14 06:21:19 +00:00
|
|
|
<img class="target">
|
2023-02-14 07:18:26 +00:00
|
|
|
<h1 id="caption-below"></h1>
|
2023-02-14 06:21:19 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
{
|
|
|
|
let target = document.querySelector("#print .target");
|
|
|
|
let simulatedRange = document.getElementById("simulated-range");
|
|
|
|
let actualRange = document.getElementById("actual-range");
|
|
|
|
|
|
|
|
const updateScale = () => {
|
|
|
|
let scale = actualRange.value / simulatedRange.value;
|
|
|
|
target.style.width = target.naturalWidth * scale + "mm";
|
2023-02-14 07:18:26 +00:00
|
|
|
};
|
2023-02-14 06:21:19 +00:00
|
|
|
simulatedRange.addEventListener("change", updateScale);
|
|
|
|
actualRange.addEventListener("change", updateScale);
|
|
|
|
target.addEventListener("load", updateScale);
|
|
|
|
|
|
|
|
document.getElementById("print-button").addEventListener("click", print.bind(window));
|
|
|
|
|
|
|
|
const updateTargetStyle = () => {
|
|
|
|
const checked = document.querySelector("#target-styles input[type=radio]:checked");
|
|
|
|
const src = checked.labels[0].getElementsByTagName("img")[0].src;
|
|
|
|
target.src = src;
|
|
|
|
};
|
|
|
|
|
2023-02-14 07:18:26 +00:00
|
|
|
document.querySelectorAll("#target-styles label").forEach(label => {
|
2023-02-14 06:21:19 +00:00
|
|
|
label.addEventListener("change", updateTargetStyle);
|
|
|
|
});
|
|
|
|
updateTargetStyle();
|
2023-02-14 07:18:26 +00:00
|
|
|
|
|
|
|
let captionInput = document.getElementById("caption-input");
|
|
|
|
let captionAbove = document.getElementById("caption-above");
|
|
|
|
let captionBelow = document.getElementById("caption-below");
|
|
|
|
const updateCaptionPosition = () => {
|
|
|
|
let value = document.querySelector("#caption-settings input[name=caption-pos]:checked").value;
|
|
|
|
captionInput.disabled = value === "none";
|
|
|
|
|
|
|
|
if (value === "above") {
|
|
|
|
captionAbove.classList.remove("vanish");
|
|
|
|
captionBelow.classList.add("vanish");
|
|
|
|
} else if (value === "below") {
|
|
|
|
captionAbove.classList.add("vanish");
|
|
|
|
captionBelow.classList.remove("vanish");
|
|
|
|
} else {
|
|
|
|
captionAbove.classList.add("vanish");
|
|
|
|
captionBelow.classList.add("vanish");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const updateCaptionText = () => {
|
|
|
|
captionAbove.innerText = captionBelow.innerText = captionInput.value;
|
|
|
|
}
|
|
|
|
document.querySelectorAll("#caption-settings input[name=caption-pos]").forEach(radio => {
|
|
|
|
radio.addEventListener("change", updateCaptionPosition);
|
|
|
|
});
|
|
|
|
captionInput.addEventListener("change", updateCaptionText);
|
|
|
|
captionInput.addEventListener("keydown", updateCaptionText);
|
|
|
|
updateCaptionText();
|
|
|
|
updateCaptionPosition();
|
2023-02-14 06:21:19 +00:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
|
|
|
|
</html>
|