gh-pages
Michał Górny 2019-09-26 19:39:18 +02:00
rodzic 28744a4487
commit d9c8582037
22 zmienionych plików z 0 dodań i 12840 usunięć

Wyświetl plik

@ -1,6 +0,0 @@
{
"presets": [
"@babel/env",
"@babel/typescript"
]
}

Wyświetl plik

@ -1,14 +0,0 @@
# editorconfig.org
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[package*.json]
indent_style = space
indent_size = 2

Wyświetl plik

@ -1,21 +0,0 @@
{
"env": {
"browser": true,
"node": true,
"es6": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-non-null-assertion": "off"
}
}

2
.gitignore vendored
Wyświetl plik

@ -1,2 +0,0 @@
dist
node_modules

Wyświetl plik

@ -1,17 +0,0 @@
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": "tab",
"font-family-name-quotes": "always-where-recommended",
"function-url-quotes": ["always", {
"except": "empty"
}],
"selector-attribute-quotes": "always",
"string-quotes": "single",
"at-rule-no-vendor-prefix": true,
"media-feature-name-no-vendor-prefix": true,
"property-no-vendor-prefix": true,
"selector-no-vendor-prefix": true,
"value-no-vendor-prefix": true
}
}

11550
package-lock.json wygenerowano

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,50 +0,0 @@
{
"name": "sejm-mandates-simulator",
"version": "1.0.0",
"description": "Simulator for the Polish Sejm 2019 election",
"scripts": {
"build": "webpack",
"start": "webpack-dev-server --inline --watch --hot",
"deploy": "gh-pages -d build -e kalkulator"
},
"keywords": [],
"author": "Michał Górny",
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-typescript": "^7.3.3",
"@babel/register": "^7.5.5",
"@types/chartist": "^0.9.46",
"@types/pug": "^2.0.4",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"babel-loader": "^8.0.6",
"css-loader": "^3.2.0",
"cssnano": "^4.1.10",
"eslint": "^6.1.0",
"eslint-loader": "^3.0.0",
"eslint-utils": "^1.4.1",
"file-loader": "^4.2.0",
"gh-pages": "^2.1.1",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"postcss": "^7.0.17",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"pug": "^2.0.4",
"pug-loader": "^2.4.0",
"stylelint": "^10.1.0",
"stylelint-config-standard": "^18.3.0",
"stylelint-webpack-plugin": "^0.10.5",
"typescript": "^3.5.3",
"webpack": "^4.39.1",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.8.0",
"webpack-livereload-plugin": "^2.2.0"
},
"dependencies": {
"chartist": "^0.11.3",
"modern-normalize": "^0.5.0"
}
}

Wyświetl plik

@ -1,9 +0,0 @@
module.exports = {
plugins: {
'postcss-import': {},
'postcss-preset-env': {
browsers: 'last 2 versions',
},
'cssnano': {},
},
};

Wyświetl plik

@ -1,638 +0,0 @@
import {
PastSupport,
Committee,
Constituency,
} from './types';
export const pastSupport: PastSupport = {
pis: 37.58,
po: 24.09,
razem: 3.62,
korwin: 4.76,
psl: 5.13,
zl: 7.55,
k15: 8.81,
nowoczesna: 7.6,
};
export const committees: Committee[] = [
{
id: 'pis',
name: 'Prawo i Sprawiedliwość',
shortName: 'PiS',
threshold: 5,
pastSupportEquivalence: [['pis', 1]],
},
{
id: 'ko',
name: 'Koalicja Obywatelska',
shortName: 'KO',
threshold: 8,
pastSupportEquivalence: [['po', 1], ['nowoczesna', 1]],
},
{
id: 'lewica',
name: 'SLD – Lewica',
shortName: 'Lew.',
threshold: 5,
pastSupportEquivalence: [['zl', 1], ['razem', 1]],
},
{
id: 'psl',
name: 'PSL – Koalicja Polska',
shortName: 'PSL',
threshold: 5,
pastSupportEquivalence: [['psl', 1], ['k15', 0.5]],
},
{
id: 'konfederacja',
name: 'Konfederacja',
shortName: 'Konf.',
threshold: 5,
pastSupportEquivalence: [['korwin', 1], ['k15', 0.5]],
},
{
id: 'mn',
name: 'Mniejszość Niemiecka',
shortName: 'MN',
threshold: 0,
pastSupportEquivalence: [],
},
];
export const constituencies: Constituency[] = [
{
name: 'Legnica',
size: 12,
pastSupport: {
pis: 35.70,
po: 25.24,
razem: 3.64,
korwin: 4.32,
psl: 3.89,
zl: 10.45,
k15: 9.59,
nowoczesna: 7.15,
},
},
{
name: 'Wałbrzych',
size: 8,
pastSupport: {
pis: 31.15,
po: 32.65,
razem: 3.41,
korwin: 4.30,
psl: 3.18,
zl: 8.76,
k15: 8.81,
nowoczesna: 6.64,
},
},
{
name: 'Wrocław',
size: 14,
pastSupport: {
pis: 31.21,
po: 30.49,
razem: 4.21,
korwin: 5.22,
psl: 2.60,
zl: 6.10,
k15: 8.74,
nowoczesna: 10.65,
},
},
{
name: 'Bydgoszcz',
size: 12,
pastSupport: {
pis: 30.20,
po: 29.64,
razem: 3.76,
korwin: 4.54,
psl: 6.07,
zl: 10.04,
k15: 7.77,
nowoczesna: 7.30,
},
},
{
name: 'Toruń',
size: 13,
pastSupport: {
pis: 33.57,
po: 25.77,
razem: 3.65,
korwin: 3.90,
psl: 6.75,
zl: 10.76,
k15: 8.32,
nowoczesna: 6.50,
},
},
{
name: 'Lublin',
size: 15,
pastSupport: {
pis: 47.57,
po: 16.59,
razem: 2.75,
korwin: 5.00,
psl: 7.74,
zl: 5.98,
k15: 9.32,
nowoczesna: 4.54,
},
},
{
name: 'Chełm',
size: 12,
pastSupport: {
pis: 48.02,
po: 12.31,
razem: 2.39,
korwin: 4.37,
psl: 11.39,
zl: 7.11,
k15: 10.47,
nowoczesna: 3.75,
},
},
{
name: 'Zielona Góra',
size: 12,
pastSupport: {
pis: 28.27,
po: 28.21,
razem: 3.99,
korwin: 4.99,
psl: 5.12,
zl: 10.02,
k15: 8.75,
nowoczesna: 9.99,
},
},
{
name: 'Łódź',
size: 10,
pastSupport: {
pis: 29.90,
po: 31.28,
razem: 4.63,
korwin: 4.78,
psl: 2.70,
zl: 10.48,
k15: 7.24,
nowoczesna: 8.99,
},
},
{
name: 'Piotrków Trybunalski',
size: 9,
pastSupport: {
pis: 46.95,
po: 15.46,
razem: 3.06,
korwin: 3.91,
psl: 7.48,
zl: 7.47,
k15: 10.08,
nowoczesna: 5.59,
},
},
{
name: 'Sieradz',
size: 12,
pastSupport: {
pis: 39.93,
po: 21.18,
razem: 3.54,
korwin: 4.10,
psl: 7.86,
zl: 8.18,
k15: 8.92,
nowoczesna: 5.32,
},
},
{
name: 'Chrzanów',
size: 8,
pastSupport: {
pis: 49.05,
po: 20.42,
razem: 3.26,
korwin: 4.45,
psl: 3.03,
zl: 5.33,
k15: 8.67,
nowoczesna: 5.79,
},
},
{
name: 'Kraków',
size: 14,
pastSupport: {
pis: 38.62,
po: 24.61,
razem: 3.88,
korwin: 6.35,
psl: 2.70,
zl: 6.38,
k15: 7.26,
nowoczesna: 9.73,
},
},
{
name: 'Nowy Sącz',
size: 10,
pastSupport: {
pis: 60.56,
po: 13.95,
razem: 2.13,
korwin: 4.31,
psl: 4.16,
zl: 2.55,
k15: 7.83,
nowoczesna: 3.69,
},
},
{
name: 'Tarnów',
size: 9,
pastSupport: {
pis: 51.99,
po: 14.71,
razem: 2.43,
korwin: 4.72,
psl: 8.08,
zl: 3.41,
k15: 9.60,
nowoczesna: 4.54,
},
},
{
name: 'Płock',
size: 10,
pastSupport: {
pis: 43.78,
po: 16.44,
razem: 3.35,
korwin: 4.07,
psl: 10.66,
zl: 8.14,
k15: 8.41,
nowoczesna: 5.15,
},
},
{
name: 'Radom',
size: 9,
pastSupport: {
pis: 47.49,
po: 17.55,
razem: 2.62,
korwin: 3.91,
psl: 9.42,
zl: 4.82,
k15: 8.41,
nowoczesna: 4.81,
},
},
{
name: 'Siedlce',
size: 12,
pastSupport: {
pis: 51.10,
po: 13.55,
razem: 2.66,
korwin: 4.35,
psl: 10.23,
zl: 4.35,
k15: 8.36,
nowoczesna: 4.63,
},
},
{
name: 'Warszawa I',
size: 20,
pastSupport: {
pis: 29.89,
po: 27.54,
razem: 5.54,
korwin: 6.18,
psl: 0.72,
zl: 8.55,
k15: 7.76,
nowoczesna: 13.39,
},
},
{
name: 'Warszawa II',
size: 12,
pastSupport: {
pis: 38.80,
po: 25.12,
razem: 3.85,
korwin: 4.81,
psl: 3.80,
zl: 5.66,
k15: 7.22,
nowoczesna: 10.01,
},
},
{
name: 'Opole',
size: 12,
pastSupport: {
pis: 27.77,
po: 26.23,
razem: 3.02,
korwin: 3.95,
psl: 3.68,
zl: 6.75,
k15: 12.57,
nowoczesna: 7.14,
},
},
{
name: 'Krosno',
size: 11,
pastSupport: {
pis: 53.51,
po: 13.76,
razem: 2.32,
korwin: 4.28,
psl: 7.28,
zl: 4.56,
k15: 9.15,
nowoczesna: 3.97,
},
},
{
name: 'Rzeszów',
size: 15,
pastSupport: {
pis: 56.11,
po: 13.11,
razem: 2.29,
korwin: 4.96,
psl: 4.67,
zl: 4.42,
k15: 9.28,
nowoczesna: 4.16,
},
},
{
name: 'Białystok',
size: 14,
pastSupport: {
pis: 45.38,
po: 16.74,
razem: 2.59,
korwin: 4.66,
psl: 8.07,
zl: 7.35,
k15: 9.07,
nowoczesna: 5.37,
},
},
{
name: 'Gdańsk',
size: 12,
pastSupport: {
pis: 29.61,
po: 34.72,
razem: 3.98,
korwin: 5.00,
psl: 3.02,
zl: 6.59,
k15: 7.15,
nowoczesna: 9.17,
},
},
{
name: 'Gdynia',
size: 14,
pastSupport: {
pis: 31.22,
po: 33.46,
razem: 4.05,
korwin: 4.43,
psl: 3.23,
zl: 6.64,
k15: 8.02,
nowoczesna: 8.22,
},
},
{
name: 'Bielsko-Biała',
size: 9,
pastSupport: {
pis: 40.42,
po: 23.57,
razem: 3.72,
korwin: 4.68,
psl: 3.42,
zl: 6.56,
k15: 9.36,
nowoczesna: 8.27,
},
},
{
name: 'Częstochowa',
size: 7,
pastSupport: {
pis: 35.82,
po: 20.95,
razem: 3.64,
korwin: 4.27,
psl: 4.99,
zl: 11.12,
k15: 11.63,
nowoczesna: 6.74,
},
},
{
name: 'Gliwice',
size: 9,
pastSupport: {
pis: 30.51,
po: 28.99,
razem: 4.15,
korwin: 5.09,
psl: 2.50,
zl: 7.21,
k15: 12.19,
nowoczesna: 8.90,
},
},
{
name: 'Rybnik',
size: 9,
pastSupport: {
pis: 39.59,
po: 24.21,
razem: 3.33,
korwin: 4.53,
psl: 1.79,
zl: 5.93,
k15: 11.31,
nowoczesna: 6.33,
},
},
{
name: 'Katowice',
size: 12,
pastSupport: {
pis: 32.92,
po: 28.37,
razem: 4.08,
korwin: 5.55,
psl: 0.99,
zl: 6.77,
k15: 10.05,
nowoczesna: 8.66,
},
},
{
name: 'Sosnowiec',
size: 9,
pastSupport: {
pis: 29.65,
po: 25.56,
razem: 4.44,
korwin: 4.81,
psl: 2.35,
zl: 13.97,
k15: 10.24,
nowoczesna: 8.97,
},
},
{
name: 'Kielce',
size: 16,
pastSupport: {
pis: 42.81,
po: 17.25,
razem: 2.80,
korwin: 4.14,
psl: 9.51,
zl: 7.87,
k15: 9.41,
nowoczesna: 4.98,
},
},
{
name: 'Elbląg',
size: 8,
pastSupport: {
pis: 31.56,
po: 30.12,
razem: 3.80,
korwin: 4.73,
psl: 6.69,
zl: 7.69,
k15: 8.24,
nowoczesna: 5.82,
},
},
{
name: 'Olsztyn',
size: 10,
pastSupport: {
pis: 30.42,
po: 27.07,
razem: 3.74,
korwin: 5.10,
psl: 8.44,
zl: 8.76,
k15: 8.97,
nowoczesna: 6.82,
},
},
{
name: 'Kalisz',
size: 12,
pastSupport: {
pis: 31.85,
po: 24.69,
razem: 3.17,
korwin: 4.25,
psl: 10.98,
zl: 8.82,
k15: 7.98,
nowoczesna: 7.04,
},
},
{
name: 'Konin',
size: 9,
pastSupport: {
pis: 37.41,
po: 20.23,
razem: 3.98,
korwin: 3.99,
psl: 6.86,
zl: 11.77,
k15: 8.83,
nowoczesna: 6.94,
},
},
{
name: 'Piła',
size: 9,
pastSupport: {
pis: 27.26,
po: 31.02,
razem: 3.92,
korwin: 4.07,
psl: 7.66,
zl: 9.15,
k15: 9.01,
nowoczesna: 6.98,
},
},
{
name: 'Poznań',
size: 10,
pastSupport: {
pis: 23.90,
po: 35.65,
razem: 4.60,
korwin: 4.77,
psl: 1.91,
zl: 8.07,
k15: 6.06,
nowoczesna: 14.49,
},
},
{
name: 'Koszalin',
size: 8,
pastSupport: {
pis: 28.58,
po: 30.07,
razem: 3.90,
korwin: 4.46,
psl: 4.13,
zl: 11.38,
k15: 9.41,
nowoczesna: 8.06,
},
},
{
name: 'Szczecin',
size: 12,
pastSupport: {
pis: 29.09,
po: 31.93,
razem: 4.12,
korwin: 5.33,
psl: 3.88,
zl: 8.56,
k15: 8.42,
nowoczesna: 8.66,
},
},
];

Wyświetl plik

@ -1,99 +0,0 @@
import Chartist, {ChartistStatic} from 'chartist';
import {committees, constituencies} from './data';
import {calculateMandates} from './mandates';
import template from './templates/constituency.pug';
import './styles.css';
const clearResults = (bar: ChartistStatic['Bar'], pie: ChartistStatic['Pie']) => {
document.querySelectorAll<HTMLTableDataCellElement>(`tr td:last-child`).forEach(td => {
td.innerHTML = '';
});
bar.detach();
pie.detach();
document.getElementById('support-bar-chart')!.innerHTML = '';
document.getElementById('division-pie-chart')!.innerHTML = '';
document.getElementById('constituency-results')!.innerHTML = '';
}
const displayConstituencyResults = () => {
const container = document.getElementById('constituency-results');
constituencies.forEach((constituency, index) => {
const data = (constituency.mandates && constituency.support)
? constituency.mandates.map((mandates, index) => ({
committee: committees[index].name,
support: (constituency.support as number[])[index],
mandates,
}))
: [];
data.sort((a, b) => b.support - a.support)
container!.insertAdjacentHTML('beforeend', template({
number: index + 1,
name: constituency.name,
size: constituency.size,
data,
}));
});
}
const handleCalculateButtonClick = (event: Event) => {
event.preventDefault();
const inputs = document.querySelectorAll<HTMLInputElement>('#support-form input');
const support = Array
.from(inputs)
.map(input => parseFloat(input.value));
if (!document.querySelector<HTMLFormElement>('#support-form')!.checkValidity()) return;
const mandates = calculateMandates(support);
mandates.forEach((value, index) => {
const committeeId = committees[index].id;
const td = document.querySelector<HTMLTableDataCellElement>(`tr.${committeeId} td:last-child`);
if (td) td.textContent = value.toString();
});
const barChartData = {
labels: committees.map(committee => committee.shortName).slice(0, -1),
series: support,
};
const barChartOptions = {
distributeSeries: true,
};
const bar = new Chartist.Bar('#support-bar-chart', barChartData, barChartOptions);
bar.on('draw', (data: {type: string; element: {attr(a: object): object}}) => {
if (data.type === 'bar') {
data.element.attr({
style: 'stroke-width: 30px',
});
}
});
const pieChartData = {
series: mandates,
};
const pieChartOptions = {
donut: true,
donutWidth: 60,
startAngle: 270,
total: 460 * 2,
labelInterpolationFnc: (value: number) => {
return value < 15 ? '' : String(value);
},
};
const pie = new Chartist.Pie('#division-pie-chart', pieChartData, pieChartOptions);
displayConstituencyResults();
inputs.forEach(input => input.addEventListener('input', () => {
clearResults(bar, pie);
}));
}
const bindActions = () => {
document
.querySelector('#calculate-button')!
.addEventListener('click', handleCalculateButtonClick);
}
document.addEventListener('DOMContentLoaded', () => {
bindActions();
});

Wyświetl plik

@ -1,62 +0,0 @@
import {committees, constituencies, pastSupport} from './data';
import {Constituency} from './types';
const calculateLocalSupport = (
support: number[],
pastSupportProjection: number[],
constituency: Constituency,
): number[] => {
const localPastSupport = constituency.pastSupport;
const localPastSupportProjection = support.map((committeeSupport, index) => (
committees[index].pastSupportEquivalence
.map(pastCommittee => localPastSupport[pastCommittee[0]] * pastCommittee[1])
.reduce((a, b) => a + b, 0)
));
const localSupportDeviation = pastSupportProjection
.map((pastCommitteSupportProjection, index) => (
localPastSupportProjection[index] / pastCommitteSupportProjection
)
);
const localSupport = support.map((committeeSupport, index) => (
committeeSupport * localSupportDeviation[index]
));
if (constituency.name === 'Opole') {
localSupport.push(8.14);
}
return localSupport;
}
export const calculateMandates = (support: number[]): number[] => {
const pastSupportProjection = support.map((committeeSupport, index) => (
committees[index].pastSupportEquivalence
.map(pastCommittee => pastSupport[pastCommittee[0]] * pastCommittee[1])
.reduce((a, b) => a + b, 0)
));
const mandates: number[] = new Array(support.length + 1).fill(0);
constituencies.forEach(constituency => {
const localSupport = calculateLocalSupport(support, pastSupportProjection, constituency);
constituency.support = localSupport;
constituency.mandates = new Array(localSupport.length).fill(0);
const filteredLocalSupport = localSupport.map((localCommitteeSupport, index) => {
if (support[index] < committees[index].threshold) return 0;
return localCommitteeSupport;
});
const quotients: {quotient: number; committeeIndex: number}[] = [];
for (let divisor = 1; divisor <= constituency.size; divisor++) {
for (let committeeIndex = 0; committeeIndex < localSupport.length; committeeIndex++) {
quotients.push({
quotient: filteredLocalSupport[committeeIndex] / divisor,
committeeIndex,
});
}
}
quotients.sort((a, b) => b.quotient - a.quotient);
quotients.slice(0, constituency.size).forEach(quotient => {
if (quotient.quotient > 0) {
mandates[quotient.committeeIndex]++;
constituency.mandates![quotient.committeeIndex]++;
}
});
});
return mandates;
}

Wyświetl plik

@ -1,5 +0,0 @@
declare module '*.pug' {
import pug = require('pug');
const content: pug.compileTemplate;
export = content;
}

Wyświetl plik

@ -1,163 +0,0 @@
@import 'modern-normalize/modern-normalize.css';
@import 'chartist/dist/chartist.min.css';
body {
color: #333;
background-color: lightgoldenrodyellow;
font-size: 15px;
}
.container {
width: 100%;
max-width: 58rem;
margin: 1rem auto;
padding: 0.25rem 1.5rem 1rem;
border: 1px solid lightgray;
background-color: white;
}
h1 {
font-size: 1.75rem;
}
p {
text-align: justify;
}
.charts-row {
display: flex;
height: auto;
margin-bottom: 1rem;
}
.ct-chart:empty {
height: 0;
}
#division-pie-chart svg {
transform-origin: (0, 100%);
transform: translate(-6%, 34%) scale(1.1);
}
#division-pie-chart .ct-label {
fill: white;
}
@media (max-width: 500px) {
.charts-row {
flex-wrap: wrap;
}
}
input[type='number'] {
appearance: textfield;
}
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
appearance: none;
margin: 0;
}
h2 {
font-size: 1rem;
line-height: 1.3;
}
#constituency-results {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
#constituency-results::after {
content: '';
flex: auto;
max-width: 26rem;
margin: 0.5rem 0;
padding: 0.5rem 1rem;
border: 1px solid white;
}
.constituency {
display: flex;
flex-wrap: wrap;
max-width: 26rem;
margin: 0.5rem 0;
padding: 0.5rem 1rem;
border: 1px solid grey;
}
.constituency-data {
width: 11rem;
}
.constituency table {
margin-left: 1rem;
}
.constituency p,
.constituency td {
font-size: 14px;
}
.constituency td:last-child {
width: 2rem;
padding-left: 1rem;
text-align: right;
}
#support-form table {
margin: 1rem auto 0;
}
#support-form button {
display: block;
margin: 1rem auto 2.5rem;
font-weight: bold;
}
#support-form input {
width: 3.5rem;
padding: 0.25rem;
margin: 0 0.25rem 0 0.5rem;
text-align: right;
}
#support-form table td,
#support-form table th {
height: 2rem;
}
#support-form table td:nth-child(2) {
white-space: nowrap;
}
#support-form table td:last-child {
text-align: right;
}
.ct-series-a .ct-bar,
.ct-series-a .ct-slice-donut {
stroke: #56e;
}
.ct-series-b .ct-bar,
.ct-series-b .ct-slice-donut {
stroke: #eb4;
}
.ct-series-c .ct-bar,
.ct-series-c .ct-slice-donut {
stroke: #d44;
}
.ct-series-d .ct-bar,
.ct-series-d .ct-slice-donut {
stroke: #1c6;
}
.ct-series-e .ct-bar,
.ct-series-e .ct-slice-donut {
stroke: #655;
}

Wyświetl plik

@ -1,10 +0,0 @@
.constituency
.constituency-data
h2 Okręg #{number} #{name}
p Łącznie #{size} mandatów
table
each datum in data
tr
td #{datum.committee}
td #{datum.mandates}

Wyświetl plik

@ -1,71 +0,0 @@
p.
Przeliczanie sondażowych wyników poparcia dla partii na uzyskane mandaty w Sejmie nie jest
łatwe. Zgodnie z obecnie obowiązującą w Polsce ordynacją wyborczą głosy na poszczególne
komitety są przeliczane na mandaty metodą DHondta osobno w każdym z 41 okręgów. Symulacja
podziału mandatów przy założeniu takiego samego wyniku we wszystkich okręgach jest bardzo
niedokładna, bowiem różnice w rozkładzie poparcia w poszczególnych okręgach mają istotne
przełożenie na uzyskiwane mandaty.
p.
Poniższy kalkulator próbuje rozwiązać ten problem poprzez symulację zróżnicowanego poparcia
partii w okręgach na podstawie szczegółowych wyników wyborów do Sejmu w 2015 roku.
Ugrupowanie, które w danym okręgu miało wtedy poparcie wyższe/niższe niż w całym kraju,
również w tej symulacji będzie miało w tym okręgu odpowiednio wyższe/niższe poparcie. Pozwala
to na sporządzenie szczegółowej prognozy podziału mandatów na poziomie poszczególnych okręgów.
p.
Oczywiście problemem pozostaje ustalenie przepływów elektoratu między ugrupowaniami
startującymi w 2015 roku a obecnymi. Można to zrobić jedynie w mocno przybliżony sposób.
W przypadku PiS-u odpowiednikiem z poprzednich wyborów jest ten sam komitet. Dla pozostałych
komitetów zastosowano następujące odpowiedniki: KO ≈ PO + Nowoczesna; Lewica ≈ Zjednoczona
Lewica + Razem; PSL ≈ PSL + ½ Kukiz15; Konfederacja ≈ KORWiN + ½ Kukiz15.
form#support-form
table
tr
th Komitet
th Poparcie
th Mandaty
tr(class='pis')
td
label(for='pis') Prawo i Sprawiedliwość
td
input(type='number' step='any' id='pis' name='pis')
| %
td
tr(class='ko')
td
label(for='ko') Koalicja Obywatelska
td
input(type='number' step='any' id='ko' name='ko')
| %
td
tr(class='lewica')
td
label(for='lewica') SLD – Lewica
td
input(type='number' step='any' id='lewica' name='lewica')
| %
td
tr(class='psl')
td
label(for='psl') PSL – Koalicja Polska
td
input(type='number' step='any' id='psl' name='psl')
| %
td
tr(class='konfederacja')
td
label(for='konfederacja') Konfederacja
td
input(type='number' step='any' id='konfederacja' name='konfederacja')
| %
td
tr(class='mn')
td Mniejszość Niemiecka
td
td
button#calculate-button Oblicz
.charts-row
#support-bar-chart.ct-chart.ct-perfect-fourth
#division-pie-chart.ct-chart.ct-perfect-fourth
#constituency-results

Wyświetl plik

@ -1,10 +0,0 @@
doctype html
html(lang='pl')
head
title Kalkulator mandatów w wyborach do Sejmu
meta(charset="UTF-8")
body
div.container
h1.main-heading Kalkulator mandatów w wyborach do Sejmu 2019
include content.pug

Wyświetl plik

@ -1,21 +0,0 @@
type PastCommiteeId = 'pis' | 'po' | 'razem' | 'korwin' | 'psl' | 'zl' | 'k15' | 'nowoczesna'
export type PastSupport = {
[pastCommitteeId in PastCommiteeId]: number;
}
export type Committee = {
id: string;
name: string;
shortName: string;
threshold: number;
pastSupportEquivalence: [PastCommiteeId, number][];
}
export type Constituency = {
name: string;
size: number;
pastSupport: PastSupport;
support?: number[];
mandates?: number[];
}

Wyświetl plik

@ -1,11 +0,0 @@
{
"compilerOptions": {
"outDir": "./dist/",
"strict": true,
"module": "es6",
"target": "es5",
"allowJs": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true
}
}

Wyświetl plik

@ -1,81 +0,0 @@
import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import LiveReloadPlugin from 'webpack-livereload-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import StyleLintPlugin from 'stylelint-webpack-plugin';
export default {
entry: './src/index.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['.ts', '.js', '.json'],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.ts$/,
exclude: /node_modules/,
enforce: 'pre',
use: {
loader: 'eslint-loader',
options: {
configFile: __dirname + '/.eslintrc.json',
},
}
},
{
test: /\.pug$/,
exclude: /node_modules/,
use: 'pug-loader',
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {importLoaders: 1},
},
{
loader: 'postcss-loader',
options: {
config: {
path: __dirname + '/postcss.config.js',
},
},
},
],
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/templates/index.pug',
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
new StyleLintPlugin({
configFile: path.resolve(__dirname, '.stylelintrc.json'),
context: path.resolve(__dirname, './src'),
files: '**/*.css',
failOnError: false,
quiet: false,
}),
new LiveReloadPlugin({
appendScriptTag: true
}),
],
};