From 7ac352f88e7ef4c6499d8988a039d120865a9079 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 13:08:17 -0700 Subject: [PATCH 01/29] feat(crdt-historical): add util for getting per 100k metrics --- .../pages/state/race-ethnicity/utils/index.js | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/utils/index.js b/src/components/pages/state/race-ethnicity/utils/index.js index 326024e54..f01a2483f 100644 --- a/src/components/pages/state/race-ethnicity/utils/index.js +++ b/src/components/pages/state/race-ethnicity/utils/index.js @@ -1,7 +1,12 @@ import { useMemo } from 'react' import { formatDateToString } from '~components/utils/format' -const getAvailableMetricFields = (latestDay, prefix, raceOnly) => { +const getAvailableMetricFieldsBase = ( + latestDay, + prefix, + raceOnly, + per100kOnly = false, +) => { /** * Returns a list of all of the available metric fields. * raceOnly: returns only race values when true, only ethnicity @@ -11,7 +16,16 @@ const getAvailableMetricFields = (latestDay, prefix, raceOnly) => { Object.keys(latestDay).forEach(value => { if (value.startsWith(prefix) && !value.includes('Total')) { - listOfMetrics.push(value) + // Push to list if this is a per100k value and we're only adding + // per 100k values... + if (per100kOnly && value.endsWith('_per100k')) { + listOfMetrics.push(value) + } + + // Push to list if we're including all values... + if (!per100kOnly) { + listOfMetrics.push(value) + } } }) @@ -21,6 +35,14 @@ const getAvailableMetricFields = (latestDay, prefix, raceOnly) => { return listOfMetrics.filter(metric => metric.includes('Ethnicity')) } +const getAvailableMetricFields = (latestDay, prefix, raceOnly) => { + return getAvailableMetricFieldsBase(latestDay, prefix, raceOnly, false) +} + +const getAvailablePer100kMetricFields = (latestDay, prefix, raceOnly) => { + return getAvailableMetricFieldsBase(latestDay, prefix, raceOnly, true) +} + const formatTableValues = timeSeriesData => { /** * Adds the formattedDate field, adds asterisks for small numbers. @@ -140,6 +162,7 @@ const isCombined = (combined, separate) => { export { getAvailableMetricFields, + getAvailablePer100kMetricFields, formatTableValues, isCombined, addPer100kValues, From 1b99d6f60bdecd3dadb8bbc76e50c953aa48c6d0 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 13:09:35 -0700 Subject: [PATCH 02/29] feat(crdt-historical): use per100k values for charts also calculate the per100k values at the template level, pass to children --- .../pages/state/race-ethnicity/charts.js | 78 ++++++++++++------- .../pages/state/race-ethnicity/hero.js | 6 ++ .../state/race-ethnicity/historical-tables.js | 13 +--- src/templates/state/race-ethnicity.js | 28 +++++-- 4 files changed, 81 insertions(+), 44 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 57f486d3a..912d15926 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -2,16 +2,26 @@ import React, { useMemo } from 'react' import { DateTime } from 'luxon' import Chart from './chart' -import { getAvailableMetricFields } from './utils' +import { getAvailablePer100kMetricFields } from './utils' import styles from './charts.module.scss' import colors from '~scss/colors.module.scss' +const ChartsSection = ({ title, children }) => ( +
+

{title}

+ {children} + {/* todo put the legend here */} +
+) + const Charts = ({ timeSeriesData, currentMetric }) => { const getMetricData = (allData, metricTitle, metrics) => { /** Restructures a single metric's racial data (i.e. cases) for charts */ const completedData = {} // store the final metric data object + const suffixToRemove = '_per100k' + metrics.forEach(metric => { const metricTimeSeries = [] // create a time series array for each metric allData.forEach(day => { @@ -22,9 +32,17 @@ const Charts = ({ timeSeriesData, currentMetric }) => { }) }) // remove the 'Cases_' prefix from the metric - const cleanMetricTitle = metric.replace(`${metricTitle}_`, '') - // add this time series to the completed object - completedData[cleanMetricTitle] = metricTimeSeries + const cleanMetricTitle = metric + .replace(`${metricTitle}_`, '') + .replace(suffixToRemove, '') + + const casesToIgnore = ['Multiracial', 'Other', 'Unknown'] + + // If this is not in the list to ignore... + if (casesToIgnore.indexOf(cleanMetricTitle) === -1) { + // Add this time series to the completed object. + completedData[cleanMetricTitle] = metricTimeSeries + } }) return completedData @@ -37,22 +55,22 @@ const Charts = ({ timeSeriesData, currentMetric }) => { */ const computedChartData = useMemo(() => { const latestDay = allData[0] - const caseMetrics = getAvailableMetricFields( + const caseMetrics = getAvailablePer100kMetricFields( latestDay, 'Cases_', raceOnly, ) - const deathMetrics = getAvailableMetricFields( + const deathMetrics = getAvailablePer100kMetricFields( latestDay, 'Deaths_', raceOnly, ) - const hospMetrics = getAvailableMetricFields( + const hospMetrics = getAvailablePer100kMetricFields( latestDay, 'Hospitalizations_', raceOnly, ) - const testMetrics = getAvailableMetricFields( + const testMetrics = getAvailablePer100kMetricFields( latestDay, 'Tests_', raceOnly, @@ -97,26 +115,30 @@ const Charts = ({ timeSeriesData, currentMetric }) => { return (
- - + + + + + +
) } diff --git a/src/components/pages/state/race-ethnicity/hero.js b/src/components/pages/state/race-ethnicity/hero.js index 743dddbe4..e2c9d1b77 100644 --- a/src/components/pages/state/race-ethnicity/hero.js +++ b/src/components/pages/state/race-ethnicity/hero.js @@ -5,6 +5,7 @@ import MetricSelector from './metric-selector' import NotesAndDownloads from './notes-and-downloads' import DataAsOf from './data-as-of' import Sources from './sources' +import Charts from './charts' import styles from './hero.module.scss' @@ -111,6 +112,7 @@ const Hero = ({ currentMetric, setCurrentMetric, timeSeriesData, + completeTimeSeriesData, combinedNotes, separateNotes, combinedTestHosp, @@ -145,6 +147,10 @@ const Hero = ({ /> } /> + formatTableValues(completeTimeSeriesData), [completeTimeSeriesData], diff --git a/src/templates/state/race-ethnicity.js b/src/templates/state/race-ethnicity.js index c6fb1221f..3fa4729df 100644 --- a/src/templates/state/race-ethnicity.js +++ b/src/templates/state/race-ethnicity.js @@ -4,6 +4,7 @@ import { graphql } from 'gatsby' import Layout from '~components/layout' import Hero from '~components/pages/state/race-ethnicity/hero' import HistoricalTables from '~components/pages/state/race-ethnicity/historical-tables' +import { addPer100kValues } from '~components/pages/state/race-ethnicity/utils' const RaceEthnicityHistoricalTemplate = ({ pageContext, path, data }) => { const state = pageContext @@ -14,12 +15,27 @@ const RaceEthnicityHistoricalTemplate = ({ pageContext, path, data }) => { // false: showing numbers, true: showing rates per 100k const [usePer100kRate, setUsePer100kRate] = useState(true) + const populationData = data.covidAcsPopulation + const timeSeriesData = data.allCovidRaceDataTimeseries.nodes + + // includes per cap values + const completeTimeSeriesData = + populationData === null + ? timeSeriesData + : addPer100kValues(timeSeriesData, populationData) + return ( { setCurrentMetric={setCurrentMetric} usePer100kRate={usePer100kRate} setUsePer100kRate={setUsePer100kRate} - timeSeriesData={data.allCovidRaceDataTimeseries.nodes} + timeSeriesData={timeSeriesData} + completeTimeSeriesData={completeTimeSeriesData} combinedNotes={data.covidRaceDataCombined} separateNotes={data.covidRaceDataSeparate} combinedTestHosp={data.covidRaceHospTestDataCombined} @@ -42,8 +59,9 @@ const RaceEthnicityHistoricalTemplate = ({ pageContext, path, data }) => { /> Date: Fri, 12 Feb 2021 14:14:35 -0700 Subject: [PATCH 03/29] fear(crdt-historical): add chart legends --- .../pages/state/race-ethnicity/charts.js | 64 ++++++++++++++----- .../state/race-ethnicity/charts.module.scss | 40 +++++++++++- 2 files changed, 85 insertions(+), 19 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 912d15926..b6df632d3 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -7,11 +7,49 @@ import { getAvailablePer100kMetricFields } from './utils' import styles from './charts.module.scss' import colors from '~scss/colors.module.scss' -const ChartsSection = ({ title, children }) => ( -
+const colorMap = { + AIAN: colors.crdtAian, + Asian: colors.crdtAsian, + Black: colors.crdtBlack, + Ethnicity_Hispanic: 'blue', + Ethnicity_NonHispanic: 'red', + LatinX: colors.crdtLatinx, + Multiracial: 'green', + NHPI: colors.crdtNhpi, + White: colors.crdtWhite, +} + +const ChartLegend = ({ legendColors, categories }) => { + 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 ethnicity (TKTKTK)', + Ethnicity_NonHispanic: 'Non Hispanic ethnicity (TKTKTK)', + } + return ( +
+ {categories.map(category => ( +
+
+ {categoryNames[category]} +
+ ))} +
+ ) +} + +const ChartsSection = ({ title, children, legendCategories }) => ( +

{title}

{children} - {/* todo put the legend here */} +
) @@ -101,21 +139,12 @@ const Charts = ({ timeSeriesData, currentMetric }) => { // todo find alternatives to red, blue, green - const colorMap = { - AIAN: colors.crdtAian, - Asian: colors.crdtAsian, - Black: colors.crdtBlack, - Ethnicity_Hispanic: 'blue', - Ethnicity_NonHispanic: 'red', - LatinX: colors.Latinx, - Multiracial: 'green', - NHPI: colors.crdtNhpi, - White: colors.crdtWhite, - } + const activeRaceCategories = Object.keys(allRaceData[currentMetric]) + const activeEthnicityCategories = Object.keys(allEthnicityData[currentMetric]) return (
- + { title={`${currentMetric} per 100k people`} /> - + div > svg { + width: 50%; + margin: 0 auto; + display: block; +} + +.legend { display: grid; grid-template-columns: 1fr 1fr; + grid-column-gap: 1rem; + grid-row-gap: 0.5rem; + justify-content: center; + align-items: center; + + margin: 0px 20%; // ignore-style-rule + + .category { + display: flex; + align-items: center; + @include margin(32, right); + + &:last-child { + @include margin(0, right); + } - @media (max-width: $viewport-lg) { - grid-template-columns: 1fr; + .swatch { + flex-shrink: 0; + @include margin(8, right); + width: 12px; + height: 12px; + } } } From 8e1de42404fdc67d3863be8d3c36c800b41d934c Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 14:19:04 -0700 Subject: [PATCH 04/29] chore(crdt-historical): update charts alignment --- .../pages/state/race-ethnicity/chart.module.scss | 1 - src/components/pages/state/race-ethnicity/charts.js | 2 +- .../pages/state/race-ethnicity/charts.module.scss | 9 ++++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/chart.module.scss b/src/components/pages/state/race-ethnicity/chart.module.scss index bc187c401..d2af99822 100644 --- a/src/components/pages/state/race-ethnicity/chart.module.scss +++ b/src/components/pages/state/race-ethnicity/chart.module.scss @@ -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); diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index b6df632d3..106f561fb 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -47,7 +47,7 @@ const ChartLegend = ({ legendColors, categories }) => { const ChartsSection = ({ title, children, legendCategories }) => (
-

{title}

+

{title}

{children}
diff --git a/src/components/pages/state/race-ethnicity/charts.module.scss b/src/components/pages/state/race-ethnicity/charts.module.scss index f26a505bb..0c677f2a7 100644 --- a/src/components/pages/state/race-ethnicity/charts.module.scss +++ b/src/components/pages/state/race-ethnicity/charts.module.scss @@ -13,14 +13,21 @@ display: block; } +.chart-section-title { + @include type-size(400); + text-align: center; + @include margin(0, bottom); +} + .legend { display: grid; grid-template-columns: 1fr 1fr; + grid-auto-rows: 1fr; grid-column-gap: 1rem; grid-row-gap: 0.5rem; justify-content: center; align-items: center; - + margin: 0px 20%; // ignore-style-rule .category { From c104ae10e2637a242da36c4f4e19ba906bee8df3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 16:04:08 -0700 Subject: [PATCH 05/29] chore(crdt-historical): update ethnicity chart legend copy --- src/components/pages/state/race-ethnicity/charts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 106f561fb..196ed25e4 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -27,8 +27,8 @@ const ChartLegend = ({ legendColors, categories }) => { Asian: 'Asian', AIAN: 'American Indian and Alaskan Native', NHPI: 'Native Hawaiian and Other Pacific Islander', - Ethnicity_Hispanic: 'Hispanic ethnicity (TKTKTK)', - Ethnicity_NonHispanic: 'Non Hispanic ethnicity (TKTKTK)', + Ethnicity_Hispanic: 'Hispanic or Latino', + Ethnicity_NonHispanic: 'Not Hispanic or Latino', } return (
From 41411d2d15730a6afbf287cd44060d02de4ed210 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 16:39:45 -0700 Subject: [PATCH 06/29] chore(crdt-historical): use auto for legend column width --- src/components/pages/state/race-ethnicity/charts.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/state/race-ethnicity/charts.module.scss b/src/components/pages/state/race-ethnicity/charts.module.scss index 0c677f2a7..e07fdcd47 100644 --- a/src/components/pages/state/race-ethnicity/charts.module.scss +++ b/src/components/pages/state/race-ethnicity/charts.module.scss @@ -21,7 +21,7 @@ .legend { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: auto auto; grid-auto-rows: 1fr; grid-column-gap: 1rem; grid-row-gap: 0.5rem; From dc6f1e57c965a69055d28c04c1b4f73cd67dc9ac Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 16:42:34 -0700 Subject: [PATCH 07/29] feat(line-chart): begin adding tooltips This is incomplete: the second argument for `hover` should be the hovered day's info, not all of the info. See line 47. --- src/components/charts/line-chart.js | 61 +++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/components/charts/line-chart.js b/src/components/charts/line-chart.js index 318342e28..667722804 100644 --- a/src/components/charts/line-chart.js +++ b/src/components/charts/line-chart.js @@ -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' @@ -24,6 +26,7 @@ const LineChart = ({ yTicks, lastXTick, perCapLabel, + renderTooltipContents, }) => { const totalXMargin = marginLeft + marginRight const totalYMargin = marginTop + marginBottom @@ -37,6 +40,34 @@ const LineChart = ({ }) }) + const [tooltip, setTooltip] = useState(null) + const [timeoutRef, setTimeoutRef] = useState(null) + + const hover = (event, dataLine) => { + console.log(dataLine) // todo get current date's info + // 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 + console.log(eventX, eventY) + + 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() @@ -159,17 +190,33 @@ const LineChart = ({ {data && ( <> {data.map(dataLine => ( - + <> + + {/* Add a wider hidden path for tooltips. */} + hover(event, dataLine)} + onFocus={event => hover(event, dataLine)} + onMouseOut={mouseOut} + onBlur={mouseOut} + /> + ))} )} + {renderTooltipContents && tooltip && ( + {renderTooltipContents(tooltip.d)} + )} ) } From d6e9ca27f8f7780380c44bcc779934b762c0ea45 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 12 Feb 2021 16:42:46 -0700 Subject: [PATCH 08/29] chore(multi-line-chart): rm old comment --- src/components/charts/multi-line-chart.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/charts/multi-line-chart.js b/src/components/charts/multi-line-chart.js index bae957c00..833651b41 100644 --- a/src/components/charts/multi-line-chart.js +++ b/src/components/charts/multi-line-chart.js @@ -182,6 +182,5 @@ const MultiLineChart = ({ ) } -// todo don't just use red export default MultiLineChart From d17c776738a6e4ceaea9e20d2ebc77469d29ca46 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 13 Feb 2021 20:06:02 -0700 Subject: [PATCH 09/29] feat(crdt-historical): add isolation feature for chart legends isolate a single line by clicking on its legend item --- .../pages/state/race-ethnicity/charts.js | 80 ++++++++++++++++--- .../state/race-ethnicity/charts.module.scss | 9 +++ 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 196ed25e4..738a3e7bd 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -1,5 +1,6 @@ -import React, { useMemo } from 'react' +import React, { useMemo, useState } from 'react' import { DateTime } from 'luxon' +import classnames from 'classnames' import Chart from './chart' import { getAvailablePer100kMetricFields } from './utils' @@ -19,7 +20,12 @@ const colorMap = { White: colors.crdtWhite, } -const ChartLegend = ({ legendColors, categories }) => { +const ChartLegend = ({ + legendColors, + categories, + selectedItem, + setSelectedItem, +}) => { const categoryNames = { White: 'White', Black: 'Black or African American', @@ -30,26 +36,53 @@ const ChartLegend = ({ legendColors, categories }) => { Ethnicity_Hispanic: 'Hispanic or Latino', Ethnicity_NonHispanic: 'Not Hispanic or Latino', } + + /** + * 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 (
{categories.map(category => ( -
+ ))}
) } -const ChartsSection = ({ title, children, legendCategories }) => ( +const ChartsSection = ({ + title, + children, + legendCategories, + selectedItem, + setSelectedItem, +}) => (

{title}

{children} - +
) @@ -142,13 +175,40 @@ const Charts = ({ timeSeriesData, currentMetric }) => { const activeRaceCategories = Object.keys(allRaceData[currentMetric]) const activeEthnicityCategories = Object.keys(allEthnicityData[currentMetric]) + const [selectedCategory, setSelectedCategory] = useState(null) + // todo handle clicks outside of the legend to reset state + + /** + * Gets the colors for the line charts. + * Greys out the non-selected values when a category is selected. + */ + const getChartColors = () => { + if (selectedCategory === null) { + return colorMap + } + + const selectedColorMap = { ...colorMap } + + Object.keys(selectedColorMap).forEach(key => { + if (key !== selectedCategory) { + selectedColorMap[key] = colors.colorSlate200 + } + }) + return selectedColorMap + } + return (
- + { Date: Sat, 13 Feb 2021 20:16:24 -0700 Subject: [PATCH 10/29] feat(crdt-charts): reset the legend by clicking outside --- .../pages/state/race-ethnicity/charts.js | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 738a3e7bd..b73c49f8b 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react' +import React, { useMemo, useState, useRef, useEffect } from 'react' import { DateTime } from 'luxon' import classnames from 'classnames' @@ -73,16 +73,19 @@ const ChartsSection = ({ legendCategories, selectedItem, setSelectedItem, + legendRef, }) => (

{title}

{children} - +
+ +
) @@ -176,7 +179,6 @@ const Charts = ({ timeSeriesData, currentMetric }) => { const activeEthnicityCategories = Object.keys(allEthnicityData[currentMetric]) const [selectedCategory, setSelectedCategory] = useState(null) - // todo handle clicks outside of the legend to reset state /** * Gets the colors for the line charts. @@ -187,7 +189,9 @@ const Charts = ({ timeSeriesData, currentMetric }) => { return colorMap } - const selectedColorMap = { ...colorMap } + const selectedColorMap = { + ...colorMap, + } Object.keys(selectedColorMap).forEach(key => { if (key !== selectedCategory) { @@ -197,6 +201,36 @@ const Charts = ({ timeSeriesData, currentMetric }) => { return selectedColorMap } + /** + * Hook that resets the selected category on clicks outside of the passed ref. + * See: https://stackoverflow.com/questions/32553158/detect-click-outside-react-component + */ + function useOutsideReset(ref) { + useEffect(() => { + /** + * Alert if clicked on outside of element + */ + function handleClickOutside(event) { + if (ref.current && !ref.current.contains(event.target)) { + // Reset the selected category + setSelectedCategory(null) + } + } + // Bind the event listener + document.addEventListener('mousedown', handleClickOutside) + return () => { + // Unbind the event listener on clean up + document.removeEventListener('mousedown', handleClickOutside) + } + }, [ref]) + } + + const raceLegendRef = useRef(null) + useOutsideReset(raceLegendRef) + + const ethnicityLegendRef = useRef(null) + useOutsideReset(ethnicityLegendRef) + return (
{ legendCategories={activeRaceCategories} selectedItem={selectedCategory} setSelectedItem={setSelectedCategory} + legendRef={raceLegendRef} > { legendCategories={activeEthnicityCategories} selectedItem={selectedCategory} setSelectedItem={setSelectedCategory} + legendRef={ethnicityLegendRef} > Date: Sat, 13 Feb 2021 20:20:54 -0700 Subject: [PATCH 11/29] feat(crdt-charts): add reset highlight button --- .../pages/state/race-ethnicity/charts.js | 9 +++++++++ .../state/race-ethnicity/charts.module.scss | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index b73c49f8b..6a1b39154 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -63,6 +63,15 @@ const ChartLegend = ({ {categoryNames[category]} ))} + {selectedItem && ( + + )}
) } diff --git a/src/components/pages/state/race-ethnicity/charts.module.scss b/src/components/pages/state/race-ethnicity/charts.module.scss index 41fc9a71b..a061416a8 100644 --- a/src/components/pages/state/race-ethnicity/charts.module.scss +++ b/src/components/pages/state/race-ethnicity/charts.module.scss @@ -30,15 +30,19 @@ margin: 0px 20%; // ignore-style-rule + .category, + .reset-button { + border: none; + background: inherit; + cursor: pointer; + } + .category { display: flex; align-items: center; - border: none; - background: inherit; @include margin(32, right); text-align: left; - cursor: pointer; &:last-child { @include margin(0, right); @@ -55,4 +59,10 @@ .active-category { font-weight: bold; } + + .reset-button { + color: $color-slate-700; + text-decoration: underline; + grid-column: span 2; + } } From 28890051dc0250a28fb40684a92655d86b4c60a0 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 13 Feb 2021 20:26:30 -0700 Subject: [PATCH 12/29] chore(crdt-charts): refactor into separate files --- .../state/race-ethnicity/chart-legend.js | 61 ++++++++++++++ .../state/race-ethnicity/charts-section.js | 28 +++++++ .../pages/state/race-ethnicity/charts.js | 84 +------------------ 3 files changed, 93 insertions(+), 80 deletions(-) create mode 100644 src/components/pages/state/race-ethnicity/chart-legend.js create mode 100644 src/components/pages/state/race-ethnicity/charts-section.js diff --git a/src/components/pages/state/race-ethnicity/chart-legend.js b/src/components/pages/state/race-ethnicity/chart-legend.js new file mode 100644 index 000000000..b165e02c0 --- /dev/null +++ b/src/components/pages/state/race-ethnicity/chart-legend.js @@ -0,0 +1,61 @@ +import React from 'react' +import classnames from 'classnames' +import styles from './charts.module.scss' + +const ChartLegend = ({ + legendColors, + categories, + selectedItem, + setSelectedItem, +}) => { + 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', + } + + /** + * 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 ( +
+ {categories.map(category => ( + + ))} + {selectedItem && ( + + )} +
+ ) +} + +export default ChartLegend diff --git a/src/components/pages/state/race-ethnicity/charts-section.js b/src/components/pages/state/race-ethnicity/charts-section.js new file mode 100644 index 000000000..e22d6c778 --- /dev/null +++ b/src/components/pages/state/race-ethnicity/charts-section.js @@ -0,0 +1,28 @@ +import React from 'react' +import styles from './charts.module.scss' +import ChartLegend from './chart-legend' + +const ChartsSection = ({ + title, + children, + legendCategories, + selectedItem, + setSelectedItem, + legendColors, + legendRef, +}) => ( +
+

{title}

+ {children} +
+ +
+
+) + +export default ChartsSection diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 6a1b39154..cf41c1b5a 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -1,14 +1,14 @@ import React, { useMemo, useState, useRef, useEffect } from 'react' import { DateTime } from 'luxon' -import classnames from 'classnames' import Chart from './chart' import { getAvailablePer100kMetricFields } from './utils' import styles from './charts.module.scss' import colors from '~scss/colors.module.scss' +import ChartsSection from './charts-section' -const colorMap = { +export const colorMap = { AIAN: colors.crdtAian, Asian: colors.crdtAsian, Black: colors.crdtBlack, @@ -20,84 +20,6 @@ const colorMap = { White: colors.crdtWhite, } -const ChartLegend = ({ - legendColors, - categories, - selectedItem, - setSelectedItem, -}) => { - 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', - } - - /** - * 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 ( -
- {categories.map(category => ( - - ))} - {selectedItem && ( - - )} -
- ) -} - -const ChartsSection = ({ - title, - children, - legendCategories, - selectedItem, - setSelectedItem, - legendRef, -}) => ( -
-

{title}

- {children} -
- -
-
-) - const Charts = ({ timeSeriesData, currentMetric }) => { const getMetricData = (allData, metricTitle, metrics) => { /** Restructures a single metric's racial data (i.e. cases) for charts */ @@ -247,6 +169,7 @@ const Charts = ({ timeSeriesData, currentMetric }) => { legendCategories={activeRaceCategories} selectedItem={selectedCategory} setSelectedItem={setSelectedCategory} + legendColors={colorMap} legendRef={raceLegendRef} > { legendCategories={activeEthnicityCategories} selectedItem={selectedCategory} setSelectedItem={setSelectedCategory} + legendColors={colorMap} legendRef={ethnicityLegendRef} > Date: Sat, 13 Feb 2021 20:32:32 -0700 Subject: [PATCH 13/29] chore: move chart legend component to common charts --- .../race-ethnicity => charts}/chart-legend.js | 16 ++----- .../charts/chart-legend.module.scss | 47 ++++++++++++++++++ .../state/race-ethnicity/charts-section.js | 41 ++++++++++------ .../state/race-ethnicity/charts.module.scss | 48 ------------------- 4 files changed, 77 insertions(+), 75 deletions(-) rename src/components/{pages/state/race-ethnicity => charts}/chart-legend.js (72%) create mode 100644 src/components/charts/chart-legend.module.scss diff --git a/src/components/pages/state/race-ethnicity/chart-legend.js b/src/components/charts/chart-legend.js similarity index 72% rename from src/components/pages/state/race-ethnicity/chart-legend.js rename to src/components/charts/chart-legend.js index b165e02c0..701d7f25e 100644 --- a/src/components/pages/state/race-ethnicity/chart-legend.js +++ b/src/components/charts/chart-legend.js @@ -1,24 +1,14 @@ import React from 'react' import classnames from 'classnames' -import styles from './charts.module.scss' +import styles from './chart-legend.module.scss' const ChartLegend = ({ legendColors, categories, selectedItem, setSelectedItem, + legendNames, }) => { - 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', - } - /** * Gets the appropriate classes for a legend item, based on the * item's category name. @@ -42,7 +32,7 @@ const ChartLegend = ({ style={{ 'background-color': legendColors[category] }} className={styles.swatch} /> - {categoryNames[category]} + {legendNames[category]} ))} {selectedItem && ( diff --git a/src/components/charts/chart-legend.module.scss b/src/components/charts/chart-legend.module.scss new file mode 100644 index 000000000..de0e289f9 --- /dev/null +++ b/src/components/charts/chart-legend.module.scss @@ -0,0 +1,47 @@ +.legend { + 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; + + margin: 0px 20%; // ignore-style-rule + + .category, + .reset-button { + border: none; + background: inherit; + cursor: pointer; + } + + .category { + display: flex; + align-items: center; + + @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; + } +} diff --git a/src/components/pages/state/race-ethnicity/charts-section.js b/src/components/pages/state/race-ethnicity/charts-section.js index e22d6c778..8ba845fec 100644 --- a/src/components/pages/state/race-ethnicity/charts-section.js +++ b/src/components/pages/state/race-ethnicity/charts-section.js @@ -1,6 +1,6 @@ import React from 'react' import styles from './charts.module.scss' -import ChartLegend from './chart-legend' +import ChartLegend from '~components/charts/chart-legend' const ChartsSection = ({ title, @@ -10,19 +10,32 @@ const ChartsSection = ({ setSelectedItem, legendColors, legendRef, -}) => ( -
-

{title}

- {children} -
- +}) => { + 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 ( +
+

{title}

+ {children} +
+ +
-
-) + ) +} export default ChartsSection diff --git a/src/components/pages/state/race-ethnicity/charts.module.scss b/src/components/pages/state/race-ethnicity/charts.module.scss index a061416a8..93a30a58e 100644 --- a/src/components/pages/state/race-ethnicity/charts.module.scss +++ b/src/components/pages/state/race-ethnicity/charts.module.scss @@ -18,51 +18,3 @@ text-align: center; @include margin(0, bottom); } - -.legend { - 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; - - margin: 0px 20%; // ignore-style-rule - - .category, - .reset-button { - border: none; - background: inherit; - cursor: pointer; - } - - .category { - display: flex; - align-items: center; - - @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; - } -} From 5add5525ab59248f60f0233b29055c8ddc7e8029 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 13 Feb 2021 20:32:49 -0700 Subject: [PATCH 14/29] chore: rm unused styles --- .../pages/state/race-ethnicity/charts.module.scss | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.module.scss b/src/components/pages/state/race-ethnicity/charts.module.scss index 93a30a58e..ae2fb73a4 100644 --- a/src/components/pages/state/race-ethnicity/charts.module.scss +++ b/src/components/pages/state/race-ethnicity/charts.module.scss @@ -1,12 +1,3 @@ -// .wrapper { -// display: grid; -// grid-template-columns: 1fr 1fr; - -// @media (max-width: $viewport-lg) { -// grid-template-columns: 1fr; -// } -// } - .chart-section > div > svg { width: 50%; margin: 0 auto; From d3431ee897e35af24b1b9d484815391833bd70ca Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 13 Feb 2021 20:34:33 -0700 Subject: [PATCH 15/29] chore: rename ChartsSection -> ChartSection --- .../{charts-section.js => chart-section.js} | 4 ++-- src/components/pages/state/race-ethnicity/charts.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/components/pages/state/race-ethnicity/{charts-section.js => chart-section.js} (94%) diff --git a/src/components/pages/state/race-ethnicity/charts-section.js b/src/components/pages/state/race-ethnicity/chart-section.js similarity index 94% rename from src/components/pages/state/race-ethnicity/charts-section.js rename to src/components/pages/state/race-ethnicity/chart-section.js index 8ba845fec..975b4ec53 100644 --- a/src/components/pages/state/race-ethnicity/charts-section.js +++ b/src/components/pages/state/race-ethnicity/chart-section.js @@ -2,7 +2,7 @@ import React from 'react' import styles from './charts.module.scss' import ChartLegend from '~components/charts/chart-legend' -const ChartsSection = ({ +const ChartSection = ({ title, children, legendCategories, @@ -38,4 +38,4 @@ const ChartsSection = ({ ) } -export default ChartsSection +export default ChartSection diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index cf41c1b5a..8bfde65da 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -6,7 +6,7 @@ import { getAvailablePer100kMetricFields } from './utils' import styles from './charts.module.scss' import colors from '~scss/colors.module.scss' -import ChartsSection from './charts-section' +import ChartSection from './chart-section' export const colorMap = { AIAN: colors.crdtAian, @@ -164,7 +164,7 @@ const Charts = ({ timeSeriesData, currentMetric }) => { return (
- { ]} title={`${currentMetric} per 100k people`} /> - - + { ]} title={`${currentMetric} per 100k people`} /> - +
) } From de9ea466356da8755441d7aef7534a5b2eb88e0d Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 13 Feb 2021 20:40:17 -0700 Subject: [PATCH 16/29] feat(chart-legend): add reset button placeholder --- src/components/charts/chart-legend.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/charts/chart-legend.js b/src/components/charts/chart-legend.js index 701d7f25e..cb5985774 100644 --- a/src/components/charts/chart-legend.js +++ b/src/components/charts/chart-legend.js @@ -35,7 +35,7 @@ const ChartLegend = ({ {legendNames[category]} ))} - {selectedItem && ( + {selectedItem ? ( + ) : ( + // this is a placeholder for the reset button so that the page doesn't + // jump when selectedItem goes from null to not null +
)}
) From 5960f3c8a6176115697acd5efc380f9475e3d479 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 13 Feb 2021 20:44:57 -0700 Subject: [PATCH 17/29] fix(race-charts): conditionally render ethnicity chart * pass isCombined to the charts component * also update the race table name to race/ethnicity as needed --- .../pages/state/race-ethnicity/charts.js | 46 +++++++++---------- .../pages/state/race-ethnicity/hero.js | 8 ++-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 8bfde65da..df0fb1561 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -20,7 +20,7 @@ export const colorMap = { White: colors.crdtWhite, } -const Charts = ({ timeSeriesData, currentMetric }) => { +const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { const getMetricData = (allData, metricTitle, metrics) => { /** Restructures a single metric's racial data (i.e. cases) for charts */ const completedData = {} // store the final metric data object @@ -102,8 +102,6 @@ const Charts = ({ timeSeriesData, currentMetric }) => { // todo add renderTooltipContents to line charts - // todo separate race and ethnicity, based on combined or separate states - // todo find alternatives to red, blue, green const activeRaceCategories = Object.keys(allRaceData[currentMetric]) @@ -165,7 +163,7 @@ const Charts = ({ timeSeriesData, currentMetric }) => { return (
{ title={`${currentMetric} per 100k people`} /> - - - + {!isCombined && ( + + + + )}
) } diff --git a/src/components/pages/state/race-ethnicity/hero.js b/src/components/pages/state/race-ethnicity/hero.js index e2c9d1b77..c4d9bc28b 100644 --- a/src/components/pages/state/race-ethnicity/hero.js +++ b/src/components/pages/state/race-ethnicity/hero.js @@ -127,10 +127,9 @@ const Hero = ({ setCurrentMetric(getFirstAvailableMetric(metrics)) }, []) - const lastReportedByState = (isCombined(combinedNotes, separateNotes) - ? combinedNotes - : separateNotes - ).stateUpdate.value + const stateIsCombined = isCombined(combinedNotes, separateNotes) + const lastReportedByState = (stateIsCombined ? combinedNotes : separateNotes) + .stateUpdate.value return (
@@ -150,6 +149,7 @@ const Hero = ({ Date: Sat, 13 Feb 2021 20:47:18 -0700 Subject: [PATCH 18/29] fix(chart-legend): update reset placholder width makes the reset placeholder span two columns, like the actual reset button --- src/components/charts/chart-legend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/charts/chart-legend.js b/src/components/charts/chart-legend.js index cb5985774..d56474cab 100644 --- a/src/components/charts/chart-legend.js +++ b/src/components/charts/chart-legend.js @@ -46,7 +46,7 @@ const ChartLegend = ({ ) : ( // this is a placeholder for the reset button so that the page doesn't // jump when selectedItem goes from null to not null -
+
)}
) From 56298f1440707e7400e6905b26bdd28232bb9e98 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Mon, 15 Feb 2021 10:05:04 -0700 Subject: [PATCH 19/29] chore(crdt-historical): create separate filters now users can filter by race and ethnicity separately * also updates the reset button copy --- src/components/charts/chart-legend.js | 2 +- .../pages/state/race-ethnicity/charts.js | 25 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/components/charts/chart-legend.js b/src/components/charts/chart-legend.js index d56474cab..5decf5288 100644 --- a/src/components/charts/chart-legend.js +++ b/src/components/charts/chart-legend.js @@ -41,7 +41,7 @@ const ChartLegend = ({ type="button" className={styles.resetButton} > - Reset highlight + Clear filter ) : ( // this is a placeholder for the reset button so that the page doesn't diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index df0fb1561..c94a39df9 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -107,13 +107,16 @@ const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { const activeRaceCategories = Object.keys(allRaceData[currentMetric]) const activeEthnicityCategories = Object.keys(allEthnicityData[currentMetric]) - const [selectedCategory, setSelectedCategory] = useState(null) + const [selectedRaceCategory, setSelectedRaceCategory] = useState(null) + const [selectedEthnicityCategory, setSelectedEthnicityCategory] = useState( + null, + ) /** * Gets the colors for the line charts. * Greys out the non-selected values when a category is selected. */ - const getChartColors = () => { + const getChartColors = selectedCategory => { if (selectedCategory === null) { return colorMap } @@ -134,7 +137,7 @@ const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { * Hook that resets the selected category on clicks outside of the passed ref. * See: https://stackoverflow.com/questions/32553158/detect-click-outside-react-component */ - function useOutsideReset(ref) { + function useOutsideReset(ref, setSelectedCategory) { useEffect(() => { /** * Alert if clicked on outside of element @@ -155,25 +158,25 @@ const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { } const raceLegendRef = useRef(null) - useOutsideReset(raceLegendRef) + useOutsideReset(raceLegendRef, setSelectedRaceCategory) const ethnicityLegendRef = useRef(null) - useOutsideReset(ethnicityLegendRef) + useOutsideReset(ethnicityLegendRef, setSelectedEthnicityCategory) return (
{ Date: Mon, 15 Feb 2021 10:39:07 -0700 Subject: [PATCH 20/29] chore(crdt-historical): update mobile styles --- src/components/charts/chart-legend.js | 61 ++++++++++--------- .../charts/chart-legend.module.scss | 27 +++++--- .../state/race-ethnicity/chart-section.js | 9 ++- ....module.scss => chart-section.module.scss} | 9 +++ .../pages/state/race-ethnicity/charts.js | 3 +- 5 files changed, 68 insertions(+), 41 deletions(-) rename src/components/pages/state/race-ethnicity/{charts.module.scss => chart-section.module.scss} (54%) diff --git a/src/components/charts/chart-legend.js b/src/components/charts/chart-legend.js index 5decf5288..d43ba6507 100644 --- a/src/components/charts/chart-legend.js +++ b/src/components/charts/chart-legend.js @@ -1,5 +1,8 @@ import React from 'react' import classnames from 'classnames' + +import { Col } from '~components/common/grid' + import styles from './chart-legend.module.scss' const ChartLegend = ({ @@ -21,34 +24,36 @@ const ChartLegend = ({ } return ( -
- {categories.map(category => ( - - ))} - {selectedItem ? ( - - ) : ( - // this is a placeholder for the reset button so that the page doesn't - // jump when selectedItem goes from null to not null -
- )} -
+ +
+ {categories.map(category => ( + + ))} + {selectedItem ? ( + + ) : ( + // this is a placeholder for the reset button so that the page doesn't + // jump when selectedItem goes from null to not null +
+ )} +
+ ) } diff --git a/src/components/charts/chart-legend.module.scss b/src/components/charts/chart-legend.module.scss index de0e289f9..6c4b3c4e2 100644 --- a/src/components/charts/chart-legend.module.scss +++ b/src/components/charts/chart-legend.module.scss @@ -1,13 +1,17 @@ -.legend { - 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; +.column-wrapper { + margin: 0 auto; +} - margin: 0px 20%; // ignore-style-rule +.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 { @@ -20,6 +24,11 @@ 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; diff --git a/src/components/pages/state/race-ethnicity/chart-section.js b/src/components/pages/state/race-ethnicity/chart-section.js index 975b4ec53..70efb7073 100644 --- a/src/components/pages/state/race-ethnicity/chart-section.js +++ b/src/components/pages/state/race-ethnicity/chart-section.js @@ -1,7 +1,10 @@ import React from 'react' -import styles from './charts.module.scss' + +import { Col } from '~components/common/grid' import ChartLegend from '~components/charts/chart-legend' +import styles from './chart-section.module.scss' + const ChartSection = ({ title, children, @@ -24,7 +27,9 @@ const ChartSection = ({ return (

{title}

- {children} + + {children} +
{ useOutsideReset(ethnicityLegendRef, setSelectedEthnicityCategory) return ( -
+
Date: Tue, 16 Feb 2021 15:41:23 -0700 Subject: [PATCH 21/29] fix: remove debugging concole.log statements --- src/components/charts/line-chart.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/charts/line-chart.js b/src/components/charts/line-chart.js index 667722804..6cb403c15 100644 --- a/src/components/charts/line-chart.js +++ b/src/components/charts/line-chart.js @@ -44,7 +44,6 @@ const LineChart = ({ const [timeoutRef, setTimeoutRef] = useState(null) const hover = (event, dataLine) => { - console.log(dataLine) // todo get current date's info // Ensure that tooltip doesn't flash when transitioning between bars if (timeoutRef) { clearTimeout(timeoutRef) @@ -52,7 +51,6 @@ const LineChart = ({ const isTouchEvent = !event.clientX const eventX = isTouchEvent ? event.touches[0].clientX : event.clientX const eventY = isTouchEvent ? event.touches[0].clientY : event.clientY - console.log(eventX, eventY) setTooltip({ top: isTouchEvent ? eventY - 130 : eventY + 10, From 50dad80e6f0e11aff307d2ab36afb90d9023c654 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Tue, 16 Feb 2021 15:42:02 -0700 Subject: [PATCH 22/29] fix(crdt-historical): hide ethnicity chart if there's no data fixes empty cases chart for Louisiana --- .../pages/state/race-ethnicity/charts.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 41d51ea5a..321cf2c50 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -162,6 +162,11 @@ const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { const ethnicityLegendRef = useRef(null) useOutsideReset(ethnicityLegendRef, setSelectedEthnicityCategory) + const chartLabel = `${currentMetric} per 100k people` + + const currentMetricIsEmpty = + Object.keys(allEthnicityData[currentMetric]).length === 0 + return (
{ data={[ { colorMap: getChartColors(selectedRaceCategory), - label: `${currentMetric} per 100k people`, + label: chartLabel, data: allRaceData[currentMetric], }, ]} - title={`${currentMetric} per 100k people`} + title={chartLabel} /> - {!isCombined && ( + {!currentMetricIsEmpty && ( { data={[ { colorMap: getChartColors(selectedEthnicityCategory), - label: `${currentMetric} per 100k people`, + label: chartLabel, data: allEthnicityData[currentMetric], }, ]} - title={`${currentMetric} per 100k people`} + title={chartLabel} /> )} + {!isCombined && currentMetricIsEmpty &&

No data state

}
) } From 2615e6ec3327ed0ec088a7015f40da70c039284b Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Tue, 16 Feb 2021 15:55:25 -0700 Subject: [PATCH 23/29] chore(crdt): move no data alert to separate file --- src/components/pages/race/dashboard/table.js | 9 ++++----- src/components/pages/race/no-data-alert.js | 11 +++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 src/components/pages/race/no-data-alert.js diff --git a/src/components/pages/race/dashboard/table.js b/src/components/pages/race/dashboard/table.js index 97d816a3e..1decf08ec 100644 --- a/src/components/pages/race/dashboard/table.js +++ b/src/components/pages/race/dashboard/table.js @@ -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' @@ -113,10 +115,7 @@ const StateTableDataCell = ({ if (index === 0) { return ( - - {state} does not report {type.toLowerCase()} data for {errorType}.{' '} - Help us get better data. - + ) } diff --git a/src/components/pages/race/no-data-alert.js b/src/components/pages/race/no-data-alert.js new file mode 100644 index 000000000..fb73352e0 --- /dev/null +++ b/src/components/pages/race/no-data-alert.js @@ -0,0 +1,11 @@ +import React from 'react' +import { Link } from 'gatsby' + +const NoDataAlert = ({ state, dataType, metric }) => ( + + {state} does not report {dataType.toLowerCase()} data for {metric}.{' '} + Help us get better data. + +) + +export default NoDataAlert From 63eb6e2d5b85802e7df7addb7711f7166fe605fb Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Tue, 16 Feb 2021 16:02:58 -0700 Subject: [PATCH 24/29] fix(crdt-historical): no data state ignore unkown ethnicity data when evaluating if a state reports ethnicity data for a given metric --- .../state/race-ethnicity/historical-tables.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/historical-tables.js b/src/components/pages/state/race-ethnicity/historical-tables.js index 0bb3f11e5..93ce87031 100644 --- a/src/components/pages/state/race-ethnicity/historical-tables.js +++ b/src/components/pages/state/race-ethnicity/historical-tables.js @@ -101,13 +101,15 @@ const HistoricalTables = ({ const reportsEthnicityData = () => { let hasNonNullValue = false - allEthnicityData[currentMetric].every(columnName => { - if (formattedTimeSeriesData[0][columnName] !== null) { - hasNonNullValue = true - return false - } - return true - }) + allEthnicityData[currentMetric] + .filter(columnName => columnName !== 'Cases_Ethnicity_Unknown') + .every(columnName => { + if (formattedTimeSeriesData[0][columnName] !== null) { + hasNonNullValue = true + return false + } + return true + }) return hasNonNullValue } From e71694440cf286735e7e3129180ee7efad58bbd3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Tue, 16 Feb 2021 17:42:49 -0700 Subject: [PATCH 25/29] chore(crdt-historical): use NoData component --- src/components/pages/state/race-ethnicity/charts.js | 13 +++++++++++-- src/components/pages/state/race-ethnicity/hero.js | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 321cf2c50..00fdab1a7 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -3,6 +3,7 @@ import { DateTime } from 'luxon' import Chart from './chart' import { getAvailablePer100kMetricFields } from './utils' +import NoData from '~components/pages/race/no-data-inner' import colors from '~scss/colors.module.scss' import ChartSection from './chart-section' @@ -19,7 +20,7 @@ export const colorMap = { White: colors.crdtWhite, } -const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { +const Charts = ({ timeSeriesData, currentMetric, isCombined, stateName }) => { const getMetricData = (allData, metricTitle, metrics) => { /** Restructures a single metric's racial data (i.e. cases) for charts */ const completedData = {} // store the final metric data object @@ -209,7 +210,15 @@ const Charts = ({ timeSeriesData, currentMetric, isCombined }) => { />
)} - {!isCombined && currentMetricIsEmpty &&

No data state

} + {!isCombined && currentMetricIsEmpty && ( +
+ +
+ )}
) } diff --git a/src/components/pages/state/race-ethnicity/hero.js b/src/components/pages/state/race-ethnicity/hero.js index c4d9bc28b..201907a48 100644 --- a/src/components/pages/state/race-ethnicity/hero.js +++ b/src/components/pages/state/race-ethnicity/hero.js @@ -150,6 +150,7 @@ const Hero = ({ timeSeriesData={completeTimeSeriesData} currentMetric={currentMetric} isCombined={stateIsCombined} + stateName={stateName} /> Date: Tue, 16 Feb 2021 17:43:27 -0700 Subject: [PATCH 26/29] feat(crdt-historical): add no-data-inner component --- src/components/pages/race/no-data-inner.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/components/pages/race/no-data-inner.js diff --git a/src/components/pages/race/no-data-inner.js b/src/components/pages/race/no-data-inner.js new file mode 100644 index 000000000..c3333898b --- /dev/null +++ b/src/components/pages/race/no-data-inner.js @@ -0,0 +1,12 @@ +import React from 'react' +import { Link } from 'gatsby' + +const NoDataInner = ({ state, dataType, metric, className }) => ( + + {state} does not report {dataType.toLowerCase()} data for{' '} + {metric.toLowerCase()}.{' '} + Help us get better data. + +) + +export default NoDataInner From 0aa6d9f51294c4602fb54dfb77a09c0f963421cf Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Tue, 16 Feb 2021 17:55:31 -0700 Subject: [PATCH 27/29] feat(crdt-historical): add no data state for charts --- src/components/pages/race/no-data-inner.js | 12 ------------ .../pages/state/race-ethnicity/charts.js | 2 +- .../pages/state/race-ethnicity/no-data-chart.js | 17 +++++++++++++++++ .../race-ethnicity/no-data-chart.module.scss | 4 ++++ 4 files changed, 22 insertions(+), 13 deletions(-) delete mode 100644 src/components/pages/race/no-data-inner.js create mode 100644 src/components/pages/state/race-ethnicity/no-data-chart.js create mode 100644 src/components/pages/state/race-ethnicity/no-data-chart.module.scss diff --git a/src/components/pages/race/no-data-inner.js b/src/components/pages/race/no-data-inner.js deleted file mode 100644 index c3333898b..000000000 --- a/src/components/pages/race/no-data-inner.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react' -import { Link } from 'gatsby' - -const NoDataInner = ({ state, dataType, metric, className }) => ( - - {state} does not report {dataType.toLowerCase()} data for{' '} - {metric.toLowerCase()}.{' '} - Help us get better data. - -) - -export default NoDataInner diff --git a/src/components/pages/state/race-ethnicity/charts.js b/src/components/pages/state/race-ethnicity/charts.js index 00fdab1a7..c1e829a18 100644 --- a/src/components/pages/state/race-ethnicity/charts.js +++ b/src/components/pages/state/race-ethnicity/charts.js @@ -3,7 +3,7 @@ import { DateTime } from 'luxon' import Chart from './chart' import { getAvailablePer100kMetricFields } from './utils' -import NoData from '~components/pages/race/no-data-inner' +import NoData from './no-data-chart' import colors from '~scss/colors.module.scss' import ChartSection from './chart-section' diff --git a/src/components/pages/state/race-ethnicity/no-data-chart.js b/src/components/pages/state/race-ethnicity/no-data-chart.js new file mode 100644 index 000000000..008a06f50 --- /dev/null +++ b/src/components/pages/state/race-ethnicity/no-data-chart.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Link } from 'gatsby' +import Alert from '~components/common/alert' + +import styles from './no-data-chart.module.scss' + +const NoDataChartPlaceholder = ({ state, dataType, metric }) => ( +
+ + {state} does not report {dataType.toLowerCase()} data for{' '} + {metric.toLowerCase()}.
+ Help us get better data. +
+
+) + +export default NoDataChartPlaceholder diff --git a/src/components/pages/state/race-ethnicity/no-data-chart.module.scss b/src/components/pages/state/race-ethnicity/no-data-chart.module.scss new file mode 100644 index 000000000..922c17dbf --- /dev/null +++ b/src/components/pages/state/race-ethnicity/no-data-chart.module.scss @@ -0,0 +1,4 @@ +.no-data-container { + display: flex; + justify-content: center; +} From e31f8e4039a1650fa1720605f9efe0395928fa22 Mon Sep 17 00:00:00 2001 From: Kevin Miller Date: Wed, 17 Feb 2021 13:50:39 -0800 Subject: [PATCH 28/29] chore: Add markdown support to image captions --- .../pages/blog/content-blocks/image-content-block.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/pages/blog/content-blocks/image-content-block.js b/src/components/pages/blog/content-blocks/image-content-block.js index f8bcc73d5..f2ea53394 100644 --- a/src/components/pages/blog/content-blocks/image-content-block.js +++ b/src/components/pages/blog/content-blocks/image-content-block.js @@ -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' @@ -56,7 +57,7 @@ const ImageContentBlock = ({ )} - {caption && {caption}} + {caption && {marked.inlineLexer(caption, [])}}
) From bb60161b6d8234b9f7fd56cc59ddc34c9bbf918b Mon Sep 17 00:00:00 2001 From: Kevin Miller Date: Wed, 17 Feb 2021 14:14:16 -0800 Subject: [PATCH 29/29] feature: Add markdown for long credit --- src/components/pages/blog/blog-content.js | 5 +++++ .../pages/blog/content-blocks/image-content-block.js | 12 +++++++++++- src/templates/blog-post.js | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/pages/blog/blog-content.js b/src/components/pages/blog/blog-content.js index b2afe1cb9..b2a4beb8b 100644 --- a/src/components/pages/blog/blog-content.js +++ b/src/components/pages/blog/blog-content.js @@ -86,9 +86,14 @@ const BlogContent = ({ content }) => { fullWidthMobile, imageLink, } = target + const longCaption = + target.childContentfulContentBlockImageLongCaptionTextNode && + target.childContentfulContentBlockImageLongCaptionTextNode + .childMarkdownRemark.rawMarkdownBody return ( )} - {caption && {marked.inlineLexer(caption, [])}} + {caption && !longCaption && {caption}} + {longCaption && ( + +
+ + )}
) diff --git a/src/templates/blog-post.js b/src/templates/blog-post.js index cb665358f..718ca85c8 100644 --- a/src/templates/blog-post.js +++ b/src/templates/blog-post.js @@ -207,6 +207,11 @@ export const query = graphql` fullWidthMobile caption imageLink + childContentfulContentBlockImageLongCaptionTextNode { + childMarkdownRemark { + rawMarkdownBody + } + } image { file { url