|
| 1 | +import React, { useState } from 'react' |
| 2 | +import { VisXYContainer, VisLine, VisAxis, VisScatter, VisCrosshair, VisTooltip, VisAnnotations } from '@unovis/react' |
| 3 | +import { CurveType } from '@unovis/ts' |
| 4 | + |
| 5 | +import { ExampleViewerDurationProps } from '@src/components/ExampleViewer' |
| 6 | + |
| 7 | +import s from './style.module.css' |
| 8 | + |
| 9 | +export const title = 'Patchy Line Chart' |
| 10 | +export const subTitle = 'Various test cases' |
| 11 | + |
| 12 | +type TestCase = { |
| 13 | + title: string; |
| 14 | + data: (number | undefined | null)[]; |
| 15 | +} |
| 16 | + |
| 17 | +const testCases: TestCase[] = [ |
| 18 | + { title: 'Gaps in middle', data: [3, 1, undefined, 7, undefined, 1, 1, undefined, 0.5, 4] }, |
| 19 | + { title: 'Longer gaps', data: [2, 3, undefined, undefined, undefined, 12, 10, undefined, undefined, 2] }, |
| 20 | + { title: 'Gaps at ends', data: [7, undefined, 9, 10, 7, 4, 5, 2, undefined, 10] }, |
| 21 | + { title: 'Gaps at true ends', data: [undefined, 2, 10, 4, 5, 2, 6, 2, 3, undefined] }, |
| 22 | + { title: 'Gaps surrounding single point', data: [5, 3, 6, undefined, 2, undefined, 10, 8, 9, 5] }, |
| 23 | + { title: 'All undefined', data: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined] }, |
| 24 | + { title: 'Single point', data: [undefined, undefined, undefined, undefined, 10, undefined] }, |
| 25 | + { title: 'Missing every other point', data: [3, undefined, 12, undefined, 7, undefined, 5, undefined, 12] }, |
| 26 | + { title: 'Includes undefined and null values', data: [3, 5, undefined, 6, 7, null, 9, 10, undefined, 4] }, |
| 27 | + |
| 28 | +] |
| 29 | + |
| 30 | +export const component = (props: ExampleViewerDurationProps): JSX.Element => { |
| 31 | + type Datum = Record<string, number> |
| 32 | + const combined = Array.from({ length: 10 }, (_, i) => ({ |
| 33 | + x: i, |
| 34 | + ...(testCases.reduce((obj, d, j) => ({ |
| 35 | + ...obj, |
| 36 | + [`y${j}`]: d.data[i], |
| 37 | + }), {})), |
| 38 | + })) |
| 39 | + const x = (d: Datum): number => d.x |
| 40 | + const getY = (i: number) => (d: Datum) => d[`y${i}`] |
| 41 | + |
| 42 | + const fallbacks = [undefined, 0, 5, 10] |
| 43 | + const [fallbackValue, setFallbackValue] = useState(fallbacks[0]) |
| 44 | + const [interpolation, setInterpolation] = useState(true) |
| 45 | + const [showScatter, setShowScatter] = useState(true) |
| 46 | + |
| 47 | + return ( |
| 48 | + <div className={s.patchyLineExample}> |
| 49 | + <div className={s.inputs}> |
| 50 | + <label> |
| 51 | + Fallback value: |
| 52 | + <select onChange={e => setFallbackValue(fallbacks[Number(e.target.value)])}> |
| 53 | + {fallbacks.map((o, i) => <option value={i}>{String(o)}</option>)} |
| 54 | + </select> |
| 55 | + </label> |
| 56 | + <label> |
| 57 | + Interpolate:<input type='checkbox' checked={interpolation} onChange={e => setInterpolation(e.target.checked)}/> |
| 58 | + </label> |
| 59 | + <label> |
| 60 | + Show Scatter: <input type='checkbox' checked={showScatter} onChange={e => setShowScatter(e.target.checked)}/> |
| 61 | + </label> |
| 62 | + </div> |
| 63 | + <div className={s.singleLines}> |
| 64 | + {testCases.map((val, i) => ( |
| 65 | + <VisXYContainer<Datum> data={combined} key={i} xDomain={[-0.2, 9.2]} yDomain={[0, 15]} height={200} width='100%'> |
| 66 | + <VisAnnotations items={[{ content: val.title, x: '50%', y: 0, textAlign: 'center' }]}/> |
| 67 | + <VisLine |
| 68 | + curveType={CurveType.Linear} |
| 69 | + duration={props.duration} |
| 70 | + fallbackValue={fallbackValue} |
| 71 | + interpolateMissingData={interpolation} |
| 72 | + x={x} |
| 73 | + y={getY(i)} |
| 74 | + /> |
| 75 | + {showScatter && <VisScatter excludeFromDomainCalculation size={2} x={x} y={d => getY(i)(d) ?? undefined}/>} |
| 76 | + <VisCrosshair template={(d: Datum) => `${d.x}, ${getY(i)(d)}`} color='var(--vis-color0)' strokeWidth='1px'/> |
| 77 | + <VisTooltip/> |
| 78 | + <VisAxis type='x'/> |
| 79 | + <VisAxis type='y' domainLine={false}/> |
| 80 | + </VisXYContainer> |
| 81 | + ))} |
| 82 | + </div> |
| 83 | + </div> |
| 84 | + ) |
| 85 | +} |
0 commit comments