Skip to content

Commit

Permalink
feat(OurMap): implements choropleth option
Browse files Browse the repository at this point in the history
  • Loading branch information
JayWelsh committed Mar 20, 2020
1 parent 3398989 commit 0c0fd7b
Show file tree
Hide file tree
Showing 8 changed files with 33,162 additions and 81 deletions.
7 changes: 7 additions & 0 deletions gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
window.addEventListener('resize', () => {
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
});

let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
175 changes: 165 additions & 10 deletions src/components/OurMap.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,201 @@
import React, { Fragment, useState } from 'react'
import { Map, TileLayer, Tooltip, Popup, CircleMarker, withLeaflet } from 'react-leaflet'
import React, { useState, useEffect } from 'react'
import { Map, TileLayer, Tooltip, CircleMarker, GeoJSON } from 'react-leaflet'
import Control from './LeafletControl';
import Fab from '@material-ui/core/Fab';
import DarkModeIcon from '@material-ui/icons/Brightness3';
import LightModeIcon from '@material-ui/icons/Brightness5';
import BubbleChartIcon from '@material-ui/icons/BubbleChart';
import BorderChartIcon from '@material-ui/icons/GridOn';
import styled from 'styled-components';
import Typography from '@material-ui/core/Typography';
import Paper from '@material-ui/core/Paper';

import SouthAfrica from "../south-africa-metadata.json";
import geojson from '../json/south-africa-geojson.json';
import { isConsideredMobile } from "../utils";

const MapBackgroundProvider = styled.div`
& > .leaflet-container {
background-color: ${props => props.darkMode ? "rgb(38, 38, 38)!important" : "#d5e8eb!important"};
}
`

export const OurMap = ({ options, markers = [] }) => {
const LegendColorSquare = styled.div`
height: 15px;
width: 15px;
margin-right: 5px;
background-color: ${props => props.color};
display: inline-block;
`

let position = [-28.738176, 24.767929];
let options = {
style: {
height: isConsideredMobile() ? 'calc(var(--vh, 1vh) * 100 - 56px)' : 'calc(var(--vh, 1vh) * 100 - 64px)',
width: '100%',
},
center: position,
zoom: isConsideredMobile() ? 4.5 : 6,
minZoom: isConsideredMobile() ? 4.5 : 5.5,
maxZoom: 8,
zoomSnap: 0.5,
}

export const OurMap = ({ groupedByProvince }) => {

let [markers, setMarkers] = useState(false);
let [darkMode, setDarkMode] = useState(true);
let [bubbleChart, setBubbleChart] = useState(true);

useEffect(() => {
let markers = [];
let maxRadius = isConsideredMobile() ? 20 : 50;
let minRadius = isConsideredMobile() ? 10 : 15;
let radiusDelta = maxRadius - minRadius;
let reachMaxRadiusAt = 61;
let { provinces } = SouthAfrica;
for (let province of Object.keys(provinces)) {
if (groupedByProvince[province]) {
let provinceCaseCount = groupedByProvince[province].length;
let setRadius = minRadius + (((provinceCaseCount * 100 / reachMaxRadiusAt) / 100) * radiusDelta);
markers.push({
position: provinces[province].position,
color: "#ff0081",
radius: setRadius,
tooltipText: (
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<sup>{provinces[province].name}</sup><br />
<b>{provinceCaseCount}</b> {provinceCaseCount > 1 ? "Cases" : "Case"}
</Typography>
)
})
} else {
markers.push({
position: provinces[province].position,
color: "green",
radius: minRadius,
tooltipText: (
<h3 class="white-monospace line-height-1 no-margin normal-font-weight">
<sup>{provinces[province].name}</sup><br />
<b>0</b> Cases
</h3>
)
})
}
}
setMarkers(markers);
}, [groupedByProvince]);

const style = (feature) => {
return {
weight: 2,
opacity: 1,
color: darkMode ? 'white' : 'black',
dashArray: '3',
fillOpacity: 0.9,
fillColor: getColor(feature.properties.NAME_1)
};
}

const onEachFeature = (feature, layer) => {
if (feature.properties && feature.properties.NAME_1) {
let provinceCaseCount = 0;
let provinceName = feature.properties.NAME_1;
if(groupedByProvince[SouthAfrica.provinceNameToAbbreviation[provinceName]]) {
provinceCaseCount = groupedByProvince[SouthAfrica.provinceNameToAbbreviation[provinceName]].length;
}else{
provinceCaseCount = 0;
}
layer.bindTooltip(`<h3 class="white-monospace line-height-1 no-margin normal-font-weight"><sup>${feature.properties.NAME_1}</sup><br/><b>${provinceCaseCount}</b>${(provinceCaseCount > 1 || provinceCaseCount === 0) ? " Cases" : " Case"}</h3>`, {
sticky: true,
className: "our-tooltip white-monospace",
direction: "auto",
});
}
}

const getColor = (provinceName) => {
let infectionCount = 0;
if(groupedByProvince[SouthAfrica.provinceNameToAbbreviation[provinceName]]) {
infectionCount = groupedByProvince[SouthAfrica.provinceNameToAbbreviation[provinceName]].length;
}
return infectionCount > 250000 ? '#800026' :
infectionCount > 50000 ? '#bd0026' :
infectionCount > 15000 ? '#e31a1c' :
infectionCount > 5000 ? '#fc4e2a' :
infectionCount > 1000 ? '#fd8d3c' :
infectionCount > 250 ? '#feb24c' :
infectionCount > 50 ? '#fed976' :
infectionCount > 1 ? '#ffffcc' :
'darkgreen';
}

if (typeof window !== 'undefined') {
return (
<MapBackgroundProvider darkMode={darkMode}>
<Map {...options}>
<Control position="topright">
<div className="flex-column">
<Fab style={{marginBottom: '15px'}} onClick={() => setDarkMode(!darkMode)} aria-label="add">
{darkMode ? <LightModeIcon /> : <DarkModeIcon />}
</Fab>
<Fab onClick={() => setBubbleChart(!bubbleChart)} aria-label="add">
{bubbleChart ? <BorderChartIcon /> : <BubbleChartIcon />}
</Fab>
</div>
</Control>
{!bubbleChart &&
<Control position="bottomright">
<Paper style={{padding: '10px'}}>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#800026'}/>250k+
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#bd0026'}/>50k-250k
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#e31a1c'}/>15k-50k
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#fc4e2a'}/>5k-15k
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#fd8d3c'}/>1k-5k
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#feb24c'}/>250-1k
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#fed976'}/>50-250
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'#ffffcc'}/>1-50
</Typography>
<Typography className={"white-monospace line-height-1"} variant="h6" component="h2">
<LegendColorSquare color={'darkgreen'}/>0
</Typography>
</Paper>
</Control>
}
<TileLayer
attribution='Data by <a href="https://dsfsi.github.io/">dsfsi</a> | &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
url={darkMode ? 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png' : 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png'}
/>
{!bubbleChart && <GeoJSON style={style} data={geojson} onEachFeature={onEachFeature}/>}
{
markers && markers.map(marker => {
bubbleChart && markers && markers.map(marker => {
return (
<CircleMarker key={marker.position} center={marker.position} color={marker.color} radius={marker.radius}>
<Tooltip sticky className={"our-tooltip"}>{marker.tooltipText}</Tooltip>
</CircleMarker>
)
})
}
<Control position="topright">
<Fab onClick={() => setDarkMode(!darkMode)} aria-label="add">
{darkMode ? <LightModeIcon /> : <DarkModeIcon />}
</Fab>
</Control>
</Map>
</MapBackgroundProvider>
)
}
return null
}

export default withLeaflet(OurMap);
export default OurMap;
15 changes: 14 additions & 1 deletion src/components/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -650,10 +650,23 @@ pre tt:after {
}

.white-monospace {
color: white;
color: white!important;
font-family: monospace!important;
}

.flex-column {
display: flex;
flex-direction: column;
}

.no-margin {
margin: 0!important;
}

.normal-font-weight {
font-weight: normal!important;
}

.our-tooltip {
background-color: #232323!important;
border: 1px solid #000!important;
Expand Down
12 changes: 6 additions & 6 deletions src/components/leaflet.css
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@
will-change: opacity;
}
.leaflet-fade-anim .leaflet-popup {
/* opacity: 0;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear; */
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
Expand All @@ -189,15 +189,15 @@
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
/* -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1); */
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
/* -webkit-transition: none;
-webkit-transition: none;
-moz-transition: none;
transition: none; */
transition: none;
}

.leaflet-zoom-anim .leaflet-zoom-hide {
Expand Down
Loading

0 comments on commit 0c0fd7b

Please sign in to comment.