Skip to content

Commit

Permalink
Merge pull request #20 from lukix/add-option-to-skip-clearing-canvas
Browse files Browse the repository at this point in the history
Add clearCanvas option
  • Loading branch information
lukix authored Jul 27, 2024
2 parents 998ec06 + 938baaf commit 9d41c8d
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 29 deletions.
84 changes: 58 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# declarative-canvas

[![npm version](https://badge.fury.io/js/declarative-canvas.svg)](https://www.npmjs.com/package/declarative-canvas)

JavaScript/TypeScript library which lets you draw on HTML5 Canvas in a declarative way.

## Installation

```
npm install declarative-canvas
```

## Example Usage

The following code draws a rectangle and a circle on a canvas.

```js
import { createDrawFunction, objectTypes } from 'declarative-canvas';

Expand All @@ -27,20 +31,26 @@ draw({ context, objects: objectsToRender });
```

## Storybook

More examples can be found in the [storybook](https://lukix.github.io/declarative-canvas). Source code of storybook stories is placed in the [src/stories](./src/storybook/stories) directory.

## API Reference

`declarative-canvas` exports four objects/functions:

- `createDrawFunction` - draw function factory,
- `objectTypes` - dictionary object of available object types which can be drawn,
- `drawMethods` - dictionary object of available drawing methods.
- `convertCanvasCoordinates` - lets you convert canvas coordinates to base coordinates that you use to render objects.

### createDrawFunction

A factory function that takes one optional argument:

```ts
(customDrawHandlers = {}) => Function
(customDrawHandlers = {}) => Function;
```

`customDrawHandlers` argument is described in [Custom draw handlers](#custom-draw-handlers) chapter.

A function returned from this factory has the following signature:
Expand All @@ -52,10 +62,14 @@ A function returned from this factory has the following signature:
canvasWidth = context.canvas && context.canvas.width,
canvasHeight = context.canvas && context.canvas.width,
camera = { position: { x: canvasWidth / 2, y: canvasHeight / 2 }, zoom: 1, rotation: 0 },
clearCanvas = true,
}) => void
```

`clearCanvas` option clears canvas before rendering objects.

### objectTypes

```js
{
CIRCLE: 'CIRCLE',
Expand All @@ -68,17 +82,20 @@ A function returned from this factory has the following signature:
```

### drawMethods

```js
{
FILL: 'FILL',
STROKE: 'STROKE',
FILL_AND_STROKE: 'FILL_AND_STROKE',
}
```

Draw method tells the renderer if the given graphical object should be drawn by filling it with some color
or just by drawing its outline (or both).

### convertCanvasCoordinates

```ts
(
x: number,
Expand All @@ -88,11 +105,13 @@ or just by drawing its outline (or both).
camera: Camera
) => { x: number, y: number }
```

A function that converts canvas coordinates (for example `event.offsetX` and `event.offsetY` from `onclick` event) to base coordinates that you use to render objects (taking into account any transformations caused by camera's position, rotation and zoom).

## Available graphical objects

### Rectangle

```ts
{
type: objectTypes.RECT;
Expand All @@ -105,16 +124,17 @@ A function that converts canvas coordinates (for example `event.offsetX` and `ev
rotation?: number;
}
```
`contextProps` - [Canvas context props](#Context-Props). *Default: `{}`*
`drawMethod` - [Draw method](#drawMethods). *Default: `drawMethods.FILL`*

`contextProps` - [Canvas context props](#Context-Props). _Default: `{}`_
`drawMethod` - [Draw method](#drawMethods). _Default: `drawMethods.FILL`_
`x` - position of the center of rectangle in X axis
`y` - position of the center of rectangle in Y axis
`width` - rectangle width
`height` - rectangle height
`rotation` - rectangle rotation in radians. *Default: `0`*

`rotation` - rectangle rotation in radians. _Default: `0`_

### Circle

```ts
{
type: objectTypes.CIRCLE;
Expand All @@ -125,13 +145,15 @@ A function that converts canvas coordinates (for example `event.offsetX` and `ev
radius: number;
}
```
`contextProps` - [Canvas context props](#Context-Props). *Default: `{}`*
`drawMethod` - [Draw method](#drawMethods). *Default: `drawMethods.FILL`*

`contextProps` - [Canvas context props](#Context-Props). _Default: `{}`_
`drawMethod` - [Draw method](#drawMethods). _Default: `drawMethods.FILL`_
`x` - position of the center of circle in X axis
`y` - position of the center of circle in Y axis
`radius` - circle radius

### Path

```ts
{
type: objectTypes.PATH;
Expand All @@ -141,12 +163,14 @@ A function that converts canvas coordinates (for example `event.offsetX` and `ev
closePath?: boolean,
}
```
`contextProps` - [Canvas context props](#Context-Props). *Default: `{}`*
`drawMethod` - [Draw method](#drawMethods). *Default: `drawMethods.FILL`*

`contextProps` - [Canvas context props](#Context-Props). _Default: `{}`_
`drawMethod` - [Draw method](#drawMethods). _Default: `drawMethods.FILL`_
`points` - array of points that make the path
`closePath` - indicates if the last point should be connected to the first point. *Default: `false`*
`closePath` - indicates if the last point should be connected to the first point. _Default: `false`_

### Image

```ts
{
type: objectTypes.IMAGE;
Expand All @@ -159,15 +183,17 @@ A function that converts canvas coordinates (for example `event.offsetX` and `ev
rotation?: number;
}
```
`contextProps` - [Canvas context props](#Context-Props). *Default: `{}`*

`contextProps` - [Canvas context props](#Context-Props). _Default: `{}`_
`image` - [Image](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image) object
`x` - position of the center of image in X axis
`y` - position of the center of image in Y axis
`width` - image width. *Defaults to image orginal width*
`height` - image height. *Defaults to image orginal height*
`rotation` - image rotation in radians. *Default: `0`*
`width` - image width. _Defaults to image orginal width_
`height` - image height. _Defaults to image orginal height_
`rotation` - image rotation in radians. _Default: `0`_

### Text

```ts
{
type: objectTypes.TEXT;
Expand All @@ -178,14 +204,16 @@ A function that converts canvas coordinates (for example `event.offsetX` and `ev
y: number;
}
```
`contextProps` - [Canvas context props](#Context-Props). *Default: `{}`*
`drawMethod` - [Draw method](#drawMethods). *Default: `drawMethods.FILL`*

`contextProps` - [Canvas context props](#Context-Props). _Default: `{}`_
`drawMethod` - [Draw method](#drawMethods). _Default: `drawMethods.FILL`_
`image` - [Image](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image) object
`text` - text to be rendered
`x` - position of the text in X axis. Text horizontal and vertical align can be adjusted by `contextProps`
`y` - position of the text in Y axis Text horizontal and vertical align can be adjusted by `contextProps`
`y` - position of the text in Y axis Text horizontal and vertical align can be adjusted by `contextProps`

### Transform

```ts
{
type: objectTypes.TRANSFORM;
Expand All @@ -200,32 +228,36 @@ A function that converts canvas coordinates (for example `event.offsetX` and `ev
rotation?: number;
}
```
`contextProps` - [Canvas context props](#Context-Props). *Default: `{}`*

`contextProps` - [Canvas context props](#Context-Props). _Default: `{}`_
`children` - array of graphical objects
`dx` - displacement of child objects in X axis. *Default: `0`*
`dy` - displacement of child objects in Y axis. *Default: `0`*
`scaleX` - scaling of child objects in X axis. *Default: `1`*
`scaleY` - scaling of child objects in Y axis. *Default: `1`*
`skewX` - skew transformation applied to child objects in X axis. *Default: `0`*
`skewY` - skew transformation applied to child objects in Y axis. *Default: `0`*
`rotation` - rotation in radians of child objects. *Default: `0`*
`dx` - displacement of child objects in X axis. _Default: `0`_
`dy` - displacement of child objects in Y axis. _Default: `0`_
`scaleX` - scaling of child objects in X axis. _Default: `1`_
`scaleY` - scaling of child objects in Y axis. _Default: `1`_
`skewX` - skew transformation applied to child objects in X axis. _Default: `0`_
`skewY` - skew transformation applied to child objects in Y axis. _Default: `0`_
`rotation` - rotation in radians of child objects. _Default: `0`_

## Context Props

For every graphical object you can specify `contextProps` property.
Before drawing graphical object, all values of `contextProps` object will be assigned
to [Canvas Rendering Context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D).
Some example values that you can use: `fillStyle`, `strokeStyle`, `lineWidth`, `filter` and so on.
After drawing the graphical object, context properties will be restored back to their orginal values.

## Custom draw handlers

If you want to expand the capabilities of `declarative-canvas` to support more object types,
you can specify custom draw handlers which will be used to draw objects with specified object type.
Draw handler is a function with the following signature:

```ts
(context, options, drawObject) => void
```

To see examples of draw handlers, you can check out default draw handlers in [src/drawHandlerFunctions](./src/drawHandlerFunctions) directory.

Custom handlers can be passed as a `customDrawHandlers` argument to `createDrawFunction`.
`customDrawHandlers` should be an object, where keys represent object types and values represent custom handlers.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "declarative-canvas",
"version": "1.2.0",
"version": "1.3.0",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"author": "Łukasz Jenczmyk",
Expand All @@ -18,7 +18,11 @@
"type": "git",
"url": "git+https://github.com/lukix/declarative-canvas.git"
},
"files": ["lib/", "!lib/storybook/", "!__tests__/"],
"files": [
"lib/",
"!lib/storybook/",
"!__tests__/"
],
"scripts": {
"dev": "tsc --watch",
"test": "jest",
Expand Down
6 changes: 5 additions & 1 deletion src/createDrawFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type DrawFunctionProps<
canvasWidth?: number;
canvasHeight?: number;
camera?: Camera;
clearCanvas?: boolean;
};

function createDrawFunction<CH extends DrawHandlersDictionary<keyof CH>>(
Expand All @@ -79,8 +80,11 @@ function createDrawFunction<CH extends DrawHandlersDictionary<keyof CH>>(
zoom: 1,
rotation: 0,
},
clearCanvas = true,
}: DrawFunctionProps<typeof defaultDrawHandlers & CH>): void {
context.clearRect(0, 0, canvasWidth, canvasHeight);
if (clearCanvas) {
context.clearRect(0, 0, canvasWidth, canvasHeight);
}
context.save();
setCameraTransform({ context, canvasWidth, canvasHeight, camera });
const drawObject = drawObjectFactory(context, drawHandlers);
Expand Down

0 comments on commit 9d41c8d

Please sign in to comment.