Pad
Interactive drawing and sketching component with support for multiple stroke types, shapes, colors, and undo/redo functionality.
Overview
VOvPad is a versatile drawing canvas component that enables freehand drawing, shape creation, and sketching capabilities. It supports multiple stroke types (dash, line, square, circle, triangle, half_triangle), customizable colors and line styles, background images, and complete undo/redo history. The component is fully touch-compatible and responds to mouse, touch, and pointer events.
Features:
- 6 stroke types with shape guides and real-time preview
- Freehand drawing with customizable brush properties
- Shape filling and styling options
- Eraser functionality with background color awareness
- Complete undo/redo history tracking
- Touch, mouse, and pointer event support
- Background image support with scaling
- Canvas locking to prevent modifications
- Export to PNG or JPEG with custom dimensions
- Full TypeScript support
Dependencies
No external dependencies required. The component uses native Canvas API.
Usage
Examples
<template>
<v-container fluid>
<v-ov-pad
ref="pad"
class="border"
:width="'100%'"
:height="'240px'"
:lock="locked"
:eraser="eraser"
:background-color="backgroundColor"
:background-image="backgroundImage"
:lineWidth="line"
:color="color"
/>
<v-btn @click="reset">Clear</v-btn>
<v-btn @click="undo">Undo</v-btn>
<v-btn @click="redo">Redo</v-btn>
<v-btn @click="locked = !locked">{{ locked ? 'Unlock' : 'Lock' }}</v-btn>
<v-menu>
<template #activator="{ props }">
<v-btn v-bind="props" :color="color">Color</v-btn>
</template>
<v-card class="pa-4">
<v-color-picker v-model="color" label="Color"></v-color-picker>
</v-card>
</v-menu>
<v-btn @click="backgroundColor = backgroundColor === 'white' ? 'lightgray' : 'white'"
>Toggle background color</v-btn
>
<v-btn @click="eraser = !eraser">{{ eraser ? 'Pen' : 'Eraser' }}</v-btn>
<v-file-input label="Background image" @change="setImage($event)"></v-file-input>
<v-slider v-model="line" label="Line width" min="1" max="20"></v-slider>
<v-btn @click="save">Save</v-btn>
</v-container>
</template>
<script setup lang="ts">
definePage({
meta: {
visibility: 'with-role',
access: 'with-role',
roles: ['developer'],
},
})
import VOvPad from '@/components/VOvPad.vue'
const pad = ref<typeof VOvPad | null>(null)
const locked = ref(false)
const eraser = ref(false)
const backgroundColor = ref('white')
const backgroundImage = ref('')
const line = ref(5)
const color = ref('#000000')
const reset = () => {
if (!pad.value) return
pad.value.reset()
}
const undo = () => {
if (!pad.value) return
pad.value.undo()
}
const redo = () => {
if (!pad.value) return
pad.value.redo()
}
const setImage = (e: Event) => {
const file = (e.target as HTMLInputElement).files?.[0]
if (file) {
backgroundImage.value = window.URL.createObjectURL(file)
}
}
const save = () => {
if (!pad.value) return
const data = pad.value.save()
console.log(data)
}
</script>
<style scoped>
* {
margin: 0.25rem;
padding: 0.25rem;
}
</style>API
Props
Dimensions
| Prop | Type | Default | Description |
|---|---|---|---|
width | string | number | '100%' | Canvas container width (CSS value or pixels) |
height | string | number | '100%' | Canvas container height (CSS value or pixels) |
Drawing Settings
| Prop | Type | Default | Description |
|---|---|---|---|
color | string | '#000000' | Drawing color (hex format) |
lineWidth | number | 5 | Brush stroke width in pixels |
lineCap | 'round' | 'square' | 'butt' | 'round' | Line ending style |
lineJoin | 'miter' | 'round' | 'bevel' | 'miter' | Line join style |
Stroke Type
| Prop | Type | Default | Description |
|---|---|---|---|
strokeType | 'dash' | 'line' | 'square' | 'circle' | 'triangle' | 'half_triangle' | 'dash' | Current drawing mode |
fillShape | boolean | false | Fill shapes instead of stroking outlines |
Background & Canvas
| Prop | Type | Default | Description |
|---|---|---|---|
backgroundColor | string | '#FFFFFF' | Canvas background color (hex format) |
backgroundImage | string | null | null | Background image URL or data URI |
canvasId | string | random | Unique identifier for canvas element |
Canvas Behavior
| Prop | Type | Default | Description |
|---|---|---|---|
eraser | boolean | false | Enable eraser mode (uses backgroundColor) |
lock | boolean | false | Prevent drawing, undo, redo, and reset operations |
Output Format
| Prop | Type | Default | Description |
|---|---|---|---|
saveAs | 'jpeg' | 'png' | 'png' | Export format |
outputWidth | number | canvas width | Custom output image width |
outputHeight | number | canvas height | Custom output image height |
Image Data
| Prop | Type | Default | Description |
|---|---|---|---|
initialImage | Stroke[] | [] | Pre-drawn strokes to load on mount |
additionalImages | Stroke[] | [] | Additional image layers |
image | string | '' | Legacy image prop for compatibility |
Events
| Event | Payload | Description |
|---|---|---|
update:image | string (data URL) | Emitted when canvas is saved or modified |
Exposed Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
clear() | - | void | Clear all canvas content without resetting state |
reset() | - | void | Reset canvas to initial state (requires lock: false) |
undo() | - | void | Undo last stroke (requires lock: false) |
redo() | - | void | Redo last undone stroke (requires lock: false) |
save() | - | string | Export canvas as data URL and emit update:image |
startDraw() | event | void | Begin drawing stroke from event coordinates |
draw() | event | void | Continue drawing (throttled to ~60fps) |
stopDraw() | - | void | Finalize current stroke and add to history |
handleResize() | - | void | Manually trigger canvas resize (called automatically on window resize) |
Stroke Types
Dash
Free-hand drawing with customizable brush properties.
startDraw() // Begin stroke
draw(event) // Draw freehand line as mouse moves
stopDraw() // Finish and save strokeLine
Click-drag to create straight line with guide preview.
startDraw() // Click to set start point
draw(event) // Drag to show line guide
stopDraw() // Release to finalize lineSquare
Click-drag to create rectangular shape.
startDraw() // Click to set first corner
draw(event) // Drag to show preview rectangle
stopDraw() // Release to finalize squareCircle
Click-drag to create circular shape based on radius.
startDraw() // Click to set center
draw(event) // Drag to adjust radius
stopDraw() // Release to finalize circleTriangle
Click-drag to create triangle shape.
startDraw() // Click to set first point
draw(event) // Drag to show triangle guide
stopDraw() // Release to finalize triangleHalf Triangle
Click-drag to create half-triangle (right triangle).
startDraw() // Click to set first point
draw(event) // Drag to show half-triangle guide
stopDraw() // Release to finalize shape