Add summary section to index.

This commit is contained in:
Joshua Bemenderfer
2022-01-01 21:50:26 -05:00
parent 94018b70ec
commit b3289258e3
27 changed files with 593 additions and 88 deletions

View File

@@ -1,5 +1,5 @@
<template>
<div :class="['bg-white shadow rounded-lg p-4 lg:p-8 max-w-none', prose ? 'prose lg:prose-base prose-headings:font-light prose-headings:text-violet-900 prose-h1:mb-0' : '']">
<div :class="['bg-white shadow rounded-lg p-4 lg:p-8 max-w-none', prose ? 'prose lg:prose-base prose-headings:font-light prose-headings:text-violet-900 prose-h1:mb-0 prose-a:text-violet-700 prose-a:font-normal' : '']">
<slot></slot>
</div>
</template>

View File

@@ -1,26 +1,26 @@
<template>
<StatCard>
<template v-slot:heading>Confirmed Cases {{last_report_date ? humanDate(last_report_date) : ''}}</template>
<template v-slot:value v-if="chips.today_cases != null">
{{chips.today_cases.toLocaleString()}}
<template v-slot:value v-if="chips.current_cases != null">
{{chips.current_cases.toLocaleString()}}
</template>
<template v-slot:meta v-if="chips.today_case_change != null">
<span v-if="chips.today_case_change > 0">Up </span>
<span v-if="chips.today_case_change < 0">Down </span>
<span :class="{'font-semibold': true, 'text-red-600': chips.today_case_change > 0, 'text-green-600': chips.today_case_change < 0}">
{{Math.abs(chips.today_case_change).toLocaleString()}} ({{chips.today_case_change_percent}}%)
<template v-slot:meta v-if="chips.current_case_change != null">
<span v-if="chips.current_case_change > 0">Up </span>
<span v-if="chips.current_case_change < 0">Down </span>
<span :class="{'font-semibold': true, 'text-red-600': chips.current_case_change > 0, 'text-green-600': chips.current_case_change < 0}">
{{Math.abs(chips.current_case_change).toLocaleString()}} ({{chips.current_case_change_percent}}%)
</span> compared to previous day
</template>
</StatCard>
<StatCard>
<template v-slot:heading>Cases per 10,000 Residents {{last_report_date ? humanDate(last_report_date) : ''}}</template>
<template v-slot:value v-if="chips.today_cases_per_capita != null">
<span v-if="chips.population">~{{chips.today_cases_per_capita.toLocaleString()}}</span>
<template v-slot:value v-if="chips.current_cases_per_capita != null">
<span v-if="chips.population">~{{chips.current_cases_per_capita.toLocaleString()}}</span>
<span v-else>No Data</span>
</template>
<template v-slot:meta v-if="chips.population">
<span class="text-violet-500 font-semibold">{{chips.today_cases.toLocaleString()}}</span> out of <span class="text-violet-500 font-semibold">{{chips.population.toLocaleString()}}</span> residents
<span class="text-violet-500 font-semibold">{{chips.current_cases.toLocaleString()}}</span> out of <span class="text-violet-500 font-semibold">{{chips.population.toLocaleString()}}</span> residents
</template>
</StatCard>
@@ -68,14 +68,14 @@ const chips = reactive({
return col(data, r, 'population')
}),
today_cases: computed(() => {
current_cases: computed(() => {
if (!data.value) return null
const r = data.value.rows.at(-1)
return col(data, r, 'cases')
}),
today_case_change: computed(() => {
current_case_change: computed(() => {
if (!data.value) return null
const today = col(data, data.value.rows.at(-1), 'cases')
@@ -83,7 +83,7 @@ const chips = reactive({
return today - yesterday
}),
today_case_change_percent: computed(() => {
current_case_change_percent: computed(() => {
if (!data.value) return null
const today = col(data, data.value.rows.at(-1), 'cases')
@@ -100,7 +100,7 @@ const chips = reactive({
return Math.abs(percent.toFixed(1))
}),
today_cases_per_capita: computed(() => {
current_cases_per_capita: computed(() => {
if (!data.value) return null
const r = data.value.rows.at(-1)

View File

@@ -28,8 +28,6 @@ watch(() => store.parameters.value.county, () => {
refreshData()
})
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -8,8 +8,6 @@ async function refreshData() {
store.data.value = await fetch(`/data/overall/cases/combined.json`).then(res => res.json())
}
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -28,8 +28,6 @@ watch(() => store.parameters.value.county, () => {
refreshData()
})
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -8,8 +8,6 @@ async function refreshData() {
store.data.value = await fetch(`/data/overall/deaths/combined.json`).then(res => res.json())
}
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -28,8 +28,6 @@ watch(() => store.parameters.value.county, () => {
refreshData()
})
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -5,11 +5,9 @@ const store = {
}
async function refreshData() {
store.data.value = await fetch(`/data/state/hospitalizations/combined.json`).then(res => res.json())
store.data.value = await fetch(`/data/overall/hospitalizations/combined.json`).then(res => res.json())
}
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -30,7 +30,7 @@
</StatCard>
<StatCard>
<template v-slot:heading>7-Day Percent Positive</template>
<template v-slot:heading>7-Day Test Positivity</template>
<template v-slot:value v-if="chips.percent_positive">
<span :class="{
'text-green-600': chips.percent_positive < 2,
@@ -41,7 +41,7 @@
{{chips.percent_positive}}<span class="font-light">%</span>
</span>
</template>
<template v-slot:meta v-if="chips.positive">
<template v-slot:meta v-if="chips.percent_positive">
<div class="inline-flex flex-wrap text-xs -mx-1">
<div class="flex-1">
<div class="px-1 text-green-600 font-medium whitespace-nowrap">Low: &lt; 2%</div>

View File

@@ -22,8 +22,6 @@ watch(() => store.parameters.value.county, () => {
refreshData()
})
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -23,8 +23,6 @@ async function refreshData() {
}
}
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -8,8 +8,6 @@ async function refreshData() {
store.data.value = await fetch(`/data/risk/health-conditions/health-conditions.json`).then(res => res.json())
}
if (globalThis.window) {
refreshData()
}
if (globalThis.window) refreshData()
export default store

View File

@@ -0,0 +1,216 @@
<template>
<StatCard>
<template v-slot:heading>Tests Reported {{last_report_date ? humanDate(last_report_date) : ''}}</template>
<template v-slot:value v-if="chips.current_testing">
{{chips.current_testing.toLocaleString()}}
</template>
<template v-slot:meta v-if="chips.current_testing">
PCR + Antigen
</template>
<template v-slot:meta v-if="chips.current_testing_change != null">
<span v-if="chips.current_testing_change > 0">Up </span>
<span v-if="chips.current_testing_change < 0">Down </span>
<span class="font-semibold text-violet-600">
{{Math.abs(chips.current_testing_change).toLocaleString()}} ({{chips.current_testing_change_percent}}%)
</span> compared to previous day
</template>
</StatCard>
<StatCard>
<template v-slot:heading>7-Day Test Positivity</template>
<template v-slot:value v-if="chips.percent_positive">
<span :class="{
'text-green-600': chips.percent_positive < 2,
'text-yellow-500': chips.percent_positive >= 2 && chips.percent_positive < 5,
'text-orange-500': chips.percent_positive >= 5 && chips.percent_positive < 20,
'text-red-800': chips.percent_positive > 20
}">
{{chips.percent_positive}}<span class="font-light">%</span>
</span>
</template>
<template v-slot:meta v-if="chips.percent_positive">
<div class="inline-flex flex-wrap text-xs -mx-1">
<div class="flex-1">
<div class="px-1 text-green-600 font-medium whitespace-nowrap">Low: &lt; 2%</div>
<div class="px-1 text-yellow-600 font-medium whitespace-nowrap">Moderate &lt; 5%</div>
</div>
<div class="flex-1">
<div class="px-1 text-orange-600 font-medium whitespace-nowrap">High &lt; 20%</div>
<div class="px-1 text-red-700 font-medium whitespace-nowrap">Very high &gt; 20%</div>
</div>
</div>
<a class="link block mt-2 text-xs" href="https://www.who.int/publications/i/item/considerations-in-adjusting-public-health-and-social-measures-in-the-context-of-covid-19-interim-guidanceLow">
Source, see p. 18
</a>
</template>
</StatCard>
<StatCard>
<template v-slot:heading>Confirmed Cases {{last_report_date ? humanDate(last_report_date) : ''}}</template>
<template v-slot:value v-if="chips.current_cases != null">
{{chips.current_cases.toLocaleString()}}
</template>
<template v-slot:meta v-if="chips.current_case_change != null">
<span v-if="chips.current_case_change > 0">Up </span>
<span v-if="chips.current_case_change < 0">Down </span>
<span :class="{'font-semibold': true, 'text-red-600': chips.current_case_change > 0, 'text-green-600': chips.current_case_change < 0}">
{{Math.abs(chips.current_case_change).toLocaleString()}} ({{chips.current_case_change_percent}}%)
</span> compared to previous day
</template>
</StatCard>
<StatCard>
<template v-slot:heading>Confirmed Deaths {{last_report_date ? humanDate(last_report_date) : ''}}</template>
<template v-slot:value v-if="chips.current_deaths != null">
{{chips.current_deaths.toLocaleString()}}
</template>
<template v-slot:meta v-if="chips.current_death_change != null">
<span v-if="chips.current_death_change > 0">Up </span>
<span v-if="chips.current_death_change < 0">Down </span>
<span :class="{'font-semibold': true, 'text-red-600': chips.current_death_change > 0, 'text-green-600': chips.current_death_change < 0}">
{{Math.abs(chips.current_death_change).toLocaleString()}} ({{chips.current_death_change_percent}}%)
</span> compared to previous day
</template>
</StatCard>
<StatCard>
<template v-slot:heading>Total Confirmed Cases</template>
<template v-slot:value v-if="chips.total_cases != null">
{{chips.total_cases.toLocaleString()}}
</template>
</StatCard>
<StatCard>
<template v-slot:heading>Total Confirmed Deaths</template>
<template v-slot:value v-if="chips.total_deaths != null">
{{chips.total_deaths.toLocaleString()}}
</template>
</StatCard>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { col, humanDate } from '@/components/charts/util'
import store from '@/components/charts/summary/store.js'
const data = store.data
const last_report_date = computed(() => {
if (!data.value) return null
return data.value.last_report_date
})
const chips = reactive({
current_testing: computed(() => {
if (!data.value) return null
return col(data.value.testing, data.value.testing.current, 'combined_performed')
}),
current_testing_change: computed(() => {
if (!data.value) return null
const today = col(data.value.testing, data.value.testing.current, 'combined_performed')
const yesterday = col(data.value.testing, data.value.testing.prev, 'combined_performed')
return today - yesterday
}),
current_testing_change_percent: computed(() => {
if (!data.value) return null
const today = col(data.value.testing, data.value.testing.current, 'combined_performed')
const yesterday = col(data.value.testing, data.value.testing.prev, 'combined_performed')
const change = today - yesterday
const percent = change > 0
? ((change / yesterday) * 100)
: ((change / today) * 100)
if (Math.abs(percent) === Infinity) return 100
if (isNaN(percent)) return 0
return Math.abs(percent.toFixed(1))
}),
percent_positive: computed(() => {
if (!data.value) return null
return col(data.value.testing, data.value.testing.current, 'seven_day_percent_positive')
}),
current_cases: computed(() => {
if (!data.value) return null
return col(data.value.cases, data.value.cases.current, 'cases')
}),
current_case_change: computed(() => {
if (!data.value) return null
const today = col(data.value.cases, data.value.cases.current, 'cases')
const yesterday = col(data.value.cases, data.value.cases.prev, 'cases')
return today - yesterday
}),
current_case_change_percent: computed(() => {
if (!data.value) return null
const today = col(data.value.cases, data.value.cases.current, 'cases')
const yesterday = col(data.value.cases, data.value.cases.prev, 'cases')
const change = today - yesterday
const percent = change > 0
? ((change / yesterday) * 100)
: ((change / today) * 100)
if (Math.abs(percent) === Infinity) return 100
if (isNaN(percent)) return 0
return Math.abs(percent.toFixed(1))
}),
current_deaths: computed(() => {
if (!data.value) return null
return col(data.value.deaths, data.value.deaths.current, 'deaths')
}),
current_death_change: computed(() => {
if (!data.value) return null
const today = col(data.value.deaths, data.value.deaths.current, 'deaths')
const yesterday = col(data.value.deaths, data.value.deaths.prev, 'deaths')
return today - yesterday
}),
current_death_change_percent: computed(() => {
if (!data.value) return null
const today = col(data.value.deaths, data.value.deaths.current, 'deaths')
const yesterday = col(data.value.deaths, data.value.deaths.prev, 'deaths')
const change = today - yesterday
const percent = change > 0
? ((change / yesterday) * 100)
: ((change / today) * 100)
if (Math.abs(percent) === Infinity) return 100
if (isNaN(percent)) return 0
return Math.abs(percent.toFixed(1))
}),
total_cases: computed(() => {
if (!data.value) return null
return col(data.value.cases, data.value.cases.current, 'total_cases')
}),
total_deaths: computed(() => {
if (!data.value) return null
return col(data.value.deaths, data.value.deaths.current, 'total_deaths')
})
})
</script>

View File

@@ -0,0 +1,13 @@
import { reactive, ref, watch } from 'vue'
const store = {
data: ref(null)
}
async function refreshData() {
store.data.value = await fetch(`/data/summary.json`).then(res => res.json())
}
if (globalThis.window) refreshData()
export default store

View File

@@ -1,7 +1,7 @@
export const colors = ['#f5f3ff','#ede9fe','#ddd6fe','#c4b5fd','#a78bfa','#8b5cf6','#7c3aed','#6d28d9','#5b21b6','#4c1d95']
export function col(data, row, column) {
const index = data.value.headers.indexOf(column)
const index = data.headers ? data.headers.indexOf(column) : data.value.headers.indexOf(column)
if (index === -1) return null
return row[index]
}