Implement constraints in web UI
This commit is contained in:
parent
38eef74e77
commit
1d4036c19e
|
@ -139,12 +139,12 @@
|
||||||
<input type="text" id="txtSeed" value="">
|
<input type="text" id="txtSeed" value="">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<!--<div class="subheading">
|
<div class="subheading">
|
||||||
Constraints:
|
Constraints:
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="file" id="conFile">
|
<input type="file" id="conFile">
|
||||||
</div>-->
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 cols-12" style="align-self: start;">
|
<div class="col-6 cols-12" style="align-self: start;">
|
||||||
<div class="col-12 subheading">
|
<div class="col-12 subheading">
|
||||||
|
|
|
@ -90,11 +90,22 @@ async function clickCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read BLT file
|
// Read BLT file
|
||||||
let filePath = document.getElementById('bltFile').value;
|
let bltPath = document.getElementById('bltFile').value;
|
||||||
filePath = filePath.substring(Math.max(filePath.lastIndexOf('\\'), filePath.lastIndexOf('/')) + 1);
|
bltPath = bltPath.substring(Math.max(bltPath.lastIndexOf('\\'), bltPath.lastIndexOf('/')) + 1);
|
||||||
|
|
||||||
let bltFile = document.getElementById('bltFile').files[0];
|
let bltFile = document.getElementById('bltFile').files[0];
|
||||||
let electionData = await bltFile.text();
|
let bltData = await bltFile.text();
|
||||||
|
|
||||||
|
// Read CON file (if applicable)
|
||||||
|
let conPath = null;
|
||||||
|
let conData = null;
|
||||||
|
if (document.getElementById('conFile').files.length > 0) {
|
||||||
|
conPath = document.getElementById('conFile').value;
|
||||||
|
conPath = conPath.substring(Math.max(conPath.lastIndexOf('\\'), conPath.lastIndexOf('/')) + 1);
|
||||||
|
|
||||||
|
let conFile = document.getElementById('conFile').files[0];
|
||||||
|
conData = await conFile.text();
|
||||||
|
}
|
||||||
|
|
||||||
// Init STV options
|
// Init STV options
|
||||||
let optsStr = [
|
let optsStr = [
|
||||||
|
@ -127,9 +138,11 @@ async function clickCount() {
|
||||||
// Dispatch to worker
|
// Dispatch to worker
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
'type': 'countElection',
|
'type': 'countElection',
|
||||||
'electionData': electionData,
|
'bltData': bltData,
|
||||||
|
'conData': conData,
|
||||||
'optsStr': optsStr,
|
'optsStr': optsStr,
|
||||||
'filePath': filePath,
|
'bltPath': bltPath,
|
||||||
|
'conPath': conPath,
|
||||||
'numbers': document.getElementById('selNumbers').value,
|
'numbers': document.getElementById('selNumbers').value,
|
||||||
'decimals': document.getElementById('txtDP').value,
|
'decimals': document.getElementById('txtDP').value,
|
||||||
'normaliseBallots': document.getElementById('chkNormaliseBallots').checked,
|
'normaliseBallots': document.getElementById('chkNormaliseBallots').checked,
|
||||||
|
|
|
@ -27,12 +27,17 @@ onmessage = function(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init election
|
// Init election
|
||||||
election = wasm['election_from_blt_' + numbers](evt.data.electionData);
|
election = wasm['election_from_blt_' + numbers](evt.data.bltData);
|
||||||
|
|
||||||
if (evt.data.normaliseBallots) {
|
if (evt.data.normaliseBallots) {
|
||||||
wasm['election_normalise_ballots_' + numbers](election);
|
wasm['election_normalise_ballots_' + numbers](election);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init constraints if applicable
|
||||||
|
if (evt.data.conData) {
|
||||||
|
wasm['election_load_constraints_' + numbers](election, evt.data.conData);
|
||||||
|
}
|
||||||
|
|
||||||
// Init STV options
|
// Init STV options
|
||||||
opts = wasm.STVOptions.new.apply(null, evt.data.optsStr);
|
opts = wasm.STVOptions.new.apply(null, evt.data.optsStr);
|
||||||
|
|
||||||
|
@ -40,7 +45,7 @@ onmessage = function(evt) {
|
||||||
opts.validate();
|
opts.validate();
|
||||||
|
|
||||||
// Describe count
|
// Describe count
|
||||||
postMessage({'type': 'describeCount', 'content': wasm['describe_count_' + numbers](evt.data.filePath, election, opts)});
|
postMessage({'type': 'describeCount', 'content': wasm['describe_count_' + numbers](evt.data.bltPath, election, opts)});
|
||||||
|
|
||||||
// Init results table
|
// Init results table
|
||||||
postMessage({'type': 'initResultsTable', 'content': wasm['init_results_table_' + numbers](election, opts)});
|
postMessage({'type': 'initResultsTable', 'content': wasm['init_results_table_' + numbers](election, opts)});
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#![allow(rustdoc::private_intra_doc_links)]
|
#![allow(rustdoc::private_intra_doc_links)]
|
||||||
|
|
||||||
|
use crate::constraints::Constraints;
|
||||||
use crate::election::{CandidateState, CountState, Election};
|
use crate::election::{CandidateState, CountState, Election};
|
||||||
use crate::numbers::{Fixed, GuardedFixed, NativeFloat64, Number, Rational};
|
use crate::numbers::{Fixed, GuardedFixed, NativeFloat64, Number, Rational};
|
||||||
use crate::stv;
|
use crate::stv;
|
||||||
|
@ -66,6 +67,13 @@ macro_rules! impl_type {
|
||||||
election.0.normalise_ballots();
|
election.0.normalise_ballots();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call [Constraints::from_con] and set [Election::constraints]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn [<election_load_constraints_$type>](election: &mut [<Election$type>], text: String) {
|
||||||
|
election.0.constraints = Some(Constraints::from_con(text.lines().map(|s| s.to_string()).into_iter()));
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper for [stv::count_init]
|
/// Wrapper for [stv::count_init]
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -303,22 +311,31 @@ fn update_results_table<N: Number>(stage_num: usize, state: &CountState<N>, opts
|
||||||
result.push(&format!(r#"<td{}>{}</td>"#, tdclasses1, state.title).into());
|
result.push(&format!(r#"<td{}>{}</td>"#, tdclasses1, state.title).into());
|
||||||
for candidate in state.election.candidates.iter() {
|
for candidate in state.election.candidates.iter() {
|
||||||
let count_card = state.candidates.get(candidate).unwrap();
|
let count_card = state.candidates.get(candidate).unwrap();
|
||||||
if count_card.state == stv::CandidateState::Elected {
|
match count_card.state {
|
||||||
result.push(&format!(r#"<td class="{}count elected">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
CandidateState::Hopeful | CandidateState::Guarded => {
|
||||||
result.push(&format!(r#"<td class="{}count elected">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
||||||
} else if count_card.state == stv::CandidateState::Excluded {
|
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
||||||
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
}
|
||||||
if count_card.votes.is_zero() {
|
CandidateState::Elected => {
|
||||||
result.push(&format!(r#"<td class="{}count excluded">Ex</td>"#, tdclasses2).into());
|
result.push(&format!(r#"<td class="{}count elected">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
||||||
} else {
|
result.push(&format!(r#"<td class="{}count elected">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
||||||
|
}
|
||||||
|
CandidateState::Doomed => {
|
||||||
|
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
||||||
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
||||||
}
|
}
|
||||||
} else if count_card.state == stv::CandidateState::Withdrawn {
|
CandidateState::Withdrawn => {
|
||||||
result.push(&format!(r#"<td class="{}count excluded"></td>"#, tdclasses2).into());
|
result.push(&format!(r#"<td class="{}count excluded"></td>"#, tdclasses2).into());
|
||||||
result.push(&format!(r#"<td class="{}count excluded">WD</td>"#, tdclasses2).into());
|
result.push(&format!(r#"<td class="{}count excluded">WD</td>"#, tdclasses2).into());
|
||||||
} else {
|
}
|
||||||
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
CandidateState::Excluded => {
|
||||||
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
|
||||||
|
if count_card.votes.is_zero() {
|
||||||
|
result.push(&format!(r#"<td class="{}count excluded">Ex</td>"#, tdclasses2).into());
|
||||||
|
} else {
|
||||||
|
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&state.exhausted.transfers, opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&state.exhausted.transfers, opts.pp_decimals)).into());
|
||||||
|
|
Loading…
Reference in New Issue