JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://raw.github.com/flot/flot/master/jquery.flot.js"></script>
<script src="https://raw.github.com/xuanluo/flot-axislabels/master/jquery.flot.axislabels.js"></script>
<div id="plot"></div>

<fieldset>
    <legend>Варьируемые параметры</legend>
    <table width="100%">
    <tr>
    <td valign="top">
    
    <table class="params">
        <tr>
            <td><label for="input-buff">Бафф</label></td>
            <td>
                <select id="input-buff"></select>
            </td>
        </tr>
        <tr>
            <td><label for="input-buff-cost" title="Себестоимость баффа из магазина нельзя расчитать, задётся пользователем">Себестоимость баффа</label></td>
            <td>
                <input type="number" id="input-buff-cost" value="0" />
                <span class="resIcon coin" title="Монеты"></span>
            </td>
        </tr>
        <tr>
            <td><label for="input-friend-buff" title="Когда вас баффает друг продолжительность баффа увеличивается в 1.5 раза, в результате себестоимость баффа за единицу времени уменьшается, общая рентабельно немного повышается">Дружеский бафф</label></td>
            <td><input type="checkbox" id="input-friend-buff" /></td>
        </tr>
        <tr>
            <td><label for="input-refill" title="Пополнение добавляет в шахту определённое количество руды, продаётся в магазине и на чёрном рынке">Пополнение</label></td>
            <td>
                <select id="input-refill"></select>
            </td>
        </tr>
        <tr>
            <td><label for="input-refill-cost" title="Пользовательская оценка себестоимости одного пополнения - обычно это стоимость в монетах, за которую пользователь купил пополение на рынке">Себестоимость пополнения</label></td>
            <td>
                <input type="number" id="input-refill-cost" value="225" />
                <span class="resIcon coin" title="Монеты"></span>
            </td>
        </tr>
        <tr>
            <td><label...

CSS

* {
    margin: 0;
    padding: 0;
}
body {
    background: #EEE;
    max-width: 800px;
    padding: 5px;
    margin: 8px auto;
}
body, table {
    font-family: sans-serif;
    font-size: 13px;
}

fieldset {
    margin: 0.2em 0 0.5em;
    border: 1px solid #999;
    padding: 0.2em 0.5em 0.5em;
    background: #FFF;
}
legend {
    padding: 0 0.3em;
    font-weight: bold;
}
table {
    border-collapse: separate;
    border-spacing: 0;
    border: none;
}
#plot {
    height: 300px;
}
#price-params input {
    width: 60px;
    text-align: center;
}
label {
    cursor: pointer;
}
input[type=number] {
    width: 80px;
}
table.params td {
    padding: 1px 4px;
}

#details {
    margin: 0.5em auto;
    border-collapse: collapse;
    background: white;
    width: 100%;
    border: 1px solid #999;
    font-size: 12px;
}
#details, #details td, #details th {
    border: 1px solid #CCC;
}
#details th {
    padding: 4px 6px;
}
#details td {
    text-align: center;
    padding: 2px 6px;
    white-space: nowrap;
}
#details td.num {
    text-align: right;
}
#details .resIcon {
    vertical-align: bottom;
}

.resIcon {
    background-repeat: no-repeat;
    background-position: 51% 49%;
    display: inline-block;
    width: 16px;
    height: 16px;
    background-size: 100%;
    vertical-align: middle;
}

.resIcon.goldOre { background-image: url('http://storage1.static.itmages.ru/i/11/1013/h_1318485730_6397589_0211241cfe.png'); }
.resIcon.coin { background-image: url('http://storage2.static.itmages.ru/i/11/1013/h_1318486085_4137671_06d8fb9815.png'); }
.resIcon.planks { background-image: url('http://www.siedlertools.de/w/images/8/89/Laubholzbretter.gif'); }
.resIcon.marble { background-image: url('http://www.siedlertools.de/w/images/8/8b/Marmor.gif'); }
.resIcon.tools { background-image: url('http://www.siedlertools.de/w/images/4/4e/Werkzeug.gif'); }
.resIcon.fish { background-image: url('http://www.siedlertools.de/w/images/7/7c/Fische.gif'); }
.resIcon.bread { background-image:...

JavaScript

$(document).ready(function() {
    
    var priceParams = {
        'planks': { title: 'Доски из дуба', cost: 8 },
        'marble': { title: 'Мрамор', cost: 9 },
        'tools': { title: 'Инструменты', cost: 10 },
        'fish': { title: 'Рыба', cost: 2 },
        'bread': { title: 'Хлеб', cost: 9 },
        'meat': { title: 'Колбасы', cost: 15 }
    };
    
    var buffs = [
        { factor: 1, time: 0, cost: {}, title: 'Нет' },
        { factor: 2, time: 0.5, cost: { fish: 10 }, title: 'Рыбное блюдо'  },
        { factor: 2, time: 2, cost: { fish: 40, bread: 20 }, title: 'Сытный бутерброд'  },
        { factor: 2, time: 6, cost: { fish: 120, bread: 60, meat: 20 }, title: 'Корзинка для пикника' },
        { factor: 3, time: 12, cost: { gem: 99 }, title: 'Корзинка c экзотическими фруктами' },
        { factor: 3, time: 24, cost: { gem: 199 }, title: 'Красный крылатый поселенец' },
        { factor: 3, time: 32, cost: { gem: true }, title: 'Печенье' },
    ];
        
    var refills = [
        { amount: 0, cost: { }, title: 'Нет' },
        { amount: 500, cost: { gem: 75 }, title: 'Золотой попугай' },
        { amount: 250, cost: { gem: 50 }, title: 'Чудо-семена' }
    ];
    
    var levelCosts = {
        1: { planks: 1400, marble: 1400, tools: 1500 },
        2: { tools: 500 },
        3: { tools: 1000 },
        4: { tools: 2000 },
        5: { tools: 5000 },
    };
    
    var EXPLORE_TIME = 4;
    var BUILD_TIME = 10/60;
    var CYCLE_TIME = 12/60;
    var STACK = 400;
    
    function formatTime(hours) {
        var h = hours | 0;
        var m = (60 * (hours % 1)) | 0;
        return (h < 10 ? '0' : '') + h.toString() + ':' + (m < 10 ? '0' : '') + m.toString();
    }
    
    function initUI() {
        var $priceParams = $('#price-params');
        var $buffs = $(');
        var $refills = $('#input-refill');
        
        $.each(priceParams, function(id, res) {
            res.$tr = $(
            '<tr>' +
                '<td><label...