feat:add undo feature for signature

pr675
Hufe921 4 years ago
parent 34529feaca
commit 571182ab3f

@ -0,0 +1 @@
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M8 6h5.5a7 7 0 010 14v-2a5 5 0 000-10H8v3L4 7l4-4v3z" fill="#3d4757" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 168 B

@ -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<Function> = []
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 = <CanvasRenderingContext2D>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() {

@ -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 {

Loading…
Cancel
Save