Skip to content

Commit

Permalink
Merge branch 'feature/ltc-facilities-map' of https://github.com/COVID…
Browse files Browse the repository at this point in the history
…19tracking/website into feature/ltc-facilities-map
  • Loading branch information
kevee committed Feb 18, 2021
2 parents 581443c + 1579c64 commit 7e8c47d
Show file tree
Hide file tree
Showing 20 changed files with 508 additions and 96 deletions.
60 changes: 60 additions & 0 deletions src/components/charts/chart-legend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react'
import classnames from 'classnames'

import { Col } from '~components/common/grid'

import styles from './chart-legend.module.scss'

const ChartLegend = ({
legendColors,
categories,
selectedItem,
setSelectedItem,
legendNames,
}) => {
/**
* Gets the appropriate classes for a legend item, based on the
* item's category name.
*/
const getCategoryStyles = categoryName => {
if (selectedItem && categoryName === selectedItem) {
return classnames(styles.category, styles.activeCategory)
}
return styles.category
}

return (
<Col width={[4, 6, 6]} className={styles.columnWrapper}>
<div className={styles.legend}>
{categories.map(category => (
<button
className={getCategoryStyles(category)}
onClick={() => setSelectedItem(category)}
type="button"
>
<div
style={{ 'background-color': legendColors[category] }}
className={styles.swatch}
/>
{legendNames[category]}
</button>
))}
{selectedItem ? (
<button
onClick={() => setSelectedItem(null)}
type="button"
className={styles.resetButton}
>
Clear filter
</button>
) : (
// this is a placeholder for the reset button so that the page doesn't
// jump when selectedItem goes from null to not null
<div className={styles.resetButton}> </div>
)}
</div>
</Col>
)
}

export default ChartLegend
56 changes: 56 additions & 0 deletions src/components/charts/chart-legend.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.column-wrapper {
margin: 0 auto;
}

.legend {
@media (min-width: $viewport-md) {
display: grid;
grid-template-columns: auto auto;
grid-auto-rows: 1fr;
grid-column-gap: 1rem;
grid-row-gap: 0.5rem;
justify-content: center;
align-items: center;
}

.category,
.reset-button {
border: none;
background: inherit;
cursor: pointer;
}

.category {
display: flex;
align-items: center;

@media (max-width: $viewport-lg) {
@include margin(0, right);
@include margin(16, bottom);
}

@include margin(32, right);
text-align: left;

&:last-child {
@include margin(0, right);
}

.swatch {
flex-shrink: 0;
@include margin(8, right);
width: 12px;
height: 12px;
}
}

.active-category {
font-weight: bold;
}

.reset-button {
color: $color-slate-700;
text-decoration: underline;
grid-column: span 2;
}
}
59 changes: 52 additions & 7 deletions src/components/charts/line-chart.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { Fragment } from 'react'
import React, { Fragment, useState } from 'react'

import { extent, max } from 'd3-array'
import { scaleLinear, scaleTime } from 'd3-scale'
import { line, curveCardinal } from 'd3-shape'
import { timeMonth, timeDay } from 'd3-time'

import Tooltip from './tooltip'

import { formatDate, formatNumber } from '~utilities/visualization'

import chartStyles from './charts.module.scss'
Expand All @@ -24,6 +26,7 @@ const LineChart = ({
yTicks,
lastXTick,
perCapLabel,
renderTooltipContents,
}) => {
const totalXMargin = marginLeft + marginRight
const totalYMargin = marginTop + marginBottom
Expand All @@ -37,6 +40,32 @@ const LineChart = ({
})
})

const [tooltip, setTooltip] = useState(null)
const [timeoutRef, setTimeoutRef] = useState(null)

const hover = (event, dataLine) => {
// Ensure that tooltip doesn't flash when transitioning between bars
if (timeoutRef) {
clearTimeout(timeoutRef)
}
const isTouchEvent = !event.clientX
const eventX = isTouchEvent ? event.touches[0].clientX : event.clientX
const eventY = isTouchEvent ? event.touches[0].clientY : event.clientY

setTooltip({
top: isTouchEvent ? eventY - 130 : eventY + 10,
left: isTouchEvent ? eventX - 80 : eventX + 5,
d: dataLine,
})
}

const mouseOut = () => {
if (timeoutRef) {
clearTimeout(timeoutRef)
}
setTimeoutRef(setTimeout(() => setTooltip(null), 200))
}

const dateDomain = extent(dates)

const xScaleTime = scaleTime()
Expand Down Expand Up @@ -159,17 +188,33 @@ const LineChart = ({
{data && (
<>
{data.map(dataLine => (
<path
d={lineFn(dataLine.data)}
stroke={dataLine.color}
strokeWidth={dataLine.stroke}
fill="none"
/>
<>
<path
d={lineFn(dataLine.data)}
stroke={dataLine.color}
strokeWidth={dataLine.stroke}
fill="none"
/>
{/* Add a wider hidden path for tooltips. */}
<path
d={lineFn(dataLine.data)}
stroke="transparent"
strokeWidth={6}
fill="none"
onMouseOver={event => hover(event, dataLine)}
onFocus={event => hover(event, dataLine)}
onMouseOut={mouseOut}
onBlur={mouseOut}
/>
</>
))}
</>
)}
</g>
</svg>
{renderTooltipContents && tooltip && (
<Tooltip {...tooltip}>{renderTooltipContents(tooltip.d)} </Tooltip>
)}
</>
)
}
Expand Down
1 change: 0 additions & 1 deletion src/components/charts/multi-line-chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,5 @@ const MultiLineChart = ({
</>
)
}
// todo don't just use red

export default MultiLineChart
5 changes: 5 additions & 0 deletions src/components/pages/blog/blog-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,14 @@ const BlogContent = ({ content }) => {
fullWidthMobile,
imageLink,
} = target
const longCaption =
target.childContentfulContentBlockImageLongCaptionTextNode &&
target.childContentfulContentBlockImageLongCaptionTextNode
.childMarkdownRemark.rawMarkdownBody
return (
<ImageContentBlock
image={image}
longCaption={longCaption}
caption={caption}
keepSize={keepSize}
fullWidthMobile={fullWidthMobile}
Expand Down
13 changes: 12 additions & 1 deletion src/components/pages/blog/content-blocks/image-content-block.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import classnames from 'classnames'
import Img from 'gatsby-image'
import marked from 'marked'
import ImageCredit from '~components/common/image-credit'
import imageContentBlockStyles from './image-content-block.module.scss'

Expand All @@ -27,6 +28,7 @@ const ImageContentBlock = ({
caption,
image,
className,
longCaption = false,
keepSize = false,
fullWidthMobile = false,
imageUrl,
Expand Down Expand Up @@ -56,7 +58,16 @@ const ImageContentBlock = ({
<ImageBlock image={image} imageUrl={imageUrl} keepSize={keepSize} />
)}

{caption && <ImageCredit>{caption}</ImageCredit>}
{caption && !longCaption && <ImageCredit>{caption}</ImageCredit>}
{longCaption && (
<ImageCredit>
<div
dangerouslySetInnerHTML={{
__html: marked.inlineLexer(longCaption, []),
}}
/>
</ImageCredit>
)}
</div>
)

Expand Down
9 changes: 4 additions & 5 deletions src/components/pages/race/dashboard/table.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react'
import { Link } from 'gatsby'
import Tooltip from '~components/common/tooltip'
import { Table, Th, Td } from '~components/common/table'

import NoDataAlert from '../no-data-alert'
import Percent from './percent'
import { Notes, DisparitySymbol, TooltipContent } from './table-symbols'

import tooltipDisparityIcon from '~images/race-dashboard/tooltip-disparity-icon.svg'
import alertBang from '~images/race-dashboard/alert-bang-orange.svg'
import stateTableStyle from './table.module.scss'
Expand Down Expand Up @@ -113,10 +115,7 @@ const StateTableDataCell = ({
if (index === 0) {
return (
<Td rowspan={rowCount} additionalClass={stateTableStyle.missingData}>
<span>
{state} does not report {type.toLowerCase()} data for {errorType}.{' '}
<Link to="/race/get-better-data">Help us get better data.</Link>
</span>
<NoDataAlert state={state} dataType={type} metric={errorType} />
</Td>
)
}
Expand Down
11 changes: 11 additions & 0 deletions src/components/pages/race/no-data-alert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'
import { Link } from 'gatsby'

const NoDataAlert = ({ state, dataType, metric }) => (
<span>
{state} does not report {dataType.toLowerCase()} data for {metric}.{' '}
<Link to="/race/get-better-data">Help us get better data.</Link>
</span>
)

export default NoDataAlert
46 changes: 46 additions & 0 deletions src/components/pages/state/race-ethnicity/chart-section.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'

import { Col } from '~components/common/grid'
import ChartLegend from '~components/charts/chart-legend'

import styles from './chart-section.module.scss'

const ChartSection = ({
title,
children,
legendCategories,
selectedItem,
setSelectedItem,
legendColors,
legendRef,
}) => {
const categoryNames = {
White: 'White',
Black: 'Black or African American',
LatinX: 'Hispanic or Latino',
Asian: 'Asian',
AIAN: 'American Indian and Alaskan Native',
NHPI: 'Native Hawaiian and Other Pacific Islander',
Ethnicity_Hispanic: 'Hispanic or Latino',
Ethnicity_NonHispanic: 'Not Hispanic or Latino',
}
return (
<div className={styles.chartSection}>
<h3 className={styles.chartSectionTitle}>{title}</h3>
<Col width={[4, 4, 6]} className={styles.column}>
{children}
</Col>
<div ref={legendRef}>
<ChartLegend
legendColors={legendColors}
categories={legendCategories}
selectedItem={selectedItem}
setSelectedItem={setSelectedItem}
legendNames={categoryNames}
/>
</div>
</div>
)
}

export default ChartSection
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.chart-section > div > svg {
width: 50%;
margin: 0 auto;
display: block;
}

.chart-section-title {
@include type-size(400);
text-align: center;
@include margin(0, bottom);
}

.column {
margin: 0 auto;

text {
// The axis labels get very large on big screens without this rule.
font-size: 9px; // ignore-style-rule
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
text-align: center;
@include padding(16, bottom);
@include margin(32, bottom);
margin-top: -28px; // ignore-style-rule

@media (max-width: $viewport-lg) {
@include margin(8, top);
Expand Down
Loading

0 comments on commit 7e8c47d

Please sign in to comment.