<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>pyRCV2 test</title> <style type="text/css"> html, body { font-family: 'Liberation Sans', FreeSans, Helvetica, Arial, sans-serif; } table { border-collapse: collapse; } td { padding: 0px 8px; } td.count { text-align: right; } tr:first-child td { vertical-align: bottom; } td.excluded { background-color: #fecfcfff; } td.elected { background-color: #d1fca7ff; } tr.info td { background-color: #edededff; } </style> </head> <body> <input type="file" id="bltFile"> <button onclick="clickBtn();">OK</button> <select id="numbers"><option value="native" selected>Native Float</option><option value="int">Native Integer</option><option value="rational">Rational</option><option value="fixed">Fixed (6 d.p.)</option></select> <table id="result"></table> <script src="http://peterolson.github.com/BigRational.js/BigInt_BigRat.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/big.js@6.0.0/big.min.js"></script> <script src="bundle.js"></script> <script> async function clickBtn() { // Read BLT file let bltFile = document.getElementById('bltFile').files[0]; let text = await bltFile.text(); // Initialise table rows let tblResults = document.getElementById('result'); tblResults.innerHTML = ''; let candMap = {}; // candidate name -> rows // Step election let worker = new Worker('worker.js'); let election, elComment, elExhausted1, elExhausted2, elLTF1, elLTF2, elTotal, elQuota; worker.onmessage = function(evt) { if (evt.data.type === 'init') { election = evt.data.election; // Comment row elComment = document.createElement('tr'); let elTd = document.createElement('td'); elComment.appendChild(elTd); tblResults.appendChild(elComment); // Candidates for (let candidate of election.candidates) { let elTr1 = document.createElement('tr'); let elTr2 = document.createElement('tr'); elTd = document.createElement('td'); elTd.setAttribute('rowspan', '2'); elTd.style.borderTop = '1px solid black'; elTd.innerText = candidate; elTr1.appendChild(elTd); tblResults.appendChild(elTr1); tblResults.appendChild(elTr2); candMap[candidate] = [elTr1, elTr2]; } // Exhausted votes row elExhausted1 = document.createElement('tr'); elExhausted1.classList.add('info'); elExhausted2 = document.createElement('tr'); elExhausted2.classList.add('info'); elTd = document.createElement('td'); elTd.setAttribute('rowspan', '2'); elTd.style.borderTop = '1px solid black'; elTd.innerText = 'Exhausted'; elExhausted1.appendChild(elTd); tblResults.appendChild(elExhausted1); tblResults.appendChild(elExhausted2); // Loss to fraction row elLTF1 = document.createElement('tr'); elLTF1.classList.add('info'); elLTF2 = document.createElement('tr'); elLTF2.classList.add('info'); elTd = document.createElement('td'); elTd.setAttribute('rowspan', '2'); elTd.style.borderTop = '1px solid black'; elTd.innerText = 'Loss to fraction'; elLTF1.appendChild(elTd); tblResults.appendChild(elLTF1); tblResults.appendChild(elLTF2); // Total row elTotal = document.createElement('tr'); elTotal.classList.add('info'); elTd = document.createElement('td'); elTd.style.borderTop = '1px solid black'; elTd.innerText = 'Total'; elTotal.appendChild(elTd); tblResults.appendChild(elTotal); // Quota row elQuota = document.createElement('tr'); elQuota.classList.add('info'); elTd = document.createElement('td'); elTd.style.borderTop = '1px solid black'; elTd.style.borderBottom = '1px solid black'; elTd.innerText = 'Quota'; elQuota.appendChild(elTd); tblResults.appendChild(elQuota); } if (evt.data.type === 'result') { let result = evt.data.result; // Display results elTd = document.createElement('td'); elTd.innerText = result.comment; elComment.appendChild(elTd); for (let [candidate, countCard] of result.candidates) { [elTr1, elTr2] = candMap[candidate]; elTd = document.createElement('td'); elTd.classList.add('count'); if (countCard.state === py.pyRCV2.model.CandidateState.WITHDRAWN || countCard.state === py.pyRCV2.model.CandidateState.EXCLUDED) { elTd.classList.add('excluded'); } else if (countCard.state === py.pyRCV2.model.CandidateState.ELECTED || countCard.state === py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED) { elTd.classList.add('elected'); } elTd.style.borderTop = '1px solid black'; if (countCard.transfers != '0.00') { elTd.innerText = countCard.transfers; } elTr1.appendChild(elTd); elTd = document.createElement('td'); elTd.classList.add('count'); if (countCard.state === py.pyRCV2.model.CandidateState.WITHDRAWN) { elTd.classList.add('excluded'); elTd.innerText = 'WD'; } else if (countCard.state === py.pyRCV2.model.CandidateState.ELECTED || countCard.state === py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED) { elTd.classList.add('elected'); elTd.innerText = countCard.votes; elTd.style.fontWeight = 'bold'; elTr1.querySelector('td:first-child').classList.add('elected'); } else if (countCard.state === py.pyRCV2.model.CandidateState.EXCLUDED) { elTd.classList.add('excluded'); elTd.innerText = 'EX'; } else { elTd.innerText = countCard.votes; } elTr2.appendChild(elTd); } // Display exhausted votes elTd = document.createElement('td'); elTd.classList.add('count'); elTd.style.borderTop = '1px solid black'; if (result.exhausted.transfers != '0.00') { elTd.innerText = result.exhausted.transfers; } elExhausted1.appendChild(elTd); elTd = document.createElement('td'); elTd.classList.add('count'); elTd.innerText = result.exhausted.votes; elExhausted2.appendChild(elTd); // Display loss to fraction elTd = document.createElement('td'); elTd.classList.add('count'); elTd.style.borderTop = '1px solid black'; if (result.loss_fraction.transfers != '0.00') { elTd.innerText = result.loss_fraction.transfers; } elLTF1.appendChild(elTd); elTd = document.createElement('td'); elTd.classList.add('count'); elTd.innerText = result.loss_fraction.votes; elLTF2.appendChild(elTd); // Display total elTd = document.createElement('td'); elTd.classList.add('count'); elTd.style.borderTop = '1px solid black'; elTd.innerText = result.total; elTotal.appendChild(elTd); // Display quota elTd = document.createElement('td'); elTd.classList.add('count'); elTd.style.borderTop = '1px solid black'; elTd.style.borderBottom = '1px solid black'; elTd.innerText = result.quota; elQuota.appendChild(elTd); } } worker.onerror = function(evt) { throw evt; } worker.postMessage({ 'numbers': document.getElementById('numbers').value, 'data': text }); } </script> </body> </html>