feat:search in table
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import { ZERO } from "../../dataset/constant/Common"
|
||||
import { EDITOR_ELEMENT_STYLE } from "../../dataset/constant/Element"
|
||||
import { EditorContext } from "../../dataset/enum/Editor"
|
||||
import { ElementType } from "../../dataset/enum/Element"
|
||||
import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
|
||||
import { RowFlex } from "../../dataset/enum/Row"
|
||||
import { IDrawImagePayload } from "../../interface/Draw"
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { IElement, IElementStyle } from "../../interface/Element"
|
||||
import { ISearchResult, ISearchResultRestArgs } from "../../interface/Search"
|
||||
import { IColgroup } from "../../interface/table/Colgroup"
|
||||
import { ITd } from "../../interface/table/Td"
|
||||
import { ITr } from "../../interface/table/Tr"
|
||||
@@ -291,19 +293,76 @@ export class CommandAdapt {
|
||||
|
||||
public search(payload: string | null) {
|
||||
if (payload) {
|
||||
const elementList = this.draw.getElementList()
|
||||
const text = elementList.map(e => !e.type || e.type === ElementType.TEXT ? e.value : ZERO)
|
||||
.filter(Boolean)
|
||||
.join('')
|
||||
const matchStartIndexList = []
|
||||
let index = text.indexOf(payload)
|
||||
while (index !== -1) {
|
||||
matchStartIndexList.push(index)
|
||||
index = text.indexOf(payload, index + 1)
|
||||
let searchMatchList: ISearchResult[] = []
|
||||
// elementList按table分隔
|
||||
const elementListGroup: { type: EditorContext, elementList: IElement[], index: number }[] = []
|
||||
const originalElementList = this.draw.getOriginalElementList()
|
||||
let lastTextElementList: IElement[] = []
|
||||
for (let e = 0; e < originalElementList.length; e++) {
|
||||
const element = originalElementList[e]
|
||||
if (element.type === ElementType.TABLE) {
|
||||
if (lastTextElementList.length) {
|
||||
elementListGroup.push({
|
||||
index: e,
|
||||
type: EditorContext.PAGE,
|
||||
elementList: lastTextElementList
|
||||
})
|
||||
lastTextElementList = []
|
||||
}
|
||||
elementListGroup.push({
|
||||
index: e,
|
||||
type: EditorContext.TABLE,
|
||||
elementList: [element]
|
||||
})
|
||||
} else {
|
||||
lastTextElementList.push(element)
|
||||
}
|
||||
}
|
||||
const searchMatch: number[][] = matchStartIndexList
|
||||
.map(i => Array(payload.length).fill(i).map((_, j) => i + j))
|
||||
this.draw.setSearchMatch(searchMatch.length ? searchMatch : null)
|
||||
// 搜索文本
|
||||
function searchClosure(payload: string | null, type: EditorContext, elementList: IElement[], restArgs?: ISearchResultRestArgs) {
|
||||
if (!payload) return
|
||||
const text = elementList.map(e => !e.type || e.type === ElementType.TEXT ? e.value : ZERO)
|
||||
.filter(Boolean)
|
||||
.join('')
|
||||
const matchStartIndexList = []
|
||||
let index = text.indexOf(payload)
|
||||
while (index !== -1) {
|
||||
matchStartIndexList.push(index)
|
||||
index = text.indexOf(payload, index + 1)
|
||||
}
|
||||
for (let m = 0; m < matchStartIndexList.length; m++) {
|
||||
const startIndex = matchStartIndexList[m]
|
||||
for (let i = 0; i < payload.length; i++) {
|
||||
const index = startIndex + i
|
||||
searchMatchList.push({
|
||||
type,
|
||||
index,
|
||||
...restArgs
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let e = 0; e < elementListGroup.length; e++) {
|
||||
const group = elementListGroup[e]
|
||||
if (group.type === EditorContext.TABLE) {
|
||||
const tableElement = group.elementList[0]
|
||||
for (let t = 0; t < tableElement.trList!.length; t++) {
|
||||
const tr = tableElement.trList![t]
|
||||
for (let d = 0; d < tr.tdList.length; d++) {
|
||||
const td = tr.tdList[d]
|
||||
const restArgs: ISearchResultRestArgs = {
|
||||
tableIndex: group.index,
|
||||
trIndex: t,
|
||||
tdIndex: d
|
||||
}
|
||||
searchClosure(payload, group.type, td.value, restArgs)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
searchClosure(payload, group.type, group.elementList)
|
||||
}
|
||||
}
|
||||
this.draw.setSearchMatch(searchMatchList)
|
||||
} else {
|
||||
this.draw.setSearchMatch(null)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import { TextParticle } from "./particle/TextParticle"
|
||||
import { PageNumber } from "./frame/PageNumber"
|
||||
import { GlobalObserver } from "../observer/GlobalObserver"
|
||||
import { TableParticle } from "./particle/table/TableParticle"
|
||||
import { ISearchResult } from "../../interface/Search"
|
||||
|
||||
export class Draw {
|
||||
|
||||
@@ -53,7 +54,7 @@ export class Draw {
|
||||
|
||||
private rowList: IRow[]
|
||||
private painterStyle: IElementStyle | null
|
||||
private searchMatchList: number[][] | null
|
||||
private searchMatchList: ISearchResult[] | null
|
||||
private visiblePageNoList: number[]
|
||||
private intersectionPageNo: number
|
||||
|
||||
@@ -252,11 +253,11 @@ export class Draw {
|
||||
}
|
||||
}
|
||||
|
||||
public getSearchMatch(): number[][] | null {
|
||||
public getSearchMatch(): ISearchResult[] | null {
|
||||
return this.searchMatchList
|
||||
}
|
||||
|
||||
public setSearchMatch(payload: number[][] | null) {
|
||||
public setSearchMatch(payload: ISearchResult[] | null) {
|
||||
this.searchMatchList = payload
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { EditorContext } from "../../../dataset/enum/Editor"
|
||||
import { IEditorOption } from "../../../interface/Editor"
|
||||
import { IElementPosition } from "../../../interface/Element"
|
||||
import { Position } from "../../position/Position"
|
||||
import { Draw } from "../Draw"
|
||||
|
||||
@@ -15,24 +17,32 @@ export class Search {
|
||||
}
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D, pageIndex: number) {
|
||||
const searchMatch = this.draw.getSearchMatch()
|
||||
if (!searchMatch || !searchMatch.length) return
|
||||
const searchMatchList = searchMatch.flat()
|
||||
const searchMatchList = this.draw.getSearchMatch()
|
||||
if (!searchMatchList || !searchMatchList.length) return
|
||||
const { searchMatchAlpha, searchMatchColor } = this.options
|
||||
const positionList = this.position.getOriginalPositionList()
|
||||
const elementList = this.draw.getOriginalElementList()
|
||||
ctx.save()
|
||||
ctx.globalAlpha = this.options.searchMatchAlpha
|
||||
ctx.fillStyle = this.options.searchMatchColor
|
||||
searchMatchList.forEach(s => {
|
||||
const position = positionList[s]
|
||||
if (!position) return
|
||||
ctx.globalAlpha = searchMatchAlpha
|
||||
ctx.fillStyle = searchMatchColor
|
||||
for (let s = 0; s < searchMatchList.length; s++) {
|
||||
const searchMatch = searchMatchList[s]
|
||||
let position: IElementPosition | null = null
|
||||
if (searchMatch.type === EditorContext.TABLE) {
|
||||
const { tableIndex, trIndex, tdIndex, index } = searchMatch
|
||||
position = elementList[tableIndex!]?.trList![trIndex!].tdList[tdIndex!]!?.positionList![index]
|
||||
} else {
|
||||
position = positionList[searchMatch.index]
|
||||
}
|
||||
if (!position) continue
|
||||
const { coordinate: { leftTop, leftBottom, rightTop }, pageNo } = position
|
||||
if (pageNo !== pageIndex) return
|
||||
if (pageNo !== pageIndex) continue
|
||||
const x = leftTop[0]
|
||||
const y = leftTop[1]
|
||||
const width = rightTop[0] - leftTop[0]
|
||||
const height = leftBottom[1] - leftTop[1]
|
||||
ctx.fillRect(x, y, width, height)
|
||||
})
|
||||
}
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,9 @@ export enum EditorComponent {
|
||||
MENU = 'menu',
|
||||
MAIN = 'main',
|
||||
FOOTER = 'footer'
|
||||
}
|
||||
|
||||
export enum EditorContext {
|
||||
PAGE = 'page',
|
||||
TABLE = 'table'
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { EditorContext } from "../dataset/enum/Editor"
|
||||
|
||||
export interface ISearchResultBasic {
|
||||
type: EditorContext;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface ISearchResultRestArgs {
|
||||
tableIndex?: number;
|
||||
trIndex?: number;
|
||||
tdIndex?: number;
|
||||
}
|
||||
|
||||
export type ISearchResult = ISearchResultBasic & ISearchResultRestArgs
|
||||
Reference in New Issue
Block a user