Skip to content

Instantly share code, notes, and snippets.

@BrunoWinck
Created December 15, 2024 23:31
Show Gist options
  • Select an option

  • Save BrunoWinck/40478fa66e56948c04cc0d7697e6d1d9 to your computer and use it in GitHub Desktop.

Select an option

Save BrunoWinck/40478fa66e56948c04cc0d7697e6d1d9 to your computer and use it in GitHub Desktop.
Web component for units conversion
class KnvUnit extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
// Parse and decode the inner text to extract the value and unit
parseContent() {
const content = this.textContent.trim();
const match = content.match(/^(\d+(?:\.\d+)?)\s*([a-zA-Z°]+)$/);
if (!match) {
return null; // Invalid format
}
const [, value, unit] = match;
return { value: parseFloat(value), unit: unit.toLowerCase() };
}
render() {
const parsed = this.parseContent();
if (!parsed) {
this.shadowRoot.innerHTML = `
<style>
span {
font-family: Arial, sans-serif;
font-size: 1rem;
color: red;
}
</style>
<span>Invalid input format</span>
`;
return;
}
const { value, unit } = parsed;
const conversion = this.convertToImperial(value, unit);
// don't issue warning, just ignore
const imperialValue = conversion ? `${this.toFraction(conversion.value)} ${conversion.unit}` : '';
this.shadowRoot.innerHTML = `
<style>
span {
font-family: Arial, sans-serif;
font-size: 1rem;
color: #333;
}
</style>
<span>${value} ${unit} (${imperialValue})</span>
`;
}
convertToImperial(value, unit) {
switch (unit) {
case 'kg': // Kilograms to Pounds
return { value: (value * 2.20462), unit: 'lbs' };
case 'm': // Meters to Feet
return { value: (value * 3.28084), unit: 'ft' };
case 'cm': // Centimeters to Inches
return { value: (value * 0.393701), unit: 'in' };
case '°c': // Celsius to Fahrenheit
return { value: ((value * 9) / 5 + 32), unit: '°F' };
case 'l': // Liters to Gallons
return { value: (value * 0.264172), unit: 'gal' };
case 'km': // Kilometers to Miles
return { value: (value * 0.621371), unit: 'mi' };
case 'g': // Grams to Ounces
return { value: (value * 0.035274), unit: 'oz' };
default:
return null; // Unsupported unit
}
}
toFraction(n0 )
{
// adapted from https://stackoverflow.com/questions/55495386/how-to-convert-decimals-to-the-nearest-fraction
// set as args with default values
const acceptableDenominators = [1, 2, 4, 8 ];
const maxDistanceToNumerator1 = 0.05;
const negative = (n0 < 0);
const n1 = (negative)?-n0:n0;
// it's a proportional error we tolerate
const maxDistanceToNumerator = n1 * maxDistanceToNumerator1;
const wholePart = Math.floor(n1);
const n = n1 - wholePart;
const denominator = acceptableDenominators.find(d =>
Math.abs(d * n - Math.round(d * n)) <= maxDistanceToNumerator
);
// No good solution keep decimals
if (typeof denominator === 'undefined') {
return n0.toFixed(2);
}
const numerator = Math.round(denominator * n);
if (denominator === 1) {
// I don't understand this case, go to next integer value?
return "" + (wholePart + numerator) * (negative ? -1 : 1);
}
return (negative ? "-" : "") +
(wholePart ? wholePart + " " : "") +
numerator + "/" + denominator;
}
}
// Register the custom element
customElements.define('knv-unit', KnvUnit);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment