Как правильно переводить единицы измерения на лету?

Рейтинг: 0Ответов: 1Опубликовано: 10.08.2023

Использую jQuery. У меня есть несколько инпутов с единицами измерения массы. Я хочу при вводе в любом из инпутов, автоматически считать и выводить в значение инпутов результат. Например ввёл в инпут с килограммами цифру 1, а он сразу посчитал для всех других единиц сколько будет 1 кг в этих единицах. Сам функционал работает как надо, но вот не пойму, почему с некоторыми единицами идут не правильные расчёты, вернее не пойму как сделать, чтобы работало правильно.

Например если ввожу 1 кг, то для грамм, центнеров и для тонн он показывается правильное значение, а для килотонны он показывает 1000000, но 1 кг не равен такого количеству килотонн. Или ввожу 1 Миллиграмм он мне считает это как 1 тонну и т.д.

Не пойму как правильно настроить расчёты в зависимости от того, в какой инпут что ввели. Помогите пожалуйста решить.

$(document).ready(function () {
    const conversionFactors = {
        "Килограммы": 1,
        "Граммы": 1000,
        "Тонны": 0.001,
        "Центнер": 0.01,
        "Миллиграмм": 1000000,
        "Сантиграмм": 10000,
        "Микрограмм": 1000000000,
        "Килотонна": 1000000,
        "Ньютон на Земле": 9.81,
        "Карат": 5000,
        "Атомная масса": 1.66e-27 * 1000,
        "Фунт": 2.20462,
        "Унция": 35.274,
        "Гран": 15432.4,
        "Стоун": 0.157473,
    };

    function updateUnitValues(sourceElement, sourceValue) {
        const parentRow = sourceElement.closest(".row.align-items-center");
        const sourceLabel = parentRow.find(".custom-label").text();

        const conversionFactor = conversionFactors[sourceLabel];
        if (typeof conversionFactor === "undefined") {
            $("input[type='text']").val("0");
            return;
        }
        const weightValue = sourceValue * (1 / conversionFactor);

        $("input[type='text']").each(function () {
            const targetLabel = $(this).closest(".row.align-items-center").find(".custom-label").text();
            const targetConversionFactor = conversionFactors[targetLabel];
            if (typeof targetConversionFactor === "undefined") {
                $(this).val("0");
            } else {
                const targetValue = weightValue * targetConversionFactor;
                $(this).val(targetValue.toString().match(/^-?\d+(?:\.\d{0,15})?/)[0]);
            }
        });
    }

    $("input[type='text']").on("input", function () {
        const sourceValue = parseFloat($(this).val().replace(",", "."));
        if (!isNaN(sourceValue)) {
            updateUnitValues($(this), sourceValue);
        } else {
            $("input[type='text']").val("");
        }
    });
});

Ответы

▲ 2

можете показать пример, не могу понять как это сделать уже несколько дней

Выше я предлагал вот такой вариант реализации.

Так же обрати внимание на значение Килотонна и Атомная масса/

const obj = {
    "Килограммы": 1,
    "Граммы": 1000,
    "Тонны": 0.001,
    "Центнер": 0.01,
    "Миллиграмм": 1000000,
    "Сантиграмм": 10000,
    "Микрограмм": 1000000000,
    "Килотонна": 0.000001,
    "Ньютон на Земле": 9.81,
    "Карат": 5000,
    "Атомная масса": 1.66e-24,
    "Фунт": 2.20462,
    "Унция": 35.274,
    "Гран": 15432.4,
    "Стоун": 0.157473,
};
const os = document.querySelector('section')
const od = document.querySelector('template').content.querySelector('.line')
Object.entries(obj).forEach(([k, v]) => {
    const o = od.cloneNode(true)
    o.querySelector('label').textContent = k
    o.querySelector('input').dataset.v = v
    os.insertAdjacentElement('beforeend', o)
})
os.addEventListener('input', e => {
    const ot = e.target
    let v = +ot.dataset.v
    v = +ot.value / v
    os.querySelectorAll('input').forEach(o => {
        if (o === ot) return
        o.value = +o.dataset.v * v
    })
})
.line {
    display: flex;
}
.line label {
    width: 150px;
}
<section></section>
<template>
    <div class='line'>
        <label></label>
        <input type='number' />
    </div>
</template>