Add constituency map

pull/15/head
Michał Górny 2023-10-10 12:16:45 +02:00
rodzic 8f91e48048
commit d74f6d567e
9 zmienionych plików z 206 dodań i 61 usunięć

Wyświetl plik

@ -17,5 +17,6 @@ module.exports = {
'^.+\\.[jt]s$': 'ts-jest',
'\\.(pug)$': 'jest-transform-pug',
'.+\\.(css)$': 'jest-transform-stub',
'^.+\\.svg$': 'jest-transform-stub',
},
};

Wyświetl plik

@ -1,8 +1,10 @@
import {BarChart, PieChart, Svg} from 'chartist';
import {benchSort, committees, constituencies} from './data';
import calculateMandates from './mandates';
import constituencyResultsTemplate from './templates/cresults.pug';
import constituencyTemplate from './templates/constituency.pug';
import tableTemplate from './templates/table.pug';
import constituenciesMap from './images/c41.svg';
import './styles/styles.css';
const {location} = window;
@ -33,7 +35,7 @@ export const clearResults = (): void => {
document.getElementById('support-bar-chart')!.innerHTML = '';
document.getElementById('division-pie-chart')!.innerHTML = '';
const constituencyResultContainer = document.getElementById('constituency-results');
if (constituencyResultContainer) constituencyResultContainer.innerHTML = '';
if (constituencyResultContainer) constituencyResultContainer.innerHTML = constituencyResultsTemplate();
if (location.search) {
const urlWithoutSearchString = location.href.split('?')[0];
window.history.pushState('', '', urlWithoutSearchString);
@ -126,21 +128,57 @@ const displayPieChart = (mandates: number[]) => {
const displayConstituencyResults = () => {
const container = document.getElementById('constituency-results');
if (container) {
constituencies.forEach((constituency, constituenyIndex) => {
const data = (constituency.mandates && constituency.support)
? constituency.mandates.map((mandates, committeeIndex) => ({
committee: committees[committeeIndex].name,
support: (constituency.support as number[])[committeeIndex],
mandates,
}))
: [];
data.sort((a, b) => b.support - a.support);
container.insertAdjacentHTML('beforeend', constituencyTemplate({
number: constituenyIndex + 1,
name: constituency.name,
size: constituency.size,
data,
}));
container.innerHTML = constituencyResultsTemplate();
const constituencyResult = document.getElementById('constituency-result')!;
const mapObject = document.getElementById('constituencies-map')! as HTMLObjectElement;
mapObject.setAttribute('data', constituenciesMap);
mapObject.addEventListener('load', () => {
const svgDocument = mapObject.contentDocument!;
const constituencyNumber = svgDocument.getElementById('constituency-number')!;
const constituencyName = svgDocument.getElementById('constituency-name')!;
const paths = svgDocument.querySelectorAll<SVGPathElement>('svg path');
paths.forEach((path) => {
const cid = parseInt(path.dataset.cid!, 10);
const constituency = constituencies[cid - 1];
const data = (constituency.mandates && constituency.support)
? constituency.mandates.map((mandates, committeeIndex) => ({
committee: committees[committeeIndex],
support: (constituency.support as number[])[committeeIndex],
mandates,
}))
: [];
data.sort((a, b) => b.support - a.support);
if (data[0].support === data[1].support) {
path.style.fill = 'lightgray';
} else {
path.classList.add(data[0].committee.id);
if (data[0].support >= 50) path.classList.add('bright50');
else if (data[0].support < 40) path.classList.add('bright30');
}
path.addEventListener('mouseover', (event) => {
const pathElement = event.target as SVGPathElement;
pathElement.style.stroke = '#444';
constituencyNumber.innerHTML = `Okręg nr ${pathElement.dataset.cid}`;
constituencyName.innerHTML = pathElement.dataset.cname as string;
});
path.addEventListener('mouseout', (event) => {
const pathElement = event.target as SVGPathElement;
pathElement.style.stroke = '#fff';
constituencyNumber.innerHTML = '';
constituencyName.innerHTML = '';
});
path.addEventListener('click', (event) => {
(event.target as SVGPathElement).style.stroke = '#ccc';
constituencyResult.innerHTML = constituencyTemplate({
number: cid,
name: constituency.name,
size: constituency.size,
data,
});
});
});
});
}
};

53
src/images/c41.svg 100644

File diff suppressed because one or more lines are too long

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 225 KiB

Wyświetl plik

@ -7,7 +7,8 @@ body {
font-size: 15px;
}
.container {
main,
footer {
width: 100%;
max-width: 58rem;
margin: 1rem auto;
@ -21,6 +22,10 @@ body {
padding: 0.25rem auto 1rem;
}
.updates-texts {
font-size: 13.5px;
}
.updates {
margin-top: -10px;
list-style-type: none;
@ -44,6 +49,8 @@ li {
display: flex;
height: auto;
margin-bottom: 1rem;
z-index: -1;
pointer-events: none;
}
.ct-chart:empty {
@ -90,40 +97,48 @@ h2 {
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-result {
flex: 1;
}
#constituency-result .info {
margin-top: 32px;
text-align: center;
}
#constituencies-map {
flex: 1;
max-width: min(438px, 90vw);
}
.constituency {
display: flex;
flex-wrap: wrap;
max-width: 26rem;
margin: 0.5rem 0;
max-width: 25rem;
margin: 0.5rem auto;
padding: 0.5rem 1rem;
border: 1px solid grey;
}
.constituency-data {
width: 11rem;
}
.constituency table {
margin-left: 1rem;
border-collapse: collapse;
}
.constituency p,
.constituency th,
.constituency td {
font-size: 14px;
}
.constituency th,
.constituency td {
padding: 4px 12px;
border: 1px solid #888;
text-align: left;
}
.constituency th:nth-child(2),
.constituency th:last-child,
.constituency td:nth-child(2),
.constituency td:last-child {
width: 2rem;
padding-left: 1rem;
text-align: right;
}
@ -149,36 +164,55 @@ h2 {
height: 2rem;
}
#support-form table td:nth-child(2) {
white-space: nowrap;
}
#support-form table td:last-child {
text-align: right;
}
:root {
--pis: #31469b;
--ko: #fca43f;
--lewica: #d44;
--td: #8bd32e;
--konfederacja: #655;
--mn: #aaa;
}
.pis {
stroke: #263778;
stroke: var(--pis);
fill: var(--pis);
}
.ko {
stroke: #fca43f;
stroke: var(--ko);
fill: var(--ko);
}
.lewica {
stroke: #d44;
stroke: var(--lewica);
fill: var(--lewica);
}
.td {
stroke: #8bd32e;
stroke: var(--td);
fill: var(--td);
}
.konfederacja {
stroke: #655;
stroke: var(--konfederacja);
fill: var(--konfederacja);
}
.mn {
stroke: #aaa;
stroke: var(--mn);
fill: var(--mn);
}
.bright30 {
filter: brightness(125%);
}
.bright50 {
filter: brightness(75%);
}
.bar-value {
@ -189,7 +223,7 @@ footer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 0.5rem 1rem;
padding: 1rem 1.5rem;
}
address {

4
src/svg.ts 100644
Wyświetl plik

@ -0,0 +1,4 @@
declare module '*.svg' {
const content: string;
export default content;
}

Wyświetl plik

@ -1,10 +1,14 @@
.constituency
.constituency-data
h2 Okręg #{number} #{name}
p Łącznie #{size} mandatów
h2 Okręg #{number} #{name}
table
tr
th Komitet
th Poparcie
th Mandaty
each datum in data
tr
td #{datum.committee}
td #{datum.committee.name}
td #{datum.support.toLocaleString('pl', {minimumFractionDigits: 1, maximumFractionDigits: 1})}%
td #{datum.mandates}
p Łącznie #{size} mandatów

Wyświetl plik

@ -1,4 +1,4 @@
div(class=(embed ? 'container embed' : 'container'))
main(class=(embed ? 'embed' : ''))
unless embed
h1 Kalkulator mandatów w wyborach do Sejmu
@ -12,8 +12,8 @@ div(class=(embed ? 'container embed' : 'container'))
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 Aktualizacje:
ol.updates
p.updates-texts Aktualizacje:
ol.updates.updates-texts
li.
2019-11-15: od teraz w prognozie brane są pod uwagę wyniki wyborów do Sejmu z 2019 roku.
li.
@ -37,6 +37,7 @@ div(class=(embed ? 'container embed' : 'container'))
unless embed
#constituency-results
footer
a.github(href='https://github.com/drastus/sejm-calculator') Kod źródłowy
address Kontakt: zrchos na serwerze gmail.com
unless embed
footer
a.github(href='https://github.com/drastus/sejm-calculator') Kod źródłowy
address Kontakt: zrchos na serwerze gmail.com

Wyświetl plik

@ -0,0 +1,4 @@
object(id="constituencies-map")
#constituency-result
p.info
em Kliknij okręg, by zobaczyć szczegółowe wyniki.

Wyświetl plik

@ -27,6 +27,16 @@ export default {
exclude: /node_modules/,
use: '@webdiscus/pug-loader',
},
{
test: /\.svg$/,
type: 'asset/resource',
generator: {
filename: (name: {filename: string}) => {
const filePath = name.filename.split('/').slice(1, -1).join('/');
return `${filePath}/[name][ext]`;
},
},
},
{
test: /\.css$/,
exclude: /node_modules/,
@ -65,11 +75,7 @@ export default {
devServer: {
watchFiles: ['src/**/*'],
client: {
overlay: {
warnings: false,
errors: true,
runtimeErrors: true,
},
overlay: false,
},
},
};