@@ -20,12 +20,12 @@ import {
2020} from '../../interface/Editor'
2121import {
2222 IElement ,
23- IElementMetrics ,
2423 IElementFillRect ,
24+ IElementMetrics ,
2525 IElementStyle
2626} from '../../interface/Element'
2727import { IRow , IRowElement } from '../../interface/Row'
28- import { deepClone , getUUID , nextTick } from '../../utils'
28+ import { deepClone , getCurrentTimeString , getUUID , nextTick } from '../../utils'
2929import { Cursor } from '../cursor/Cursor'
3030import { CanvasEvent } from '../event/CanvasEvent'
3131import { GlobalEvent } from '../event/GlobalEvent'
@@ -65,6 +65,7 @@ import {
6565} from '../../dataset/enum/Editor'
6666import { Control } from './control/Control'
6767import {
68+ formatElementList ,
6869 deleteSurroundElementList ,
6970 getIsBlockElement ,
7071 getSlimCloneElementList ,
@@ -78,7 +79,6 @@ import {
7879 ControlComponent ,
7980 ControlIndentation
8081} from '../../dataset/enum/Control'
81- import { formatElementList } from '../../utils/element'
8282import { WorkerManager } from '../worker/WorkerManager'
8383import { Previewer } from './particle/previewer/Previewer'
8484import { DateParticle } from './particle/date/DateParticle'
@@ -108,6 +108,8 @@ import { ITd } from '../../interface/table/Td'
108108import { PageBorder } from './frame/PageBorder'
109109import { Actuator } from '../actuator/Actuator'
110110import { TableOperate } from './particle/table/TableOperate'
111+ import { TrackType } from '../../dataset/enum/Track'
112+ import { Track } from './interactive/Track'
111113
112114export class Draw {
113115 private container : HTMLDivElement
@@ -134,6 +136,7 @@ export class Draw {
134136 private background : Background
135137 private search : Search
136138 private group : Group
139+ private track : Track
137140 private underline : Underline
138141 private strikeout : Strikeout
139142 private highlight : Highlight
@@ -179,6 +182,7 @@ export class Draw {
179182 private intersectionPageNo : number
180183 private lazyRenderIntersectionObserver : IntersectionObserver | null
181184 private printModeData : Required < IEditorData > | null
185+ private hideTrack : boolean
182186
183187 constructor (
184188 rootContainer : HTMLElement ,
@@ -213,6 +217,7 @@ export class Draw {
213217 this . background = new Background ( this )
214218 this . search = new Search ( this )
215219 this . group = new Group ( this )
220+ this . track = new Track ( this )
216221 this . underline = new Underline ( this )
217222 this . strikeout = new Strikeout ( this )
218223 this . highlight = new Highlight ( this )
@@ -270,6 +275,7 @@ export class Draw {
270275 this . intersectionPageNo = 0
271276 this . lazyRenderIntersectionObserver = null
272277 this . printModeData = null
278+ this . hideTrack = false
273279
274280 this . render ( {
275281 isInit : true ,
@@ -353,6 +359,79 @@ export class Draw {
353359 element => element . title ?. disabled || element . control ?. disabled
354360 )
355361 }
362+ // 添加痕迹信息
363+ public addReviewInformation ( elementList : IElement [ ] , type : TrackType ) {
364+ if ( this . mode !== EditorMode . REVIEW ) return
365+ const trackId = getUUID ( )
366+ const len = elementList . length
367+ for ( let i = 0 ; i < len ; i ++ ) {
368+ const element = elementList [ i ]
369+ element . trackId = trackId
370+ element . trackType = type
371+ element . track = {
372+ author : this . options . user . name ,
373+ date : getCurrentTimeString ( )
374+ }
375+ if ( this . hideTrack && type === TrackType . DELETE ) element . hide = true
376+ }
377+ }
378+ // 隐藏、显示痕迹
379+ public hideReview ( ) {
380+ this . hideTrack = true
381+ const len = this . elementList . length
382+ for ( let i = 0 ; i < len ; i ++ ) {
383+ const el = this . elementList [ i ]
384+ if ( el . type === ElementType . TABLE ) {
385+ const trList = el . trList !
386+ trList . forEach ( tr => {
387+ tr . tdList . forEach ( td => {
388+ td . value . forEach ( ( el , index ) => {
389+ if ( el . trackId && el . trackType === TrackType . DELETE ) {
390+ td . value [ index ] . hide = true
391+ }
392+ } )
393+ } )
394+ } )
395+ } else if ( el . trackId && el . trackType === TrackType . DELETE ) {
396+ el . hide = true
397+ }
398+ }
399+ this . clearSideEffect ( )
400+ this . render ( {
401+ isSetCursor : false ,
402+ isSubmitHistory : false
403+ } )
404+ }
405+ public showReview ( ) {
406+ this . hideTrack = false
407+ const len = this . elementList . length
408+ for ( let i = 0 ; i < len ; i ++ ) {
409+ const el = this . elementList [ i ]
410+ if ( el . type === ElementType . TABLE ) {
411+ const trList = el . trList !
412+ trList . forEach ( tr => {
413+ tr . tdList . forEach ( td => {
414+ td . value . forEach ( ( el , index ) => {
415+ if ( el . trackId && el . trackType === TrackType . DELETE && el . hide ) {
416+ delete td . value [ index ] . hide
417+ }
418+ } )
419+ } )
420+ } )
421+ } else if ( el . trackId && el . trackType === TrackType . DELETE && el . hide ) {
422+ delete el . hide
423+ }
424+ }
425+ this . clearSideEffect ( )
426+ this . render ( {
427+ isSetCursor : false ,
428+ isSubmitHistory : false
429+ } )
430+ }
431+
432+ public getHideTrackMode ( ) : boolean {
433+ return this . hideTrack
434+ }
356435
357436 public isDesignMode ( ) {
358437 return this . mode === EditorMode . DESIGN
@@ -848,6 +927,10 @@ export class Draw {
848927 return this . radioParticle
849928 }
850929
930+ public getTrack ( ) : Track {
931+ return this . track
932+ }
933+
851934 public getControl ( ) : Control {
852935 return this . control
853936 }
@@ -1296,7 +1379,12 @@ export class Draw {
12961379 const availableWidth = innerWidth - offsetX
12971380 // 增加起始位置坐标偏移量
12981381 x += curRow . elementList . length === 1 ? offsetX : 0
1299- if (
1382+ if ( element . hide ) {
1383+ metrics . width = 0
1384+ metrics . height = 0
1385+ metrics . boundingBoxDescent = 0
1386+ metrics . boundingBoxAscent = 0
1387+ } else if (
13001388 element . type === ElementType . IMAGE ||
13011389 element . type === ElementType . LATEX
13021390 ) {
@@ -1993,6 +2081,13 @@ export class Draw {
19932081 const isWrap = isForceBreak || isWidthNotEnough
19942082 // 新行数据处理
19952083 if ( isWrap ) {
2084+ // 整行宽度为0 隐藏行不保留高度
2085+ if ( curRow . width === 0 ) {
2086+ const emptyPara = curRow . elementList . length === 1 && curRow . elementList [ 0 ] . value === ZERO
2087+ if ( ! emptyPara ) {
2088+ curRow . height = 0
2089+ }
2090+ }
19962091 const row : IRow = {
19972092 width : metrics . width ,
19982093 height,
@@ -2254,7 +2349,9 @@ export class Draw {
22542349 } = positionList [ curRow . startIndex + j ]
22552350 const preElement = curRow . elementList [ j - 1 ]
22562351 // 元素绘制
2257- if ( element . type === ElementType . IMAGE ) {
2352+ if ( element . hide ) {
2353+ this . textParticle . complete ( )
2354+ } else if ( element . type === ElementType . IMAGE ) {
22582355 this . textParticle . complete ( )
22592356 // 浮动图片单独绘制
22602357 if (
@@ -2501,6 +2598,44 @@ export class Draw {
25012598 if ( ! group . disabled && element . groupIds ) {
25022599 this . group . recordFillInfo ( element , x , y , metrics . width , curRow . height )
25032600 }
2601+ // todo : 留痕信息记录
2602+ if ( element . trackId ) {
2603+ // 如果前后类型不一致
2604+ if ( preElement ?. trackId && preElement ?. trackType && element ?. trackType && element . trackType !== preElement . trackType ) {
2605+ if ( ! this . hideTrack ) {
2606+ this . track . render ( ctx )
2607+ } else {
2608+ this . track . clearRectInfo ( )
2609+ }
2610+ }
2611+ // 基线文字测量信息
2612+ const standardMetrics = this . textParticle . measureBasisWord (
2613+ ctx ,
2614+ this . getElementFont ( element )
2615+ )
2616+ const rowMargin = this . getElementRowMargin ( element )
2617+
2618+ if ( element . trackType === TrackType . INSERT ) {
2619+ const offsetX = element . left || 0
2620+ const coordinateX = x - offsetX
2621+ const coordinateY = y + curRow . height - rowMargin + 1
2622+ const width = metrics . width + offsetX
2623+ const height = curRow . height
2624+ this . track . recordInsertRectInfo ( element , coordinateX , coordinateY , width , height )
2625+ } else if ( element . trackType === TrackType . DELETE ) {
2626+ let adjustY = y + offsetY + standardMetrics . actualBoundingBoxDescent * scale - metrics . height / 2
2627+ if ( element . type === ElementType . IMAGE || element . type === ElementType . LATEX || element . type === ElementType . TABLE ) {
2628+ adjustY = y + ( element . height ! / 2 ) + offsetY
2629+ }
2630+ this . track . recordDeleteRectInfo ( element , x , adjustY , metrics . width , curRow . height )
2631+ }
2632+ } else if ( preElement ?. trackId ) {
2633+ if ( ! this . hideTrack ) {
2634+ this . track . render ( ctx )
2635+ } else {
2636+ this . track . clearRectInfo ( )
2637+ }
2638+ }
25042639 index ++
25052640 // 绘制表格内元素
25062641 if ( element . type === ElementType . TABLE ) {
@@ -2538,6 +2673,11 @@ export class Draw {
25382673 this . strikeout . render ( ctx )
25392674 // 绘制批注样式
25402675 this . group . render ( ctx )
2676+ if ( ! this . hideTrack ) {
2677+ this . track . render ( ctx )
2678+ } else {
2679+ this . track . clearRectInfo ( )
2680+ }
25412681 // 绘制选区
25422682 if ( ! isPrintMode ) {
25432683 if ( rangeRecord . width && rangeRecord . height ) {
@@ -2944,5 +3084,7 @@ export class Draw {
29443084 this . getHyperlinkParticle ( ) . clearHyperlinkPopup ( )
29453085 // 日期控件
29463086 this . getDateParticle ( ) . clearDatePicker ( )
3087+ // 痕迹显示
3088+ this . getTrack ( ) . clearTrackPopup ( )
29473089 }
29483090}
0 commit comments