diff --git a/pages/course/hover-effect/toggle-class-in-js.tsx b/pages/course/hover-effect/toggle-class-in-js.tsx index 29bd81b9..f556e126 100644 --- a/pages/course/hover-effect/toggle-class-in-js.tsx +++ b/pages/course/hover-effect/toggle-class-in-js.tsx @@ -17,6 +17,7 @@ import { } from '@/component/ExerciseDoubleSandbox'; import { ExerciseAccordion } from '@/component/ExerciseAccordion'; import { Graph23 } from '@/viz/exercise/PieFirstSolution/Graph'; +import { Graph42 } from '@/viz/exercise/PieHoverEffectSolution/Graph'; const previousURL = '/course/hover-effect/css-descendant-selector'; const currentURL = '/course/hover-effect/toggle-class-in-js'; @@ -204,6 +205,7 @@ const containerRef = useRef(); > Visit project + {/* - - @@ -217,7 +219,7 @@ const containerRef = useRef(); localStorageId={currentLesson.link} exercises={[ { - title: Your first pie chart! 🍭, + title: Your first pie chart! 🍰, content: , }, { @@ -234,8 +236,9 @@ const exercises: Exercise[] = [ whyItMatters: ( <>

- With the SVG and D3 foundations you’ve built, creating a new chart - type becomes a breeze! + Time to learn a new chart type! Check the{' '} + pie chart page for the full in-depth + tutorial.

), @@ -243,12 +246,11 @@ const exercises: Exercise[] = [ <> ), diff --git a/viz/exercise/PieHoverEffectPractice/Graph.tsx b/viz/exercise/PieHoverEffectPractice/Graph.tsx new file mode 100644 index 00000000..25419fbf --- /dev/null +++ b/viz/exercise/PieHoverEffectPractice/Graph.tsx @@ -0,0 +1,40 @@ +import * as d3 from 'd3'; +import { data, DataItem } from './data'; +import { useRef } from 'react'; +import styles from './graph.module.css'; + +const MARGIN = 30; +const width = 400; +const height = 400; +const colors = ['#98abc5', '#8a89a6', '#7b6888', '#6b486b', '#a05d56']; + +export const Graph = () => { + const containerRef = useRef(null); + + const radius = Math.min(width, height) / 2 - MARGIN; + + const pieGenerator = d3.pie().value((d) => d.value); + const pie = pieGenerator(data); + + const arcPathGenerator = d3.arc(); + const arcs = pie.map((p) => + arcPathGenerator({ + innerRadius: 0, + outerRadius: radius, + startAngle: p.startAngle, + endAngle: p.endAngle, + }) + ); + + return ( + + + {arcs.map((arc, i) => { + return ( + + ); + })} + + + ); +}; diff --git a/viz/exercise/PieHoverEffectPractice/data.ts b/viz/exercise/PieHoverEffectPractice/data.ts new file mode 100644 index 00000000..4069b832 --- /dev/null +++ b/viz/exercise/PieHoverEffectPractice/data.ts @@ -0,0 +1,12 @@ +export type DataItem = { + name: string; + value: number; +}; + +export const data: DataItem[] = [ + { name: "Mark", value: 90 }, + { name: "Robert", value: 12 }, + { name: "Emily", value: 34 }, + { name: "Marion", value: 53 }, + { name: "Nicolas", value: 98 }, +] diff --git a/viz/exercise/PieHoverEffectPractice/graph.module.css b/viz/exercise/PieHoverEffectPractice/graph.module.css new file mode 100644 index 00000000..107eee4e --- /dev/null +++ b/viz/exercise/PieHoverEffectPractice/graph.module.css @@ -0,0 +1,12 @@ +.container .slice { + opacity: 0.8; + cursor: pointer; +} + +.container.hasHighlight .slice { + opacity: 0.2; +} + +.container.hasHighlight .slice:hover { + opacity: 1; +} diff --git a/viz/exercise/PieHoverEffectPractice/index.js b/viz/exercise/PieHoverEffectPractice/index.js new file mode 100644 index 00000000..fa564d27 --- /dev/null +++ b/viz/exercise/PieHoverEffectPractice/index.js @@ -0,0 +1,6 @@ +// File used to render something in codesandbox only +import ReactDOM from 'react-dom'; +import { Graph } from './Graph'; + +const rootElement = document.getElementById('root'); +ReactDOM.render(, rootElement); diff --git a/viz/exercise/PieHoverEffectPractice/package.json b/viz/exercise/PieHoverEffectPractice/package.json new file mode 100644 index 00000000..84ed1985 --- /dev/null +++ b/viz/exercise/PieHoverEffectPractice/package.json @@ -0,0 +1,29 @@ +{ + "name": "pie-chart-basic", + "version": "1.0.0", + "description": "", + "keywords": [], + "main": "index.js", + "dependencies": { + "react": "17.0.2", + "d3": "7.1.1", + "react-dom": "17.0.2", + "react-scripts": "4.0.0" + }, + "devDependencies": { + "@babel/runtime": "7.13.8", + "typescript": "4.1.3" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/viz/exercise/PieHoverEffectSolution/Graph.tsx b/viz/exercise/PieHoverEffectSolution/Graph.tsx new file mode 100644 index 00000000..92ced5d0 --- /dev/null +++ b/viz/exercise/PieHoverEffectSolution/Graph.tsx @@ -0,0 +1,60 @@ +import * as d3 from 'd3'; +import { data, DataItem } from './data'; +import { useRef } from 'react'; +import styles from './graph.module.css'; + +const MARGIN = 30; +const width = 400; +const height = 400; +const colors = ['#98abc5', '#8a89a6', '#7b6888', '#6b486b', '#a05d56']; + +export const Graph = () => { + const containerRef = useRef(null); + + const radius = Math.min(width, height) / 2 - MARGIN; + + const pieGenerator = d3.pie().value((d) => d.value); + const pie = pieGenerator(data); + + const arcPathGenerator = d3.arc(); + const arcs = pie.map((p) => + arcPathGenerator({ + innerRadius: 0, + outerRadius: radius, + startAngle: p.startAngle, + endAngle: p.endAngle, + }) + ); + + return ( + + + {arcs.map((arc, i) => { + return ( + { + if (containerRef.current) { + containerRef.current.classList.add(styles.hasHighlight); + } + }} + onMouseLeave={() => { + if (containerRef.current) { + containerRef.current.classList.remove(styles.hasHighlight); + } + }} + /> + ); + })} + + + ); +}; diff --git a/viz/exercise/PieHoverEffectSolution/data.ts b/viz/exercise/PieHoverEffectSolution/data.ts new file mode 100644 index 00000000..4069b832 --- /dev/null +++ b/viz/exercise/PieHoverEffectSolution/data.ts @@ -0,0 +1,12 @@ +export type DataItem = { + name: string; + value: number; +}; + +export const data: DataItem[] = [ + { name: "Mark", value: 90 }, + { name: "Robert", value: 12 }, + { name: "Emily", value: 34 }, + { name: "Marion", value: 53 }, + { name: "Nicolas", value: 98 }, +] diff --git a/viz/exercise/PieHoverEffectSolution/graph.module.css b/viz/exercise/PieHoverEffectSolution/graph.module.css new file mode 100644 index 00000000..107eee4e --- /dev/null +++ b/viz/exercise/PieHoverEffectSolution/graph.module.css @@ -0,0 +1,12 @@ +.container .slice { + opacity: 0.8; + cursor: pointer; +} + +.container.hasHighlight .slice { + opacity: 0.2; +} + +.container.hasHighlight .slice:hover { + opacity: 1; +} diff --git a/viz/exercise/PieHoverEffectSolution/index.js b/viz/exercise/PieHoverEffectSolution/index.js new file mode 100644 index 00000000..fa564d27 --- /dev/null +++ b/viz/exercise/PieHoverEffectSolution/index.js @@ -0,0 +1,6 @@ +// File used to render something in codesandbox only +import ReactDOM from 'react-dom'; +import { Graph } from './Graph'; + +const rootElement = document.getElementById('root'); +ReactDOM.render(, rootElement); diff --git a/viz/exercise/PieHoverEffectSolution/package.json b/viz/exercise/PieHoverEffectSolution/package.json new file mode 100644 index 00000000..84ed1985 --- /dev/null +++ b/viz/exercise/PieHoverEffectSolution/package.json @@ -0,0 +1,29 @@ +{ + "name": "pie-chart-basic", + "version": "1.0.0", + "description": "", + "keywords": [], + "main": "index.js", + "dependencies": { + "react": "17.0.2", + "d3": "7.1.1", + "react-dom": "17.0.2", + "react-scripts": "4.0.0" + }, + "devDependencies": { + "@babel/runtime": "7.13.8", + "typescript": "4.1.3" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +}