Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tldraw/tldraw/llms.txt

Use this file to discover all available pages before exploring further.

DrawShapeUtil handles freehand drawing shapes created with the draw tool, supporting both pen and mouse input with configurable stroke smoothing.

Type signature

class DrawShapeUtil extends ShapeUtil<TLDrawShape>

Features

  • Freehand drawing with pressure sensitivity
  • Pen vs mouse input handling
  • Closed/filled shapes
  • Multiple segments for long drawings
  • Draw-style strokes with natural variation
  • Automatic simplification

Configuration options

interface DrawShapeOptions {
  /**
   * The maximum number of points in a line before the draw tool will begin a new shape.
   * A higher number will lead to poor performance while drawing very long lines.
   */
  readonly maxPointsPerShape: number // default: 600
}

Default props

getDefaultProps(): TLDrawShape['props'] {
  return {
    segments: [],
    color: 'black',
    fill: 'none',
    dash: 'draw',
    size: 'm',
    isComplete: false,
    isClosed: false,
    isPen: false,
    scale: 1,
    scaleX: 1,
    scaleY: 1,
  }
}

Properties

segments
TLDrawShapeSegment[]
required
Array of drawing segments. Each segment contains encoded points.
isComplete
boolean
default:"false"
Whether the drawing is complete (user finished drawing).
isClosed
boolean
default:"false"
Whether the shape is a closed loop that can be filled.
isPen
boolean
default:"false"
Whether the shape was drawn with a pen (affects smoothing).
scale
number
default:"1"
Overall scale of the shape.
scaleX
number
default:"1"
Horizontal scale factor from resizing.
scaleY
number
default:"1"
Vertical scale factor from resizing.

Geometry

Draw shapes have different geometry based on their characteristics:

Single point (dot)

new Circle2d({
  x: -sw,
  y: -sw,
  radius: sw,
  isFilled: true,
})

Closed shape

new Polygon2d({
  points: strokePoints,
  isFilled: shape.props.fill !== 'none',
})

Open path

new Polyline2d({
  points: strokePoints,
})

Methods

getGeometry()

Returns appropriate geometry (Circle2d for dots, Polygon2d for closed shapes, Polyline2d for open strokes).

hideResizeHandles()

hideResizeHandles(shape: TLDrawShape): boolean {
  return getIsDot(shape)
}
Hides resize handles for single-point dots.

hideRotateHandle()

hideRotateHandle(shape: TLDrawShape): boolean {
  return getIsDot(shape)
}
Hides rotation handle for dots.

onResize()

Updates scaleX and scaleY properties based on resize:
onResize(shape: TLDrawShape, info: TLResizeInfo<TLDrawShape>) {
  const newScaleX = info.scaleX * shape.props.scaleX
  const newScaleY = info.scaleY * shape.props.scaleY
  if (newScaleX === 0 || newScaleY === 0) return

  return {
    props: {
      scaleX: newScaleX,
      scaleY: newScaleY,
    },
  }
}

expandSelectionOutlinePx()

Expands selection outline to account for stroke width:
expandSelectionOutlinePx(shape: TLDrawShape): number {
  const multiplier = shape.props.dash === 'draw' ? 1.6 : 1
  return ((STROKE_SIZES[shape.props.size] * multiplier) / 2) * shape.props.scale
}

Indicator

Uses canvas-based indicator for better performance:
useLegacyIndicator() {
  return false
}

getIndicatorPath(shape: TLDrawShape): Path2D {
  const strokePoints = getStrokePoints(allPointsFromSegments, options)
  const solidStrokePath =
    strokePoints.length > 1
      ? getSvgPathFromStrokePoints(strokePoints, shape.props.isClosed)
      : getDot(allPointsFromSegments[0], sw)

  return new Path2D(solidStrokePath)
}

Export

toSvg()

Exports the draw shape as SVG with proper scaling:
toSvg(shape: TLDrawShape, ctx: SvgExportContext) {
  ctx.addExportDef(getFillDefForExport(shape.props.fill))
  const scaleFactor = 1 / shape.props.scale
  return (
    <g transform={`scale(${scaleFactor})`}>
      <DrawShapeSvg shape={shape} zoomOverride={1} />
    </g>
  )
}

Stroke rendering

Draw shapes use the perfect-freehand algorithm for natural-looking strokes:
  • Pen input: Less smoothing for precise control
  • Mouse input: More smoothing for cleaner lines
  • Draw dash style: Ink-like variation
  • Other dash styles: Solid stroke with dash array

Example: Configure draw options

import { DrawShapeUtil } from 'tldraw'

const CustomDrawUtil = DrawShapeUtil.configure({
  maxPointsPerShape: 1000, // Allow longer drawings
})

Example: Working with draw shapes

// Check if a draw shape is just a dot
function isDot(shape: TLDrawShape): boolean {
  return shape.props.segments.length === 1 && 
         shape.props.segments[0].path.length < 24
}

// Get all draw shapes that are closed
const closedDrawings = editor.getCurrentPageShapes()
  .filter((s): s is TLDrawShape => 
    s.type === 'draw' && s.props.isClosed
  )