|
| 1 | +# Artboard |
| 2 | + |
| 3 | +The artboard component is responsible for controllling all the graphics management. It creates turtles, |
| 4 | +canvases for each turtle, control the turtle(sprite) movements, communicate a particular turtle to draw |
| 5 | +on canvas. Any change to the background canvas can be done by manipulating this component. |
| 6 | + |
| 7 | +Artboard is composed of three components. |
| 8 | + |
| 9 | +1. Underlay |
| 10 | +2. Manager |
| 11 | +3. Interactor |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +## Underlay |
| 16 | + |
| 17 | +This refers to main canvas in the background which holds the palettes, menus and blocks. It will be |
| 18 | +present even if there are no turtles (sprite). |
| 19 | + |
| 20 | +## Interactor |
| 21 | + |
| 22 | +It is the interaction point between the canvases and other components. |
| 23 | + |
| 24 | +## Manager |
| 25 | + |
| 26 | +This is the main sub component of artboard as it is responsible for handling all artboards.For e.g. |
| 27 | +it can add a new artboard(canvas), remove an existing artboard, renders a particular turtle to draw |
| 28 | +on artboard, etc. It receives signals from monitor component to do a change in a particular artboard. |
| 29 | +It maintains a list of artboards which are currently present in the program. Before knowing how it |
| 30 | +handles several artboards let us take a look at the overall design structure of artboard and turtle. |
| 31 | + |
| 32 | +### Turtle and Artboard |
| 33 | + |
| 34 | +There is a dedicated canvas for each turtle and all drawings corresponding to the its turtle reside |
| 35 | +in it. We can say there is one-to-one relationship between artboard and turtle. Artboard is designed |
| 36 | +based on MVVM (Model-View-ViewModel). The model of an artboard contains properties specific to its |
| 37 | +artboard like line parameters, arc parameters, etc. The ViewModel contains a reference to the |
| 38 | +corresponding DOM element. e.g. - canvas and turtle positions, style etc.The view component is basically |
| 39 | +a HTML canvas generated by p5 library and all the functions to draw line, arcs, clear, etc are written |
| 40 | +using p5 library. See the below figure for more clarity. |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | +## File Structure |
| 45 | + |
| 46 | +All relevant folders and files of artboard are listed down - |
| 47 | + |
| 48 | +- Types |
| 49 | + - artboard.d.ts |
| 50 | + - context.d.ts |
| 51 | + |
| 52 | +- Components |
| 53 | + - artboard |
| 54 | + - Artboard.tsx |
| 55 | + - Manager.tsx |
| 56 | + - Underlay.tsx |
| 57 | + - Monitor.ts |
| 58 | + |
| 59 | +- Context |
| 60 | + - ArtBoardContext.ts |
| 61 | + |
| 62 | +- Models |
| 63 | + - artboard |
| 64 | + - ArtBoardDraw.ts |
| 65 | + - Artboard.ts |
| 66 | + - ArtboardManager.ts |
| 67 | + - Turtle.ts |
| 68 | + |
| 69 | +- Views |
| 70 | + - artboard |
| 71 | + - Artboard.scss |
| 72 | + - Artboard.tsx |
| 73 | + - ArtboardHandler.tsx |
| 74 | + - ArtboardSketch.tsx |
| 75 | + - ArtboardTurtle.tsx |
| 76 | + |
| 77 | +## p5 Library and Artboard |
| 78 | + |
| 79 | +[p5](https://p5js.org/) library is used to create and handle canvases. p5 provides many inbuilt |
| 80 | +functions to draw graphics and control over the canvas.p5.js has a number of predefined functions |
| 81 | +which we can use to draw anything we want. The most basic (and necessary) functions are the setup() |
| 82 | +and draw() functions. A simple canvas using p5 in react can be created like this. |
| 83 | + |
| 84 | +[`p5 Canvas is created in instance mode.`](https://github.com/processing/p5.js/wiki/Global-and-instance-mode) |
| 85 | + |
| 86 | +```typescript |
| 87 | +const Sketch = (sketch: P5Instance): void => { |
| 88 | + let demoCanvas: p5.Element; |
| 89 | + |
| 90 | + /** This is a setup function */ |
| 91 | + sketch.setup = () => { |
| 92 | + demoCanvas = sketch.createCanvas(1200, 600); |
| 93 | + }; |
| 94 | + |
| 95 | + /** This is a draw function */ |
| 96 | + sketch.draw = () => { |
| 97 | + sketch.background(220); |
| 98 | + sketch.ellipse(50, 50, 80, 80); |
| 99 | + }; |
| 100 | +}; |
| 101 | +``` |
| 102 | + |
| 103 | +It creates a canvas as p5 element with a circle on top of it. There are two important functions `setup` |
| 104 | +and `draw`. The code inside the `draw()` function runs continuously from top to bottom until the |
| 105 | +program is stopped. The setup function runs only once in the beginning. |
| 106 | + |
| 107 | +### Integration p5 Sketches with React |
| 108 | + |
| 109 | +By using React we get all the advantages of declarative code with clean, reusable and reactive |
| 110 | +components. All the while still maintaining the easy to use abstractions exposed by p5. The above |
| 111 | +sketch defintion is called inside a react component. |
| 112 | + |
| 113 | +### How Do We Add A Sketch In React? |
| 114 | + |
| 115 | +The sample sketch above is written in plain JavaScript and we can’t just write the same code in react. |
| 116 | +We have to add it using a few manipulations. |
| 117 | + |
| 118 | +Adding a sketch in react is fairly simple, we need to do three basic things: |
| 119 | + |
| 120 | +1. Create a function which encapsulates our sketch |
| 121 | +2. Create a p5 object using the p5 package that we installed earlier |
| 122 | +3. Pass our sketch to the p5 object as an argument |
| 123 | + |
| 124 | +The canvas is wrapped inside a react component so that we can use some of the lifecycle to manipulate |
| 125 | +it accordingly. |
| 126 | + |
| 127 | +```typescript |
| 128 | +const DemoSketch: React.FC<P5WrapperProps> = ({ sketch, children, ...props }) => { |
| 129 | + |
| 130 | + /** Sketch takes a P5Instance of canvas, props contains attributes like bg color, etc*/ |
| 131 | + const demoSketch = createRef<HTMLDivElement>(); |
| 132 | + const [instance, setInstance] = useState<P5Instance>(); |
| 133 | + const id = `demo-sketch`; |
| 134 | + useEffect(() => { |
| 135 | + instance?.updateWithProps?.(props); |
| 136 | + }, [props]); |
| 137 | + |
| 138 | + useEffect(() => { |
| 139 | + if (demoSketch.current === null) return; |
| 140 | + instance?.remove(); |
| 141 | + const canvas = new p5(Sketch, document.getElementById(id) as HTMLElement) as P5Instance; |
| 142 | + canvas.updateWithProps?.(props); |
| 143 | + setInstance(canvas); |
| 144 | + }, [sketch, demoSketch.current]); |
| 145 | + |
| 146 | + return ( |
| 147 | + <div id={id} ref={demoSketch}> |
| 148 | + {children} |
| 149 | + </div> |
| 150 | + ); |
| 151 | +}; |
| 152 | +``` |
| 153 | + |
| 154 | +For more information on the integration of p5 sketches with react, please read this |
| 155 | +[post](https://levelup.gitconnected.com/integrating-p5-sketches-into-your-react-app-de44a8c74e91). |
| 156 | + |
| 157 | +## Artboard and react hooks |
| 158 | + |
| 159 | +```typescript |
| 160 | +sketch.updateWithProps = (props: SketchProps) => { |
| 161 | + if (props.color) { |
| 162 | + bgcolor = parseInt(props.color, 10); |
| 163 | + } |
| 164 | +}; |
| 165 | + |
| 166 | +useEffect(() => { |
| 167 | + instance?.updateWithProps?.(props); |
| 168 | +}, [props]); |
| 169 | +``` |
| 170 | + |
| 171 | +We declare a reference variable called "demoSketch" using React's useRef hook. This just let's our |
| 172 | +other libraries have a Node.js or reference insertion point. It's important that we pass |
| 173 | +"domSketch.current" into DOM because ".current" gives the actual HTML Node.js we want. And finally, |
| 174 | +we return some jsx of a div that has the ref attribute equal to the value of our useRef hook variable. |
| 175 | + |
| 176 | +Similarly, useEffect hook is used to reflect the change on the canvas. In the above example we see |
| 177 | +the `updateWithProps()` function, which is called when the properties of a wrapper component are |
| 178 | +changed. Read more [here](https://github.com/jamesrweb/react-p5-wrapper). |
0 commit comments