-
Notifications
You must be signed in to change notification settings - Fork 716
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(demo): add radial bars demo using Arc (#1785)
- Loading branch information
Showing
7 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
23 changes: 23 additions & 0 deletions
23
packages/visx-demo/src/components/Gallery/RadialBarsTile.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from 'react'; | ||
import RadialBars, { RadialBarsProps } from '../../sandboxes/visx-radial-bars/Example'; | ||
import GalleryTile from '../GalleryTile'; | ||
|
||
export { default as packageJson } from '../../sandboxes/visx-radial-bars/package.json'; | ||
|
||
const tileStyles = { background: '#3dbdb1' }; | ||
const detailsStyles = { color: '#93F9B9' }; | ||
const exampleProps = { showControls: false }; | ||
|
||
export default function BarsTile() { | ||
return ( | ||
<GalleryTile<RadialBarsProps> | ||
title="Radial Bars" | ||
description="<Shape.Arc />" | ||
exampleProps={exampleProps} | ||
exampleRenderer={RadialBars} | ||
exampleUrl="/radial-bars" | ||
tileStyles={tileStyles} | ||
detailsStyles={detailsStyles} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React from 'react'; | ||
import RadialBars from '../sandboxes/visx-radial-bars/Example'; | ||
import packageJson from '../sandboxes/visx-radial-bars/package.json'; | ||
import Show from '../components/Show'; | ||
import RadialBarsSource from '!!raw-loader!../sandboxes/visx-radial-bars/Example'; | ||
|
||
function BarsRadialPage() { | ||
return ( | ||
<Show | ||
events | ||
component={RadialBars} | ||
title="Radial Bars" | ||
codeSandboxDirectoryName="visx-radial-bars" | ||
packageJson={packageJson} | ||
> | ||
{RadialBarsSource} | ||
</Show> | ||
); | ||
} | ||
export default BarsRadialPage; |
156 changes: 156 additions & 0 deletions
156
packages/visx-demo/src/sandboxes/visx-radial-bars/Example.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import React, { useMemo, useState } from 'react'; | ||
import { Arc } from '@visx/shape'; | ||
import { Group } from '@visx/group'; | ||
import { GradientLightgreenGreen } from '@visx/gradient'; | ||
import { scaleBand, scaleRadial } from '@visx/scale'; | ||
import { Text } from '@visx/text'; | ||
import letterFrequency, { LetterFrequency } from '@visx/mock-data/src/mocks/letterFrequency'; | ||
|
||
const data = letterFrequency; | ||
|
||
const getLetter = (d: LetterFrequency) => d.letter; | ||
const getLetterFrequency = (d: LetterFrequency) => Number(d.frequency) * 100; | ||
|
||
const frequencySort = (a: LetterFrequency, b: LetterFrequency) => b.frequency - a.frequency; | ||
const alphabeticalSort = (a: LetterFrequency, b: LetterFrequency) => | ||
a.letter.localeCompare(b.letter); | ||
|
||
const toRadians = (x: number) => (x * Math.PI) / 180; | ||
const toDegrees = (x: number) => (x * 180) / Math.PI; | ||
|
||
const barColor = '#93F9B9'; | ||
const margin = { top: 20, bottom: 20 }; | ||
|
||
export type RadialBarsProps = { | ||
width: number; | ||
height: number; | ||
showControls?: boolean; | ||
}; | ||
|
||
export default function Example({ width, height, showControls = true }: RadialBarsProps) { | ||
const [rotation, setRotation] = useState(0); | ||
const [sortAlphabetically, setSortAlphabetically] = useState(true); | ||
|
||
// bounds | ||
const xMax = width; | ||
const yMax = height - margin.top - margin.bottom; | ||
const radiusMax = Math.min(xMax, yMax) / 2; | ||
|
||
const innerRadius = radiusMax / 3; | ||
|
||
const xDomain = useMemo( | ||
() => data.sort(sortAlphabetically ? alphabeticalSort : frequencySort).map(getLetter), | ||
[sortAlphabetically], | ||
); | ||
|
||
const xScale = useMemo( | ||
() => | ||
scaleBand<string>({ | ||
range: [0 + rotation, 2 * Math.PI + rotation], | ||
domain: xDomain, | ||
padding: 0.2, | ||
}), | ||
[rotation, xDomain], | ||
); | ||
|
||
const yScale = useMemo( | ||
() => | ||
scaleRadial<number>({ | ||
range: [innerRadius, radiusMax], | ||
domain: [0, Math.max(...data.map(getLetterFrequency))], | ||
}), | ||
[innerRadius, radiusMax], | ||
); | ||
|
||
return width < 10 ? null : ( | ||
<> | ||
<svg width={width} height={height}> | ||
<GradientLightgreenGreen id="green" /> | ||
<rect width={width} height={height} fill="url(#green)" rx={14} /> | ||
<Group top={yMax / 2 + margin.top} left={xMax / 2}> | ||
{data.map((d) => { | ||
const letter = getLetter(d); | ||
const startAngle = xScale(letter); | ||
const midAngle = startAngle + xScale.bandwidth() / 2; | ||
const endAngle = startAngle + xScale.bandwidth(); | ||
|
||
const outerRadius = yScale(getLetterFrequency(d)) ?? 0; | ||
|
||
// convert polar coordinates to cartesian for drawing labels | ||
const textRadius = outerRadius + 4; | ||
const textX = textRadius * Math.cos(midAngle - Math.PI / 2); | ||
const textY = textRadius * Math.sin(midAngle - Math.PI / 2); | ||
|
||
return ( | ||
<> | ||
<Arc | ||
key={`bar-${letter}`} | ||
cornerRadius={4} | ||
startAngle={startAngle} | ||
endAngle={endAngle} | ||
outerRadius={outerRadius} | ||
innerRadius={innerRadius} | ||
fill={barColor} | ||
/> | ||
<Text | ||
x={textX} | ||
y={textY} | ||
dominantBaseline="end" | ||
textAnchor="middle" | ||
fontSize={16} | ||
fontWeight="bold" | ||
fill={barColor} | ||
angle={toDegrees(midAngle)} | ||
> | ||
{letter} | ||
</Text> | ||
</> | ||
); | ||
})} | ||
</Group> | ||
</svg> | ||
{showControls && ( | ||
<div className="controls"> | ||
<label> | ||
<strong>Rotate</strong> | ||
<input | ||
type="range" | ||
min="0" | ||
max="360" | ||
value={toDegrees(rotation)} | ||
onChange={(e) => setRotation(toRadians(Number(e.target.value)))} | ||
/> | ||
{toDegrees(rotation).toFixed(0)}° | ||
</label> | ||
<br /> | ||
<div> | ||
<strong>Sort bars</strong> | ||
<label> | ||
<input | ||
type="radio" | ||
checked={sortAlphabetically} | ||
onChange={(e) => setSortAlphabetically(true)} | ||
/> | ||
Alphabetically | ||
</label> | ||
<label> | ||
<input | ||
type="radio" | ||
checked={!sortAlphabetically} | ||
onChange={(e) => setSortAlphabetically(false)} | ||
/> | ||
By frequency | ||
</label> | ||
</div> | ||
<br /> | ||
</div> | ||
)} | ||
<style jsx>{` | ||
.controls { | ||
font-size: 14px; | ||
line-height: 1.5em; | ||
} | ||
`}</style> | ||
</> | ||
); | ||
} |
12 changes: 12 additions & 0 deletions
12
packages/visx-demo/src/sandboxes/visx-radial-bars/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react'; | ||
import { createRoot } from 'react-dom/client'; | ||
import ParentSize from '@visx/responsive/lib/components/ParentSize'; | ||
|
||
import Example from './Example'; | ||
import './sandbox-styles.css'; | ||
|
||
const root = createRoot(document.getElementById('root')!); | ||
|
||
root.render( | ||
<ParentSize>{({ width, height }) => <Example width={width} height={height} />}</ParentSize>, | ||
); |
29 changes: 29 additions & 0 deletions
29
packages/visx-demo/src/sandboxes/visx-radial-bars/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"name": "@visx/demo-radial-bars", | ||
"description": "Standalone visx radial bars demo.", | ||
"main": "index.tsx", | ||
"private": true, | ||
"dependencies": { | ||
"@babel/runtime": "^7.8.4", | ||
"@types/react": "^18", | ||
"@types/react-dom": "^18", | ||
"@visx/gradient": "latest", | ||
"@visx/group": "latest", | ||
"@visx/mock-data": "latest", | ||
"@visx/responsive": "latest", | ||
"@visx/scale": "latest", | ||
"@visx/shape": "latest", | ||
"@visx/text": "latest", | ||
"react": "^18", | ||
"react-dom": "^18", | ||
"react-scripts-ts": "3.1.0", | ||
"typescript": "^3" | ||
}, | ||
"keywords": [ | ||
"visualization", | ||
"d3", | ||
"react", | ||
"visx", | ||
"bar" | ||
] | ||
} |
8 changes: 8 additions & 0 deletions
8
packages/visx-demo/src/sandboxes/visx-radial-bars/sandbox-styles.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
html, | ||
body, | ||
#root { | ||
height: 100%; | ||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, | ||
'Open Sans', 'Helvetica Neue', sans-serif; | ||
line-height: 2em; | ||
} |