🏠 Home 

Koalitionenrechner - wahlrecht.de

11/13/2024, 11:00:16 PM


Install this script?
  1. // ==UserScript==
  2. // @name Koalitionenrechner - wahlrecht.de
  3. // @namespace Violentmonkey Scripts
  4. // @match https://www.wahlrecht.de/umfragen/
  5. // @grant none
  6. // @version 5.1
  7. // @author Sidem
  8. // @description 11/13/2024, 11:00:16 PM
  9. // ==/UserScript==
  10. /* jshint esversion: 6 */
  11. window.addEventListener('load', function () {
  12. var script = document.createElement('script');
  13. script.src = 'https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js';
  14. document.head.appendChild(script);
  15. let setNewChart = () => { };
  16. let setNewCoalitionChart = () => { };
  17. let seatFactor = 1.0;
  18. let data = [
  19. { id: 'cdu', name: 'CDU/CSU', icon: '⚫️', color: '#000000FF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/tYm4PG9/CDUCSU.png" alt="CDUCSU" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEUAAACnej3aAAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  20. { id: 'spd', name: 'SPD', icon: '🔴', color: '#E3000FFF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/LScLCYC/SPD.png" alt="SPD" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEXjAA+cYU6yAAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  21. { id: 'gru', name: 'GRÜNE', icon: '🟢', color: '#64A12DFF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/M6cx5K3/GRUENE.png" alt="GRUENE" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEVkoS0aZ4/7AAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  22. { id: 'fdp', name: 'FDP', icon: '🟡', color: '#FFED00FF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/m093TBw/FDP.png" alt="FDP" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEX/7QDyMoSWAAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  23. { id: 'lin', name: 'LINKE', icon: '🟣', color: '#FF0000FF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/Mp4TFzX/LINKE.png" alt="LINKE" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEX/AAAZ4gk3AAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  24. { id: 'afd', name: 'AfD', icon: '🔵', color: '#009DE0FF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/3hzmWRr/AfD.png" alt="AfD" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEUAneDDnyv1AAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  25. { id: 'frw', name: 'FW', icon: '⚪️', color: '#FF8800FF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/3hzmWRr/AfD.png" alt="FW" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEVmZmZ8VoIEAAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  26. { id: 'bsw', name: 'BSW', icon: '🟠', color: '#CC0077FF', votes: 0, projectedSeats: 0, logoUrl: '<img src="https://i.ibb.co/3hzmWRr/AfD.png" alt="BSW" border="0">', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEXMAHfxrrZhAAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' },
  27. { id: 'son', name: 'Sonstige', icon: '⚪️', color: '#AAAAAAFF', votes: 0, projectedSeats: 0, logoUrl: '', colorUri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEVmZmZ8VoIEAAAAC0lEQVQI12MgEQAAADAAAWV61nwAAAAASUVORK5CYII=' }
  28. ];
  29. let voteData = data;
  30. let coalitionData = [];
  31. let columnHover = '';
  32. function calculateWeight(date, newestDate) {
  33. let daysOld = (newestDate - date.getTime()) / (1000 * 60 * 60 * 24);
  34. return 5 * Math.exp(-Math.log(5) * daysOld / 30);
  35. }
  36. function calculateWeightedAverage(rowId) {
  37. let dates = [];
  38. let values = [];
  39. let weights = [];
  40. let dateRow = document.getElementById('datum');
  41. let dataRow = document.getElementById(rowId);
  42. let cells = dataRow.getElementsByTagName('td');
  43. let dateCells = dateRow.getElementsByTagName('td');
  44. let thirtyDaysAgo = new Date();
  45. thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  46. for (let i = 1; i < cells.length - 2; i++) {
  47. let dateSpan = dateCells[i].querySelector('span.li');
  48. let value = cells[i].textContent.trim();
  49. if (dateSpan && value !== '–') {
  50. let dateText = dateSpan.textContent;
  51. let dateParts = dateText.split('.');
  52. let date = new Date(dateParts[2], dateParts[1] - 1, dateParts[0]);
  53. if (date >= thirtyDaysAgo) {
  54. let numValue = parseFloat(value.replace(' %', '').replace(',', '.'));
  55. if (!isNaN(numValue)) {
  56. dates.push(date);
  57. values.push(numValue);
  58. }
  59. }
  60. }
  61. }
  62. if (values.length === 0) return '–';
  63. let newest = Math.max(...dates.map(d => d.getTime()));
  64. weights = dates.map(date => calculateWeight(date, newest));
  65. let weightSum = weights.reduce((a, b) => a + b, 0);
  66. let weightedSum = values.reduce((sum, value, i) => sum + value * weights[i], 0);
  67. let r###lt = (weightedSum / weightSum).toFixed(1);
  68. return r###lt % 1 === 0 ? Math.round(r###lt) + ' %' : r###lt + ' %';
  69. }
  70. function updateTooltipsWithWeights() {
  71. let dateRow = document.getElementById('datum');
  72. let dateCells = dateRow.getElementsByTagName('td');
  73. let dates = [];
  74. let newestDate = null;
  75. for (let i = 1; i < dateCells.length - 2; i++) {
  76. let dateSpan = dateCells[i].querySelector('span.li');
  77. if (dateSpan) {
  78. let dateText = dateSpan.textContent;
  79. let dateParts = dateText.split('.');
  80. let date = new Date(dateParts[2], dateParts[1] - 1, dateParts[0]);
  81. dates.push({ cell: dateCells[i], date: date });
  82. if (!newestDate || date > newestDate) {
  83. newestDate = date;
  84. }
  85. }
  86. }
  87. for (let dateObj of dates) {
  88. let weight = calculateWeight(dateObj.date, newestDate.getTime());
  89. let cell = dateObj.cell;
  90. let thirtyDaysAgo = new Date();
  91. thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  92. if (dateObj.date >= thirtyDaysAgo) {
  93. let currentTitle = cell.getAttribute('title') || '';
  94. let weightText = `\nGewichtung: ${weight.toFixed(2)}x`;
  95. if (currentTitle.includes('Gewichtung:')) {
  96. cell.setAttribute('title', currentTitle.replace(/\nGewichtung:.*/, weightText));
  97. } else {
  98. cell.setAttribute('title', currentTitle + weightText);
  99. }
  100. }
  101. }
  102. }
  103. function insertAverageColumn() {
  104. let headerRow = document.querySelector('thead tr');
  105. let newHeader = document.createElement('th');
  106. newHeader.className = 'in';
  107. newHeader.innerHTML = 'Durch-<br>schnitt';
  108. headerRow.insertBefore(newHeader, headerRow.lastElementChild.previousElementSibling);
  109. let dateRow = document.getElementById('datum');
  110. let dateTd = document.createElement('td');
  111. dateTd.className = 'di';
  112. dateRow.insertBefore(dateTd, dateRow.lastElementChild.previousElementSibling);
  113. let partyIds = ["cdu", "spd", "gru", "fdp", "lin", "afd", "frw", "bsw", "son"];
  114. partyIds.forEach(partyId => {
  115. let row = document.getElementById(partyId);
  116. if (row) {
  117. let avgTd = document.createElement('td');
  118. avgTd.className = 'di col-avg';
  119. avgTd.style.cursor = 'pointer';
  120. avgTd.textContent = calculateWeightedAverage(partyId);
  121. avgTd.onclick = getChart;
  122. avgTd.addEventListener("mouseenter", function (e) {
  123. let column = document.getElementsByClassName('col-avg');
  124. for (let item of column) {
  125. item.style.backdropFilter = 'brightness(0.5)';
  126. }
  127. });
  128. avgTd.addEventListener("mouseleave", function (e) {
  129. let column = document.getElementsByClassName('col-avg');
  130. for (let item of column) {
  131. item.style.backdropFilter = 'unset';
  132. }
  133. });
  134. row.insertBefore(avgTd, row.lastElementChild.previousElementSibling);
  135. }
  136. });
  137. let r###lts = partyIds.map(partyId => {
  138. let valStr = calculateWeightedAverage(partyId);
  139. let valNum = parseFloat(valStr.replace('%', '').trim());
  140. return isNaN(valNum) ? 0 : valNum;
  141. });
  142. let sum = r###lts.reduce((a, b) => a + b, 0);
  143. if (sum > 0) {
  144. r###lts = r###lts.map(val => (val / sum) * 100);
  145. }
  146. partyIds.forEach((partyId, i) => {
  147. let row = document.getElementById(partyId);
  148. if (row) {
  149. // Die Durchschnitts-Spalte wird z.B. anhand ihrer CSS-Klasse gefunden.
  150. let avgCell = row.querySelector('.col-avg');
  151. if (avgCell) {
  152. avgCell.textContent = r###lts[i].toFixed(1) + ' %';
  153. }
  154. }
  155. });
  156. }
  157. function insertCustomColumn() {
  158. // Add header
  159. let headerRow = document.querySelector('thead tr');
  160. let newHeader = document.createElement('th');
  161. newHeader.className = 'in custom-header';
  162. newHeader.innerHTML = 'Custom<br>Werte';
  163. headerRow.insertBefore(newHeader, headerRow.lastElementChild);
  164. // Add empty cell in date row
  165. let dateRow = document.getElementById('datum');
  166. let dateTd = document.createElement('td');
  167. dateTd.className = 'di';
  168. dateRow.insertBefore(dateTd, dateRow.lastElementChild);
  169. // Add cells with number inputs for each party
  170. let partyIds = ["cdu", "spd", "gru", "fdp", "lin", "afd", "frw", "bsw", "son"];
  171. let currentValues = {};
  172. // Initialize with current average values
  173. partyIds.forEach(partyId => {
  174. let row = document.getElementById(partyId);
  175. if (row) {
  176. let avgCell = row.querySelector('.col-avg');
  177. if (avgCell) {
  178. let value = parseFloat(avgCell.textContent.replace(',', '.').replace('%', '').trim()) || 0;
  179. currentValues[partyId] = value;
  180. }
  181. }
  182. });
  183. function updateAllValues(changedPartyId, newValue) {
  184. newValue = Math.max(0, Math.min(100, newValue));
  185. const oldValue = currentValues[changedPartyId];
  186. const difference = newValue - oldValue;
  187. let otherPartiesTotal = Object.entries(currentValues)
  188. .filter(([id]) => id !== changedPartyId)
  189. .reduce((sum, [, value]) => sum + value, 0);
  190. if (otherPartiesTotal + newValue !== 100) {
  191. const targetOtherTotal = 100 - newValue;
  192. const factor = targetOtherTotal / otherPartiesTotal;
  193. Object.keys(currentValues).forEach(partyId => {
  194. if (partyId !== changedPartyId) {
  195. currentValues[partyId] *= factor;
  196. const input = document.querySelector(`#${partyId} .custom-input`);
  197. if (input) {
  198. input.value = currentValues[partyId].toFixed(1);
  199. }
  200. }
  201. });
  202. }
  203. currentValues[changedPartyId] = newValue;
  204. return currentValues;
  205. }
  206. partyIds.forEach(partyId => {
  207. let row = document.getElementById(partyId);
  208. if (row) {
  209. let customTd = document.createElement('td');
  210. customTd.className = 'di custom-cell';
  211. let container = document.createElement('div');
  212. container.style.display = 'flex';
  213. container.style.alignItems = 'center';
  214. container.style.justifyContent = 'center';
  215. let input = document.createElement('input');
  216. input.style.cursor = 'pointer';
  217. input.type = 'number';
  218. input.className = 'custom-input';
  219. input.min = '0';
  220. input.max = '100';
  221. input.step = '0.1';
  222. input.value = currentValues[partyId].toFixed(1);
  223. input.style.width = '60px';
  224. let percentSymbol = document.createElement('span');
  225. percentSymbol.textContent = '%';
  226. percentSymbol.style.marginLeft = '2px';
  227. input.addEventListener('change', (e) => {
  228. let newValue = parseFloat(e.target.value) || 0;
  229. updateAllValues(partyId, newValue);
  230. Object.entries(currentValues).forEach(([id, value]) => {
  231. const otherInput = document.querySelector(`#${id} .custom-input`);
  232. if (otherInput) {
  233. otherInput.value = value.toFixed(1);
  234. }
  235. });
  236. getChart({ target: customTd });
  237. });
  238. input.addEventListener('blur', (e) => {
  239. e.target.value = parseFloat(e.target.value || 0).toFixed(1);
  240. });
  241. container.appendChild(input);
  242. container.appendChild(percentSymbol);
  243. customTd.appendChild(container);
  244. customTd.onclick = getChart;
  245. customTd.classList.add('col-custom');
  246. row.insertBefore(customTd, row.lastElementChild);
  247. }
  248. });
  249. }
  250. function getCombinations(array) {
  251. var r###lt = [];
  252. for (var i = 1; i < (1 << array.length); i++) {
  253. var subset = [];
  254. for (var j = 0; j < array.length; j++)
  255. if (i & (1 << j))
  256. subset.push(array[j]);
  257. r###lt.push(subset);
  258. }
  259. return r###lt;
  260. }
  261. function cleanVote(str) {
  262. if (str.includes('\n')) {
  263. let split = str.split('\n');
  264. return cleanVote(split[0].split(' ')[1]) + cleanVote(split[1].split(' ')[1]);
  265. }
  266. if (str.includes('–')) return 0;
  267. return parseFloat(str.replace(',', '.').replace(' %', ''));
  268. }
  269. function getPartyByIdentifier(identifier) {
  270. for (let p of voteData) {
  271. if (p.name == identifier || p.color == identifier || p.icon == identifier || p.id == identifier) {
  272. return p;
  273. }
  274. }
  275. return { id: 'son', name: 'Sonstige', icon: '⚪️', color: '#666666', votes: 0 };
  276. }
  277. let allPossibleCoalitions = getCombinations(['⚫️', '🔴', '🟣', '🟡', '🟢', '🔵', '🟠', '⚪️']);
  278. allPossibleCoalitions = allPossibleCoalitions.filter((el) => { return (el.length >= 1 && el.length < 5) }); // filter to only 2-4 party coalitions
  279. let coalitions = allPossibleCoalitions.filter((el) => {
  280. return true;
  281. if (el.includes('🔵') && el.includes('🟢')) return false;
  282. if (el.includes('🔵') && el.includes('🔴')) return false;
  283. if (el.includes('🔵') && el.includes('🟣')) return false;
  284. if (el.includes('🟣') && el.includes('🟡')) return false;
  285. if (el.includes('🟣') && el.includes('⚫️')) return false;
  286. return true;
  287. });
  288. function isPermutation(a, b) {
  289. return b.filter(x => !a.includes(x)).length === 0 && a.length == 3;
  290. }
  291. function coalitionSymbol(coalition) {
  292. if (isPermutation(coalition, ['⚫️', '🔴', '🟢'])) return "<img src='https://fla###n.com/w20/ke.png' alt='🇰🇪' title='Kenia'>";
  293. if (isPermutation(coalition, ['⚫️', '🔴', '🟡'])) return "<img src='https://fla###n.com/w20/de.png' alt='🇩🇪' title='Deutschland'>";
  294. if (isPermutation(coalition, ['⚫️', '🟡', '🟢'])) return "<img src='https://fla###n.com/w20/jm.png' alt='🇯🇲' title='Jamaika'>";
  295. if (isPermutation(coalition, ['🟣', '🔴', '🟢'])) return "<img src='https://fla###n.com/w20/by.png' alt='🇧🇾' title='Weissrussland'>";
  296. if (isPermutation(coalition, ['⚫️', '🟡', '🔵'])) return "<img src='https://fla###n.com/w20/bs.png' alt='🇧🇸' title='Bahamas'>";
  297. if (isPermutation(coalition, ['🟡', '🔴', '🟢'])) return "🚦";
  298. return "";
  299. }
  300. function getCoalitions() {
  301. let str = "<strong>Anteil der Sitze im Bundestag</strong>";
  302. let r###lts = [];
  303. for (let coalition of coalitions) {
  304. let currentCoalitionVotes = 0;
  305. let containsBelow = false;
  306. coalition.sort((p1, p2) => { return getPartyByIdentifier(p2).votes - getPartyByIdentifier(p1).votes });
  307. for (let p of coalition) {
  308. if (currentCoalitionVotes >= 50.0) containsBelow = true;
  309. currentCoalitionVotes += getPartyByIdentifier(p).votes * seatFactor;
  310. if (getPartyByIdentifier(p).name == "Sonstige") containsBelow = true;
  311. if (getPartyByIdentifier(p).votes < 5.0) containsBelow = true;
  312. }
  313. if (!containsBelow) r###lts.push({ coalition: coalition.join(""), parties: coalition, votes: currentCoalitionVotes });
  314. }
  315. r###lts.sort((a, b) => { return b.votes - a.votes; });
  316. let line = false;
  317. let weight = "bold;";
  318. for (let c of r###lts) {
  319. if (!line && c.votes < 50) {
  320. line = true;
  321. weight = '100;';
  322. }
  323. str += "<p style='margin: 0px; font-size: 1rem; font-weight: " + weight + "'><strong style='display: inline-block; vertical-align: middle; width: 64px;'>" + c.parties.map((e) => { return '<img class="partyColor" src="' + getPartyByIdentifier(e).colorUri + '" alt="' + getPartyByIdentifier(e).icon + '" title="' + getPartyByIdentifier(e).name + '" />'; }).join("") + "</strong>" + c.votes.toFixed(1) + "% " + coalitionSymbol(c.parties) + "</p>";
  324. }
  325. coalitionData = r###lts;
  326. //str += "<button id='copyCoalitionBtn'>Copy</button>";
  327. coalitionBox.innerHTML = str;
  328. let copyBtn = document.createElement('button');
  329. copyBtn.innerText = "Copy";
  330. copyBtn.onclick = (e) => {
  331. navigator.clipboard.writeText(getCoalitionString(coalitionBox)).then(() => {
  332. console.log("success");
  333. }, function () {
  334. console.log("failed writing clipboard");
  335. });
  336. };
  337. coalitionBox.appendChild(copyBtn);
  338. setNewCoalitionChart();
  339. }
  340. const getCoalitionString = (container) => {
  341. let str = "";
  342. for (let p of container.childNodes) {
  343. for (let item of p.childNodes) {
  344. if (item.nodeName == 'STRONG') {
  345. for (let color of item.childNodes) {
  346. str += color.alt;
  347. }
  348. } else if (item.nodeName == '#text' && item.data != 'Copy') {
  349. str += item.data;
  350. } else if (item.nodeName == 'IMG') {
  351. str += item.alt;
  352. }
  353. }
  354. str += "\n";
  355. }
  356. return str;
  357. };
  358. let getBelowFivePercentage = () => {
  359. let total = getPartyByIdentifier('son').votes;
  360. let partyIds = ["cdu", "spd", "gru", "fdp", "lin", "afd", "frw", "bsw"];
  361. for (let id of partyIds) {
  362. let thisVotes = getPartyByIdentifier(id).votes;
  363. if (thisVotes < 5.0) total += thisVotes;
  364. }
  365. return total;
  366. };
  367. let getChart = (e) => {
  368. let isCustomColumn = e.target.classList.contains('custom-cell') ||
  369. e.target.closest('.custom-cell') !== null;
  370. let i = 0;
  371. voteData = [];
  372. if (isCustomColumn) {
  373. // Handle custom column values
  374. for (let partyId of ["cdu", "spd", "gru", "fdp", "lin", "afd", "frw", "bsw", "son"]) {
  375. let input = document.querySelector(`#${partyId} .custom-input`);
  376. if (input) {
  377. let value = parseFloat(input.value) || 0;
  378. voteData.push({ ...data[i], votes: value });
  379. }
  380. i++;
  381. }
  382. } else {
  383. // Handle regular columns
  384. let colDataElements = document.getElementsByClassName(e.target.classList[e.target.classList.length - 1]);
  385. for (let el of colDataElements) {
  386. voteData.push({ ...data[i], votes: cleanVote(el.innerText) });
  387. i++;
  388. }
  389. }
  390. voteData.sort((a, b) => { return b.votes - a.votes; });
  391. seatFactor = 1 / ((100 - getBelowFivePercentage()) / 100);
  392. getCoalitions();
  393. setNewChart();
  394. };
  395. let getCoalitionDatasets = () => {
  396. let datasets = [];
  397. let numberset = [];
  398. for (let party of voteData) {
  399. numberset = [];
  400. if (party.name != 'Sonstige' && party.votes >= 5.0) {
  401. for (let coalition of coalitionData) {
  402. if (coalition.parties.includes(party.icon)) {
  403. numberset.push(party.votes * seatFactor);
  404. } else {
  405. numberset.push(0);
  406. }
  407. }
  408. datasets.push({ label: party.name, data: numberset, backgroundColor: party.color });
  409. }
  410. }
  411. return datasets;
  412. }
  413. let partyIds = ["cdu", "spd", "gru", "fdp", "lin", "afd", "frw", "bsw", "son"];
  414. let rows = document.getElementsByTagName('tr');
  415. for (let row of rows) {
  416. if (partyIds.includes(row.id)) {
  417. let numbers = row.getElementsByTagName('td');
  418. let n = 0;
  419. for (let number of numbers) {
  420. if (n != 0 && n != 9) {
  421. number.classList.add('col-' + n);
  422. number.onclick = getChart;
  423. number.style.cursor = 'pointer';
  424. number.addEventListener("mouseenter", function (e) {
  425. let columnClass = e.target.classList[e.target.classList.length - 1];
  426. let column = document.getElementsByClassName(columnClass);
  427. for (let item of column) {
  428. item.style.backdropFilter = 'brightness(0.5)';
  429. }
  430. });
  431. number.addEventListener("mouseleave", function (e) {
  432. let columnClass = e.target.classList[e.target.classList.length - 1];
  433. let column = document.getElementsByClassName(columnClass);
  434. for (let item of column) {
  435. item.style.backdropFilter = 'unset';
  436. }
  437. });
  438. }
  439. n++;
  440. }
  441. }
  442. }
  443. let info = document.getElementById('info');
  444. let coalitionBox = document.createElement('div');
  445. coalitionBox.setAttribute('id', 'coalitionBox');
  446. info.parentNode.insertBefore(coalitionBox, info);
  447. let table = document.querySelector('.wilko');
  448. table.id = 'tableBox';
  449. table.parentNode.id = 'tableContainer';
  450. script.onload = function () {
  451. let ctx = document.getElementById('myChart').getContext('2d');
  452. let myChart = {};
  453. let ctx2 = document.getElementById('myCoalitionChart').getContext('2d');
  454. let myCoalitionChart = {};
  455. setNewChart = () => {
  456. if (myChart instanceof Chart) {
  457. myChart.data.labels = voteData.map(a => a.name);
  458. myChart.data.datasets[0].data = voteData.map(a => a.votes);
  459. myChart.data.datasets[0].backgroundColor = voteData.map(a => a.color);
  460. myChart.update();
  461. } else {
  462. myChart = new Chart(ctx, {
  463. type: 'bar',
  464. data: {
  465. labels: voteData.map(a => a.name),
  466. datasets: [{
  467. label: '% der Stimmen',
  468. data: voteData.map(a => a.votes),
  469. backgroundColor: voteData.map(a => a.color),
  470. borderWidth: 1,
  471. circumference: 180,
  472. rotation: 270
  473. }]
  474. },
  475. options: {
  476. scales: {
  477. y: {
  478. suggestedMin: 0,
  479. //suggestedMax: 50
  480. }
  481. }
  482. }
  483. });
  484. }
  485. };
  486. setNewCoalitionChart = () => {
  487. if (myCoalitionChart instanceof Chart) {
  488. myCoalitionChart.data.labels = coalitionData.map(a => "");
  489. myCoalitionChart.data.datasets = [...getCoalitionDatasets(), {
  490. label: '50% Grenze',
  491. data: coalitionData.map(a => 50),
  492. borderColor: "#000000",
  493. backgroundColor: "#000000",
  494. type: 'line',
  495. order: 10
  496. }];
  497. myCoalitionChart.update();
  498. } else {
  499. myCoalitionChart = new Chart(ctx2, {
  500. type: 'bar',
  501. data: {
  502. labels: coalitionData.map(a => ""),
  503. datasets: [...getCoalitionDatasets(), {
  504. label: '50% Grenze',
  505. data: coalitionData.map(a => 50),
  506. borderColor: "#000000",
  507. backgroundColor: "#000000",
  508. type: 'line',
  509. order: 10
  510. }]
  511. },
  512. options: {
  513. radius: 0,
  514. indexAxis: 'y',
  515. scales: {
  516. x: {
  517. suggestedMin: 0,
  518. suggestedMax: 50,
  519. stacked: true
  520. },
  521. y: {
  522. stacked: true
  523. }
  524. },
  525. responsive: true,
  526. plugins: {
  527. legend: {
  528. position: 'right',
  529. },
  530. title: {
  531. display: true,
  532. text: 'Mögliche Koalitionen (% der projezierten Sitze)'
  533. }
  534. }
  535. }
  536. });
  537. }
  538. };
  539. };
  540. let chartContainer = document.createElement('div');
  541. chartContainer.id = 'chartBox';
  542. info.parentNode.insertBefore(chartContainer, info);
  543. let chartBox = document.createElement('canvas');
  544. chartBox.id = 'myChart';
  545. chartContainer.appendChild(chartBox);
  546. let coalitionChartContainer = document.createElement('div');
  547. coalitionChartContainer.id = 'coalitionContainer';
  548. info.parentNode.insertBefore(coalitionChartContainer, info);
  549. let coalitionChartBox = document.createElement('canvas');
  550. coalitionChartBox.id = 'myCoalitionChart';
  551. coalitionChartContainer.appendChild(coalitionChartBox);
  552. var style = document.createElement("style");
  553. style.type = "text/css";
  554. let styleRows = ["cdu", "spd", "gru", "fdp", "lin", "afd", "frw", "bsw", "son"];
  555. for (let x of styleRows) {
  556. style.innerHTML += `
  557. tr#${x} > td, tr#${x} > th {
  558. background-color: ${getPartyByIdentifier(x).color.slice(0, -2)}66 !important;
  559. }
  560. `;
  561. }
  562. style.innerHTML += `
  563. #tableContainer {
  564. display: flex;
  565. flex-direction: column;
  566. align-items: center;
  567. justify-content: center;
  568. }
  569. #tableBox {
  570. width: 90%;
  571. }
  572. #coalitionBox {
  573. width: 10%;
  574. }
  575. #r###ltContainer {
  576. display:flex;
  577. }
  578. #chartBox {
  579. width: 45%;
  580. }
  581. #coalitionContainer {
  582. width: 45%;
  583. }
  584. #myChart {
  585. }
  586. .col-10 {
  587. color: black;
  588. }
  589. .custom-cell {
  590. padding: 8px;
  591. text-align: center;
  592. }
  593. .custom-input {
  594. padding: 2px 4px;
  595. text-align: right;
  596. }
  597. table.wilko {
  598. border-spacing: 0px;
  599. }
  600. .custom-input[type=number] {
  601. -moz-appearance: textfield;
  602. }
  603. `;
  604. document.head.appendChild(style);
  605. let container = document.createElement('div');
  606. container.id = 'r###ltContainer';
  607. info.parentNode.insertBefore(container, info);
  608. container.appendChild(coalitionBox);
  609. container.appendChild(chartContainer);
  610. container.appendChild(coalitionChartContainer);
  611. insertAverageColumn();
  612. insertCustomColumn();
  613. updateTooltipsWithWeights();
  614. }, false);