Skip to content

Commit

Permalink
j
Browse files Browse the repository at this point in the history
  • Loading branch information
holtzy committed Nov 8, 2024
1 parent 984b4a9 commit 8069b14
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 38 deletions.
4 changes: 3 additions & 1 deletion component/ChartOrSandbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type ChartOrSandboxProps = {
height?: number;
maxWidth?: number;
caption?: string | ReactNode;
fileToOpen?: string;
};

export const ChartOrSandbox = ({
Expand All @@ -21,6 +22,7 @@ export const ChartOrSandbox = ({
height = 400,
maxWidth = 800,
caption,
fileToOpen,
}: ChartOrSandboxProps) => {
const [showSandbox, setShowSandbox] = useState(false);

Expand All @@ -38,7 +40,7 @@ export const ChartOrSandbox = ({
{showSandbox ? (
<div className="flex flex-col items-center justify-center w-full">
<div style={{ maxWidth: 2000 }} className="w-full z-50">
<CodeSandbox vizName={vizName} />
<CodeSandbox vizName={vizName} fileToOpen={fileToOpen} />
</div>
<div className="flex justify-center mt-2">
<Button size="sm" onClick={() => setShowSandbox(!showSandbox)}>
Expand Down
88 changes: 55 additions & 33 deletions pages/course/animation/react-spring-for-dataviz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
ExerciseDoubleSandbox,
} from '@/component/ExerciseDoubleSandbox';
import { ExerciseAccordion } from '@/component/ExerciseAccordion';
import { Graph14 } from '@/viz/exercise/AnimationSimpleCircleSolution/Graph';
import { Graph11 } from '@/viz/exercise/AnimationSimpleDivSolution/Graph';

const previousURL = '/course/animation/introduction';
const currentURL = '/course/animation/react-spring-for-dataviz';
Expand Down Expand Up @@ -234,6 +234,7 @@ export const Circle = ({ position }) => {
maxWidth={800}
height={200}
caption="A very basic animation using react and react-spring."
fileToOpen={'Circle.tsx'}
/>

<Accordion type="single" collapsible>
Expand Down Expand Up @@ -304,6 +305,7 @@ const springProps = useSpring({
feel. Try them in this sandbox!
</p>
}
fileToOpen={'Circle.tsx'}
/>
<p>To use one of the presets, you can do something like this:</p>
<CodeBlock
Expand Down Expand Up @@ -382,6 +384,7 @@ return (
maxWidth={800}
height={200}
caption="Smooth animation where circle size is derived from X position."
fileToOpen={'Circle.tsx'}
/>

<h2>Animating Text</h2>
Expand All @@ -401,6 +404,7 @@ return (
maxWidth={800}
height={200}
caption="Demo: react-spring can also animate text, colors and so much more!"
fileToOpen={'Circle.tsx'}
/>

<h2>Exercises</h2>
Expand Down Expand Up @@ -445,28 +449,25 @@ const exercises: Exercise[] = [
{
whyItMatters: (
<>
<p>
Let’s apply what we just learned by creating your first{' '}
<code>canvas</code> element, modifying it using a <code>ref</code> and{' '}
<code>useEffect</code>.
</p>
<p>And while we’re at it, let’s explore how to adjust opacity!</p>
<p>Just applying the very basic usage we just learned</p>
</>
),
toDo: (
<>
<ul>
<li>
Use <code>useRef()</code> to create a ref targeting the canvas
element.
Create a <code>Circle.tsx</code> file that makes a{' '}
<code>Circle</code> component
</li>
<li>
Add a <code>useEffect()</code> hook to draw a blue circle on the
canvas.
Create a <code>position</code> state in <code>Graph.tsx</code>. Each
time the user click on the SVG area, this position must toggle
between <code>40</code> and <code>width - 40</code>
</li>
<li>
Adjust the circle’s opacity with the <code>globalAlpha</code>{' '}
property.
Provide the position to the <code>Circle</code> component. Render a
circle at this <code>x</code> position, animate its movement with{' '}
<code>react-spring</code>.
</li>
</ul>
</>
Expand All @@ -479,49 +480,67 @@ const exercises: Exercise[] = [
whyItMatters: (
<>
<p>
Unlike SVG elements, strokes and fills must be drawn separately on the
canvas. 😱
react-spring can animate many sorts of values. Opacity is one of them,
but text, and colors work too!
</p>
</>
),
toDo: (
<>
<ul>
<li>Draw a rectangle on the canvas.</li>
<li>
Use <code>strokeRect()</code> and <code>fillRect()</code> to apply a
green stroke and fill it with pink.
Same as previous exercise, but add a property for the{' '}
<code>opacity</code>.
</li>
<li>
<code>opacity</code> must toggle between <code>0.2</code> and{' '}
<code>1</code> depending on if the circle is on the left or on the
right.
</li>
</ul>
</>
),
practiceSandbox: 'exercise/CanvasRectOutlinePractice',
solutionSandbox: 'exercise/CanvasRectOutlineSolution',
practiceSandbox: 'exercise/AnimationDefaultPractice',
solutionSandbox: 'exercise/AnimationSimpleCircleOpacitySolution',
fileToOpen: 'Graph.tsx',
},
{
whyItMatters: (
<>
<p>
When working with canvas drawings, you’ll often need to clear previous
content.{' '}
<code>react-spring</code> does not only work with SVG! HTML elements
can be animated too!
</p>
<p>
This is possible with <code>clearRect()</code>.
note also that the spring can be made directly in the{' '}
<code>Graph</code> component. Making a separate component to organise
your work is nice IMO, but not required.
</p>
</>
),
toDo: (
<>
<ul>
<li>Draw a large circle on the canvas.</li>
<li>
Use <code>clearRect()</code> to erase part of the circle.
In <code>Graph.tsx</code>, render a parent <code>div</code> using
the <code>width</code> and <code>height</code> provided at the top
of the component instead of the usual SVG area.
</li>
<li>
In this <code>div</code>, render another <code>div</code>. It must
be square, have a <code>backgroundColor</code> of <code>red</code>{' '}
and be absolutely positioned.
</li>
<li>
Now make the red <code>div</code> moves from right to left when user
clicks on the parent div.
</li>
</ul>
</>
),
practiceSandbox: 'exercise/CanvasClearRectPractice',
solutionSandbox: 'exercise/CanvasClearRectSolution',
practiceSandbox: 'exercise/AnimationDefaultPractice',
solutionSandbox: 'exercise/AnimationSimpleDivSolution',
fileToOpen: 'Graph.tsx',
},
{
whyItMatters: (
Expand All @@ -547,8 +566,9 @@ const exercises: Exercise[] = [
</ul>
</>
),
practiceSandbox: 'exercise/CanvasBasicLinePractice',
solutionSandbox: 'exercise/CanvasBasicLineSolution',
practiceSandbox: 'exercise/AnimationDefaultPractice',
solutionSandbox: 'exercise/AnimationSimpleCircleOpacitySolution',
fileToOpen: 'Graph.tsx',
},
{
whyItMatters: (
Expand All @@ -571,8 +591,9 @@ const exercises: Exercise[] = [
</ul>
</>
),
practiceSandbox: 'exercise/CanvasTenCirclesPractice',
solutionSandbox: 'exercise/CanvasTenCirclesSolution',
practiceSandbox: 'exercise/AnimationDefaultPractice',
solutionSandbox: 'exercise/AnimationSimpleCircleOpacitySolution',
fileToOpen: 'Graph.tsx',
},
{
whyItMatters: (
Expand All @@ -598,7 +619,8 @@ const exercises: Exercise[] = [
</ul>
</>
),
practiceSandbox: 'exercise/CanvasBasicTextPractice',
solutionSandbox: 'exercise/CanvasBasicTextSolution',
practiceSandbox: 'exercise/AnimationDefaultPractice',
solutionSandbox: 'exercise/AnimationSimpleCircleOpacitySolution',
fileToOpen: 'Graph.tsx',
},
];
8 changes: 4 additions & 4 deletions viz/ReactSpringText/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ReactDOM from "react-dom";
import { ReactSpringMostBasic } from "./ReactSpringMostBasic";
import ReactDOM from 'react-dom';
import { ReactSpringTextDemo } from './ReactSpringTextDemo';

const rootElement = document.getElementById("root");
ReactDOM.render(<ReactSpringMostBasic width={800} height={300} />, rootElement);
const rootElement = document.getElementById('root');
ReactDOM.render(<ReactSpringTextDemo width={800} height={300} />, rootElement);
25 changes: 25 additions & 0 deletions viz/exercise/AnimationSimpleCircleOpacitySolution/Circle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { animated, useSpring } from 'react-spring';

type CircleVizProps = {
position: number;
color: string;
opacity: number;
};

export const Circle = ({ position, color, opacity }: CircleVizProps) => {
const springProps = useSpring({
to: { position, color, opacity },
});

return (
<animated.circle
strokeWidth={2}
fillOpacity={springProps.opacity}
r={38}
cy={50}
cx={springProps.position}
stroke={springProps.color}
fill={springProps.color}
/>
);
};
25 changes: 25 additions & 0 deletions viz/exercise/AnimationSimpleCircleOpacitySolution/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useState } from 'react';
import { Circle } from './Circle';

const width = 500;
const height = 300;

export const Graph = () => {
const [position, setPosition] = useState(40);

return (
<svg
width={width}
height={height}
onClick={() => {
position > 100 ? setPosition(40) : setPosition(width - 50);
}}
>
<Circle
position={position}
color={position > 200 ? 'red' : 'blue'}
opacity={position > 200 ? 0.2 : 1}
/>
</svg>
);
};
6 changes: 6 additions & 0 deletions viz/exercise/AnimationSimpleCircleOpacitySolution/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);
31 changes: 31 additions & 0 deletions viz/exercise/AnimationSimpleCircleOpacitySolution/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"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",
"@react-spring/web": "^9.3.1",
"react-spring": "9.3.2"
},
"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"
]
}
24 changes: 24 additions & 0 deletions viz/exercise/AnimationSimpleDivSolution/Circle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { animated, useSpring } from 'react-spring';

type CircleVizProps = {
position: number;
color: string;
};

export const Circle = ({ position, color }: CircleVizProps) => {
const springProps = useSpring({
to: { position, color },
});

return (
<animated.circle
strokeWidth={2}
fillOpacity={0.4}
r={38}
cy={50}
cx={springProps.position}
stroke={springProps.color}
fill={springProps.color}
/>
);
};
33 changes: 33 additions & 0 deletions viz/exercise/AnimationSimpleDivSolution/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState } from 'react';
import { animated, useSpring } from 'react-spring';

const width = 500;
const height = 300;

export const Graph = () => {
const [position, setPosition] = useState(40);

const springProps = useSpring({
to: { left: position },
});

return (
<div
style={{ width, height, position: 'relative' }}
onClick={() => {
setPosition(position > 100 ? 40 : width - 50);
}}
>
<animated.div
style={{
left: springProps.left,
top: 50,
position: 'absolute',
width: 50,
height: 50,
backgroundColor: 'red',
}}
></animated.div>
</div>
);
};
6 changes: 6 additions & 0 deletions viz/exercise/AnimationSimpleDivSolution/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 8069b14

Please sign in to comment.