Skip to content

Commit

Permalink
feat: add zone tooltip #367
Browse files Browse the repository at this point in the history
  • Loading branch information
Hufe921 committed Dec 22, 2023
1 parent 57fdcb8 commit 095414f
Show file tree
Hide file tree
Showing 16 changed files with 183 additions and 2 deletions.
4 changes: 4 additions & 0 deletions docs/en/guide/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,9 @@ interface ILang {
pageBreak: {
displayName: string
}
zone: {
headerTip: string
footerTip: string
}
}
```
1 change: 1 addition & 0 deletions docs/en/guide/option.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ interface IEditorOption {
placeholder?: IPlaceholder // Placeholder text
group?: IGroup // Group option. {opacity?:number; backgroundColor?:string; activeOpacity?:number; activeBackgroundColor?:string; disabled?:boolean}
pageBreak?: IPageBreak // PageBreak option。{font?:string; fontSize?:number; lineDash?:number[];}
zone?: IZoneOption // Zone option。{tipDisabled?:boolean;}
}
```
Expand Down
4 changes: 4 additions & 0 deletions docs/guide/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,9 @@ interface ILang {
pageBreak: {
displayName: string
}
zone: {
headerTip: string
footerTip: string
}
}
```
1 change: 1 addition & 0 deletions docs/guide/option.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ interface IEditorOption {
placeholder?: IPlaceholder // 编辑器空白占位文本
group?: IGroup // 成组配置。{opacity?:number; backgroundColor?:string; activeOpacity?:number; activeBackgroundColor?:string; disabled?:boolean}
pageBreak?: IPageBreak // 分页符配置。{font?:string; fontSize?:number; lineDash?:number[];}
zone?: IZoneOption // 编辑器区域配置。{tipDisabled?:boolean;}
}
```

Expand Down
27 changes: 27 additions & 0 deletions src/editor/assets/css/zone/zone.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,31 @@

.ce-zone-indicator-border__right {
border-right: 2px dashed rgb(238, 238, 238);
}

.ce-zone-tip {
display: none;
align-items: center;
height: 30px;
white-space: nowrap;
position: fixed;
opacity: .9;
background-color: #000000;
padding: 0 5px;
border-radius: 4px;
z-index: 9;
transition: all .3s;
outline: none;
user-select: none;
pointer-events: none;
transform: translate(10px, 10px);
}

.ce-zone-tip.show {
display: flex;
}

.ce-zone-tip span {
color: #ffffff;
font-size: 12px;
}
4 changes: 4 additions & 0 deletions src/editor/core/i18n/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,9 @@
},
"pageBreak": {
"displayName": "Page Break"
},
"zone": {
"headerTip": "Double click to edit header",
"footerTip": "Double click to edit footer"
}
}
4 changes: 4 additions & 0 deletions src/editor/core/i18n/lang/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,9 @@
},
"pageBreak": {
"displayName": "分页符"
},
"zone": {
"headerTip": "双击编辑页眉",
"footerTip": "双击编辑页脚"
}
}
2 changes: 1 addition & 1 deletion src/editor/core/position/Position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export class Position {
positionList = this.getOriginalPositionList()
}
const zoneManager = this.draw.getZone()
const curPageNo = this.draw.getPageNo()
const curPageNo = payload.pageNo ?? this.draw.getPageNo()
const isMainActive = zoneManager.isMainActive()
const positionNo = isMainActive ? curPageNo : 0
for (let j = 0; j < positionList.length; j++) {
Expand Down
5 changes: 5 additions & 0 deletions src/editor/core/zone/Zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IEditorOption } from '../../interface/Editor'
import { nextTick } from '../../utils'
import { Draw } from '../draw/Draw'
import { I18n } from '../i18n/I18n'
import { ZoneTip } from './ZoneTip'

export class Zone {
private readonly INDICATOR_PADDING = 2
Expand All @@ -24,6 +25,10 @@ export class Zone {
this.container = draw.getContainer()
this.currentZone = EditorZone.MAIN
this.indicatorContainer = null
// 区域提示
if (!this.options.zone.tipDisabled) {
new ZoneTip(draw)
}
}

public isHeaderActive(): boolean {
Expand Down
94 changes: 94 additions & 0 deletions src/editor/core/zone/ZoneTip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { EDITOR_PREFIX } from '../../dataset/constant/Editor'
import { EditorZone } from '../../dataset/enum/Editor'
import { throttle } from '../../utils'
import { Draw } from '../draw/Draw'
import { I18n } from '../i18n/I18n'
import { Position } from '../position/Position'

export class ZoneTip {
private position: Position
private i18n: I18n
private container: HTMLDivElement
private pageContainer: HTMLDivElement

private isDisableMouseMove: boolean
private tipContainer: HTMLDivElement
private tipContent: HTMLSpanElement
private currentMoveZone: EditorZone | undefined

constructor(draw: Draw) {
this.position = draw.getPosition()
this.i18n = draw.getI18n()
this.container = draw.getContainer()
this.pageContainer = draw.getPageContainer()

const { tipContainer, tipContent } = this._drawZoneTip()
this.tipContainer = tipContainer
this.tipContent = tipContent
this.isDisableMouseMove = true
this.currentMoveZone = EditorZone.MAIN

this._watchMouseMoveZoneChange()
}

private _watchMouseMoveZoneChange() {
this.pageContainer.addEventListener(
'mousemove',
throttle((evt: MouseEvent) => {
if (this.isDisableMouseMove) return
const pageNo = Number((<HTMLCanvasElement>evt.target).dataset.index)
if (Number.isNaN(pageNo)) {
this._updateZoneTip(false)
} else {
const positionInfo = this.position.getPositionByXY({
x: evt.offsetX,
y: evt.offsetY,
pageNo
})
this.currentMoveZone = positionInfo.zone
this._updateZoneTip(
positionInfo.zone === EditorZone.HEADER ||
positionInfo.zone === EditorZone.FOOTER,
evt.x,
evt.y
)
}
}, 250)
)
// mouseenter后mousemove有效,避免因节流导致的mouseleave后继续执行逻辑
this.pageContainer.addEventListener('mouseenter', () => {
this.isDisableMouseMove = false
})
this.pageContainer.addEventListener('mouseleave', () => {
this.isDisableMouseMove = true
this._updateZoneTip(false)
})
}

private _drawZoneTip() {
const tipContainer = document.createElement('div')
tipContainer.classList.add(`${EDITOR_PREFIX}-zone-tip`)
const tipContent = document.createElement('span')
tipContainer.append(tipContent)
this.container.append(tipContainer)
return {
tipContainer,
tipContent
}
}

private _updateZoneTip(visible: boolean, left?: number, top?: number) {
if (visible) {
this.tipContainer.classList.add('show')
this.tipContainer.style.left = `${left}px`
this.tipContainer.style.top = `${top}px`
this.tipContent.innerText = this.i18n.t(
`zone.${
this.currentMoveZone === EditorZone.HEADER ? 'headerTip' : 'footerTip'
}`
)
} else {
this.tipContainer.classList.remove('show')
}
}
}
5 changes: 5 additions & 0 deletions src/editor/dataset/constant/Zone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { IZoneOption } from '../../interface/Zone'

export const defaultZoneOption: Readonly<Required<IZoneOption>> = {
tipDisabled: true
}
9 changes: 8 additions & 1 deletion src/editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ import { LETTER_CLASS } from './dataset/constant/Common'
import { INTERNAL_CONTEXT_MENU_KEY } from './dataset/constant/ContextMenu'
import { IRange } from './interface/Range'
import { deepClone, splitText } from './utils'
import { IZoneOption } from './interface/Zone'
import { defaultZoneOption } from './dataset/constant/Zone'

export default class Editor {
public command: Command
Expand Down Expand Up @@ -132,6 +134,10 @@ export default class Editor {
...defaultPageBreakOption,
...options.pageBreak
}
const zoneOptions: Required<IZoneOption> = {
...defaultZoneOption,
...options.zone
}

const editorOptions: DeepRequired<IEditorOption> = {
mode: EditorMode.EDIT,
Expand Down Expand Up @@ -187,7 +193,8 @@ export default class Editor {
title: titleOptions,
placeholder: placeholderOptions,
group: groupOptions,
pageBreak: pageBreakOptions
pageBreak: pageBreakOptions,
zone: zoneOptions
}
// 数据处理
data = deepClone(data)
Expand Down
2 changes: 2 additions & 0 deletions src/editor/interface/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { IPageNumber } from './PageNumber'
import { IPlaceholder } from './Placeholder'
import { ITitleOption } from './Title'
import { IWatermark } from './Watermark'
import { IZoneOption } from './Zone'

export interface IEditorData {
header?: IElement[]
Expand Down Expand Up @@ -79,6 +80,7 @@ export interface IEditorOption {
placeholder?: IPlaceholder
group?: IGroup
pageBreak?: IPageBreak
zone?: IZoneOption
}

export interface IEditorResult {
Expand Down
1 change: 1 addition & 0 deletions src/editor/interface/Position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface ICurrentPosition {
export interface IGetPositionByXYPayload {
x: number
y: number
pageNo?: number
isTable?: boolean
td?: ITd
tablePosition?: IElementPosition
Expand Down
3 changes: 3 additions & 0 deletions src/editor/interface/Zone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface IZoneOption {
tipDisabled?: boolean
}
19 changes: 19 additions & 0 deletions src/editor/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ export function debounce(func: Function, delay: number) {
}
}

export function throttle(func: Function, delay: number) {
let lastExecTime = 0
let timer: number
return function (this: any, ...args: any[]) {
const currentTime = Date.now()
if (currentTime - lastExecTime >= delay) {
window.clearTimeout(timer)
func.apply(this, args)
lastExecTime = currentTime
} else {
window.clearTimeout(timer)
timer = window.setTimeout(() => {
func.apply(this, args)
lastExecTime = currentTime
}, delay)
}
}
}

export function deepClone<T>(obj: T): T {
if (!obj || typeof obj !== 'object') {
return obj
Expand Down

0 comments on commit 095414f

Please sign in to comment.