Keep it simple
Your code is overly complex as you are doing too many conversions C <=> F, C <=> Ra, and Ra <=> F can all be avoided.
When doing any type of unit conversion select a base unit and then only convert between the base unit and other units.
By using a base unit you can do all the conversions with only 6 formulas, rather than the 12 you are currently using.
General review
HTML
It is important for the content of a web page to have machine readable information that is unambiguous and semantically meaningful. Many people need assistance to interact with web pages, if the machine can not understand the content these people can not use the page.
Also bots (such as search engines use to rank pages) can not accurately assess a page's content if it does not understand what the page contains.
I am not HTML expert so these are just the basic points. See rewrite for more info
Use appropriate elements
- Use the Labels to label inputs
- The different units temperatures are a list, use an unordered list to hold the inputs and labels.
Related data
Do NOT! use id
to store semantic information. That does not mean you should not use meaningful id
names, rather you should add the semantic information using more appropriate attributes and or elements.
For example you use the event.target.id
to determine which unit is being changed. Rather than use the id store the input elements unit type as a dataset
attribute. See rewrite
JavaScript
window
Your use of window
is redundant as window
is the global this (scope).
window.oninput = function(event) {
is identical to oninput = function(event) {
Add listeners don`t set listeners
You should avoid assigning event listeners directly as they can be overwritten, by you accidentally, or by 3rd party content. E.G. adverts.
Use addEventListener
as it adds listeners
E.G. oninput = function(event) { /*... code ... */ }
should be addEventListener("input", function(event) { /*... code ... */ });
NOTE: The event name when using addEventListener
does not include the on
prefix. "oninput"
becomes "input"
Constants
For variables that do not change declare them as constants. eg const campo = event.target.id;
Indentation
Watch your indentation, the four lines below var i = document.ge...
are incorrectly indented.
Use standard keyboard characters
The use of º
via the keyboard dance LEFT ALT 167 is unnecessary as it adds nothing to the quality or readability of the code.
Magic Numbers
Numbers seldom have meaning on there own. They are also easy to get wrong it you have a lot of them. Give numbers names by defining them as constants.
1.8
could mean anything... so remove the guess work with const RANKINE_SCALE = 1.8
Problem
Inputs can get stuck because the input step and min values are not set or incorrect
Changing the number of decimal points means you must change the step value for each input. E.G. Decimal 0 step 1, Decimal 1 step 0.1, 2 step 0.01, and so on.
To control the step position you can not set the min
attribute to be a value that is not divisible by step. For all by Kelvin and Rankine the min value is problematic.
But using Kelvin as a the base unit we need only define its min
attribute and in JS make sure its >= 0 so that the other units don't go out of bounds.
Rewrite
The rewrite add some CSS, a lot of HTML and splits the JS into many parts.
Only the Kelvin input value is defined with a min and step and value. The other values are set when the JavaScript first runs by calling decimalEvent
Each temperature input uses data-unit=""
to name the unit used. This name is used to lookup the correct conversion function in the object toKelvin
.
Temperature and decimal input events are split. The decimal listener will call the Temperature listener which will use the default target kelvin if called without an event
const F_SCALE = 1.8, F_OFFSET = 459.67;
const C_OFFSET = 273.15;
const toKelvin = {
Celsius: t => t + C_OFFSET,
Farenheit: t => (t + F_OFFSET) / F_SCALE,
Rankine: t => t / F_SCALE,
Kelvin: t => t,
};
const fromKelvin = {
Celsius: k => celsiusIn.value = round(k - C_OFFSET),
Farenheit: k => farenheitIn.value = round(k * F_SCALE - F_OFFSET),
Rankine: k => rankineIn.value = round(k * F_SCALE),
Kelvin: k => kelvinIn.value = round(k),
};
const round = val => Math.round(val * round.scale) / round.scale;
decimalIn.addEventListener("input", decimalEvent);
temperatureList.addEventListener("input", temperatureEvent);
decimalEvent();
function decimalEvent() {
const step = 1 / (round.scale = 10 ** decimalIn.value);
celsiusIn.step = step;
kelvinIn.step = step;
farenheitIn.step = step;
rankineIn.step = step;
temperatureEvent();
}
function temperatureEvent({target = kelvinIn} = {}) {
if (target.value !== "") {
const unit = target.dataset.units;
const kelvin = Math.max(0, toKelvin[unit](round(Number(target.value))));
for (const convert of Object.values(fromKelvin)) { convert(kelvin) }
}
}
label {
font-size: large;
}
input {
width: 3em;
}
ul {
width: 220px;
display: flex;
flex-direction: column;
list-style-type: none;
padding-inline-start: 0px;
}
li input {
float: right;
width: 7em;
}
<h3>Temperature unit converter</h3>
<input type="number" min="0" max="5" value="0" step="1" id="decimalIn">
<label for="decimalIn"><small>Decimals<small></label>
<ul id="temperatureList">
<li>
<label for="celsiusIn">Celsius (ºC) </label>
<input id="celsiusIn" type="number" data-units ="Celsius">
</li>
<li>
<label for="kelvinIn">Kelvin (K) </label>
<input id="kelvinIn" type="number" min="0" value="293" step="1" data-units="Kelvin">
</li>
<li>
<label for="farenheitIn">Farenheit (ºF) </label>
<input id="farenheitIn" type="number" data-units="Farenheit">
</li>
<li>
<label for="rankineIn">Rankine (ºRa) </label>
<input id="rankineIn" type="number" data-units="Rankine">
</li>
</ul>
Update
The original rewrite had a few problems.
- Could not type negative values in some situations
- Was converting digits past the decimal count
- Was displaying trailing zeros. Eg
0.000
should be just 0
The code has been changed to ignore partial inputs. E.G. the negative sign '-' before the numbers are added.
Using Math.round
rather than Number.toFixed
to set the number of decimal places.
Round the decimals before converting to base unit (kelvin) to stop fractions past the number of decimal making changes to other units.