Add Stacked Bar Graph component (Closes #3) #37
|
@ -0,0 +1,35 @@
|
|||
.container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.barStack:hover {
|
||||
filter: drop-shadow(0 0 calc(4rem / 16) var(--label));
|
||||
}
|
||||
|
||||
.legend {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
font-size: calc(16rem / 16);
|
||||
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.toolTip {
|
||||
font-family: "Inconsolata", monospace;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
background-color: var(--label);
|
||||
color: var(--primary-background);
|
||||
pointer-events: none;
|
||||
border-radius: calc(10rem / 16);
|
||||
padding: calc(10rem / 16);
|
||||
}
|
||||
|
||||
.toolTip p {
|
||||
margin: 0 calc(5rem / 16);
|
||||
font-size: calc(16rem / 16);
|
||||
}
|
||||
|
||||
.key {
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,455 @@
|
|||
import { AxisLeft, AxisBottom } from "@visx/axis";
|
||||
import { localPoint } from "@visx/event";
|
||||
import { GridRows, GridColumns } from "@visx/grid";
|
||||
import { Group } from "@visx/group";
|
||||
import { LegendOrdinal } from "@visx/legend";
|
||||
import { Point } from "@visx/point";
|
||||
import { scaleBand, scaleLinear, scaleOrdinal } from "@visx/scale";
|
||||
import { BarStack, BarStackHorizontal, Line } from "@visx/shape";
|
||||
import { SeriesPoint } from "@visx/shape/lib/types";
|
||||
import { withTooltip, Tooltip } from "@visx/tooltip";
|
||||
import { WithTooltipProvidedProps } from "@visx/tooltip/lib/enhancers/withTooltip";
|
||||
import React from "react";
|
||||
import { Color } from "utils/Color";
|
||||
|
||||
import styles from "./StackedBarGraph.module.css";
|
||||
|
||||
interface StackedBarData {
|
||||
category: string;
|
||||
a258wang
commented
Have we considered
? Have we considered
```typescript
interface StackedBarData {
category: string;
values: {
[key: string]: number;
};
}
```
?
This would allow for a key called "category", at the expense of more nesting.
a258wang
commented
~~Also is there a reason why the value can be `number | string` and not just `number`?~~ EDIT: nvm, it's to make TS stop complaining
https://stackoverflow.com/questions/54460029/typescript-inteface-where-id-must-be-number-and-other-properties-must-be-strin
e26chiu
commented
I have considered the above, but it doesn't work since the format of the data doesn't match what is expected in the props
It specifically needs I have considered the above, but it doesn't work since the format of the data doesn't match what is expected in the props `data` taken by the `<BarStack>` component:
```
<BarStack<StackedBarData, string>
data={data}
keys={keys}
```
It specifically needs `category` to be a key in `data` and all the other keys to be directly nested inside of `data` (cannot be nested inside of `values`).
|
||||
[key: string]: number | string;
|
||||
}
|
||||
|
||||
type TooltipData = {
|
||||
bar: SeriesPoint<StackedBarData>;
|
||||
key: string;
|
||||
index: number;
|
||||
height: number;
|
||||
width: number;
|
||||
x: number;
|
||||
y: number;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export type StackedBarProps = {
|
||||
data: StackedBarData[];
|
||||
/** Width of the entire graph, in pixels, greater than 10. */
|
||||
width: number;
|
||||
/** Height of the entire graph, in pixels. */
|
||||
height: number;
|
||||
/** Names of the groups appearing in the legend */
|
||||
keys: string[];
|
||||
/** Colours for each key */
|
||||
colorRange: string[];
|
||||
/** Distance between the edge of the graph and the area where the bars are drawn, in pixels. */
|
||||
margin: { top: number; left: number };
|
||||
/** Number of ticks for the value axis */
|
||||
numTicksValueAxis?: number;
|
||||
/** Distance between the left axis labels and the start of the lines of the graph, in px. */
|
||||
axisLeftOffset?: number;
|
||||
/** Distance between the bottom axis and the bottom of the container of the graph, in px. */
|
||||
axisBottomOffset?: number;
|
||||
/** Distance between the right side of the graph and the legend, in px. */
|
||||
legendLeftOffset?: number;
|
||||
/** Distance between the top of the graph and the legend, in px. */
|
||||
legendTopOffset?: number;
|
||||
/** Width of the lines in the graph, in px. */
|
||||
strokeWidth?: number;
|
||||
/** Length of the dashes and the gaps in the graph, in px. */
|
||||
strokeDashArray?: string;
|
||||
/** Padding between each bar in the stacked bar graph, from 0 to 1 */
|
||||
scalePadding?: number;
|
||||
/** Margin for each item in the legend */
|
||||
itemMargin?: string;
|
||||
/** Factor multiplied with an offset to center the labels of the category-axis depending on the width/height of the graph.
|
||||
* >1 for width/height <600 and <1 for width/height >600 (vertical=width/horizontal=height) */
|
||||
categoryAxisLeftFactor?: number;
|
||||
a258wang
commented
NIT: background should be NIT: background should be `Color.label`
|
||||
};
|
||||
|
||||
let tooltipTimeout: number;
|
||||
|
||||
export const StackedBarGraphVertical = withTooltip<
|
||||
StackedBarProps,
|
||||
TooltipData
|
||||
>(
|
||||
({
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
keys,
|
||||
colorRange,
|
||||
margin,
|
||||
scalePadding = 0.3,
|
||||
numTicksValueAxis = 6,
|
||||
axisLeftOffset = 40,
|
||||
axisBottomOffset = 40,
|
||||
strokeWidth = 2.5,
|
||||
strokeDashArray = "10,4",
|
||||
legendLeftOffset = 40,
|
||||
legendTopOffset = 40,
|
||||
itemMargin = "15px 0 0 0",
|
||||
categoryAxisLeftFactor = 1,
|
||||
tooltipOpen,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
tooltipData,
|
||||
hideTooltip,
|
||||
showTooltip,
|
||||
}: StackedBarProps & WithTooltipProvidedProps<TooltipData>) => {
|
||||
const yTotals = data.reduce((allTotals, currCategory) => {
|
||||
const yTotal = keys.reduce((categoryTotal, k) => {
|
||||
categoryTotal += currCategory[k] as number;
|
||||
return categoryTotal;
|
||||
}, 0);
|
||||
allTotals.push(yTotal);
|
||||
return allTotals;
|
||||
}, [] as number[]);
|
||||
|
||||
const TICK_LABEL_FONT_WEIGHT = 800;
|
||||
|
||||
// accessors
|
||||
const getCategory = (d: StackedBarData) => d.category;
|
||||
|
||||
// scales
|
||||
const categoryScale = scaleBand<string>({
|
||||
domain: data.map(getCategory),
|
||||
padding: scalePadding,
|
||||
});
|
||||
const valueScale = scaleLinear<number>({
|
||||
domain: [0, Math.max(...yTotals)],
|
||||
nice: true,
|
||||
});
|
||||
const colorScale = scaleOrdinal<string, string>({
|
||||
domain: keys,
|
||||
range: colorRange,
|
||||
a258wang
commented
Any reason why we're using the TooltipInPortal here instead of the regular Tooltip we're using everywhere else? Any reason why we're using the TooltipInPortal here instead of the regular Tooltip we're using everywhere else?
|
||||
});
|
||||
|
||||
// bounds
|
||||
const xMax = width;
|
||||
const yMax = height - margin.top - axisBottomOffset;
|
||||
|
||||
a258wang
commented
NIT: redundant if we have NIT: redundant if we have `return width < 10 ? null : ...` down below
|
||||
categoryScale.rangeRound([0, xMax - axisLeftOffset]);
|
||||
valueScale.range([yMax, 0]);
|
||||
|
||||
a258wang
commented
Just curious, why 50? Just curious, why 50?
|
||||
return width < 10 ? null : (
|
||||
<div className={styles.container}>
|
||||
<svg width={width} height={height}>
|
||||
<Group top={margin.top} left={margin.left}>
|
||||
<GridRows
|
||||
scale={valueScale}
|
||||
width={xMax}
|
||||
height={yMax}
|
||||
left={axisLeftOffset}
|
||||
numTicks={numTicksValueAxis}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<GridColumns
|
||||
scale={categoryScale}
|
||||
height={yMax}
|
||||
left={axisLeftOffset}
|
||||
offset={categoryScale.bandwidth() / 2}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<Group left={axisLeftOffset}>
|
||||
<BarStack<StackedBarData, string>
|
||||
data={data}
|
||||
keys={keys}
|
||||
x={getCategory}
|
||||
xScale={categoryScale}
|
||||
yScale={valueScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{(barStacks) =>
|
||||
barStacks.map((barStack) =>
|
||||
barStack.bars.map((bar) => (
|
||||
<rect
|
||||
className={styles.barStack}
|
||||
key={`bar-stack-${barStack.index}-${bar.index}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
height={bar.height}
|
||||
width={bar.width / 2}
|
||||
fill={bar.color}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
onMouseMove={(event) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
const eventSvgCoords = localPoint(event);
|
||||
const left = bar.x + bar.width / 2;
|
||||
showTooltip({
|
||||
tooltipData: bar,
|
||||
tooltipTop: eventSvgCoords?.y,
|
||||
tooltipLeft: left,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)
|
||||
}
|
||||
</BarStack>
|
||||
</Group>
|
||||
<Line
|
||||
fill={Color.tertiaryBackground}
|
||||
to={new Point({ x: axisLeftOffset, y: 0 })}
|
||||
from={new Point({ x: axisLeftOffset, y: yMax })}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<AxisBottom
|
||||
top={yMax}
|
||||
scale={categoryScale}
|
||||
left={
|
||||
((categoryScale.bandwidth() * 100) / width) *
|
||||
categoryAxisLeftFactor
|
||||
}
|
||||
hideTicks
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
a258wang
commented
Why divide by 5? Why divide by 5?
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => ({
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
})}
|
||||
/>
|
||||
<AxisLeft
|
||||
scale={valueScale}
|
||||
top={5}
|
||||
numTicks={numTicksValueAxis}
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => {
|
||||
return {
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
</svg>
|
||||
<div
|
||||
className={styles.legend}
|
||||
style={{ left: width + legendLeftOffset, top: legendTopOffset }}
|
||||
>
|
||||
<LegendOrdinal
|
||||
scale={colorScale}
|
||||
direction="column"
|
||||
itemMargin={itemMargin}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{tooltipOpen && tooltipData ? (
|
||||
<Tooltip
|
||||
className={styles.toolTip}
|
||||
top={tooltipTop}
|
||||
left={tooltipLeft}
|
||||
unstyled
|
||||
>
|
||||
<p className={styles.key}>{tooltipData.key}</p>
|
||||
<p>{tooltipData.bar.data[tooltipData.key]}</p>
|
||||
<p>{getCategory(tooltipData.bar.data)}</p>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const StackedBarGraphHorizontal = withTooltip<
|
||||
StackedBarProps,
|
||||
TooltipData
|
||||
>(
|
||||
({
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
keys,
|
||||
colorRange,
|
||||
margin,
|
||||
scalePadding = 0.3,
|
||||
numTicksValueAxis = 6,
|
||||
axisLeftOffset = 40,
|
||||
axisBottomOffset = 40,
|
||||
strokeWidth = 2.5,
|
||||
strokeDashArray = "10,4",
|
||||
legendLeftOffset = 40,
|
||||
legendTopOffset = 40,
|
||||
itemMargin = "15px 0 0 0",
|
||||
categoryAxisLeftFactor = 1,
|
||||
tooltipOpen,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
tooltipData,
|
||||
hideTooltip,
|
||||
showTooltip,
|
||||
}: StackedBarProps & WithTooltipProvidedProps<TooltipData>) => {
|
||||
const yTotals = data.reduce((allTotals, currCategory) => {
|
||||
const yTotal = keys.reduce((categoryTotal, k) => {
|
||||
categoryTotal += currCategory[k] as number;
|
||||
return categoryTotal;
|
||||
}, 0);
|
||||
allTotals.push(yTotal);
|
||||
return allTotals;
|
||||
}, [] as number[]);
|
||||
|
||||
const TICK_LABEL_FONT_WEIGHT = 800;
|
||||
|
||||
// accessors
|
||||
const getCategory = (d: StackedBarData) => d.category;
|
||||
|
||||
// scales
|
||||
const valueScale = scaleLinear<number>({
|
||||
domain: [0, Math.max(...yTotals)],
|
||||
nice: true,
|
||||
});
|
||||
const categoryScale = scaleBand<string>({
|
||||
domain: data.map(getCategory),
|
||||
padding: scalePadding,
|
||||
});
|
||||
const colorScale = scaleOrdinal<string, string>({
|
||||
domain: keys,
|
||||
range: colorRange,
|
||||
});
|
||||
|
||||
// bounds
|
||||
const xMax = width;
|
||||
const yMax = height - margin.top - axisBottomOffset;
|
||||
|
||||
categoryScale.rangeRound([yMax, 0]);
|
||||
a258wang
commented
Please change the range to Please change the range to `[0, yMax]` - it makes it so the order of the categories is the same top-to-bottom when the graph has horizontal bars vs. left-to-right when the graph has vertical bars.
|
||||
valueScale.range([0, xMax - axisLeftOffset]);
|
||||
|
||||
return width < 10 ? null : (
|
||||
<div className={styles.container}>
|
||||
<svg width={width} height={height}>
|
||||
<Group top={margin.top} left={margin.left}>
|
||||
<GridRows
|
||||
scale={categoryScale}
|
||||
width={xMax}
|
||||
height={yMax}
|
||||
offset={categoryScale.bandwidth() / 2}
|
||||
left={axisLeftOffset}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<GridColumns
|
||||
scale={valueScale}
|
||||
height={yMax}
|
||||
numTicks={numTicksValueAxis}
|
||||
left={axisLeftOffset}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<Group left={axisLeftOffset}>
|
||||
<BarStackHorizontal<StackedBarData, string>
|
||||
data={data}
|
||||
keys={keys}
|
||||
y={getCategory}
|
||||
xScale={valueScale}
|
||||
yScale={categoryScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{(barStacks) =>
|
||||
barStacks.map((barStack) =>
|
||||
barStack.bars.map((bar) => (
|
||||
<rect
|
||||
className={styles.barStack}
|
||||
key={`bar-stack-${barStack.index}-${bar.index}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
height={bar.height / 2}
|
||||
width={bar.width}
|
||||
fill={bar.color}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
onMouseMove={(event) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
const eventSvgCoords = localPoint(event);
|
||||
const left = bar.x + bar.width / 2;
|
||||
showTooltip({
|
||||
tooltipData: bar,
|
||||
tooltipTop: eventSvgCoords?.y,
|
||||
tooltipLeft: left,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)
|
||||
}
|
||||
</BarStackHorizontal>
|
||||
</Group>
|
||||
<AxisBottom
|
||||
top={yMax}
|
||||
scale={valueScale}
|
||||
left={axisLeftOffset}
|
||||
numTicks={numTicksValueAxis}
|
||||
hideAxisLine
|
||||
hideTicks
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => ({
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
})}
|
||||
/>
|
||||
<AxisLeft
|
||||
top={
|
||||
-((categoryScale.bandwidth() * 100) / width) *
|
||||
categoryAxisLeftFactor
|
||||
}
|
||||
scale={categoryScale}
|
||||
hideAxisLine
|
||||
hideTicks
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => {
|
||||
return {
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
</svg>
|
||||
<div
|
||||
className={styles.legend}
|
||||
style={{ left: width + legendLeftOffset, top: legendTopOffset }}
|
||||
>
|
||||
<LegendOrdinal
|
||||
scale={colorScale}
|
||||
direction="column"
|
||||
itemMargin={itemMargin}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{tooltipOpen && tooltipData ? (
|
||||
<Tooltip
|
||||
className={styles.toolTip}
|
||||
top={tooltipTop}
|
||||
left={tooltipLeft}
|
||||
unstyled
|
||||
>
|
||||
<p className={styles.key}>{tooltipData.key}</p>
|
||||
<p>{tooltipData.bar.data[tooltipData.key]}</p>
|
||||
<p>{getCategory(tooltipData.bar.data)}</p>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -80,6 +80,45 @@ export const moreMockCategoricalData = [
|
|||
{ key: "Dart", value: 2.21 },
|
||||
];
|
||||
|
||||
export const mockStackedBarGraphData = [
|
||||
{
|
||||
category: "1A",
|
||||
"geese watchers": 60,
|
||||
"geese breeders": 80,
|
||||
"geese catchers": 90,
|
||||
},
|
||||
{
|
||||
category: "1B",
|
||||
"geese watchers": 25,
|
||||
"geese breeders": 37,
|
||||
"geese catchers": 80,
|
||||
},
|
||||
{
|
||||
category: "2A",
|
||||
"geese watchers": 40,
|
||||
"geese breeders": 50,
|
||||
"geese catchers": 70,
|
||||
},
|
||||
{
|
||||
category: "2B",
|
||||
"geese watchers": 40,
|
||||
"geese breeders": 80,
|
||||
"geese catchers": 88,
|
||||
},
|
||||
{
|
||||
category: "3A",
|
||||
"geese watchers": 15,
|
||||
"geese breeders": 30,
|
||||
"geese catchers": 45,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockStackedBarKeys = [
|
||||
"geese watchers",
|
||||
"geese breeders",
|
||||
"geese catchers",
|
||||
];
|
||||
|
||||
export const mockTimelineData = [
|
||||
{
|
||||
time: "Fall 2020",
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"@visx/event": "^2.6.0",
|
||||
"@visx/grid": "^2.10.0",
|
||||
"@visx/group": "^2.10.0",
|
||||
"@visx/legend": "^2.10.0",
|
||||
"@visx/mock-data": "^2.1.2",
|
||||
"@visx/scale": "^2.2.2",
|
||||
"@visx/shape": "^2.10.0",
|
||||
|
@ -973,6 +974,21 @@
|
|||
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/legend": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/legend/-/legend-2.10.0.tgz",
|
||||
"integrity": "sha512-OI8BYE6QQI9eXAng/C7UzuVw7d0fwlzrth6RmrdhlyT1K+BA3WpExapV+pDfwxu/tkEik8Ps5cZRV6HjX1/Mww==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.5.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/mock-data": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-2.1.2.tgz",
|
||||
|
@ -5086,6 +5102,18 @@
|
|||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"@visx/legend": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/legend/-/legend-2.10.0.tgz",
|
||||
"integrity": "sha512-OI8BYE6QQI9eXAng/C7UzuVw7d0fwlzrth6RmrdhlyT1K+BA3WpExapV+pDfwxu/tkEik8Ps5cZRV6HjX1/Mww==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"@visx/mock-data": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-2.1.2.tgz",
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"@visx/event": "^2.6.0",
|
||||
"@visx/grid": "^2.10.0",
|
||||
"@visx/group": "^2.10.0",
|
||||
"@visx/legend": "^2.10.0",
|
||||
"@visx/mock-data": "^2.1.2",
|
||||
"@visx/scale": "^2.2.2",
|
||||
"@visx/shape": "^2.10.0",
|
||||
|
|
|
@ -3,6 +3,8 @@ import { BoxPlot } from "components/Boxplot";
|
|||
import {
|
||||
mockCategoricalData,
|
||||
moreMockCategoricalData,
|
||||
mockStackedBarKeys,
|
||||
mockStackedBarGraphData,
|
||||
mockBoxPlotData,
|
||||
mockQuoteData,
|
||||
mockQuoteDataLong,
|
||||
|
@ -11,11 +13,16 @@ import {
|
|||
} from "data/mocks";
|
||||
import { sectionsData } from "data/routes";
|
||||
import React from "react";
|
||||
import { Color } from "utils/Color";
|
||||
|
||||
import { About } from "@/components/About";
|
||||
import { PieChart } from "@/components/PieChart";
|
||||
import { QuotationCarousel } from "@/components/QuotationCarousel";
|
||||
import { Sections } from "@/components/Sections";
|
||||
import {
|
||||
StackedBarGraphVertical,
|
||||
StackedBarGraphHorizontal,
|
||||
} from "@/components/StackedBarGraph";
|
||||
import { Timeline } from "@/components/Timeline";
|
||||
|
||||
import { CenterWrapper } from "../components/CenterWrapper";
|
||||
|
@ -26,7 +33,7 @@ import styles from "./playground.module.css";
|
|||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<div className={styles.page} suppressHydrationWarning>
|
||||
<h1>Playground</h1>
|
||||
<p>Show off your components here!</p>
|
||||
|
||||
|
@ -95,6 +102,48 @@ export default function Home() {
|
|||
}))}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
<code>{"<StackedBarGraphVertical />"}</code>
|
||||
</h2>
|
||||
<StackedBarGraphVertical
|
||||
width={600}
|
||||
height={400}
|
||||
keys={mockStackedBarKeys}
|
||||
colorRange={[
|
||||
Color.primaryAccent,
|
||||
Color.secondaryAccentLight,
|
||||
Color.primaryAccentLighter,
|
||||
]}
|
||||
data={mockStackedBarGraphData}
|
||||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
}}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
<code>{"<StackedBarGraphHorizontal />"}</code>
|
||||
</h2>
|
||||
<p>
|
||||
<code>{"<StackedBarGraphHorizontal />"}</code> takes the same props as{" "}
|
||||
<code>{"<StackedBarGraphVertical />"}</code>.
|
||||
</p>
|
||||
<StackedBarGraphHorizontal
|
||||
width={600}
|
||||
height={400}
|
||||
keys={mockStackedBarKeys}
|
||||
colorRange={[
|
||||
Color.primaryAccent,
|
||||
Color.secondaryAccentLight,
|
||||
Color.primaryAccentLighter,
|
||||
]}
|
||||
data={mockStackedBarGraphData}
|
||||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
}}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
<code>{"<Timeline />"}</code>
|
||||
</h2>
|
||||
|
|
NIT:
calc(16rem / 16)
instead ofpx
in this file