feat:选区样式变化监听

pr675
黄云飞 4 years ago
parent 1f703336ca
commit 8926127fa5

@ -36,7 +36,7 @@ export class Cursor {
public setCursorPosition(evt: MouseEvent) { public setCursorPosition(evt: MouseEvent) {
const positionIndex = this.position.getPositionByXY(evt.offsetX, evt.offsetY) const positionIndex = this.position.getPositionByXY(evt.offsetX, evt.offsetY)
if (~positionIndex) { if (~positionIndex) {
this.range.setRange(0, 0) this.range.setRange(positionIndex, positionIndex)
setTimeout(() => { setTimeout(() => {
this.draw.render({ curIndex: positionIndex, isSubmitHistory: false }) this.draw.render({ curIndex: positionIndex, isSubmitHistory: false })
}) })

@ -8,6 +8,7 @@ import { Cursor } from "../cursor/Cursor"
import { CanvasEvent } from "../event/CanvasEvent" import { CanvasEvent } from "../event/CanvasEvent"
import { GlobalEvent } from "../event/GlobalEvent" import { GlobalEvent } from "../event/GlobalEvent"
import { HistoryManager } from "../history/HistoryManager" import { HistoryManager } from "../history/HistoryManager"
import { Listener } from "../listener/Listener"
import { Position } from "../position/Position" import { Position } from "../position/Position"
import { RangeManager } from "../range/RangeManager" import { RangeManager } from "../range/RangeManager"
import { Background } from "./Background" import { Background } from "./Background"
@ -24,6 +25,7 @@ export class Draw {
private options: Required<IEditorOption> private options: Required<IEditorOption>
private position: Position private position: Position
private elementList: IElement[] private elementList: IElement[]
private listener: Listener
private cursor: Cursor private cursor: Cursor
private range: RangeManager private range: RangeManager
@ -39,11 +41,18 @@ export class Draw {
private painterStyle: IElementStyle | null private painterStyle: IElementStyle | null
private searchMatchList: number[][] | null private searchMatchList: number[][] | null
constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, options: Required<IEditorOption>, elementList: IElement[]) { constructor(
canvas: HTMLCanvasElement,
ctx: CanvasRenderingContext2D,
options: Required<IEditorOption>,
elementList: IElement[],
listener: Listener
) {
this.canvas = canvas this.canvas = canvas
this.ctx = ctx this.ctx = ctx
this.options = options this.options = options
this.elementList = elementList this.elementList = elementList
this.listener = listener
this.historyManager = new HistoryManager() this.historyManager = new HistoryManager()
this.position = new Position(this) this.position = new Position(this)
@ -64,6 +73,8 @@ export class Draw {
this.rowCount = 0 this.rowCount = 0
this.painterStyle = null this.painterStyle = null
this.searchMatchList = null this.searchMatchList = null
this.setDefaultRange()
} }
public getOptions(): Required<IEditorOption> { public getOptions(): Required<IEditorOption> {
@ -86,6 +97,10 @@ export class Draw {
return this.elementList return this.elementList
} }
public getListener(): Listener {
return this.listener
}
public getCursor(): Cursor { public getCursor(): Cursor {
return this.cursor return this.cursor
} }
@ -117,6 +132,15 @@ export class Draw {
this.searchMatchList = payload this.searchMatchList = payload
} }
private setDefaultRange() {
if (!this.elementList.length) return
setTimeout(() => {
const curIndex = this.elementList.length - 1
this.range.setRange(curIndex, curIndex)
this.range.setRangeStyle()
})
}
private getFont(el: IElement): string { private getFont(el: IElement): string {
const { defaultSize, defaultFont } = this.options const { defaultSize, defaultFont } = this.options
return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${el.size || defaultSize}px ${el.font || defaultFont}` return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${el.size || defaultSize}px ${el.font || defaultFont}`
@ -223,8 +247,8 @@ export class Draw {
this.ctx.fillText(element.value, x, y + curRow.ascent) this.ctx.fillText(element.value, x, y + curRow.ascent)
// 选区绘制 // 选区绘制
const { startIndex, endIndex } = this.range.getRange() const { startIndex, endIndex } = this.range.getRange()
if (startIndex < index && index <= endIndex) { if (startIndex !== endIndex && startIndex < index && index <= endIndex) {
this.range.drawRange(x, y, metrics.width, curRow.height) this.range.render(x, y, metrics.width, curRow.height)
} }
index++ index++
x += metrics.width x += metrics.width

@ -115,8 +115,9 @@ export class CanvasEvent {
} else { } else {
elementList.splice(index, 1) elementList.splice(index, 1)
} }
this.range.setRange(0, 0) const curIndex = isCollspace ? index - 1 : startIndex
this.draw.render({ curIndex: isCollspace ? index - 1 : startIndex }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex })
} else if (evt.key === KeyMap.Enter) { } else if (evt.key === KeyMap.Enter) {
const enterText: IElement = { const enterText: IElement = {
value: ZERO value: ZERO
@ -126,17 +127,20 @@ export class CanvasEvent {
} else { } else {
elementList.splice(startIndex + 1, endIndex - startIndex, enterText) elementList.splice(startIndex + 1, endIndex - startIndex, enterText)
} }
this.range.setRange(0, 0) const curIndex = index + 1
this.draw.render({ curIndex: index + 1 }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex })
} else if (evt.key === KeyMap.Left) { } else if (evt.key === KeyMap.Left) {
if (index > 0) { if (index > 0) {
this.range.setRange(0, 0) const curIndex = index - 1
this.draw.render({ curIndex: index - 1, isSubmitHistory: false }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex, isSubmitHistory: false })
} }
} else if (evt.key === KeyMap.Right) { } else if (evt.key === KeyMap.Right) {
if (index < position.length - 1) { if (index < position.length - 1) {
this.range.setRange(0, 0) const curIndex = index + 1
this.draw.render({ curIndex: index + 1, isSubmitHistory: false }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex, isSubmitHistory: false })
} }
} else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) { } else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) {
const { rowNo, index, coordinate: { leftTop, rightTop } } = cursorPosition const { rowNo, index, coordinate: { leftTop, rightTop } } = cursorPosition
@ -171,8 +175,9 @@ export class CanvasEvent {
maxIndex = position.index maxIndex = position.index
} }
} }
this.range.setRange(0, 0) const curIndex = maxIndex
this.draw.render({ curIndex: maxIndex, isSubmitHistory: false }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex, isSubmitHistory: false })
} }
} else if (evt.ctrlKey && evt.key === KeyMap.Z) { } else if (evt.ctrlKey && evt.key === KeyMap.Z) {
this.historyManager.undo() this.historyManager.undo()
@ -188,8 +193,9 @@ export class CanvasEvent {
if (!isCollspace) { if (!isCollspace) {
writeText(position.slice(startIndex + 1, endIndex + 1).map(p => p.value).join('')) writeText(position.slice(startIndex + 1, endIndex + 1).map(p => p.value).join(''))
elementList.splice(startIndex + 1, endIndex - startIndex) elementList.splice(startIndex + 1, endIndex - startIndex)
this.range.setRange(0, 0) const curIndex = startIndex
this.draw.render({ curIndex: startIndex }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex })
} }
} else if (evt.ctrlKey && evt.key === KeyMap.A) { } else if (evt.ctrlKey && evt.key === KeyMap.A) {
this.range.setRange(0, position.length - 1) this.range.setRange(0, position.length - 1)
@ -215,8 +221,9 @@ export class CanvasEvent {
} else { } else {
elementList.splice(startIndex + 1, endIndex - startIndex, ...inputData) elementList.splice(startIndex + 1, endIndex - startIndex, ...inputData)
} }
this.range.setRange(0, 0) const curIndex = (isCollspace ? index : startIndex) + inputData.length
this.draw.render({ curIndex: (isCollspace ? index : startIndex) + inputData.length }) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex })
} }
public paste(evt: ClipboardEvent) { public paste(evt: ClipboardEvent) {

@ -2,6 +2,7 @@ import { EDITOR_COMPONENT } from "../../dataset/constant/Editor"
import { findParent } from "../../utils" import { findParent } from "../../utils"
import { Cursor } from "../cursor/Cursor" import { Cursor } from "../cursor/Cursor"
import { Draw } from "../draw/Draw" import { Draw } from "../draw/Draw"
import { RangeManager } from "../range/RangeManager"
import { CanvasEvent } from "./CanvasEvent" import { CanvasEvent } from "./CanvasEvent"
export class GlobalEvent { export class GlobalEvent {
@ -10,12 +11,14 @@ export class GlobalEvent {
private draw: Draw private draw: Draw
private cursor: Cursor | null private cursor: Cursor | null
private canvasEvent: CanvasEvent private canvasEvent: CanvasEvent
private range: RangeManager
constructor(canvas: HTMLCanvasElement, draw: Draw, canvasEvent: CanvasEvent) { constructor(canvas: HTMLCanvasElement, draw: Draw, canvasEvent: CanvasEvent) {
this.canvas = canvas this.canvas = canvas
this.draw = draw this.draw = draw
this.canvasEvent = canvasEvent this.canvasEvent = canvasEvent
this.cursor = null this.cursor = null
this.range = draw.getRange()
} }
register() { register() {
@ -23,10 +26,11 @@ export class GlobalEvent {
document.addEventListener('click', (evt) => { document.addEventListener('click', (evt) => {
this.recoverCursor(evt) this.recoverCursor(evt)
this.setRangeStyle()
}) })
document.addEventListener('mouseup', () => { document.addEventListener('mouseup', () => {
this.updateDragState() this.setDragState()
}) })
} }
@ -46,8 +50,12 @@ export class GlobalEvent {
this.cursor.recoveryCursor() this.cursor.recoveryCursor()
} }
updateDragState() { setDragState() {
this.canvasEvent.setIsAllowDrag(false) this.canvasEvent.setIsAllowDrag(false)
} }
setRangeStyle() {
this.range.setRangeStyle()
}
} }

@ -4,7 +4,7 @@ export class HistoryManager {
private undoStack: Array<Function> = [] private undoStack: Array<Function> = []
private redoStack: Array<Function> = [] private redoStack: Array<Function> = []
undo() { public undo() {
if (this.undoStack.length > 1) { if (this.undoStack.length > 1) {
const pop = this.undoStack.pop()! const pop = this.undoStack.pop()!
this.redoStack.push(pop) this.redoStack.push(pop)
@ -14,7 +14,7 @@ export class HistoryManager {
} }
} }
redo() { public redo() {
if (this.redoStack.length) { if (this.redoStack.length) {
const pop = this.redoStack.pop()! const pop = this.redoStack.pop()!
this.undoStack.push(pop) this.undoStack.push(pop)
@ -22,7 +22,7 @@ export class HistoryManager {
} }
} }
execute(fn: Function) { public execute(fn: Function) {
this.undoStack.push(fn) this.undoStack.push(fn)
if (this.redoStack.length) { if (this.redoStack.length) {
this.redoStack = [] this.redoStack = []
@ -32,4 +32,12 @@ export class HistoryManager {
} }
} }
public isCanUndo(): boolean {
return this.undoStack.length > 1
}
public isCanRedo(): boolean {
return !!this.redoStack.length
}
} }

@ -0,0 +1,11 @@
import { IRangeStyleChange } from "../../interface/Listener"
export class Listener {
public rangeStyleChange: IRangeStyleChange | null
constructor() {
this.rangeStyleChange = null
}
}

@ -2,6 +2,8 @@ import { IEditorOption } from "../../interface/Editor"
import { IElement } from "../../interface/Element" import { IElement } from "../../interface/Element"
import { IRange } from "../../interface/Range" import { IRange } from "../../interface/Range"
import { Draw } from "../draw/Draw" import { Draw } from "../draw/Draw"
import { HistoryManager } from "../history/HistoryManager"
import { Listener } from "../listener/Listener"
export class RangeManager { export class RangeManager {
@ -9,11 +11,15 @@ export class RangeManager {
private options: Required<IEditorOption> private options: Required<IEditorOption>
private range: IRange private range: IRange
private draw: Draw private draw: Draw
private listener: Listener
private historyManager: HistoryManager
constructor(ctx: CanvasRenderingContext2D, options: Required<IEditorOption>, draw: Draw) { constructor(ctx: CanvasRenderingContext2D, options: Required<IEditorOption>, draw: Draw) {
this.ctx = ctx this.ctx = ctx
this.options = options this.options = options
this.draw = draw this.draw = draw
this.listener = draw.getListener()
this.historyManager = draw.getHistoryManager()
this.range = { this.range = {
startIndex: 0, startIndex: 0,
endIndex: 0 endIndex: 0
@ -36,15 +42,45 @@ export class RangeManager {
this.range.endIndex = endIndex this.range.endIndex = endIndex
} }
public drawRange(x: number, y: number, width: number, height: number) { public setRangeStyle() {
const { startIndex, endIndex } = this.range if (!this.listener.rangeStyleChange) return
if (startIndex !== endIndex) { let curElementList = this.getSelection()
if (!curElementList) {
const elementList = this.draw.getElementList()
const { endIndex } = this.range
curElementList = [elementList[endIndex]]
}
const curElement = curElementList[curElementList.length - 1]
// 富文本
let bold = !~curElementList.findIndex(el => !el.bold)
let italic = !~curElementList.findIndex(el => !el.italic)
let underline = !~curElementList.findIndex(el => !el.underline)
let strikeout = !~curElementList.findIndex(el => !el.strikeout)
const color = curElement.color || null
const highlight = curElement.highlight || null
// 菜单
const format = !!this.draw.getPainterStyle()
const undo = this.historyManager.isCanUndo()
const redo = this.historyManager.isCanRedo()
this.listener.rangeStyleChange({
undo,
redo,
format,
bold,
italic,
underline,
strikeout,
color,
highlight
})
}
public render(x: number, y: number, width: number, height: number) {
this.ctx.save() this.ctx.save()
this.ctx.globalAlpha = this.options.rangeAlpha this.ctx.globalAlpha = this.options.rangeAlpha
this.ctx.fillStyle = this.options.rangeColor this.ctx.fillStyle = this.options.rangeColor
this.ctx.fillRect(x, y, width, height) this.ctx.fillRect(x, y, width, height)
this.ctx.restore() this.ctx.restore()
} }
}
} }

@ -5,10 +5,12 @@ import { IElement } from './interface/Element'
import { Draw } from './core/draw/Draw' import { Draw } from './core/draw/Draw'
import { Command } from './core/command/Command' import { Command } from './core/command/Command'
import { CommandAdapt } from './core/command/CommandAdapt' import { CommandAdapt } from './core/command/CommandAdapt'
import { Listener } from './core/listener/Listener'
export default class Editor { export default class Editor {
public command: Command public command: Command
public listener: Listener
constructor(canvas: HTMLCanvasElement, elementList: IElement[], options: IEditorOption = {}) { constructor(canvas: HTMLCanvasElement, elementList: IElement[], options: IEditorOption = {}) {
const editorOptions: Required<IEditorOption> = { const editorOptions: Required<IEditorOption> = {
@ -43,10 +45,12 @@ export default class Editor {
text.value = ZERO text.value = ZERO
} }
}) })
// 监听
this.listener = new Listener()
// 启动 // 启动
const draw = new Draw(canvas, ctx, editorOptions, elementList) const draw = new Draw(canvas, ctx, editorOptions, elementList, this.listener)
draw.render() draw.render()
// 对外命令 // 命令
this.command = new Command(new CommandAdapt(draw)) this.command = new Command(new CommandAdapt(draw))
} }

@ -0,0 +1,13 @@
export interface IRangeStype {
undo: boolean;
redo: boolean;
format: boolean;
bold: boolean;
italic: boolean;
underline: boolean;
strikeout: boolean;
color: string | null;
highlight: string | null;
}
export type IRangeStyleChange = (payload: IRangeStype) => void;

@ -130,4 +130,9 @@ window.onload = function () {
instance.command.executePrint() instance.command.executePrint()
} }
// 内部事件监听
instance.listener.rangeStyleChange = function (payload) {
console.log('payload: ', payload);
}
} }
Loading…
Cancel
Save