-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
176 lines (155 loc) · 9.15 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moldova EU Referendum Live Results</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
<style>
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.emoji-large {
font-size: 3rem;
margin-bottom: 0.5rem;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-4xl">
<h1 class="text-4xl font-bold text-center text-blue-600 mb-2">Moldova EU Referendum</h1>
<div class="bg-white rounded-lg shadow-lg p-6">
<div class="pulse text-center text-green-500 text-sm mb-6">Live updating every 10 seconds</div>
<div class="mb-8">
<div class="flex justify-between items-center mb-2">
<h2 class="text-xl font-semibold">Votes Counted</h2>
<span id="totalProcessed" class="text-gray-600">Loading...</span>
</div>
<div class="bg-gray-200 rounded-full h-4 overflow-hidden">
<div id="progressBar" class="bg-blue-500 h-full transition-all duration-500 ease-in-out"></div>
</div>
<p id="validVotes" class="text-right text-sm text-gray-600 mt-1">Loading...</p>
</div>
<div class="grid grid-cols-2 gap-4 mb-8">
<div class="bg-green-100 rounded-lg p-4 text-center">
<h3 class="text-xl font-semibold text-green-700 mb-2">"Yes" Votes 🇪🇺</h3>
<p class="text-4xl font-bold text-green-600" id="yesVotes">Loading...</p>
<p class="text-xl text-green-600" id="yesPercentage">Loading...</p>
</div>
<div class="bg-red-100 rounded-lg p-4 text-center">
<h3 class="text-xl font-semibold text-red-700 mb-2">"No" Votes 💩</h3>
<p class="text-4xl font-bold text-red-600" id="noVotes">Loading...</p>
<p class="text-xl text-red-600" id="noPercentage">Loading...</p>
</div>
</div>
<div id="currentLead" class="rounded-lg p-4 mb-8 text-center">
<div class="emoji-large" id="leadingEmoji"></div>
<h3 class="text-2xl font-bold mb-2" id="leadingOption">Loading...</h3>
<p class="text-xl" id="voteDifference">Loading...</p>
<p class="text-lg" id="percentageLead">Loading...</p>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="bg-purple-100 rounded-lg p-4">
<h3 class="text-xl font-semibold text-purple-700 mb-2">For "Yes" to Win</h3>
<p class="text-3xl font-bold text-purple-600" id="additionalYesVotes">Loading...</p>
<p class="text-sm text-purple-600" id="requiredYesPercentage">Loading...</p>
</div>
<div class="bg-yellow-100 rounded-lg p-4">
<h3 class="text-xl font-semibold text-yellow-700 mb-2">Estimated Remaining Votes</h3>
<p class="text-3xl font-bold text-yellow-600" id="remainingVotes">Loading...</p>
<p class="text-sm text-yellow-600" id="totalVotes">Loading...</p>
</div>
</div>
</div>
</div>
<script>
const YES_ID = 146983;
const NO_ID = 146990;
async function fetchElectionData() {
try {
const response = await fetch('https://corsproxy.io/?https://pv.cec.md/api/api/reports/GetElectionResults?electionType=5');
const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching election data:", error);
return null;
}
}
async function calculateElectionData() {
const electionData = await fetchElectionData();
if (!electionData) {
console.error("Failed to fetch election data");
return;
}
const nationalData = electionData.Circumscriptions.filter(c => c.Type === 1);
if (nationalData.length !== 2) {
console.error("Unexpected national data structure");
return;
}
const yesData = nationalData.find(d => d.ElectionCompetitorMemberId === YES_ID);
const noData = nationalData.find(d => d.ElectionCompetitorMemberId === NO_ID);
if (!yesData || !noData) {
console.error("Could not find Yes or No data");
return;
}
const validVotesProcessed = yesData.BallotsValidVotes;
const totalBallots = yesData.TotalBalots;
const processedBallots = yesData.TotalBalotsProcessed;
const processedPercentage = (processedBallots / totalBallots) * 100;
const yesVotes = yesData.BallotCount;
const noVotes = noData.BallotCount;
const yesPercentage = (yesVotes / validVotesProcessed) * 100;
const noPercentage = (noVotes / validVotesProcessed) * 100;
const totalVotesEstimate = Math.round(validVotesProcessed / (processedPercentage / 100));
const remainingVotes = totalVotesEstimate - validVotesProcessed;
const yesVotesNeededToWin = Math.ceil(totalVotesEstimate / 2) + 1;
const yesVotesStillNeeded = yesVotesNeededToWin - yesVotes;
const voteDifference = Math.abs(yesVotes - noVotes);
const leadingOption = yesVotes > noVotes ? "Yes" : "No";
const winningPercentage = leadingOption === "Yes" ? yesPercentage : noPercentage;
const losingPercentage = leadingOption === "Yes" ? noPercentage : yesPercentage;
const percentageDifference = winningPercentage - losingPercentage;
const requiredYesPercentage = yesVotesStillNeeded > 0 ? ((yesVotesStillNeeded / remainingVotes) * 100).toFixed(2) : 0;
document.getElementById('validVotes').textContent = validVotesProcessed.toLocaleString() + " votes counted";
document.getElementById('totalProcessed').textContent = processedPercentage.toFixed(2) + "% of total votes";
document.getElementById('progressBar').style.width = processedPercentage + "%";
document.getElementById('yesVotes').textContent = yesVotes.toLocaleString();
document.getElementById('yesPercentage').textContent = yesPercentage.toFixed(2) + "%";
document.getElementById('noVotes').textContent = noVotes.toLocaleString();
document.getElementById('noPercentage').textContent = noPercentage.toFixed(2) + "%";
const currentLeadElement = document.getElementById('currentLead');
const leadingOptionElement = document.getElementById('leadingOption');
if (leadingOption === "Yes") {
currentLeadElement.className = "bg-green-100 rounded-lg p-4 mb-8 text-center";
leadingOptionElement.className = "text-2xl font-bold mb-2 text-green-600";
document.getElementById('leadingEmoji').textContent = "🇪🇺";
} else {
currentLeadElement.className = "bg-red-100 rounded-lg p-4 mb-8 text-center";
leadingOptionElement.className = "text-2xl font-bold mb-2 text-red-600";
document.getElementById('leadingEmoji').textContent = "💩";
}
leadingOptionElement.textContent = `"${leadingOption}" is winning`;
document.getElementById('voteDifference').textContent = "by " + voteDifference.toLocaleString() + " votes";
document.getElementById('percentageLead').textContent = `(${percentageDifference.toFixed(2)}% lead)`;
document.getElementById('remainingVotes').textContent = remainingVotes.toLocaleString();
document.getElementById('totalVotes').textContent = "of " + totalVotesEstimate.toLocaleString() + " total estimated";
if (yesVotesStillNeeded <= 0) {
document.getElementById('additionalYesVotes').textContent = "Yes has won";
document.getElementById('requiredYesPercentage').textContent = "";
} else if (yesVotesStillNeeded > remainingVotes) {
document.getElementById('additionalYesVotes').textContent = "Yes cannot win";
document.getElementById('requiredYesPercentage').textContent = "Not enough remaining votes";
} else {
document.getElementById('additionalYesVotes').textContent = yesVotesStillNeeded.toLocaleString();
document.getElementById('requiredYesPercentage').textContent = "Yes votes needed to win (" + requiredYesPercentage + "% of remaining)";
}
}
calculateElectionData();
setInterval(calculateElectionData, 10000); // Update every 10 seconds
</script>
</body>
</html>