# Why Declarativas?

## Comparisons

### Summary

Here I will show a comparison between raw canvas, declarativas without jsx, and with jsx, using a function that will render a rotating 20x20 square centered on 100,100 in the canvas.

### Declarativas Goals

One thing to note is declarativas isn't meant to make canvas programs shorter. While custom components can be made to manage multiple canvas calls, the main goal is to make canvas more approachable to the React generation of javascript developers. Thinking about canvas in terms of components makes things easier to manage, and using a virtual canvas operations (similar to virtual dom), it is far easier to test your canvas application and have predictable output, as well as build logical hierarchies.

### Raw Canvas

```javascript
const ctx = document.querySelector('canvas').getContext('2d');

const draw = (lastTimestamp, angle) => (timestamp) => {
  const delta = lastTimestamp
    ? (timestamp - lastTimestamp) / 1000
    : 0;
  
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  
  ctx.save();
  
  ctx.translate(100, 100);
  ctx.rotate(angle * Math.PI / 180);
  
  ctx.fillStyle = 'blue';
  ctx.fillRect(-10, -10, 20, 20);
  
  ctx.restore();
  
  requestAnimationFrame(draw(timestamp, angle + (10 * delta)));
}

requestAnimationFrame(draw(null, 0));
```

#### Pros

* No extra learning on top of the canvas API
* Shortest program

#### Cons

* No meaningful relationship between calls
  * `save` does not imply a later `restore`
  * A lack of hierarchy makes it non-obvious what mutations to the canvas state require the save and restore
* No community consensus on how to build drawing components
* Arguments to some functions are non-obvious

### Declarativas without JSX

```javascript
import {
  render, createElement as c,
  Stateful, Translate, Rotate, ClearCanvas, Properties, FillRect,
} from 'declarativas';
const { , Rect } = components;

const ctx = document.querySelector('canvas').getContext('2d');

const draw = (lastTimestamp, angle) => (timestamp) => {
  const delta = lastTimestamp
    ? (timestamp - lastTimestamp) / 1000
    : 0;
    
  render(
    ctx,
    c(Stateful, {}, [
      c(ClearCanvas, {}),
      c(Translate, { x: 100, y: 100 }),
      c(Rotate, { angle: angle * Math.PI / 180 }),
      
      c(Properties, { fillStyle: 'blue' }),
      c(FillRect, { x: -10, y: -10, w: 20, h: 20 }),
    ]),
  );
  
  requestAnimationFrame(draw(timestamp, angle + (10 * delta)));
}

requestAnimationFrame(draw(null, 0));
```

#### Pros

* Hierarchy of drawing operations
* Clear distinction of drawing code from logic
* Named parameters
* Declarative components can make the code easier to debug and test

#### Cons

* The `createElement` (aliased as `c`) function can look awkward
* More code
* Adds dependency
* Could feel foreign

### Declarativas with JSX

```javascript
/** @jsx c */
import {
  render, createElement as c,
  Group, ClearCanvas, RevertableState, Translate, Rotate, Properties, FillRect,
} from 'declarativas';

const ctx = document.querySelector('canvas').getContext('2d');

const render = (lastTimestamp, angle) => (timestamp) => {
  const delta = lastTimestamp
    ? (timestamp - lastTimestamp) / 1000
    : 0;
    
  render(
    <Group>
      <ClearCanvas />
      <Stateful>
        <Translate x={100} y={100} />
        <Rotate angle={angle * Math.PI / 180} />
        
        <Properties fillStyle="blue" />
        <FillRect x={-10} y={-10} w={20} h={20} />
      </Stateful>
    </Group>,
    ctx,
  );
  
  requestAnimationFrame(draw(timestamp, angle + (10 * delta)));
}

requestAnimationFrame(draw(null, 0));
```

#### Pros

* Hierarchy of drawing operations
* Clear distinction of drawing code from logic
* Named parameters
* Declarative components can make the code easier to debug and test
* Higher familiarity to the code (from the perspective of React) because of the JSX transform used for operations

#### Cons

* More code
* Adds dependency
* Could feel foreign

## TL;DR

If you want a very lean bare-metal canvas experience, there is nothing distinctly wrong with the javascript API for CanvasContext2d. If you want a more manageable code-base that uses a lot of canvas, I do think declarativas has a well defined use. I personally enjoy the way I can draw with declarativas, and hope you would try it and see the difference.
