Skip to content

Commit

Permalink
Add charting library with common chart types (#1104)
Browse files Browse the repository at this point in the history
* feat: resolve linting issues in charts pkg

* refactor: replace .displayName with function names where possible

* build: remove rollup config

* build: update essex scripts; rebuild yarn lock

* build: set @chart-parts/charts version

* build: remove duplicate command

* build: remove custom storybook config

* build: rename story files

* build: update essex/scripts
  • Loading branch information
darthtrevino authored Jun 23, 2020
1 parent 1cc9659 commit aa1f2fa
Show file tree
Hide file tree
Showing 94 changed files with 3,677 additions and 1,200 deletions.
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.js text eol=lf
*.jsx text eol=lf
*.json text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.md text eol=lf
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"release:packages": "lerna run release --stream",
"lint": "essex lint --strict --docs",
"unit_test": "essex test --coverage",
"ci": "run-s lint build unit_test test:packages",
"git_is_clean": "essex git-is-clean",
"ci": "run-s lint build unit_test test:packages git_is_clean",
"publish_libs": "lerna publish",
"changelog": "conventional-changelog -p eslint -i CHANGELOG.md -s -r 0",
"release": "run-s clean test publish_libs changelog release:packages"
Expand All @@ -20,9 +21,9 @@
"devDependencies": {
"@essex/eslint-config": "^7.0.3",
"@essex/eslint-plugin": "^7.0.3",
"@essex/scripts": "^7.0.4",
"@typescript-eslint/eslint-plugin": "^3.1.0",
"@typescript-eslint/parser": "^3.1.0",
"@essex/scripts": "^7.3.1",
"@typescript-eslint/eslint-plugin": "^3.4.0",
"@typescript-eslint/parser": "^3.4.0",
"conventional-changelog-cli": "^2.0.23",
"cross-env": "^7.0.2",
"jest-html": "^1.5.0",
Expand Down
36 changes: 36 additions & 0 deletions packages/client/charts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@chart-parts/charts",
"version": "0.1.3",
"description": "Constructed chart archetypes for chart-parts",
"author": "Amber Hoak ([email protected])",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/typings/index.d.ts",
"license": "MIT",
"scripts": {
"clean": "essex clean",
"build": "essex build",
"watch": "essex watch",
"serve": "essex start-storybook",
"start": "run-p watch serve"
},
"dependencies": {
"@chart-parts/interfaces": "^0.1.3",
"@chart-parts/react": "^0.1.3",
"@chart-parts/transform": "^0.1.3",
"@types/node": "^14.0.13",
"@types/react": "^16.9.38",
"@types/react-dom": "^16.9.8"
},
"devDependencies": {
"@chart-parts/react-svg-renderer": "^0.1.3",
"@types/react-color": "^3.0.2",
"@types/webpack-env": "^1.15.2",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"peerDependencies": {
"react": ">= 16.9.0",
"react-dom": ">= 16.9.0"
}
}
18 changes: 18 additions & 0 deletions packages/client/charts/src/AreaChart/AreaChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import React, { memo } from 'react'
import { AreaChartProps } from './types'
import { StackedAreaChart } from './variants/StackedAreaChart'
import { PlainAreaChart } from './variants/PlainAreaChart'

export const AreaChart: React.FC<AreaChartProps> = memo(function AreaChart(
props,
) {
if (props.groupBy) {
return <StackedAreaChart {...props} />
} else {
return <PlainAreaChart {...props} />
}
})
6 changes: 6 additions & 0 deletions packages/client/charts/src/AreaChart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
export * from './AreaChart'
export * from './types'
51 changes: 51 additions & 0 deletions packages/client/charts/src/AreaChart/marks/AreaMarks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import React, { memo } from 'react'
import { FillMarkProps } from '../../types'
import { Area } from '@chart-parts/react'
import { Interpolation, MarkEncoding } from '@chart-parts/interfaces'
import {
encodeCategoryAriaTitle,
encodeCategoryAriaDescription,
} from '../../hooks'

const DEFAULT_STROKE = 'black'
const DEFAULT_FILL = 'steelblue'
const DEFAULT_FILL_OPACITY = 1
const DEFAULT_STROKE_WIDTH = 2

const encodeX: MarkEncoding<number> = ({ d, x }) => x(d.key)
const encodeY: MarkEncoding<number> = ({ d, y }) => y(d.value)
const encodeY2: MarkEncoding<number> = ({ y }) => y(0)

export const AreaMarks: React.FC<FillMarkProps> = memo(function AreaMarks({
onClick,
onMouseEnter,
onMouseLeave,
fill = DEFAULT_FILL,
fillOpacity = DEFAULT_FILL_OPACITY,
stroke = DEFAULT_STROKE,
strokeWidth = DEFAULT_STROKE_WIDTH,
}) {
return (
<Area
table="data"
tabIndex={-1}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
fill={fill}
stroke={stroke}
fillOpacity={fillOpacity}
strokeWidth={strokeWidth}
interpolate={Interpolation.Monotone}
ariaTitle={encodeCategoryAriaTitle}
ariaDescription={encodeCategoryAriaDescription}
x={encodeX}
y={encodeY}
y2={encodeY2}
/>
)
})
53 changes: 53 additions & 0 deletions packages/client/charts/src/AreaChart/marks/StackedAreaMarks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import React, { memo } from 'react'
import { FillMarkProps } from '../../types'
import { Area } from '@chart-parts/react'
import { Interpolation, MarkEncoding } from '@chart-parts/interfaces'
import {
encodeCategoryAriaTitle,
encodeCategoryAriaDescription,
} from '../../hooks'

const DEFAULT_FILL: MarkEncoding<string> = ctx => ctx.color(ctx.d._category)
const DEFAULT_FILL_OPACITY = 1
const DEFAULT_STROKE = 'black'
const DEFAULT_STROKE_WIDTH = 2

const encodeX: MarkEncoding<number> = ({ d, x }) => x(d.key)
const encodeY: MarkEncoding<number> = ({ d, y }) => y(d.y0)
const encodeY2: MarkEncoding<number> = ({ d, y }) => y(d.y1)

export const StackedAreaMarks: React.FC<FillMarkProps> = memo(
function StackedAreaMarks({
onClick,
onMouseEnter,
onMouseLeave,
fill = DEFAULT_FILL,
fillOpacity = DEFAULT_FILL_OPACITY,
stroke = DEFAULT_STROKE,
strokeWidth = DEFAULT_STROKE_WIDTH,
}) {
return (
<Area
table="faceted"
tabIndex={-1}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
fill={fill}
fillOpacity={fillOpacity}
interpolate={Interpolation.Monotone}
stroke={stroke}
strokeWidth={strokeWidth}
ariaTitle={encodeCategoryAriaTitle}
ariaDescription={encodeCategoryAriaDescription}
x={encodeX}
y={encodeY}
y2={encodeY2}
/>
)
},
)
11 changes: 11 additions & 0 deletions packages/client/charts/src/AreaChart/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { CommonChartProps, FillMarkProps, AxisProps } from '../types'

export interface AreaChartProps extends CommonChartProps, FillMarkProps {
groupBy?: string
xAxisProps?: AxisProps
yAxisProps?: AxisProps
}
62 changes: 62 additions & 0 deletions packages/client/charts/src/AreaChart/variants/PlainAreaChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import React, { useMemo, memo } from 'react'
import { Axis, LinearScale, Dimension } from '@chart-parts/react'
import { AxisOrientation } from '@chart-parts/interfaces'
import { createChartContainer } from '../../util'
import { AreaMarks } from '../marks/AreaMarks'
import { AreaChartProps } from '../types'

const Container = createChartContainer('Area Chart')

export const PlainAreaChart: React.FC<AreaChartProps> = memo(
function PlainAreaChart({
data,
height,
width,
title,
chartPadding,
description,
children,
xAxisProps,
yAxisProps,
...props
}) {
return (
<Container
width={width}
height={height}
data={useMemo(() => ({ data }), [data])}
title={title}
description={description}
padding={chartPadding}
>
<LinearScale
name="x"
domain="data.key"
range={Dimension.Width}
zero={false}
/>
<LinearScale
name="y"
domain="data.value"
range={Dimension.Height}
nice
zero
/>

<Axis
orient={AxisOrientation.Bottom}
scale="x"
tickCount={20}
{...xAxisProps}
/>
<Axis orient={AxisOrientation.Left} scale="y" {...yAxisProps} />
<AreaMarks {...props} />
{children}
</Container>
)
},
)
92 changes: 92 additions & 0 deletions packages/client/charts/src/AreaChart/variants/StackedAreaChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import React, { memo, useMemo } from 'react'
import {
Axis,
Group,
LinearScale,
Dimension,
OrdinalScale,
CategoricalColorScheme,
} from '@chart-parts/react'
import { AxisOrientation } from '@chart-parts/interfaces'
import { stack, dataset } from '@chart-parts/transform'
import { useDataGroupSorted, useGroupByFaceting } from '../../hooks'
import { createChartContainer } from '../../util'
import { StackedAreaMarks } from '../marks/StackedAreaMarks'
import { AreaChartProps } from '../types'

const Container = createChartContainer('Stacked Area Chart')

export const StackedAreaChart: React.FC<AreaChartProps> = memo(
function StackedAreaChart({
data,
height,
width,
title,
chartPadding,
description,
children,
groupBy,
xAxisProps,
yAxisProps,
...props
}) {
return (
<Container
width={width}
height={height}
data={useStackedAreaChartData(groupBy, data)}
title={title}
description={description}
padding={chartPadding}
>
<LinearScale name="x" domain="data.key" range={Dimension.Width} />
<LinearScale
name="y"
domain="data.y1"
range={Dimension.Height}
nice
zero
/>
<Axis
orient={AxisOrientation.Bottom}
scale="x"
labelPadding={10}
tickSize={10}
{...xAxisProps}
/>
<OrdinalScale
name="color"
domain="data._category"
colorScheme={CategoricalColorScheme.category10}
/>
<Axis orient={AxisOrientation.Left} scale="y" {...yAxisProps} />
<Group table="data" facet={useGroupByFaceting(groupBy)}>
<StackedAreaMarks {...props} />
{children}
</Group>
</Container>
)
},
)

function useStackedAreaChartData(groupBy: string | undefined, data: any[]) {
const dataSorted = useDataGroupSorted(groupBy, data)
const dataMapping = useMemo(() => {
let mapped = data
if (dataSorted) {
const ds = dataset().addTable(
'data',
dataSorted,
stack('value').groupBy('key').sort({ field: '_category' }),
)
mapped = ds.getTable('data')
}

return mapped
}, [data, dataSorted])
return useMemo(() => ({ data: dataMapping }), [dataMapping])
}
19 changes: 19 additions & 0 deletions packages/client/charts/src/BarChart/BarChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import React, { memo } from 'react'
import { BarChartProps } from './types'
import { StackedBarChart } from './variants/StackedBarChart'
import { GroupedBarChart } from './variants/GroupedBarChart'
import { PlainBarChart } from './variants/PlainBarChart'

export const BarChart: React.FC<BarChartProps> = memo(function BarChart(props) {
if (props.groupBy && props.stacked) {
return <StackedBarChart {...props} />
} else if (props.groupBy) {
return <GroupedBarChart {...props} />
} else {
return <PlainBarChart {...props} />
}
})
7 changes: 7 additions & 0 deletions packages/client/charts/src/BarChart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
export * from './BarChart'
export * from './types'
export * from './marks/BarTips'
Loading

0 comments on commit aa1f2fa

Please sign in to comment.