Rebecca-Chou 5 months ago
commit 3bde1f4032
  1. 7
      components/CenterWrapper.module.css
  2. 11
      components/CenterWrapper.tsx
  3. 26
      components/PieChart.module.css
  4. 180
      components/PieChart.tsx
  5. 15
      data/mocks.ts
  6. 1
      package-lock.json
  7. 43
      pages/playground.tsx

@ -0,0 +1,7 @@
.textbox {
width: 80%;
padding: calc(80rem / 16);
background-color: var(--secondary-background);
border-radius: calc(20rem / 16);
margin: 0 auto;
}

@ -0,0 +1,11 @@
import React, { ReactNode } from "react";
import styles from "./CenterWrapper.module.css";
export interface TextboxProps {
children: ReactNode;
}
export function CenterWrapper({ children }: TextboxProps) {
return <section className={styles.textbox}>{children}</section>;
}

@ -0,0 +1,26 @@
.piePath {
fill: var(--tertiary-background);
}
.labelPath {
fill-opacity: 0;
}
.pieText,
.labelText {
fill: var(--label);
font-weight: 800;
}
.pieText {
display: none;
}
.group:hover > .piePath {
fill: var(--primary-accent);
filter: drop-shadow(0px 0px calc(6rem / 16) var(--primary-accent));
}
.group:hover .pieText {
display: inline;
}

@ -0,0 +1,180 @@
import { Group } from "@visx/group";
import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie";
import { Text } from "@visx/text";
import React from "react";
import styles from "./PieChart.module.css";
interface PieChartProps {
data: PieChartData[];
/** Width of the entire graph, including labels, in pixels. */
width: number;
/** Width of the outer ring of labels, in pixels. Label text may be cut off if specified value is too small. */
labelWidth: number;
/** Distance between pie slices, in pixels. */
padRadius?: number;
/** Distance of gap in center of pie graph, in pixels. */
innerRadius?: number;
/** Font size of text inside the pie, in pixels. */
pieTextSize?: number;
/** X-axis offset of the pie text, in pixels. */
pieTextXOffset?: number;
/** Y-axis offset of the pie text, in pixels. */
pieTextYOffset?: number;
/** Accessor function to get value to display as pie text from datum. */
getPieDisplayValueFromDatum?: (datum: PieChartData) => string;
/** Font size of labels outside the pie, in pixels. */
labelTextSize?: number;
/** X-axis offset of the label text, in pixels. */
labelTextXOffset?: number;
/** Y-axis offset of the label text, in pixels. */
labelTextYOffset?: number;
/** Accessor function to get value to display as label text from datum. */
getLabelDisplayValueFromDatum?: (datum: PieChartData) => string;
className?: string;
}
interface PieChartData {
category: string;
value: number;
}
export function PieChart({
data,
width,
labelWidth,
padRadius = width * 0.35,
innerRadius = width * 0.015,
pieTextSize = 40,
pieTextXOffset = 0,
pieTextYOffset = 10,
getPieDisplayValueFromDatum = (datum: PieChartData) => `${datum.value}%`,
labelTextSize = 40,
labelTextXOffset = 0,
labelTextYOffset = 0,
getLabelDisplayValueFromDatum = (datum: PieChartData) => `${datum.category}`,
className,
}: PieChartProps) {
const pieWidth = width * 0.5 - labelWidth;
return (
<svg className={className} width={width} height={width}>
<Group top={width * 0.5} left={width * 0.5}>
<Pie
data={data}
pieValue={(d: PieChartData) => d.value}
cornerRadius={10}
padAngle={0.075}
padRadius={padRadius}
innerRadius={innerRadius}
outerRadius={pieWidth}
>
{(pie) => (
<PieSlice
{...pie}
pieTextSize={pieTextSize}
pieTextXOffset={pieTextXOffset}
pieTextYOffset={pieTextYOffset}
getPieDisplayValueFromDatum={getPieDisplayValueFromDatum}
/>
)}
</Pie>
<Pie
data={data}
pieValue={(d: PieChartData) => d.value}
innerRadius={pieWidth}
outerRadius={width * 0.5}
>
{(pie) => (
<PieSliceLabel
{...pie}
labelTextSize={labelTextSize}
labelTextXOffset={labelTextXOffset}
labelTextYOffset={labelTextYOffset}
getLabelDisplayValueFromDatum={getLabelDisplayValueFromDatum}
/>
)}
</Pie>
</Group>
</svg>
);
}
type PieSliceProps<PieChartData> = ProvidedProps<PieChartData> & {
pieTextSize: number;
pieTextXOffset: number;
pieTextYOffset: number;
getPieDisplayValueFromDatum: (datum: PieChartData) => string;
};
export function PieSlice({
path,
arcs,
pieTextSize,
pieTextXOffset,
pieTextYOffset,
getPieDisplayValueFromDatum,
}: PieSliceProps<PieChartData>) {
return (
<>
{arcs.map((arc) => {
const [centroidX, centroidY] = path.centroid(arc);
const pathArc = path(arc) as string;
return (
<Group className={styles.group} key={`arc-${arc.data.category}`}>
<path className={styles.piePath} d={pathArc} />
<Text
className={styles.pieText}
x={centroidX + pieTextXOffset}
y={centroidY + pieTextYOffset}
textAnchor="middle"
fontSize={pieTextSize}
>
{`${getPieDisplayValueFromDatum(arc.data)}`}
</Text>
</Group>
);
})}
</>
);
}
type PieSliceLabelProps<PieChartData> = ProvidedProps<PieChartData> & {
labelTextSize: number;
labelTextXOffset: number;
labelTextYOffset: number;
getLabelDisplayValueFromDatum: (datum: PieChartData) => string;
};
export function PieSliceLabel({
path,
arcs,
labelTextSize,
labelTextXOffset,
labelTextYOffset,
getLabelDisplayValueFromDatum,
}: PieSliceLabelProps<PieChartData>) {
return (
<>
{arcs.map((arc) => {
const [centroidX, centroidY] = path.centroid(arc);
const pathArc = path(arc) as string;
return (
<Group className={styles.group} key={`arc-${arc.data.category}`}>
<path className={styles.labelPath} d={pathArc} />
<Text
className={styles.labelText}
x={centroidX + labelTextXOffset}
y={centroidY + labelTextYOffset}
textAnchor="middle"
fontSize={labelTextSize}
>
{`${getLabelDisplayValueFromDatum(arc.data)}`}
</Text>
</Group>
);
})}
</>
);
}

@ -36,6 +36,21 @@ export const mockCategoricalData = [
},
];
export const mockPieData = [
{
category: "Nightingale",
value: 42,
},
{
category: "Quail",
value: 48,
},
{
category: "Cuckoo",
value: 10,
},
];
export const moreMockCategoricalData = [
{ key: "Python", value: 29.53 },
{ key: "Java", value: 17.06 },

1
package-lock.json generated

@ -5,7 +5,6 @@
"requires": true,
"packages": {
"": {
"name": "cs-2022-class-profile",
"version": "0.1.0",
"dependencies": {
"@visx/axis": "^2.10.0",

@ -6,11 +6,14 @@ import {
mockBoxPlotData,
mockQuoteData,
mockQuoteDataLong,
mockPieData,
} from "data/mocks";
import React from "react";
import { PieChart } from "@/components/PieChart";
import { QuotationCarousel } from "@/components/QuotationCarousel";
import { CenterWrapper } from "../components/CenterWrapper";
import { ColorPalette } from "../components/ColorPalette";
import { LineGraph } from "../components/LineGraph";
import { WordCloud } from "../components/WordCloud";
@ -22,8 +25,13 @@ export default function Home() {
<div className={styles.page}>
<h1>Playground</h1>
<p>Show off your components here!</p>
<h2>
<code>{"<PieChart />"}</code>
</h2>
<div style={{ padding: "30px" }}>
<PieChart data={mockPieData} width={800} labelWidth={215} />
</div>
<ColorPalette />
<h2>
<code>{"<BarGraphHorizontal />"}</code>
</h2>
@ -39,7 +47,6 @@ export default function Home() {
right: 20,
}}
/>
<h2>
<code>{"<BarGraphVertical />"}</code>
</h2>
@ -59,7 +66,6 @@ export default function Home() {
right: 20,
}}
/>
<h2>
<code>{"<WordCloud />"}</code>
</h2>
@ -69,6 +75,37 @@ export default function Home() {
value: word.value,
}))}
/>
<h2>
<code>{"<Textbox />"}</code>
</h2>
<CenterWrapper>
<h1>Preface</h1>
<p>
The CS Class Profile consists of data relevant to CS, CFM, and CS/BBA
students. These were combined with the knowledge that students in
these programs tend to have similar experiences, as many of the same
CS required courses are shared. In the standard co-op offering, CS and
CFM take 4 years and 2 semesters to complete, while CS/BBA can take up
to a full 5 years.
</p>
<p>
Computer Science (and the others) is known to be a very prestigious
program, and is very well known in Canada as well as across the world.
For prospective students or anyone who is interested in learning more
about what the students are like, this CS Class Profile will attempt
to answer some of your questions, and you may even learn a thing or
two you didnt expect!
</p>
<p>
The survey questions were approved by the Institutional Analysis &
Planning, where all University of Waterloo stakeholders that are
interested in conducting a non-academic research survey involving a
large portion of the UWaterloo population are reviewed and approved.
The entirety of the survey creation and data processing was done by
the UW Computer Science Club, so please check us out if you enjoy what
you see!
</p>
</CenterWrapper>
<h2>
<code>{"<BoxPlot />"}</code>

Loading…
Cancel
Save