Показать сообщение отдельно
  #37 (permalink)  
Старый 13.08.2017, 05:02
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

Сообщение от MC-XOBAHCK
остальные виды смогу теперь сам добавить
Несомненно. Это в качестве коды - теперь будем считать как и ранее предполагалось, делая перерасчет и при смене единиц измерения через триггер. В коде выше он был убран потому, что расчет производился бы только для первой группы и плюс возникали бы некоторые ошибки.

Как работает расчет для группы понятно, теперь мы просто изменим обращение к группе - не по классу текущего поля, а будем циклом обходить их родительские контейнеры. А для того чтобы было удобнее их идентифицировать, индикатором родителя будет не имя класса, а атрибут. Для первой комнаты это будет:

<div class="row plos" data-area="rectangle">

для второй

<div class="row plos" data-area="triangle">

Остальной html-код остается без изменения.

Код обработчиков практически тот же самый, только изменим селекторы полей, ну и циклом обход родителей. Как ранее предлагалось, массив описывающий единицы измерения заменен массивом объектов, в которых описаны единицы измерения, символ квадрата, значений после запятой, множитель. Значения кнопок выбора служат индексами этого массива.

Добавим расчет пирамиды Хеопса, у которой основания смежных сторон может быть не равно, что с добавлением расчета площади основания даст более трех площадей для расчета и вывода. Все это ради показать, что первое задается функцией calculate для соответствующей группы, а второе, количеством элементов вывода и возвращаемым функцией calculate массиве рассчитанных площадей. Основной код при этом не будет изменяться, добавляются только html-элементы группы и расчет для нее в функции calculate.

<html>
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
function calculate(group, values) {
    var a, b;
    switch(group) {
        case 'rectangle': a = values[0] * values[1], b = values[2] * values[3];
                          return [a, b, a && b ? (a + b) * 2 : 0];
                          break;
        case 'triangle':  a = values[0] * values[1] * .5, b = (values[2] + values[3]) * values[4] * .5;
                          return [a, b, a && b ? (a + b) * 2 : 0];
                          break;
        case 'pyramid':   a = values[0] * values[1] * .5, b = values[0] * values[2] * .5;
                          return [a, b, values[1] * values[2], a && b ? (a + b) * 2 : 0];                    
    }   
}

$(function() {
    var dim = [{unt: 'м', sqr: '²', dec: 2, mul: .001}, {unt: 'мм', sqr: '²',  dec: 0, mul: 1000}],
        side = $('input:text')
        .on('keyup', function() {
            this.value = this.value.replace(/[,\.]+/,'.').replace(/[^\d.]/,'');
            
            var u = unit.filter(':checked').val();
            
            //расчет площадей для всех заполненных полей
            $('[data-area]').each(function() {
                //группу определяет атрибут data-area    
                var group = $(this).data('area'),
                    values = $.map(side.filter('.'+group), function(e) {
                        var v = parseFloat(e.value);
                        return v || 0
                    }),
                    area = calculate(group, values);
                
                $(this).find('.area').each(function(i, e) {
                    $(e).text(
                        area[i] ? area[i].toFixed(dim[u].dec) + ' ' + dim[u].unt + dim[u].sqr : ''  
                    )
                })
            })
    }), 
    unit = $('input:radio')
        .change(function() {
            var u = this.value;
            $('.unit').text(dim[u].unt); 
            side.val(function() {
                var v = parseFloat(this.value); 
                if(v) return (v * dim[u].mul).toFixed(dim[u].dec) 
            }).trigger('keyup');
    });
});
  </script>
</head>
  
<body>
    <label><input type="radio" name="unit" value="0" checked="" /> метры</label>
    <label><input type="radio" name="unit" value="1" /> миллиметры</label>
    <h3>Пирамида</h3>
    <p>Стены треугольные. Противоположные стены равны</p>
    <div class="row plos" data-area="pyramid">           
        <div class="col-sm-6">
            <h4>Треугольная стена</h4>
                <div class="st1">Высота стен: </div>
                <div class="st2"><input class="pyramid" /> <span class="unit">м</span></div>
                <div class="st1">Длина основания первой стены: </div>
                <div class="st2"><input class="pyramid" /> <span class="unit">м</span></div>
                <div class="st1">Длина основания второй стены: </div>
                <div class="st2"><input class="pyramid" /> <span class="unit">м</span></div>
        </div>
        <div class="col-sm-6">
            Площадь 1 стены: <span class="area"></span><br>
            Площадь 2 стены: <span class="area"></span><br>
            Площадь основания: <span class="area"></span><br>
            Площадь всех стен: <span class="area"></span>
        </div>   
    </div>  
</body>
</html>


По мере добавления различных расчетов станет ясно, что функция calculate, это в общем то диспетчер-сборщик и расчеты площадей однотипных фигур выгоднее поместить в функции, если они могут быть в различных комнатах. Диспетчер знает к какой из них обратиться и в каком порядке помещать расчеты в возвращаемый массив.

До этого момента в формулах расчета площадей не встречалось деления. Если таковое будет, то надо помнить о делении на ноль. В языках программирования такая ситуация возвращает ошибку, кроме Javascript, который возвращает Infinity. Хрен их знает этих разработчиков JS при чем тут бесконечность, процессоров с бесконечной разрядностью в ближайшем тысячелетии точно не будет. А с точки зрения архитектора бесконечные размеры стен точно беспредел, поэтому такие ситуации нужно проверять, ибо булево значение Infinity равно true.

Последний раз редактировалось laimas, 13.08.2017 в 12:25.
Ответить с цитированием