diff --git a/test.html b/test.html index fcd7e18..8863ff3 100644 --- a/test.html +++ b/test.html @@ -28,120 +28,121 @@ let bltFile = document.getElementById('bltFile').files[0]; let text = await bltFile.text(); - let election = py.pyRCV2.blt.readBLT(text); - - // Create counter - let counter = py.pyRCV2.method.STVCCounter.STVCCounter(election); - - // Reset - let result = counter.reset(); - // Initialise table rows let tblResults = document.getElementById('result'); tblResults.innerHTML = ''; - let candMap = new Map(); // Map Candidate -> rows - - // Comment row - let 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.py_name; - elTr1.appendChild(elTd); - - tblResults.appendChild(elTr1); - tblResults.appendChild(elTr2); - - candMap.set(candidate, [elTr1, elTr2]); - } - - // Exhausted votes row - let elExhausted1 = document.createElement('tr'); - let elExhausted2 = document.createElement('tr'); - - 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); - - // Quota row - let elQuota = document.createElement('tr'); - elTd = document.createElement('td'); - elTd.style.borderTop = '1px solid black'; - elTd.innerText = 'Quota'; - elQuota.appendChild(elTd); - tblResults.appendChild(elQuota); + let candMap = {}; // candidate name -> rows // Step election - result = counter.reset(); + let worker = new Worker('worker.js'); + let election, elComment, elExhausted1, elExhausted2, elQuota; - do { - // Display results - elTd = document.createElement('td'); - elTd.innerText = result.comment; - elComment.appendChild(elTd); - - for (let [candidate, countCard] of result.candidates.impl) { - [elTr1, elTr2] = candMap.get(candidate); + 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'); + elExhausted2 = document.createElement('tr'); + + 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); + + // Quota row + elQuota = document.createElement('tr'); elTd = document.createElement('td'); elTd.style.borderTop = '1px solid black'; - if (countCard.transfers.pp(2) != '0.00') { - elTd.innerText = countCard.transfers.pp(2); + 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.style.borderTop = '1px solid black'; + if (countCard.transfers != '0.00') { + elTd.innerText = countCard.transfers; + } + elTr1.appendChild(elTd); + + elTd = document.createElement('td'); + if (countCard.state == py.pyRCV2.model.CandidateState.WITHDRAWN) { + elTd.innerText = 'WD'; + } else if (countCard.state == py.pyRCV2.model.CandidateState.ELECTED || countCard.state == py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED) { + elTd.innerText = countCard.votes; + elTd.style.fontWeight = 'bold'; + } else if (countCard.state == py.pyRCV2.model.CandidateState.EXCLUDED) { + elTd.innerText = 'EX'; + } else { + elTd.innerText = countCard.votes; + } + elTr2.appendChild(elTd); } - elTr1.appendChild(elTd); + + // Display exhausted votes + elTd = document.createElement('td'); + elTd.style.borderTop = '1px solid black'; + if (result.exhausted.transfers != '0.00') { + elTd.innerText = result.exhausted.transfers; + } + elExhausted1.appendChild(elTd); elTd = document.createElement('td'); - if (countCard.state == py.pyRCV2.model.CandidateState.WITHDRAWN) { - elTd.innerText = 'WD'; - } else if (countCard.state == py.pyRCV2.model.CandidateState.ELECTED || countCard.state == py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED) { - elTd.innerText = countCard.votes.pp(2); - elTd.style.fontWeight = 'bold'; - } else if (countCard.state == py.pyRCV2.model.CandidateState.EXCLUDED) { - elTd.innerText = 'EX'; - } else { - elTd.innerText = countCard.votes.pp(2); - } - elTr2.appendChild(elTd); + elTd.innerText = result.exhausted.votes; + elExhausted2.appendChild(elTd); + + // Display quota + elTd = document.createElement('td'); + elTd.style.borderTop = '1px solid black'; + elTd.innerText = result.quota; + elQuota.appendChild(elTd); } - - // Display exhausted votes - elTd = document.createElement('td'); - elTd.style.borderTop = '1px solid black'; - if (result.exhausted.transfers.pp(2) != '0.00') { - elTd.innerText = result.exhausted.transfers.pp(2); - } - elExhausted1.appendChild(elTd); - - elTd = document.createElement('td'); - elTd.innerText = result.exhausted.votes.pp(2); - elExhausted2.appendChild(elTd); - - // Display quota - elTd = document.createElement('td'); - elTd.style.borderTop = '1px solid black'; - elTd.innerText = result.quota.pp(2); - elQuota.appendChild(elTd); - - // Step election - result = counter.step(); - if (py.isinstance(result, py.pyRCV2.model.CountCompleted)) { - break; - } - } while (true); + } + + worker.onerror = function(evt) { + throw evt; + } + + worker.postMessage(text); } diff --git a/worker.js b/worker.js new file mode 100644 index 0000000..bb55bd7 --- /dev/null +++ b/worker.js @@ -0,0 +1,51 @@ +importScripts('http://peterolson.github.com/BigRational.js/BigInt_BigRat.min.js', 'bundle.js'); + +onmessage = function(evt) { + let election = py.pyRCV2.blt.readBLT(evt.data); + postMessage({'type': 'init', 'election': { + 'candidates': election.candidates.map(c => c.py_name) + }}); + + // Create counter + let counter = py.pyRCV2.method.STVCCounter.STVCCounter(election); + + // Reset + let result = counter.reset(); + + postMessage({'type': 'result', 'result': { + 'comment': result.comment, + 'candidates': result.candidates.py_items().map(([c, cc]) => [c.py_name, { + 'transfers': cc.transfers.pp(2), + 'votes': cc.votes.pp(2), + 'state': cc.state + }]), + 'exhausted': { + 'transfers': result.exhausted.transfers.pp(2), + 'votes': result.exhausted.votes.pp(2) + }, + 'quota': result.quota.pp(2) + }}); + + // Step election + while (true) { + result = counter.step(); + if (py.isinstance(result, py.pyRCV2.model.CountCompleted)) { + postMessage({'type': 'done'}); + break; + } else { + postMessage({'type': 'result', 'result': { + 'comment': result.comment, + 'candidates': result.candidates.py_items().map(([c, cc]) => [c.py_name, { + 'transfers': cc.transfers.pp(2), + 'votes': cc.votes.pp(2), + 'state': cc.state + }]), + 'exhausted': { + 'transfers': result.exhausted.transfers.pp(2), + 'votes': result.exhausted.votes.pp(2) + }, + 'quota': result.quota.pp(2) + }}); + } + } +}