Merge branch 'main' of https://git.csclub.uwaterloo.ca/www/cs-2022-class-profile
This commit is contained in:
commit
3bde1f4032
|
@ -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 = [
|
export const moreMockCategoricalData = [
|
||||||
{ key: "Python", value: 29.53 },
|
{ key: "Python", value: 29.53 },
|
||||||
{ key: "Java", value: 17.06 },
|
{ key: "Java", value: 17.06 },
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cs-2022-class-profile",
|
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@visx/axis": "^2.10.0",
|
"@visx/axis": "^2.10.0",
|
||||||
|
|
|
@ -6,11 +6,14 @@ import {
|
||||||
mockBoxPlotData,
|
mockBoxPlotData,
|
||||||
mockQuoteData,
|
mockQuoteData,
|
||||||
mockQuoteDataLong,
|
mockQuoteDataLong,
|
||||||
|
mockPieData,
|
||||||
} from "data/mocks";
|
} from "data/mocks";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
import { PieChart } from "@/components/PieChart";
|
||||||
import { QuotationCarousel } from "@/components/QuotationCarousel";
|
import { QuotationCarousel } from "@/components/QuotationCarousel";
|
||||||
|
|
||||||
|
import { CenterWrapper } from "../components/CenterWrapper";
|
||||||
import { ColorPalette } from "../components/ColorPalette";
|
import { ColorPalette } from "../components/ColorPalette";
|
||||||
import { LineGraph } from "../components/LineGraph";
|
import { LineGraph } from "../components/LineGraph";
|
||||||
import { WordCloud } from "../components/WordCloud";
|
import { WordCloud } from "../components/WordCloud";
|
||||||
|
@ -22,8 +25,13 @@ export default function Home() {
|
||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
<h1>Playground</h1>
|
<h1>Playground</h1>
|
||||||
<p>Show off your components here!</p>
|
<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 />
|
<ColorPalette />
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
<code>{"<BarGraphHorizontal />"}</code>
|
<code>{"<BarGraphHorizontal />"}</code>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -39,7 +47,6 @@ export default function Home() {
|
||||||
right: 20,
|
right: 20,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
<code>{"<BarGraphVertical />"}</code>
|
<code>{"<BarGraphVertical />"}</code>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -59,7 +66,6 @@ export default function Home() {
|
||||||
right: 20,
|
right: 20,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
<code>{"<WordCloud />"}</code>
|
<code>{"<WordCloud />"}</code>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -69,6 +75,37 @@ export default function Home() {
|
||||||
value: word.value,
|
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 didn’t 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>
|
<h2>
|
||||||
<code>{"<BoxPlot />"}</code>
|
<code>{"<BoxPlot />"}</code>
|
||||||
|
|
Loading…
Reference in New Issue