Skip to content

Commit

Permalink
Display loading indicators while content is loading (#88)
Browse files Browse the repository at this point in the history
This commit displays indicators while content is loading. Because the
PieChart and BarChart components are managed by `recharts`, I could not
use `blueprintjs` skeleton classes. Therefore these have manual loading
effects, and may appear slightly different than the table, which uses
the `blueprintjs` skeleton class.

Progress bars were added as an extra visual indicator for people with
bad eyesight. Building the search index for the constraints is now done
in a web worker so that the UI does not hang up while loading data.

Closes: #87

Squashed commits:
* Upgrade yarn to 2.1
* Show loader for pie chart
* show progress bar
* Show loader for bar chart
* Show loader for table chart
* Fix: index large data for searching in a web worker
  • Loading branch information
JM-Mendez authored Jul 15, 2020
1 parent 8ae72fe commit dc624f3
Show file tree
Hide file tree
Showing 20 changed files with 800 additions and 157 deletions.
Binary file removed .yarn/cache/fsevents-patch-c1e499bda9-6fb6ae0c1e.zip
Binary file not shown.
Binary file not shown.
Binary file removed .yarn/cache/resolve-patch-2fb34a43ac-fe7e72ddef.zip
Binary file not shown.
Binary file removed .yarn/cache/resolve-patch-859b777b3b-5238277188.zip
Binary file not shown.
Binary file removed .yarn/cache/resolve-patch-aec3b70245-a977306c59.zip
Binary file not shown.
Binary file removed .yarn/cache/resolve-patch-c66c1ab009-76954aad72.zip
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@
"stylelint-declaration-block-no-ignored-properties": "^2.3.0",
"stylelint-webpack-plugin": "^2.0.0",
"typescript": "^3.9.6",
"webpack-bundle-analyzer": "^3.8.0"
"webpack-bundle-analyzer": "^3.8.0",
"worker-loader": "^2.0.0"
},
"resolutions": {
"webpack": "4.42.0"
Expand Down
2 changes: 1 addition & 1 deletion src/components/Constraints/SelectPopup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const SelectPopup = ({
// the value directly to the added constraints list when clicked, so we reset the input here
const renderInputValue = () => ''
const filterQuery = (query, items) => {
if (query === '' && searchIndex) {
if (query === '' && searchIndex?.current !== null) {
return items.filter((i) => !selectedValues.includes(i.name))
}

Expand Down
159 changes: 96 additions & 63 deletions src/components/DataViz/BarChart.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ELEVATION_0 } from '@blueprintjs/core/lib/esm/common/classes'
import { ProgressBar } from '@blueprintjs/core'
import { assign } from '@xstate/immer'
import React from 'react'
import {
Expand All @@ -14,33 +14,44 @@ import {
} from 'recharts'
import { FETCH_INITIAL_SUMMARY } from 'src/actionConstants'
import { fetchSummary } from 'src/fetchSummary'
import { blinkingSkeletonAnimation } from 'src/styleUtils'
import { Machine } from 'xstate'

import { useMachineBus } from '../../machineBus'
import { barChartLoadingData } from '../loadingData/barChartData'
import { DATA_VIZ_COLORS } from './dataVizColors'

const renderCustomTick = ({ x, y, payload }) => {
const renderCustomTick = (isLoading) => ({ x, y, payload }) => {
return (
<g transform={`translate(${x},${y})`}>
<text
x={0}
y={0}
dy={10}
fontSize="var(--fs-desktopS1)"
fontStyle="var(--fw-medium)"
textAnchor="end"
fill="var(--grey5)"
transform="rotate(-55)"
>
{payload.value}
</text>
{isLoading ? (
<rect width={5} height={50} fill="var(--grey2)" transform="rotate(45)">
{payload.value}
</rect>
) : (
<text
x={0}
y={0}
dy={10}
fontSize="var(--fs-desktopS1)"
fontStyle="var(--fw-medium)"
textAnchor="end"
fill="var(--grey5)"
transform="rotate(-55)"
>
{payload.value}
</text>
)}
</g>
)
}

const colorizeBars = (data) =>
const colorizeBars = (data, isLoading) =>
data.map((entry, index) => (
<Cell key={entry} fill={DATA_VIZ_COLORS[index % DATA_VIZ_COLORS.length]} />
<Cell
key={entry}
fill={isLoading ? 'var(--grey2)' : DATA_VIZ_COLORS[index % DATA_VIZ_COLORS.length]}
/>
))

export const BarChartMachine = Machine(
Expand All @@ -53,7 +64,7 @@ export const BarChartMachine = Machine(
max: 0,
buckets: 0,
uniqueValues: 0,
average: ELEVATION_0,
average: 0,
stdev: 0,
},
lengthSummary: [],
Expand All @@ -70,7 +81,7 @@ export const BarChartMachine = Machine(
id: 'fetchGeneLength',
src: 'fetchGeneLength',
onDone: {
target: 'idle',
target: 'pending',
actions: 'setLengthSummary',
},
onError: {
Expand All @@ -79,6 +90,11 @@ export const BarChartMachine = Machine(
},
},
},
pending: {
after: {
500: 'idle',
},
},
},
},
{
Expand Down Expand Up @@ -127,11 +143,12 @@ export const BarChartMachine = Machine(
)

export const BarChart = () => {
const [
{
context: { lengthStats, lengthSummary },
},
] = useMachineBus(BarChartMachine)
const [state] = useMachineBus(BarChartMachine)

const { lengthSummary, lengthStats } = state.context

const isLoading = !state.matches('idle')
const summary = isLoading ? barChartLoadingData : lengthSummary

const { max, min, buckets, uniqueValues, average, stdev } = lengthStats

Expand All @@ -142,7 +159,7 @@ export const BarChart = () => {
const title = `Distribution of ${uniqueValues} Gene Lengths`
const subtitle = `Min: ${min} ⚬ Max: ${max} ⚬ Avg: ${avgFixed} ⚬ Stdev: ${stdevFixed}`

const chartData = lengthSummary.map((item, idx) => {
const chartData = summary.map((item, idx) => {
const lowerLimit = Math.round(min + elementsPerBucket * idx)
const upperLimit = Math.round(min + elementsPerBucket * (idx + 1))

Expand All @@ -158,44 +175,60 @@ export const BarChart = () => {
})

return (
<ResponsiveContainer width="100%" height="100%">
<RBarChart data={chartData} barCategoryGap="20%" margin={{ left: 100, bottom: 200 }}>
<Bar dataKey="data">{colorizeBars(chartData)}</Bar>
<Tooltip
itemStyle={{
color: 'var(--blue9)',
}}
wrapperStyle={{
border: '2px solid var(--blue9)',
borderRadius: '3px',
}}
formatter={(_, __, props) => [props.payload.count, 'Total Values']}
/>
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<XAxis dataKey="distribution" interval={0} tick={renderCustomTick}>
<Label
fill="var(--blue9)"
fontWeight={500}
value={title}
offset={120}
position="bottom"
/>
<Label
fill="var(--blue9)"
fontWeight={500}
value={subtitle}
position="bottom"
offset={150}
/>
</XAxis>
{chartData.length > 0 && (
<Brush dataKey="distribution" y={290}>
<RBarChart>
<Bar dataKey="data">{colorizeBars(chartData)}</Bar>
</RBarChart>
</Brush>
)}
</RBarChart>
</ResponsiveContainer>
<>
<ResponsiveContainer
width="100%"
height="95%"
css={isLoading ? blinkingSkeletonAnimation : {}}
>
<RBarChart data={chartData} barCategoryGap="20%" margin={{ left: 100, bottom: 200 }}>
<Bar dataKey="data">{colorizeBars(chartData, isLoading)}</Bar>
{!isLoading && (
<Tooltip
itemStyle={{
color: 'var(--blue9)',
}}
wrapperStyle={{
border: '2px solid var(--blue9)',
borderRadius: '3px',
}}
formatter={(_, __, props) => [props.payload.count, 'Total Values']}
/>
)}
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<XAxis dataKey="distribution" interval={0} tick={renderCustomTick(isLoading)}>
<Label
fill="var(--blue9)"
fontWeight={500}
value={isLoading ? 'Loading Bar data' : title}
offset={120}
position="bottom"
/>
<Label
fill="var(--blue9)"
fontWeight={500}
value={subtitle}
position="bottom"
offset={150}
content={
isLoading
? () => <rect width="70%" height={16} y={250} x="25%" fill="var(--grey2)" />
: null
}
/>
</XAxis>
{chartData.length > 0 && (
<Brush dataKey="distribution" y={280}>
<RBarChart>
<Bar dataKey="data">{colorizeBars(chartData, isLoading)}</Bar>
</RBarChart>
</Brush>
)}
</RBarChart>
</ResponsiveContainer>
{isLoading && (
<ProgressBar intent="primary" css={{ width: '50%', marginLeft: '35%', marginTop: 20 }} />
)}
</>
)
}
1 change: 0 additions & 1 deletion src/components/DataViz/DataViz.story.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ BarChart.parameters = {

const pieMockMachine = PieChartMachine.withContext({
allClassOrganisms: organismSummary.results,
filteredOrganisms: [],
classView: '',
})

Expand Down
Loading

0 comments on commit dc624f3

Please sign in to comment.