diff --git a/src/assets/images/signature-undo.svg b/src/assets/images/signature-undo.svg
new file mode 100644
index 0000000..518a37f
--- /dev/null
+++ b/src/assets/images/signature-undo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/components/signature/Signature.ts b/src/components/signature/Signature.ts
index ad9d33c..e045d8d 100644
--- a/src/components/signature/Signature.ts
+++ b/src/components/signature/Signature.ts
@@ -16,33 +16,36 @@ export interface ISignatureOptions {
}
export class Signature {
- private x: number
- private y: number
- private isDrawing: boolean
+ private readonly MAX_RECORD_COUNT = 1000
+ private undoStack: Array = []
+ private x = 0
+ private y = 0
+ private isDrawing = false
+ private isDrawn = false
private canvasWidth: number
private canvasHeight: number
private options: ISignatureOptions
private mask: HTMLDivElement
private container: HTMLDivElement
private trashContainer: HTMLDivElement
+ private undoContainer: HTMLDivElement
private canvas: HTMLCanvasElement
private ctx: CanvasRenderingContext2D
constructor(options: ISignatureOptions) {
- this.x = 0
- this.y = 0
- this.isDrawing = false
this.options = options
this.canvasWidth = options.width || 390
this.canvasHeight = options.height || 180
- const { mask, container, trashContainer, canvas } = this._render()
+ const { mask, container, trashContainer, undoContainer, canvas } = this._render()
this.mask = mask
this.container = container
this.trashContainer = trashContainer
+ this.undoContainer = undoContainer
this.canvas = canvas
this.ctx = canvas.getContext('2d')
this.ctx.lineCap = 'round'
this._bindEvent()
+ this._clearUndoFn()
}
private _render() {
@@ -79,11 +82,21 @@ export class Signature {
// 操作区
const operationContainer = document.createElement('div')
operationContainer.classList.add('signature-operation')
+ // 撤销
+ const undoContainer = document.createElement('div')
+ undoContainer.classList.add('signature-operation__undo')
+ const undoIcon = document.createElement('i')
+ const undoLabel = document.createElement('span')
+ undoLabel.innerText = '撤销'
+ undoContainer.append(undoIcon)
+ undoContainer.append(undoLabel)
+ operationContainer.append(undoContainer)
+ // 清空画布
const trashContainer = document.createElement('div')
trashContainer.classList.add('signature-operation__trash')
const trashIcon = document.createElement('i')
const trashLabel = document.createElement('span')
- trashLabel.innerText = '清空画布'
+ trashLabel.innerText = '清空'
trashContainer.append(trashIcon)
trashContainer.append(trashLabel)
operationContainer.append(trashContainer)
@@ -137,18 +150,44 @@ export class Signature {
mask,
canvas,
container,
- trashContainer
+ trashContainer,
+ undoContainer
}
}
private _bindEvent() {
this.trashContainer.onclick = this._clearCanvas.bind(this)
+ this.undoContainer.onclick = this._undo.bind(this)
this.canvas.onmousedown = this._startDraw.bind(this)
this.canvas.onmousemove = this._draw.bind(this)
this.container.onmouseup = this._stopDraw.bind(this)
}
+ private _undo() {
+ if (this.undoStack.length > 1) {
+ this.undoStack.pop()
+ if (this.undoStack.length) {
+ this.undoStack[this.undoStack.length - 1]()
+ }
+ }
+ }
+
+ private _saveUndoFn(fn: Function) {
+ this.undoStack.push(fn)
+ while (this.undoStack.length > this.MAX_RECORD_COUNT) {
+ this.undoStack.shift()
+ }
+ }
+
+ private _clearUndoFn() {
+ const clearFn = () => {
+ this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
+ }
+ this.undoStack = [clearFn]
+ }
+
private _clearCanvas() {
+ this._clearUndoFn()
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
}
@@ -168,10 +207,20 @@ export class Signature {
this.ctx.stroke()
this.x = offsetX
this.y = offsetY
+ this.isDrawn = true
}
private _stopDraw() {
this.isDrawing = false
+ if (this.isDrawn) {
+ const imageData = this.ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight)
+ const self = this
+ this._saveUndoFn(function () {
+ self.ctx.clearRect(0, 0, self.canvasWidth, self.canvasHeight)
+ self.ctx.putImageData(imageData, 0, 0)
+ })
+ this.isDrawn = false
+ }
}
private _toDataURL() {
diff --git a/src/components/signature/signature.css b/src/components/signature/signature.css
index e7121d8..98050eb 100644
--- a/src/components/signature/signature.css
+++ b/src/components/signature/signature.css
@@ -50,7 +50,7 @@
background: url(../../assets/images/close.svg);
}
-.signature-operation__trash {
+.signature-operation>div {
cursor: pointer;
display: inline-flex;
align-items: center;
@@ -58,30 +58,36 @@
user-select: none;
}
-.signature-operation__trash:hover {
+.signature-operation>div:hover {
color: #6e7175;
}
-.signature-operation__trash i {
+.signature-operation>div i {
width: 24px;
height: 24px;
display: inline-block;
+}
+
+.signature-operation__undo {
+ background: url(../../assets/images/signature-undo.svg) no-repeat;
+}
+
+.signature-operation__trash {
background: url(../../assets/images/trash.svg) no-repeat;
}
-.signature-operation__trash span {
+.signature-operation>div span {
font-size: 12px;
- margin-left: 5px;
+ margin: 0 5px;
}
.signature-canvas {
margin: 15px 0;
- border: 1px solid #e9e9e9;
user-select: none;
}
.signature-canvas canvas {
- background: #fbfbfb;
+ background: #f3f5f7;
}
.signature-menu {