Hace mucho tiempo en mis inicios en la programación hice un conversor de unidades usando JavaScript, HTML, CSS y los frameworks Bootstrap y jQuery. Era para mi clase de física. Hoy vengo a presentarlo y compartirlo por si a alguien más le sirve.

Es un simple convertidor de unidades web que transforma de una unidad a otra. Soporta:
- Longitud
- Masa
- Tiempo
- Energía
- Frecuencia
- Presión
- Tamaño de datos
- Temperatura
- Velocidad
- Volumen
- Área
A través de este post te mostraré cómo funciona, cómo descargarlo y cómo está hecho.
Unidades soportadas
Soporta todos los grupos de unidades de medidas listadas anteriormente. Por ejemplo en longitud tiene metros, kilómetros, etcétera. En masa tiene gramo, kilogramo, y así para cada categoría.
He escrito todas las unidades y sus equivalencias en un diccionario. Es un archivo grande pues tiene todas las equivalencias como si fuera la base de datos. Se ve así (aunque no es el completo):
/**
* Created by Luis Cabrera Benito on 27/01/2016.
*/
var unidades = {
'Longitud': {
'grupo': 'Longitud',
'unidades': [
'kilometro',
'metro',
'centimetro',
'milimetro',
'micrometro',
'nanometro',
'milla',
'yarda',
'pie',
'pulgada'
],
'equivalencias': {
'kilometro': {
'kilometro': 1,
'metro': 1000,
'centimetro': 100000,
'milimetro': 1e+6,
'micrometro': 1e+9,
'nanometro': 1e+12,
'milla': 0.621371,
'yarda': 1093.61,
'pie': 3280.84,
'pulgada': 39370.1
},
}
};
Ahora ese archivo es leído desde el verdadero conversor cuya plantilla HTML es la siguiente en donde cargamos los scripts incluyendo a jQuery.
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="./css/bootstrap.css">
<link rel="stylesheet" href="./css/fa.css">
<link rel="stylesheet" href="./css/styles.css">
<title>Conversor de unidades - Dennis</title>
</head>
<body>
<div class="container-fluid">
<div class="row "><br>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="form-group">
<label for="principal">¿Qué quieres convertir?
<button class="btn btn-info" id="mostrarEjemplo">Ver un ejemplo</button>
</label>
<input type="text" class="form-control" id="principal" placeholder="256 bits a megabytes"
autocomplete="off">
</div>
<br>
<div class="alert" id="resultado">
</div>
<br>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 ocultable" hidden="hidden">
<div class="row ">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="form-group">
<label for="grupoUnidades">Unidad de medida</label>
<select name="grupoUnidades" id="grupoUnidades" class="form-control"></select>
</div>
</div>
<br><br>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
<label for="primeraUnidad">De</label>
<input id="inputPrimeraUnidad" type="text" class="form-control">
<select name="primeraUnidad" id="primeraUnidad" class="form-control select"></select>
</div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
<label for="segundaUnidad">A</label>
<input id="inputSegundaUnidad" type="text" class="form-control">
<select name="segundaUnidad" id="segundaUnidad" class="form-control"></select>
</div>
</div>
</div>
<br><br><br>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<button id="btn-about" class="btn btn-primary form-control"><i
class="material-icons fa fa-info-circle"></i> Acerca de
</button>
</div>
</div>
<div id="acercaDe" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="text-center">¡Hola!, me llamo Dennis y puedo convertir unidades.<br>
<strong>Nota:</strong>
Por el momento no entiendo las abreviaciones como "km" o "m",
pero mejoraré día a día. <i class="fa fa-smile-o"></i></h4>
</div>
<div class="modal-body">
<strong>Unidades que puedo convertir hasta el momento:</strong>
<ul class="list-group">
<li class="list-group-item list-group-item-success">Longitud</li>
<li class="list-group-item list-group-item-success">Masa</li>
<li class="list-group-item list-group-item-success">Tiempo - Gracias a <strong><a
href="https://twitter.com/MariJose961128">Marijo Sacramento</a></strong> por
escribir las equivalencias
</li>
<li class="list-group-item list-group-item-success">Energía - Gracias a <strong><a
href="https://twitter.com/MariJose961128">Marijo Sacramento</a></strong> por
escribir las equivalencias
</li>
<li class="list-group-item list-group-item-success">Frecuencia - Gracias a <strong><a
href="https://twitter.com/MariJose961128">Marijo Sacramento</a></strong> por
escribir las equivalencias
</li>
<li class="list-group-item list-group-item-success">Presión - Gracias a <strong><a
href="https://twitter.com/MariJose961128">Marijo Sacramento</a></strong> por
escribir las equivalencias
</li>
<li class="list-group-item list-group-item-success">Tamaño de datos - Gracias a <strong><a
href="https://twitter.com/MariJose961128">Marijo Sacramento</a></strong> por
escribir las equivalencias
</li>
<li class="list-group-item list-group-item-success">Temperatura</li>
<li class="list-group-item list-group-item-success">Velocidad</li>
<li class="list-group-item list-group-item-success">Volumen</li>
<li class="list-group-item list-group-item-success">Área - Gracias a <strong><a
href="https://twitter.com/MariJose961128">Marijo Sacramento</a></strong> por
escribir las equivalencias
</li>
</ul>
<br>
<p>Más unidades vienen en camino...</p>
<p>Creado y mantenido por <a href="https://www.facebook.com/cabrerabenito">Luis Cabrera
Benito</a></p>
<p>Programado en Javascript utilizando jQuery. Los estilos y algunas funcionalidades son gracias
a Bootstrap.</p>
<p>Código fuente disponible en GitHub. <a
href="https://github.com/parzibyte/dennis-conversor">Ver código</a></p>
<hr>
<p>Bautizado como Dennis en honor a <strong><a
href="https://es.wikipedia.org/wiki/Dennis_Ritchie">Dennis Ritchie</a></strong></p>
<blockquote>
<p>Vacía tu memoria con un <i>free()</i>, como un puntero.
<br>
Si casteas un puntero a un <i>entero</i>, se convierte en un <i>entero</i>,
<br>
si casteas un puntero a un <i>struct</i>, se convierte en un <i>struct</i>.
<br>
El puntero puede estallar,
<br>
el puntero se puede sobrecargar,
<br>
¡Sé un puntero, amigo mío!
</p>
<footer>Dennis Ritchie</footer>
</blockquote>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
</div>
</div>
</div>
</div>
<div id="manual" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="text-center">Cómo hablarle a Dennis</h4>
</div>
<div class="modal-body text-center">
<p>Dennis aceptará que le hables como a una persona con frases como:</p><br>
<ul class="list-group">
<li class="list-group-item list-group-item-success">1 milla a metros</li>
<li class="list-group-item list-group-item-success">15.05 libra por pulgada cuadrada en
atmosfera
</li>
<li class="list-group-item list-group-item-success">28 año natural a siglo</li>
<li class="list-group-item list-group-item-success">11 kilohertz a hercios</li>
<li class="list-group-item list-group-item-success">96 bits en kilobits</li>
</ul>
<br>
<p><strong>Nota: </strong>Dennis acepta palabras en singular, y en plural (por ejemplo,
"metros") pero solamente si
la unidad no tiene espacios. Ya que por ejemplo "grados celsius" no será detectado
correctamente. En ese caso
es mejor escribir "grado celsius".</p>
<br>
<p>Conforme vayas escribiendo, Dennis te avisará si es que tienes un error</p>
<img src="./img/1.png" alt="Imagen 1" class="img img-responsive img-thumbnail">
<br>
<p>Si Dennis no reconoce una unidad (a veces es porque no reconoce los plurales, por ejemplo
"años naturales") te lo dirá.</p>
<img src="./img/2.png" alt="Imagen 2" class="img img-responsive img-thumbnail"><br>
<br>
<p>Una vez que Dennis haya reconocido lo que le dijiste, lo convertirá y te mostrará unos
formularios</p>
<img src="./img/3.png" alt="Imagen 3" class="img img-responsive img-thumbnail"><br>
<p>Dichos formularios son para que interactúes mejor con Dennis, y no tengas que estar
escribiendo.</p>
<p>Puedes mover y cambiar valores a tu gusto.</p>
<img src="./img/4.png" alt="Imagen 4" class="img img-responsive img-thumbnail"><br>
<img src="./img/5.png" alt="Imagen 5" class="img img-responsive img-thumbnail"><br>
<img src="./img/6.png" alt="Imagen 6" class="img img-responsive img-thumbnail"><br>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Entendido</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript" src="./js/bootstrap.js"></script>
<script type="text/javascript" src="./js/unidades.js"></script>
<script type="text/javascript" src="./js/conversor.js"></script>
</body>
</html>
Escuchamos ya sea que cambie el input o unos de los seleccionadores y se hace la conversión, quedando el código así:
/**
* Created by Luis Cabrera Benito on 25/01/2016.
*/
$(document).ready(function () {
principal();
$selectPrimerGrupo.val('metro');
});
var $inputPrincipal = $('input#principal'),
$resultado = $('div#resultado'),
$selectGrupoUnidades = $('select#grupoUnidades'),
$selectPrimerGrupo = $('select#primeraUnidad'),
$selectSegundoGrupo = $('select#segundaUnidad'),
$inputPrimerGrupo = $('input#inputPrimeraUnidad'),
$inputSegundoGrupo = $('input#inputSegundaUnidad'),
$btnEjemplo = $('button#mostrarEjemplo'),
$ventanaAcercaDe = $('div#acercaDe'),
$btnAcercaDe = $('button#btn-about'),
contador = 0,
segundosCambiaPlaceholder = 1,
limiteLongitudNumeros = 16,
palabrasPermitidas = ["en", "a"],
sugerencias = [
"20 hercios a kilohertz",
"1 milimetro en pies",
"14.6 miligramos en onzas",
"256 bits a megabytes",
"15 mes a horas",
"256 bits a megabytes"
];
function aLetraCapital(palabra) {
return palabra[0].toUpperCase() + palabra.slice(1, palabra.length);
}
function cambiaPlaceholder() {
if (contador < sugerencias.length) {
$inputPrincipal.attr('placeholder', sugerencias[contador]);
contador++;
} else {
contador = 0;
}
}
function compruebaValores(oracion) {
if (oracion) {
var oracionCortada = cortaOracion(oracion);
if (isNaN(oracionCortada)) {
var numero = oracionCortada.numero,
unidad1 = oracionCortada.u1.toLowerCase(),
unidad2 = oracionCortada.u2.toLowerCase();
if (!isNaN(numero)) {
if (numero.length <= limiteLongitudNumeros - 1) {
if (dameGrupo(unidad1) === false) {
unidad1 = unidad1.slice(0, -1);
}
if (dameGrupo(unidad2) === false) {
unidad2 = unidad2.slice(0, -1);
}
var grupoUnidad1 = dameGrupo(unidad1),
grupoUnidad2 = dameGrupo(unidad2);
if (grupoUnidad1 !== false) {
if (grupoUnidad2 !== false) {
if (grupoUnidad1 === grupoUnidad2) {
convierte(grupoUnidad1, grupoUnidad2, numero, unidad1, unidad2, false);
} else {
escribeError('Los grupos de unidades no son compatibles: <strong>' + unidad1 + ' y ' + unidad2 + '</strong>');
}
} else {
escribeError('La segunda unidad no existe: <strong>' + unidad2 + '</strong>');
}
} else {
escribeError('La primera unidad no existe: <strong>' + unidad1 + '</strong>');
}
} else {
escribeError('Lo siento, solamente se permiten números de <strong>16 cifras</strong> sin incluir el punto decimal');
}
} else {
escribeError('La primera parte de la oración no es un número: <strong>' + numero + '</strong>');
}
} else {
switch (oracionCortada) {
case 0:
escribeError('No entiendo lo que quieres. Recuerda que debes unir con "en" o "a", por ejemplo "1 milla <strong>a</strong> metros"');
break;
case 1:
escribeError('No entiendo lo que quieres. Recuerda que no debes <strong>incluir espacios</strong> al inicio');
break;
}
}
} else {
$('.ocultable').hide();
}
}
function convierte(grupo, grupo2, numero, u1, u2, esDelSegundoInput) {
var resultado = dameEquivalencia(grupo, u1, u2) * numero;
if (grupo === "Temperatura") {
resultado = grados(grupo, u1, u2, numero);
}
llenaPrimerGrupo($selectPrimerGrupo, grupo);
llenaSegundoGrupo($selectSegundoGrupo, grupo2);
$selectGrupoUnidades.val(grupo);
if (esDelSegundoInput) {
$inputPrimerGrupo.val(resultado);
$inputSegundoGrupo.val(numero);
$selectPrimerGrupo.val(u2);
$selectSegundoGrupo.val(u1);
} else {
$inputPrimerGrupo.val(numero);
$inputSegundoGrupo.val(resultado);
$selectPrimerGrupo.val(u1);
$selectSegundoGrupo.val(u2);
}
escribeResultado(numero, u1, u2, resultado);
}
function cortaOracion(o) {
var posicionPrimerNumero = o.indexOf(" ");
if (posicionPrimerNumero > 0) {
var primerNumero = o.slice(0, posicionPrimerNumero);
var posicionNexo;
var nexo;
var x;
for (x in palabrasPermitidas) {
posicionNexo = o.indexOf(" " + palabrasPermitidas[x] + " ", posicionPrimerNumero + 1);
if (posicionNexo !== -1) {
break;
}
}
if (posicionNexo !== -1) {
nexo = palabrasPermitidas[x];
var unidad1 = o.slice(posicionPrimerNumero + 1, posicionNexo);
var unidad2 = o.slice(posicionNexo + 2 + nexo.length, o.length);
return {
'numero': primerNumero,
'u1': unidad1,
'u2': unidad2
};
} else {
return 0;
}
} else {
return 1;
}
}
function dameEquivalencia(grupo, u1, u2) {
return unidades[grupo].equivalencias[u1][u2];
}
function dameGrupo(unidad) {
for (var x in unidades) {
if (unidades[x].unidades.indexOf(unidad) !== -1) {
return unidades[x].grupo;
}
}
return false;
}
function escribeError(mensaje) {
$('.ocultable').hide();
$resultado
.removeClass('alert-success')
.addClass('alert-danger');
$resultado.html('<h5>' + mensaje + '</h5>');
}
function escribeResultado(numero, u1, u2, resultado) {
var primeraUnidadFinal = (numero === 1) ? u1 : u1 + 's';
var cadenaSegundaUnidad = (resultado === 1) ? u2 : u2 + 's';
var cadenaEquivalencia = (numero === 1) ? " equivale " : " equivalen ";
var mensaje = '<h5>'
+ '<strong>' + numero + '</strong>'
+ ' '
+ primeraUnidadFinal
+ cadenaEquivalencia + 'a '
+ '<strong>' + resultado + '</strong>'
+ ' '
+ cadenaSegundaUnidad
+ '</h5>';
$resultado
.removeClass('alert-danger')
.addClass('alert-success');
$resultado.html(mensaje);
$('.ocultable').show();
}
function escuchaElementos() {
$selectGrupoUnidades.change(function () {
llenaPrimerGrupo($selectPrimerGrupo, $(this).val());
llenaSegundoGrupo($selectSegundoGrupo, $(this).val());
$inputPrimerGrupo.val(1);
$inputPrimerGrupo.keyup();
convierte(
$(this).val(),
$(this).val(),
$inputPrimerGrupo.val(),
$selectPrimerGrupo.val(),
$selectSegundoGrupo.val(), false);
});
$selectPrimerGrupo.change(function () {
convierte(
$selectGrupoUnidades.val(),
$selectGrupoUnidades.val(),
$inputPrimerGrupo.val(),
$(this).val(),
$selectSegundoGrupo.val(), false);
});
$selectSegundoGrupo.change(function () {
convierte(
$selectGrupoUnidades.val(),
$selectGrupoUnidades.val(),
$inputPrimerGrupo.val(),
$selectPrimerGrupo.val(),
$(this).val(), false);
});
$inputPrimerGrupo.keyup(function () {
if (!isNaN($(this).val())) {
if ($(this).val()) {
if ($(this).val().length <= limiteLongitudNumeros - 1) {
convierte(
$selectGrupoUnidades.val(),
$selectGrupoUnidades.val(),
$(this).val(),
$selectPrimerGrupo.val(),
$selectSegundoGrupo.val(), false);
} else {
escribeError('Lo siento, solamente se permiten números de <strong>16 cifras</strong> sin incluir el punto decimal');
$('.ocultable').show();
}
}
} else {
escribeError('Ingresa un número en la caja de texto número 1');
$('.ocultable').show();
}
});
$inputSegundoGrupo.keyup(function () {
if (!isNaN($(this).val())) {
if ($(this).val()) {
if ($(this).val().length <= limiteLongitudNumeros - 1) {
convierte(
$selectGrupoUnidades.val(),
$selectGrupoUnidades.val(),
$(this).val(),
$selectSegundoGrupo.val(),
$selectPrimerGrupo.val(), true);
} else {
escribeError('Lo siento, solamente se permiten números de <strong>16 cifras</strong> sin incluir el punto decimal');
$('.ocultable').show();
}
}
} else {
escribeError('Ingresa un número en la caja de texto número 2');
$('.ocultable').show();
}
});
$btnAcercaDe.click(function () {
$ventanaAcercaDe.modal('show');
});
$inputPrincipal.keyup(function () {
compruebaValores($(this).val());
});
$btnEjemplo.click(function () {
$('div#manual').modal('show');
});
}
function grados(grupo, u1, u2, numero) {
if (grupo === "Temperatura") {
switch (u1) {
case "grado fahrenheit":
switch (u2) {
case "grado fahrenheit":
return numero;
break;
case "grado celsius":
return (numero - 32) * (5 / 9);
break;
case "kelvin":
return ((5 * (numero - 32)) / 9) + 273.15;
break;
}
break;
case "grado celsius":
switch (u2) {
case "grado fahrenheit":
return 32 + ((9 / 5) * numero );
break;
case "grado celsius":
return numero;
break;
case "kelvin":
return numero + 273.15;
break;
}
break;
case "kelvin":
switch (u2) {
case "grado fahrenheit":
return ((9 * (numero - 273.15)) / 5) + 32;
break;
case "grado celsius":
return numero - 273.15;
break;
case "kelvin":
return numero;
break;
}
break;
}
}
}
function llenaPrimerGrupo(selector, grupo) {
selector.empty();
for (var x in unidades[grupo].unidades) {
selector.append($('<option>', {
value: unidades[grupo].unidades[x],
text: aLetraCapital(unidades[grupo].unidades[x])
}));
}
}
function llenaSegundoGrupo(selector, grupo) {
selector.empty();
for (var x in unidades[grupo].unidades) {
selector.append($('<option>', {
value: unidades[grupo].unidades[x],
text: aLetraCapital(unidades[grupo].unidades[x])
}));
}
}
function llenaSelectUnidades(selector) {
for (var opcion in unidades) {
selector.append($('<option>', {
value: opcion,
text: opcion
}));
}
}
function principal() {
$inputPrincipal.focus();
setInterval(cambiaPlaceholder, segundosCambiaPlaceholder * 1000);
llenaSelectUnidades($selectGrupoUnidades);
escuchaElementos();
$('.ocultable').hide();
}
Poniendo todo junto
Todo este conversor está hecho con Bootstrap (tanto estilos como funcionamiento de modals) y jQuery. Sé que jQuery ya casi no se usa pero recuerda que este programa fue hecho hace 5 años y apenas lo he publicado.
Si quieres el código fuente completo lo dejo en GitHub. También puedes acceder a una demostración aquí.
Estoy aquí para ayudarte 
Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto
No te pierdas ninguno de mis posts 
Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
Editor WYSIWYG con JavaScript
En estos días estuve buscando un editor HTML o un editor WYSIWYG, parecido al editor de WordPress pero de una manera muy simple. Las siglas hacen referencia a What you see is what you get, que es algo como: lo que ves, es lo que obtienes. Puedes probar el resultado…
En "HTML"

Extraer el texto de una imagen con JavaScript y Tesseract.js – Aplicación web
Hace algún tiempo presenté el uso de la librería de JavaScript llamada Tesseract.Js, la cual sirve para extraer el texto de una imagen o convertir una imagen a texto. Aparte de extraer el texto de una imagen también lo puede hacer de una foto o de una imagen escaneada como…
En "Bootstrap 4"

Menú responsivo de Bootstrap 4 sin dependencias
En este post voy a mostrarte un ejemplo de código para tener el menú responsivo de Bootstrap sin dependencias como jQuery, usando únicamente algunas líneas de JavaScript puro. Bootstrap es el framework CSS por excelencia. Casi todo programador web lo conoce, es de hecho una base que hay que tener.…
En "Bootstrap 4"