diff --git a/packages/visx-demo/src/components/Gallery/RadialBarsTile.tsx b/packages/visx-demo/src/components/Gallery/RadialBarsTile.tsx new file mode 100644 index 000000000..3a9d49bb9 --- /dev/null +++ b/packages/visx-demo/src/components/Gallery/RadialBarsTile.tsx @@ -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 ( + + title="Radial Bars" + description="" + exampleProps={exampleProps} + exampleRenderer={RadialBars} + exampleUrl="/radial-bars" + tileStyles={tileStyles} + detailsStyles={detailsStyles} + /> + ); +} diff --git a/packages/visx-demo/src/components/Gallery/index.tsx b/packages/visx-demo/src/components/Gallery/index.tsx index d54d24e4b..36fa01b87 100644 --- a/packages/visx-demo/src/components/Gallery/index.tsx +++ b/packages/visx-demo/src/components/Gallery/index.tsx @@ -36,6 +36,7 @@ import * as PatternsTile from './PatternsTile'; import * as PiesTile from './PiesTile'; import * as PolygonsTile from './PolygonsTile'; import * as RadarTile from './RadarTile'; +import * as RadialBarsTile from './RadialBarsTile'; import * as ResponsiveTile from './ResponsiveTile'; import * as SplitLinePathTile from './SplitLinePathTile'; import * as StackedAreasTile from './StackedAreasTile'; @@ -95,6 +96,7 @@ export const tiles = [ PackTile, PolygonsTile, RadarTile, + RadialBarsTile, ResponsiveTile, SplitLinePathTile, StatsPlotTile, diff --git a/packages/visx-demo/src/pages/radial-bars.tsx b/packages/visx-demo/src/pages/radial-bars.tsx new file mode 100644 index 000000000..f0285ea91 --- /dev/null +++ b/packages/visx-demo/src/pages/radial-bars.tsx @@ -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 ( + + {RadialBarsSource} + + ); +} +export default BarsRadialPage; diff --git a/packages/visx-demo/src/sandboxes/visx-radial-bars/Example.tsx b/packages/visx-demo/src/sandboxes/visx-radial-bars/Example.tsx new file mode 100644 index 000000000..f059945fb --- /dev/null +++ b/packages/visx-demo/src/sandboxes/visx-radial-bars/Example.tsx @@ -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({ + range: [0 + rotation, 2 * Math.PI + rotation], + domain: xDomain, + padding: 0.2, + }), + [rotation, xDomain], + ); + + const yScale = useMemo( + () => + scaleRadial({ + range: [innerRadius, radiusMax], + domain: [0, Math.max(...data.map(getLetterFrequency))], + }), + [innerRadius, radiusMax], + ); + + return width < 10 ? null : ( + <> + + + + + {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 ( + <> + + + {letter} + + + ); + })} + + + {showControls && ( +
+ +
+
+ Sort bars    + + +
+
+
+ )} + + + ); +} diff --git a/packages/visx-demo/src/sandboxes/visx-radial-bars/index.tsx b/packages/visx-demo/src/sandboxes/visx-radial-bars/index.tsx new file mode 100644 index 000000000..537d244f5 --- /dev/null +++ b/packages/visx-demo/src/sandboxes/visx-radial-bars/index.tsx @@ -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( + {({ width, height }) => }, +); diff --git a/packages/visx-demo/src/sandboxes/visx-radial-bars/package.json b/packages/visx-demo/src/sandboxes/visx-radial-bars/package.json new file mode 100644 index 000000000..1ad224e97 --- /dev/null +++ b/packages/visx-demo/src/sandboxes/visx-radial-bars/package.json @@ -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" + ] +} diff --git a/packages/visx-demo/src/sandboxes/visx-radial-bars/sandbox-styles.css b/packages/visx-demo/src/sandboxes/visx-radial-bars/sandbox-styles.css new file mode 100644 index 000000000..b91993723 --- /dev/null +++ b/packages/visx-demo/src/sandboxes/visx-radial-bars/sandbox-styles.css @@ -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; +}