Skip to content

Commit

Permalink
feat(hdom-canvas): add ellipse() / ellipticArc(), update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Jan 20, 2019
1 parent 6f341c5 commit 9a50769
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 42 deletions.
133 changes: 96 additions & 37 deletions packages/hdom-canvas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,42 @@
This project is part of the
[@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo.

<!-- TOC depthFrom:2 depthTo:3 -->

- [@thi.ng/hdom-canvas](#thinghdom-canvas)
- [About](#about)
- [Status](#status)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Usage examples](#usage-examples)
- [How it works](#how-it-works)
- [Restrictions & behavior controls](#restrictions--behavior-controls)
- [HDPI support](#hdpi-support)
- [SVG conversion](#svg-conversion)
- [Supported shape types](#supported-shape-types)
- [Group](#group)
- [Definition group](#definition-group)
- [Circle](#circle)
- [Rect](#rect)
- [Arc](#arc)
- [Line](#line)
- [Horizontal Line](#horizontal-line)
- [Vertical Line](#vertical-line)
- [Polyline / Polygon](#polyline--polygon)
- [Path](#path)
- [Points](#points)
- [Text](#text)
- [Image](#image)
- [Gradients](#gradients)
- [Attributes](#attributes)
- [Coordinate transformations](#coordinate-transformations)
- [Transform matrix](#transform-matrix)
- [Translation](#translation)
- [Scaling](#scaling)
- [Rotation](#rotation)
- [Authors](#authors)
- [License](#license)
<!-- TOC depthFrom:2 depthTo:4 -->

- [About](#about)
- [Status](#status)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Usage examples](#usage-examples)
- [How it works](#how-it-works)
- [Restrictions & behavior controls](#restrictions--behavior-controls)
- [HDPI support](#hdpi-support)
- [SVG conversion](#svg-conversion)
- [Supported shape types](#supported-shape-types)
- [Group](#group)
- [Definition group](#definition-group)
- [Circle](#circle)
- [Ellipse](#ellipse)
- [Rect](#rect)
- [Arc](#arc)
- [Line](#line)
- [Horizontal Line](#horizontal-line)
- [Vertical Line](#vertical-line)
- [Polyline / Polygon](#polyline--polygon)
- [Path](#path)
- [SVG paths with arc segments](#svg-paths-with-arc-segments)
- [Points](#points)
- [Text](#text)
- [Image](#image)
- [Gradients](#gradients)
- [Attributes](#attributes)
- [Coordinate transformations](#coordinate-transformations)
- [Transform matrix](#transform-matrix)
- [Translation](#translation)
- [Scaling](#scaling)
- [Rotation](#rotation)
- [Authors](#authors)
- [License](#license)

<!-- /TOC -->

Expand Down Expand Up @@ -94,6 +95,31 @@ start(() => {
});
```

Usage with
[@thi.ng/geom3](https://github.com/thi-ng/umbrella/tree/master/packages/geom3)
shape primitives:

```ts
import { start } from "@thi.ng/hdom";
import { canvas } from "@thi.ng/hdom-canvas";
import * as g from "@thi.ng/geom3";

start(() => {
const t = Date.now() * 0.001;
return [canvas, { width: 100, height: 100 },
g.group(
{ translate: [50,50], fill: "none" },
g.withAttribs(
g.asPolygon(g.circle(50), 6),
{ rotate: (Date.now() * 0.01) % (Math.PI * 2), stroke: "red" }
),
g.star(25 + 25 * Math.sin(t), 6, [0.5, 1], { stroke: "blue" }),
)
];
});

```

## How it works

The package provides a `canvas` component which uses the branch-local
Expand All @@ -105,8 +131,11 @@ component, but are then translated into canvas API draw commands during
the hdom update process. Any embedded shape component functions receive
the user context object as first arg, just like normal hdom components.

Shape components are expressed in standard hiccup syntax, however with
the following...
Shape components are expressed in standard hiccup syntax (or as objects
implementing the `IToHiccup()` interface, like the shape types provided
by
[@thi.ng/geom3](https://github.com/thi-ng/umbrella/tree/master/packages/geom3)),
and with the following...

### Restrictions & behavior controls

Expand Down Expand Up @@ -236,6 +265,12 @@ used, should always come first in a scene tree.
["circle", attribs, [x, y], radius]
```

### Ellipse

```ts
["ellipse", attribs, [x, y], [rx,ry], axisTheta?, start?, end?, ccw?]
```
### Rect
```ts
Expand All @@ -251,6 +286,9 @@ clamped to `Math.min(w, h)/2`.
["arc", attribs, [x, y], radius, startAngle, endAngle, anticlockwise?]
```
Only circular arcs are supported in this format. Please see [note about
differences to SVG](#svg-paths-with-arc-segments).
### Line
```ts
Expand Down Expand Up @@ -305,6 +343,27 @@ relative to the end point of the previous segment.
| `["A", [x1,y1], [x2, y2], r]` | Arc |
| `["Z"]` | Close (sub)path |
#### SVG paths with arc segments
**IMPORTANT:** Due to differences between SVG and canvas API arc
handling, SVG paths containing arc segments are **NOT** compatible with
the above format. To draw such paths reliably, these should first be
converted to use cubics. E.g. here using
[@thi.ng/geom3](https://github.com/thi-ng/umbrella/tree/master/packages/geom3):
```ts
import { normalizedPath, pathFromSVG } from "@thi.ng/geom3";

// path w/ ac segments
const a = pathFromSvg("M0,0H80A20,20,0,0,1,100,20V30A20,20,0,0,1,80,50")[0];

// normalized to only use cubic curves
const b = normalizedPath(a);

asSvg(b);
// <path d="M0.00,0.00C26.67,0.00,53.33,0.00,80.00,0.00C91.05,0.00,100.00,8.95,100.00,20.00C100.00,23.33,100.00,26.67,100.00,30.00C100.00,41.05,91.05,50.00,80.00,50.00"/>
```
### Points
```ts
Expand Down
35 changes: 30 additions & 5 deletions packages/hdom-canvas/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ const walk =
case "circle":
circularArc(ctx, attribs, shape[2], shape[3]);
break;
case "ellipse":
ellipticArc(ctx, attribs, shape[2], shape[3], shape[4], shape[5], shape[6]);
break;
case "arc":
circularArc(ctx, attribs, shape[2], shape[3], shape[4], shape[5]);
break;
Expand Down Expand Up @@ -505,29 +508,31 @@ const path = (
ctx.lineTo(b[0], b[1]);
a = b;
break;
// horizontal line
// horizontal line rel
case "h":
b = [a[0] + b, a[1]];
ctx.lineTo(b[0], b[1]);
a = b;
break;
// horizontal line abs
case "H":
b = [b, a[1]];
ctx.lineTo(b[0], b[1]);
a = b;
break;
// vertical line
// vertical line rel
case "v":
b = [a[0], a[1] + b];
ctx.lineTo(b[0], b[1]);
a = b;
break;
// vertical line abs
case "V":
b = [a[0], b];
ctx.lineTo(b[0], b[1]);
a = b;
break;
// cubic / bezier curve to
// cubic curve rel
case "c":
c = s[2];
d = s[3];
Expand All @@ -539,6 +544,7 @@ const path = (
);
a = d;
break;
// cubic curve abs
case "C":
c = s[2];
d = s[3];
Expand All @@ -549,7 +555,7 @@ const path = (
);
a = d;
break;
// quadratic curve to
// quadratic curve rel
case "q":
c = s[2];
c = [a[0] + c[0], a[1] + c[1]];
Expand All @@ -559,6 +565,7 @@ const path = (
);
a = c;
break;
// quadratic curve abs
case "Q":
c = s[2];
ctx.quadraticCurveTo(
Expand All @@ -567,7 +574,8 @@ const path = (
);
a = c;
break;
// arc to
// circular arc rel
// Note: NOT compatible w/ SVG arc segments
case "a":
c = s[2];
c = [a[0] + c[0], a[1] + c[1]];
Expand All @@ -578,6 +586,8 @@ const path = (
);
a = c;
break;
// circular arc abs
// Note: NOT compatible w/ SVG arc segments
case "A":
c = s[2];
ctx.arcTo(
Expand Down Expand Up @@ -611,6 +621,21 @@ const circularArc = (
endShape(ctx, attribs);
};

const ellipticArc = (
ctx: CanvasRenderingContext2D,
attribs: IObjectOf<any>,
pos: ReadonlyVec,
r: ReadonlyVec,
axis = 0,
start = 0,
end = TAU,
ccw = false
) => {
ctx.beginPath();
ctx.ellipse(pos[0], pos[1], r[0], r[1], axis, start, end, ccw);
endShape(ctx, attribs);
};

const rect = (ctx: CanvasRenderingContext2D,
attribs: IObjectOf<any>,
pos: ReadonlyVec,
Expand Down

0 comments on commit 9a50769

Please sign in to comment.