Skip to content

Commit 6970365

Browse files
feat(Pilkada2024): color boundaries by margin-of-victory & UI improvements (#78)
1 parent c40fd98 commit 6970365

File tree

2 files changed

+51
-19
lines changed

2 files changed

+51
-19
lines changed

modules/Pilkada2024/BoundaryLayers.tsx

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export type BoundaryLayersProps = {
1919
code: string
2020
}
2121

22+
const MIN_OPACITY = 0.1
23+
const MAX_OPACITY = 0.7
24+
2225
export default function BoundaryLayers({
2326
election,
2427
code: parentCode,
@@ -56,22 +59,41 @@ export default function BoundaryLayers({
5659
{childAreas.map((_childArea) => {
5760
const votes = getVotesByArea(_childArea.code)
5861

59-
// Calculate the winner
60-
const winner = Object.keys(candidates).reduce((acc, id) => {
61-
if (votes[id] > votes[acc]) {
62-
return id
63-
}
64-
return acc
65-
})
62+
// Prepare numeric votes for sorting
63+
const candidateIds = Object.keys(candidates)
64+
const numericVotes = candidateIds.map((id) => ({
65+
id,
66+
val: votes[id],
67+
}))
68+
69+
// Sort descending to get winner and runner-up
70+
numericVotes.sort((a, b) => b.val - a.val)
71+
const winnerId = numericVotes[0]?.id
72+
const winnerVal = numericVotes[0].val
73+
const runnerUpVal = numericVotes[1]?.val ?? 0
74+
75+
// Total numeric votes
76+
const total = numericVotes.reduce((s, x) => s + x.val, 0)
77+
78+
// Compute margin = winnerShare - runnerUpShare, in [0,1]
79+
const winnerShare = winnerVal / total
80+
const runnerUpShare = runnerUpVal / total
81+
const margin = Math.max(0, winnerShare - runnerUpShare)
82+
83+
// Emphasize large margins using power > 1 (exponent = 2)
84+
const EXPONENT = 2
85+
const transformed = Math.max(0, Math.min(1, margin)) ** EXPONENT
6686

6787
return (
6888
<AreaBoundary
6989
area={childArea}
7090
key={_childArea.code}
7191
code={_childArea.code}
7292
pathOptions={{
73-
color: `var(--chart-${candidates[winner].nomor_urut})`,
74-
fillOpacity: 0.3,
93+
color: `var(--chart-${candidates[winnerId].nomor_urut})`,
94+
fillColor: `var(--chart-${candidates[winnerId].nomor_urut})`,
95+
fillOpacity:
96+
MIN_OPACITY + (MAX_OPACITY - MIN_OPACITY) * transformed,
7597
}}
7698
eventHandlers={{
7799
add: (e) => {

modules/Pilkada2024/Sidebar.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
'use client'
22

33
import { EraserIcon, LoaderCircleIcon } from 'lucide-react'
4+
import Link from 'next/link'
45
import { useState } from 'react'
56
import { toast } from 'sonner'
67
import { Combobox } from '@/components/Combobox'
78
import ComboboxArea from '@/components/ComboboxArea'
9+
import GitHubIcon from '@/components/icons/GitHubIcon'
810
import { Button } from '@/components/ui/button'
911
import { config } from '@/lib/config'
1012
import { Area } from '@/lib/const'
@@ -115,16 +117,24 @@ export default function Sidebar() {
115117
/>
116118
)}
117119

118-
<Button
119-
variant="outline"
120-
className="mt-auto items-center"
121-
onClick={() => {
122-
clear()
123-
}}
124-
>
125-
<EraserIcon />
126-
Clear all results
127-
</Button>
120+
{seleted && (
121+
<Button variant="outline" className="mt-2 items-center" onClick={clear}>
122+
<EraserIcon />
123+
Clear all results
124+
</Button>
125+
)}
126+
127+
<span className="text-xs text-foreground/60 mt-4 flex flex-wrap justify-center items-center">
128+
Data from:
129+
<Link
130+
href="https://github.com/razanfawwaz/pilkada-scrap"
131+
target="_blank"
132+
className="inline-flex justify-center items-center ml-1 gap-1 underline"
133+
>
134+
<GitHubIcon className="w-4 h-4" />
135+
razanfawwaz/pilkada-scrap
136+
</Link>
137+
</span>
128138
</div>
129139
)
130140
}

0 commit comments

Comments
 (0)