import {findLastIndex} from "lodash" enum actionType { start, line, finished, } // 动作类 class Actions { records: Array = [] painter: CanvasRenderingContext2D canvas: HTMLCanvasElement background: string = 'rgba(255,255,250,1)' isEndLind = false prePoint?: Point lineWidth = 1.5 constructor (params: {canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, height?: number, width?: number, background?: string, lineWidth?: number}) { this.canvas = params.canvas this.painter = params.ctx || this.canvas.getContext('2d') params.background && (this.background = params.background) params.lineWidth && (this.lineWidth = params.lineWidth) this.initBg() } // 获取step _steps () { let len = this.records.length if (len) { let arr: Array<{start: number, end: number}> = [] let o: {start: number, end: number} | any = {} this.records.forEach((action, index) => { if (action.type === actionType.start) { o.start = index } if (action.type === actionType.finished) { o.end = index arr.push(Object.assign({}, o)) o = {} } }) return arr } return [] } // 添加 add (action: Action) { this.records.splice(this.records.length, 0, action) } // 重新绘制,可用用back之中 reDraw () { this.painter.lineWidth = this.lineWidth const steps = this._steps() if (steps.length > 0) { this.initBg() for (let stpe of steps) { const actions = this.records.slice(stpe.start, stpe.end + 1) for (let _action of actions) { switch (_action.type) { case actionType.start: this.painter.beginPath() this.painter.moveTo(...(_action.point as [ number, number ])) break; case actionType.finished: this.painter.stroke() break; default: this.painter.lineTo(...(_action.point as [ number, number ])) } } } } } // 回退一步 back () { if (this.records.length > 0) { const steps = this._steps() const len = steps.length - 1 if (len === 0) { return this.clear() } const lastStep = steps[ len - 1 ] this.records = this.records.slice(0, lastStep.end + 1) this.reDraw() } } private _wipeOver () { this.painter.clearRect(0, 0, this.canvas.width, this.canvas.height) this.initBg() } //绘制方法 draw (action: Action) { const none = this.records.length === 0 const hasOne = this.records.length === 1 && this.records[ 0 ].type === actionType.start // 如果有一个则设置 if (hasOne) { this.prePoint = this.records[ 0 ].point } // 如果没有或者只有一个且是start则返回 if (none || hasOne) return const temp = Object.assign({}, this.prePoint) const point = (action.point as Point) this.prePoint = point this.painter.lineWidth = this.lineWidth switch (action.type) { case actionType.start: break case actionType.finished: const steps = this._steps() this._drawFragment(steps[ steps.length - 1 ]) break; default: this.painter.beginPath() this.painter.moveTo(temp.x, temp.y) this.painter.lineTo(point.x, point.y) this.painter.stroke() } } // 绘制片断 private _drawFragment (fragment: {start: number, end: number}) { const points = this.records.slice(fragment.start, fragment.end + 1) this.painter.lineWidth = this.lineWidth points.forEach(action => { const point = (action.point as [ number, number ]) switch (action.type) { case actionType.start: this.painter.beginPath() this.painter.moveTo(...point) break case actionType.finished: this.painter.lineTo(...point) this.painter.stroke() break; default: this.painter.lineTo(...point) } }) } // 初始化背景 initBg () { const ctx = this.painter ctx.fillStyle = this.background ctx.fillRect(0, 0, this.canvas.width, this.canvas.height) } // 清除画布 clear (keep = false) { this.records = [] this._wipeOver() } } // 动作 class Action { type: actionType point?: Point constructor (type: actionType, point?: Point) { this.type = type this.point = point } } // 点 class Point extends Array { [ 0 ]: number [ 1 ]: number x: number y: number constructor (x: number, y: number) { super(2) this[ 0 ] = this.x = x this[ 1 ] = this.y = y } } export { Action, Point, actionType } export default Actions