简体中文 | English
A Vue 3 + TypeScript signature canvas component for desktop and mobile web apps. It supports high-DPI rendering, empty-signature detection, image replay, readonly mode, undo/redo, tracing guides, background image composition, export rotation, JPEG background fill, and full TypeScript typings.
Starting from 2.0.0, this package is a full rewrite and is not compatible with Vue 2 or the old 1.x build setup.
- New version: Vue 3 + TypeScript + Vite.
- Legacy version: Vue 2 + Vue CLI, available as
1.x. - If your project still uses Vue 2, install the legacy version:
npm i sign-canvas@1You can also switch to the 1.x branch for the old source code and documentation.
- Fixes interrupted drawing in Chrome/Edge mobile emulation and real touch-screen environments.
- Applies the critical canvas interaction styles at runtime, including
touch-action: noneand text-selection prevention, reducing the risk of browser gestures interrupting touch drawing when the consumer forgets to import CSS. - Hardens pointer capture and active pointer tracking, so touch or pen input leaving the canvas does not prematurely cut off the current stroke.
sign-canvas@2 targets Vue 3 Web/H5 environments and depends on browser DOM Canvas and Pointer Events.
The main package does not guarantee compatibility with uni-app mini-program, native App, or other non-standard DOM runtimes. If you only use uni-app H5, you may verify it in your own project. For mini-program or App targets, consider building a dedicated adapter instead of mixing platform-specific branches into this web package.
npm i sign-canvas<template>
<SignCanvas
ref="signCanvasRef"
v-model="signature"
:options="options"
@change="status = $event"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import SignCanvas, {
type SignCanvasExpose,
type SignCanvasOptions,
type SignatureStatus
} from 'sign-canvas';
const signature = ref<string | null>(null);
const signCanvasRef = ref<SignCanvasExpose | null>(null);
const status = ref<SignatureStatus>({
empty: true,
strokes: 0,
hasImage: false,
canUndo: false,
canRedo: false,
history: 0,
redo: 0
});
const options: SignCanvasOptions = {
canvasWidth: 600,
canvasHeight: 360,
isDpr: true,
isSign: true,
writeColor: '#101010',
bgColor: '#fff',
imgType: 'png'
};
function submit() {
if (signCanvasRef.value?.isEmpty()) {
return;
}
const image = signCanvasRef.value?.toDataURL();
}
</script>import { createApp } from 'vue';
import SignCanvas from 'sign-canvas';
import App from './App.vue';
createApp(App).use(SignCanvas).mount('#app');| Option | Type | Default | Description |
|---|---|---|---|
canvasWidth |
number |
600 |
CSS width in non-fullscreen mode |
canvasHeight |
number |
600 |
CSS height in non-fullscreen mode |
isFullScreen |
boolean |
false |
Use browser viewport size |
isFullCover |
boolean |
false |
Use fixed positioning in fullscreen mode |
isDpr |
boolean |
false |
Scale the real canvas by devicePixelRatio for sharper rendering |
isSign |
boolean |
false |
Signature mode uses fixed line width; disabled mode uses dynamic line width |
isShowBorder |
boolean |
true |
Draw border and helper guidelines |
bgColor |
string |
none |
Canvas/export background color; none means transparent |
backgroundImage |
string |
'' |
Background image URL, base64, or CORS-enabled remote image |
backgroundImageFit |
contain | cover | stretch | center |
cover |
Background image fitting mode |
backgroundImageOpacity |
number |
1 |
Background image opacity, from 0 to 1 |
borderWidth |
number |
1 |
Border and guideline width |
borderColor |
string |
#ff787f |
Border and guideline color |
writeWidth |
number |
5 |
Fixed pen width in signature mode |
maxWriteWidth |
number |
30 |
Maximum dynamic pen width |
minWriteWidth |
number |
5 |
Minimum dynamic pen width |
writeColor |
string |
#101010 |
Pen color |
lineCap |
CanvasLineCap |
round |
Line cap |
lineJoin |
CanvasLineJoin |
round |
Line join |
imgType |
png | jpeg | jpg | webp |
png |
Export image type |
quality |
number |
1 |
Export quality and scale ratio, from 0.1 to 1 |
jpegBgColor |
string |
#fff |
Fill color for transparent areas when exporting JPEG |
exportRotate |
0 | 90 | 180 | 270 |
0 |
Rotation angle applied to exported images |
enableResize |
boolean |
true |
Redraw automatically on window resize |
disabled |
boolean |
false |
Disable drawing |
readonly |
boolean |
false |
Readonly display mode |
allowEmpty |
boolean |
false |
Allow exporting an empty canvas |
enableHistory |
boolean |
true |
Record stroke history for undo and redo |
enableShortcuts |
boolean |
true |
Enable Ctrl+Z, Ctrl+Y, and Ctrl+Shift+Z shortcuts |
maxHistory |
number |
100 |
Maximum number of pen-down history entries |
guideEnabled |
boolean |
false |
Enable tracing/guide layer |
guideText |
string |
'' |
Guide text |
guideFont |
string |
700 96px serif |
Guide text font, using Canvas font syntax |
guideTextColor |
string |
#101010 |
Guide text color |
guideTextOpacity |
number |
0.16 |
Guide text opacity, from 0 to 1 |
guideImage |
string |
'' |
Guide image URL; takes priority over guideText |
guideImageFit |
contain | cover | stretch | center |
contain |
Guide image fitting mode |
guideImageOpacity |
number |
0.24 |
Guide image opacity, from 0 to 1 |
backgroundImage and the guide layer are auxiliary layers. They are visible on the canvas and are composed into exported images, but they do not count as real signature content. They are excluded from isEmpty(), stroke count, and undo/redo history.
const options: SignCanvasOptions = {
canvasWidth: 720,
canvasHeight: 360,
bgColor: '#fff',
backgroundImage: contractImageBase64,
backgroundImageFit: 'cover',
guideEnabled: true,
guideText: 'John Doe',
guideFont: '700 96px serif',
guideTextColor: '#101010',
guideTextOpacity: 0.16
};To use an image as the tracing template, configure guideImage. It takes priority over guideText.
const options: SignCanvasOptions = {
guideEnabled: true,
guideImage: '/trace-template.png',
guideImageFit: 'contain',
guideImageOpacity: 0.22
};exportRotate only affects the output image generated by toDataURL(), saveAsImg(), downloadSignImg(), and automatic v-model updates. It does not rotate the canvas displayed on the page.
const options: SignCanvasOptions = {
imgType: 'jpeg',
jpegBgColor: '#fff',
exportRotate: 90
};Call methods through a component ref:
signCanvasRef.value?.clear();
signCanvasRef.value?.toDataURL();
signCanvasRef.value?.fromDataURL(base64);
signCanvasRef.value?.undo();
signCanvasRef.value?.redo();| Method | Return | Description |
|---|---|---|
clear(payload?) |
void |
Clear the canvas |
canvasClear(payload?) |
void |
Legacy alias of clear |
toDataURL(payload?) |
string | null |
Export the canvas; returns null for empty canvas by default |
saveAsImg(payload?) |
string | null |
Legacy alias of toDataURL |
downloadSignImg(name?) |
string | null |
Download the current signature image |
dealImage(quality?) |
string | null |
Legacy compressed export method |
fromDataURL(dataURL, payload?) |
Promise<string | null> |
Replay an existing signature image and continue drawing |
undo() |
boolean |
Undo the latest pen-down action |
redo() |
boolean |
Redo the latest undone pen-down action |
canUndo() |
boolean |
Whether undo is available |
canRedo() |
boolean |
Whether redo is available |
getStrokes() |
SignStroke[] |
Get a snapshot of current stroke data |
isEmpty() |
boolean |
Whether there is no real signature content |
getSignatureStatus() |
SignatureStatus |
Return { empty, strokes, hasImage, canUndo, canRedo, history, redo } |
redraw() |
void |
Redraw manually |
initCanvas() |
void |
Reinitialize canvas size manually |
The component records history by pen-down actions instead of individual line segments. A continuous stroke is undone as one action.
Ctrl+Z/Command+Z: undoCtrl+Y/Command+Y: redoCtrl+Shift+Z/Command+Shift+Z: redo
Keyboard shortcuts are ignored when the event target is an input, textarea, select, or contenteditable element. When multiple signature canvases exist on the same page, shortcuts only affect the focused canvas.
| Event | Payload | Description |
|---|---|---|
update:modelValue |
string | null |
Vue 3 v-model update |
confirm |
string | null |
Legacy-compatible event |
start |
{ x, y } |
Drawing starts |
end |
{ x, y } |
Drawing ends |
change |
SignatureStatus |
Signature status changes |
clear |
none | Canvas is cleared |
undo |
SignatureStatus |
Undo succeeds |
redo |
SignatureStatus |
Redo succeeds |
npm install
npm run dev
npm run type-check
npm run libnpm run lib outputs:
lib/sign-canvas.jslib/sign-canvas.umd.cjslib/sign-canvas.csslib/types/**/*.d.ts
https://langyuxiansheng.github.io/vue-sign-canvas/
- Full rewrite and breaking upgrade. Vue 2 projects should keep using
sign-canvas@1or the1.xbranch. - Upgraded to Vue 3 + TypeScript + Vite.
- Uses Pointer Events for unified desktop and mobile input.
- Preserves existing strokes when
optionschange. - Adds
isEmpty()andgetSignatureStatus()for required-signature validation. - Adds
fromDataURL()for image replay and continued editing. - Adds
readonlyanddisabled. - Adds stroke history, undo, redo, and keyboard shortcuts.
- Adds custom background image composition.
- Adds tracing/guide layer with text and image modes.
- Adds export rotation for
0 / 90 / 180 / 270degrees. - Fills JPEG transparent areas by default to avoid black backgrounds.
- Outputs
.d.tsfiles for TypeScript projects.


