File size: 2,125 Bytes
867080c b4a0c57 7cdde63 92b2164 00e463a 867080c 00e463a b4a0c57 00e463a 867080c 00e463a 867080c b4a0c57 867080c 00e463a 867080c 7cdde63 867080c 7cdde63 00e463a 867080c 00e463a 7cdde63 00e463a 7cdde63 00e463a 867080c 00e463a 867080c 7cdde63 867080c b4a0c57 867080c |
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 |
import { useRef, useEffect, useState } from 'react'
import * as Plot from '@observablehq/plot'
const smoothProgressBar = fraction => {
const blocks = ['β', 'β', 'β', 'β', 'β', 'β', 'β', 'β']
const width = 10
const totalUnits = width * 8
const filledUnits = Math.round(fraction * totalUnits)
const fullBlocks = Math.floor(filledUnits / 8)
const remainder = filledUnits % 8
return ('β'.repeat(fullBlocks) + (remainder > 0 ? blocks[remainder - 1] : '')) || 'β'
}
const makeTitle = data => d => {
const languages = data.countries[
d.properties?.ISO_A2_EH
]?.languages.toSorted((a, b) => b.population - a.population)
const pop = languages
?.map(a => a.population)
.reduce((prev, a) => prev + a, 0)
const langstring =
languages
?.slice(0, 10)
.map(a => `${smoothProgressBar(a.population / pop)} ${a.name}`)
.join('\n\n') + (languages?.length > 10 ? `\n\n...` : '')
return `${d.properties.ADMIN}\n\n${langstring}`
}
const WorldMap = ({ data }) => {
const containerRef = useRef()
const [mapData, setMapData] = useState()
useEffect(() => {
fetch('/world.geo.json')
.then(res => res.json())
.then(setMapData)
}, [])
useEffect(() => {
if (mapData === undefined) return
const countries = mapData
const plot = Plot.plot({
width: 750,
height: 500,
projection: 'equal-earth',
marks: [
Plot.geo(countries, {
fill: d => data.countries[d.properties?.ISO_A2_EH]?.score,
title: makeTitle(data),
tip: true
})
],
color: {
scheme: 'Greens',
unknown: 'gray',
label: 'Score',
legend: true,
domain: [0, 0.5]
},
style: {
fontFamily: 'monospace'
}
})
containerRef.current.append(plot)
return () => plot.remove()
}, [mapData])
return (
<div
ref={containerRef}
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
/>
)
}
export default WorldMap
|