[]previous and next page

Shapes

The built-in shapes, the props they share, and the one idea that makes CanvasFlow precise - every shape has real geometry.

The built-in shapes#

type What it is Notable props
geo Rectangles, ellipses, diamonds, stars, clouds and 13 more geo, w, h, text, fill, edges
text Text, auto-sized or with a fixed width text, autoSize, w, font, fontSize
note A sticky note text, color
draw Freehand strokes, with pen pressure points, isPen, isClosed
highlight The highlighter points
line A line through any number of points points, arrowKind, closed, line ends
arrow An arrow that can bind to shapes and carry a label start, mid, end, arrowKind, text
image An image (from a file, the clipboard or a URL) assetId, w, h, radius
embed YouTube, Vimeo, Figma, CodePen and other embeds url, w, h
frame A frame that clips and owns the shapes inside it name, w, h, background
spec A data-driven shape from a plugin (see Plugins) specId, w, h

The geo kinds, drawn by the engine itself:

rectangle
ellipse
diamond
triangle
pentagon
hexagon
octagon
star
parallelogram
trapezoid
arrow-right
arrow-left
arrow-up
arrow-down
cloud
heart
check-box
x-box
18 geo kinds. Each one is a real outline: hit-testing, snapping and arrow bindings use it.

Every shape has real geometry#

This is the idea the whole engine rests on. Each shape type has a getGeometry() that returns its true outline: the points of a star, the curve of a hand-drawn ellipse, the stroke of a 1.5 px line, the rounded corners when edges are round.

That one outline is used for everything:

  • Hover and click. Clicking inside a star with no fill selects nothing. Clicking its edge selects it.
  • The selection outline, which hugs the shape instead of its bounding box.
  • The marquee and the lasso, in touch or contain mode.
  • The eraser, which follows the path of your pointer across real strokes.
  • Snapping, to edges and centers.
  • Arrow bindings, which land on the outline, not on an invisible box.

A live CanvasFlow editor runs here when JavaScript is on.

Hover and click the shapes. The outline you see is the area you hit.

The hit area is generous where it should be: thin lines get a tolerance that grows for touch and pen, so they're easy to grab, while the outline stays exact.

Props and styles#

Shapes share style props with the same names, which is how one style panel works for every shape:

Prop Values
color black, grey, white, red, orange, yellow, green, teal, blue, violet, pink, brown, or any CSS color
fill none, semi, solid, hachure, cross-hatch, dots
size s, m, l, xl (stroke width)
dash solid, dashed, dotted
sketch 0, 1, 2 (sloppiness)
font hand, sans, serif, mono

A shape supports a style when its default props contain that key. When nothing is selected, the panel shows the styles the current tool will use, and new shapes pick them up. More in Styles and themes.

fill: 'none'
fill: 'semi'
fill: 'solid'
fill: 'hachure'
fill: 'cross-hatch'
fill: 'dots'

Working with shapes#

ts
// Create (props you leave out come from the defaults and current styles)
const id = editor.createShape({ type: 'note', x: 0, y: 0, props: { text: 'Ship Friday' } })

// Read
const shape = editor.getShape(id)
const bounds = editor.getShapePageBounds(id)
const geometry = editor.getShapeGeometry(shape!)

// Update and delete
editor.updateShape({ id, rotation: Math.PI / 12, props: { color: 'green' } })
editor.deleteShapes([id])

Frames and groups#

Frames are shapes that own other shapes: drag something into a frame and it becomes a child (its parentId is the frame), clipped to the frame and moved with it.

Groups are not shapes. A group is an id in each member's groupIds. Clicking a grouped shape selects the group; double-click enters it to select inside. Groups nest.

ts
const group = editor.groupShapes(ids)
editor.ungroupShapes(ids)

Unknown shapes are kept#

If a document contains a shape type your app doesn't register (a plugin someone else had, a newer version), CanvasFlow keeps the record and draws a labeled placeholder. Nothing is dropped, and it renders properly again when the type is available.

Next#