Skip to content

Commit

Permalink
k
Browse files Browse the repository at this point in the history
  • Loading branch information
holtzy committed Nov 4, 2024
1 parent 9f456ca commit c5418e9
Show file tree
Hide file tree
Showing 23 changed files with 659 additions and 0 deletions.
80 changes: 80 additions & 0 deletions pages/course/hover-effect/css-descendant-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import { Badge } from '@/component/UI/badge';
import GraphGallery from '@/component/GraphGallery';
import { TreemapHoverEffectDemo } from '@/viz/TreemapHoverEffect/TreemapHoverEffectDemo';
import Link from 'next/link';
import {
Exercise,
ExerciseDoubleSandbox,
} from '@/component/ExerciseDoubleSandbox';
import { ExerciseAccordion } from '@/component/ExerciseAccordion';
import { Graph9 } from '@/viz/exercise/LollipopFirstSolution/Graph';
import { Graph12 } from '@/viz/exercise/LollipopHoverEffectSolution/Graph';

const previousURL = '/course/hover-effect/css-pseudo-class';
const currentURL = '/course/hover-effect/css-descendant-selector';
Expand Down Expand Up @@ -135,6 +142,79 @@ export default function Home() {
'streamgraph-hover-effect.gif',
]}
/>

{/* -
-
-
-
-
-
- */}
<h2>Exercices</h2>
<ExerciseAccordion
localStorageId={currentLesson.link}
exercises={[
{
title: <span>Your first lollipop! 🍭</span>,
content: <ExerciseDoubleSandbox exercise={exercises[0]} />,
},
{
title: <span>Lollipop with hover effect</span>,
content: <ExerciseDoubleSandbox exercise={exercises[1]} />,
},
]}
/>
</LayoutCourse>
);
}

const exercises: Exercise[] = [
{
whyItMatters: (
<>
<p>
With the SVG and d3 fundations you have, it is a breeze to create a
new chart type!
</p>
</>
),
toDo: (
<>
<ul>
<li>A dataset is provided in the sandbox folder</li>
<li>
Build a cleveland chart with this dataset. (It is a variation of the
lollipop, handy to compare 2 values across many groups!)
</li>
<li>Check the solution tab to see how the graph must look like</li>
</ul>
</>
),
practiceSandbox: 'exercise/LollipopFirstPractice',
solutionSandbox: 'exercise/LollipopFirstSolution',
},

{
whyItMatters: (
<>
<p>
Descendant selectors are so good to create fancy hover effect using
CSS only!
</p>
</>
),
toDo: (
<>
<ul>
<li>Add a class for the SVG container</li>
<li>
Using CSS descendant selector, highlight the hovered row, and dim
other rows.
</li>
</ul>
</>
),
practiceSandbox: 'exercise/LollipopHoverEffectPractice',
solutionSandbox: 'exercise/LollipopHoverEffectSolution',
},
];
43 changes: 43 additions & 0 deletions viz/exercise/LollipopFirstPractice copy/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as d3 from 'd3';
import { data } from './data';

const width = 500;
const height = 500;
const MARGIN = { top: 30, right: 30, bottom: 30, left: 80 };

export const Graph = () => {
const boundsWidth = width - MARGIN.right - MARGIN.left;
const boundsHeight = height - MARGIN.top - MARGIN.bottom;

// Y axis is for groups
const groups = data.sort((a, b) => b.value1 - a.value1).map((d) => d.name);
const yScale = d3.scaleBand().domain(groups).range([0, boundsHeight]);

// X axis
const [min, max] = d3.extent(data.map((d) => d.value1));

const xScale = d3
.scaleLinear()
.domain([0, max || 10])
.range([0, boundsWidth]);

// Build the shapes
const allShapes = data.map((d, i) => {
// TODO
return null;
});

return (
<div>
<svg width={width} height={height}>
<g
width={boundsWidth}
height={boundsHeight}
transform={`translate(${[MARGIN.left, MARGIN.top].join(',')})`}
>
{allShapes}
</g>
</svg>
</div>
);
};
11 changes: 11 additions & 0 deletions viz/exercise/LollipopFirstPractice copy/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const data = [
{ name: "Mark", value1: 90, value2: 72 },
{ name: "Robert", value1: 12, value2: 10 },
{ name: "Emily", value1: 34, value2: 14 },
{ name: "Marion", value1: 53, value2: 24 },
{ name: "Nicolas", value1: 98, value2: 58 },
{ name: "Mélanie", value1: 23, value2: 20 },
{ name: "Gabriel", value1: 18, value2: 10 },
{ name: "Jean", value1: 104, value2: 70 },
{ name: "Paul", value1: 2, value2: 1 },
]
6 changes: 6 additions & 0 deletions viz/exercise/LollipopFirstPractice copy/index.js
Original file line number Diff line number Diff line change
@@ -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(<Graph />, rootElement);
29 changes: 29 additions & 0 deletions viz/exercise/LollipopFirstPractice copy/package.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
43 changes: 43 additions & 0 deletions viz/exercise/LollipopFirstPractice/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as d3 from 'd3';
import { data } from './data';

const width = 500;
const height = 500;
const MARGIN = { top: 30, right: 30, bottom: 30, left: 80 };

export const Graph = () => {
const boundsWidth = width - MARGIN.right - MARGIN.left;
const boundsHeight = height - MARGIN.top - MARGIN.bottom;

// Y axis is for groups
const groups = data.sort((a, b) => b.value1 - a.value1).map((d) => d.name);
const yScale = d3.scaleBand().domain(groups).range([0, boundsHeight]);

// X axis
const [min, max] = d3.extent(data.map((d) => d.value1));

const xScale = d3
.scaleLinear()
.domain([0, max || 10])
.range([0, boundsWidth]);

// Build the shapes
const allShapes = data.map((d, i) => {
// TODO
return null;
});

return (
<div>
<svg width={width} height={height}>
<g
width={boundsWidth}
height={boundsHeight}
transform={`translate(${[MARGIN.left, MARGIN.top].join(',')})`}
>
{allShapes}
</g>
</svg>
</div>
);
};
11 changes: 11 additions & 0 deletions viz/exercise/LollipopFirstPractice/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const data = [
{ name: "Mark", value1: 90, value2: 72 },
{ name: "Robert", value1: 12, value2: 10 },
{ name: "Emily", value1: 34, value2: 14 },
{ name: "Marion", value1: 53, value2: 24 },
{ name: "Nicolas", value1: 98, value2: 58 },
{ name: "Mélanie", value1: 23, value2: 20 },
{ name: "Gabriel", value1: 18, value2: 10 },
{ name: "Jean", value1: 104, value2: 70 },
{ name: "Paul", value1: 2, value2: 1 },
]
6 changes: 6 additions & 0 deletions viz/exercise/LollipopFirstPractice/index.js
Original file line number Diff line number Diff line change
@@ -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(<Graph />, rootElement);
29 changes: 29 additions & 0 deletions viz/exercise/LollipopFirstPractice/package.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
83 changes: 83 additions & 0 deletions viz/exercise/LollipopFirstSolution/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as d3 from 'd3';
import { data } from './data';

const width = 500;
const height = 500;
const MARGIN = { top: 30, right: 30, bottom: 30, left: 80 };

export const Graph = () => {
const boundsWidth = width - MARGIN.right - MARGIN.left;
const boundsHeight = height - MARGIN.top - MARGIN.bottom;

// Y axis is for groups
const groups = data.sort((a, b) => b.value1 - a.value1).map((d) => d.name);
const yScale = d3.scaleBand().domain(groups).range([0, boundsHeight]);

// X axis
const [min, max] = d3.extent(data.map((d) => d.value1));

const xScale = d3
.scaleLinear()
.domain([0, max || 10])
.range([0, boundsWidth]);

// Build the shapes
const allShapes = data.map((d, i) => {
const y = yScale(d.name) + yScale.bandwidth() / 2;

return (
<g key={i}>
<line
x1={xScale(d.value1)}
y1={y}
y2={y}
x2={xScale(d.value2)}
opacity={0.7}
stroke="grey"
strokeWidth={1}
/>
<circle
cy={y}
cx={xScale(d.value1)}
opacity={0.7}
stroke="#69b3a2"
fill="#69b3a2"
strokeWidth={1}
r={5}
/>
<circle
cy={y}
cx={xScale(d.value2)}
opacity={0.7}
stroke="#9d174d"
fill="#9d174d"
strokeWidth={1}
r={5}
/>
<text
x={xScale(0) - 7}
y={y}
textAnchor="end"
alignmentBaseline="central"
fontSize={12}
>
{d.name}
</text>
</g>
);
});

return (
<div>
<svg width={width} height={height}>
<g
width={boundsWidth}
height={boundsHeight}
transform={`translate(${[MARGIN.left, MARGIN.top].join(',')})`}
>
{allShapes}
</g>
</svg>
</div>
);
};
11 changes: 11 additions & 0 deletions viz/exercise/LollipopFirstSolution/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const data = [
{ name: "Mark", value1: 90, value2: 72 },
{ name: "Robert", value1: 12, value2: 10 },
{ name: "Emily", value1: 34, value2: 14 },
{ name: "Marion", value1: 53, value2: 24 },
{ name: "Nicolas", value1: 98, value2: 58 },
{ name: "Mélanie", value1: 23, value2: 20 },
{ name: "Gabriel", value1: 18, value2: 10 },
{ name: "Jean", value1: 104, value2: 70 },
{ name: "Paul", value1: 2, value2: 1 },
]
6 changes: 6 additions & 0 deletions viz/exercise/LollipopFirstSolution/index.js
Original file line number Diff line number Diff line change
@@ -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(<Graph />, rootElement);
Loading

0 comments on commit c5418e9

Please sign in to comment.