feat: set control highlight rule #332
This commit is contained in:
@@ -891,3 +891,13 @@ Usage:
|
|||||||
```javascript
|
```javascript
|
||||||
instance.command.executeSetControlExtension(payload: ISetControlExtensionOption)
|
instance.command.executeSetControlExtension(payload: ISetControlExtensionOption)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## executeSetControlHighlight
|
||||||
|
|
||||||
|
Feature: Set control highlight (by keyword)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.command.executeSetControlHighlight(payload: ISetControlHighlightOption)
|
||||||
|
```
|
||||||
|
|||||||
@@ -891,3 +891,13 @@ instance.command.executeSetControlValue(payload: ISetControlValueOption)
|
|||||||
```javascript
|
```javascript
|
||||||
instance.command.executeSetControlExtension(payload: ISetControlExtensionOption)
|
instance.command.executeSetControlExtension(payload: ISetControlExtensionOption)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## executeSetControlHighlight
|
||||||
|
|
||||||
|
功能:设置控件高亮(根据关键词)
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.command.executeSetControlHighlight(payload: ISetControlHighlightOption)
|
||||||
|
```
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export class Command {
|
|||||||
public executeSetZone: CommandAdapt['setZone']
|
public executeSetZone: CommandAdapt['setZone']
|
||||||
public executeSetControlValue: CommandAdapt['setControlValue']
|
public executeSetControlValue: CommandAdapt['setControlValue']
|
||||||
public executeSetControlExtension: CommandAdapt['setControlExtension']
|
public executeSetControlExtension: CommandAdapt['setControlExtension']
|
||||||
|
public executeSetControlHighlight: CommandAdapt['setControlHighlight']
|
||||||
public getCatalog: CommandAdapt['getCatalog']
|
public getCatalog: CommandAdapt['getCatalog']
|
||||||
public getImage: CommandAdapt['getImage']
|
public getImage: CommandAdapt['getImage']
|
||||||
public getOptions: CommandAdapt['getOptions']
|
public getOptions: CommandAdapt['getOptions']
|
||||||
@@ -221,6 +222,7 @@ export class Command {
|
|||||||
// 控件
|
// 控件
|
||||||
this.executeSetControlValue = adapt.setControlValue.bind(adapt)
|
this.executeSetControlValue = adapt.setControlValue.bind(adapt)
|
||||||
this.executeSetControlExtension = adapt.setControlExtension.bind(adapt)
|
this.executeSetControlExtension = adapt.setControlExtension.bind(adapt)
|
||||||
|
this.executeSetControlHighlight = adapt.setControlHighlight.bind(adapt)
|
||||||
this.getControlValue = adapt.getControlValue.bind(adapt)
|
this.getControlValue = adapt.getControlValue.bind(adapt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
IGetControlValueOption,
|
IGetControlValueOption,
|
||||||
IGetControlValueResult,
|
IGetControlValueResult,
|
||||||
ISetControlExtensionOption,
|
ISetControlExtensionOption,
|
||||||
|
ISetControlHighlightOption,
|
||||||
ISetControlValueOption
|
ISetControlValueOption
|
||||||
} from '../../interface/Control'
|
} from '../../interface/Control'
|
||||||
import {
|
import {
|
||||||
@@ -2197,6 +2198,10 @@ export class CommandAdapt {
|
|||||||
this.draw.getControl().setExtensionByConceptId(payload)
|
this.draw.getControl().setExtensionByConceptId(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setControlHighlight(payload: ISetControlHighlightOption) {
|
||||||
|
this.draw.getControl().setHighlightList(payload)
|
||||||
|
}
|
||||||
|
|
||||||
public getContainer(): HTMLDivElement {
|
public getContainer(): HTMLDivElement {
|
||||||
return this.draw.getContainer()
|
return this.draw.getContainer()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1821,6 +1821,8 @@ export class Draw {
|
|||||||
if (this.mode !== EditorMode.PRINT) {
|
if (this.mode !== EditorMode.PRINT) {
|
||||||
this.margin.render(ctx, pageNo)
|
this.margin.render(ctx, pageNo)
|
||||||
}
|
}
|
||||||
|
// 控件高亮
|
||||||
|
this.control.renderHighlightList(ctx, pageNo)
|
||||||
// 渲染元素
|
// 渲染元素
|
||||||
const index = rowList[0].startIndex
|
const index = rowList[0].startIndex
|
||||||
this.drawRow(ctx, {
|
this.drawRow(ctx, {
|
||||||
@@ -1935,6 +1937,8 @@ export class Draw {
|
|||||||
if (searchKeyword) {
|
if (searchKeyword) {
|
||||||
this.search.compute(searchKeyword)
|
this.search.compute(searchKeyword)
|
||||||
}
|
}
|
||||||
|
// 控件关键词高亮
|
||||||
|
this.control.computeHighlightList()
|
||||||
}
|
}
|
||||||
// 清除光标等副作用
|
// 清除光标等副作用
|
||||||
this.imageObserver.clearAll()
|
this.imageObserver.clearAll()
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { ControlComponent, ControlType } from '../../../dataset/enum/Control'
|
import { ControlComponent, ControlType } from '../../../dataset/enum/Control'
|
||||||
import { EditorZone } from '../../../dataset/enum/Editor'
|
import { EditorZone } from '../../../dataset/enum/Editor'
|
||||||
import { ElementType } from '../../../dataset/enum/Element'
|
import { ElementType } from '../../../dataset/enum/Element'
|
||||||
|
import { DeepRequired } from '../../../interface/Common'
|
||||||
import {
|
import {
|
||||||
IControl,
|
IControl,
|
||||||
IControlContext,
|
IControlContext,
|
||||||
|
IControlHighlight,
|
||||||
IControlInitOption,
|
IControlInitOption,
|
||||||
IControlInstance,
|
IControlInstance,
|
||||||
IControlOption,
|
IControlOption,
|
||||||
@@ -13,6 +15,7 @@ import {
|
|||||||
ISetControlExtensionOption,
|
ISetControlExtensionOption,
|
||||||
ISetControlValueOption
|
ISetControlValueOption
|
||||||
} from '../../../interface/Control'
|
} from '../../../interface/Control'
|
||||||
|
import { IEditorOption } from '../../../interface/Editor'
|
||||||
import { IElement, IElementPosition } from '../../../interface/Element'
|
import { IElement, IElementPosition } from '../../../interface/Element'
|
||||||
import { EventBusMap } from '../../../interface/EventBus'
|
import { EventBusMap } from '../../../interface/EventBus'
|
||||||
import { IRange } from '../../../interface/Range'
|
import { IRange } from '../../../interface/Range'
|
||||||
@@ -28,6 +31,7 @@ import { Listener } from '../../listener/Listener'
|
|||||||
import { RangeManager } from '../../range/RangeManager'
|
import { RangeManager } from '../../range/RangeManager'
|
||||||
import { Draw } from '../Draw'
|
import { Draw } from '../Draw'
|
||||||
import { CheckboxControl } from './checkbox/CheckboxControl'
|
import { CheckboxControl } from './checkbox/CheckboxControl'
|
||||||
|
import { ControlSearch } from './interactive/ControlSearch'
|
||||||
import { SelectControl } from './select/SelectControl'
|
import { SelectControl } from './select/SelectControl'
|
||||||
import { TextControl } from './text/TextControl'
|
import { TextControl } from './text/TextControl'
|
||||||
|
|
||||||
@@ -40,7 +44,9 @@ export class Control {
|
|||||||
private range: RangeManager
|
private range: RangeManager
|
||||||
private listener: Listener
|
private listener: Listener
|
||||||
private eventBus: EventBus<EventBusMap>
|
private eventBus: EventBus<EventBusMap>
|
||||||
private options: IControlOption
|
private controlSearch: ControlSearch
|
||||||
|
private options: DeepRequired<IEditorOption>
|
||||||
|
private controlOptions: IControlOption
|
||||||
private activeControl: IControlInstance | null
|
private activeControl: IControlInstance | null
|
||||||
|
|
||||||
constructor(draw: Draw) {
|
constructor(draw: Draw) {
|
||||||
@@ -48,11 +54,32 @@ export class Control {
|
|||||||
this.range = draw.getRange()
|
this.range = draw.getRange()
|
||||||
this.listener = draw.getListener()
|
this.listener = draw.getListener()
|
||||||
this.eventBus = draw.getEventBus()
|
this.eventBus = draw.getEventBus()
|
||||||
|
this.controlSearch = new ControlSearch(this)
|
||||||
|
|
||||||
this.options = draw.getOptions().control
|
this.options = draw.getOptions()
|
||||||
|
this.controlOptions = this.options.control
|
||||||
this.activeControl = null
|
this.activeControl = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 搜索高亮匹配
|
||||||
|
public setHighlightList(payload: IControlHighlight[]) {
|
||||||
|
this.controlSearch.setHighlightList(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
public computeHighlightList() {
|
||||||
|
const highlightList = this.controlSearch.getHighlightList()
|
||||||
|
if (highlightList.length) {
|
||||||
|
this.controlSearch.computeHighlightList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderHighlightList(ctx: CanvasRenderingContext2D, pageNo: number) {
|
||||||
|
const highlightMatchResult = this.controlSearch.getHighlightMatchResult()
|
||||||
|
if (highlightMatchResult.length) {
|
||||||
|
this.controlSearch.renderHighlightList(ctx, pageNo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getDraw(): Draw {
|
public getDraw(): Draw {
|
||||||
return this.draw
|
return this.draw
|
||||||
}
|
}
|
||||||
@@ -395,7 +422,7 @@ export class Control {
|
|||||||
type: ElementType.CONTROL,
|
type: ElementType.CONTROL,
|
||||||
control: startElement.control,
|
control: startElement.control,
|
||||||
controlComponent: ControlComponent.PLACEHOLDER,
|
controlComponent: ControlComponent.PLACEHOLDER,
|
||||||
color: this.options.placeholderColor
|
color: this.controlOptions.placeholderColor
|
||||||
}
|
}
|
||||||
formatElementContext(elementList, [newElement], startIndex)
|
formatElementContext(elementList, [newElement], startIndex)
|
||||||
this.draw.spliceElementList(
|
this.draw.spliceElementList(
|
||||||
@@ -561,7 +588,7 @@ export class Control {
|
|||||||
const formatValue = [{ value }]
|
const formatValue = [{ value }]
|
||||||
formatElementList(formatValue, {
|
formatElementList(formatValue, {
|
||||||
isHandleFirstElement: false,
|
isHandleFirstElement: false,
|
||||||
editorOptions: this.draw.getOptions()
|
editorOptions: this.options
|
||||||
})
|
})
|
||||||
const text = new TextControl(element, this)
|
const text = new TextControl(element, this)
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import { ElementType } from '../../../../dataset/enum/Element'
|
||||||
|
import { DeepRequired } from '../../../../interface/Common'
|
||||||
|
import {
|
||||||
|
IControlHighlight,
|
||||||
|
IControlHighlightRule
|
||||||
|
} from '../../../../interface/Control'
|
||||||
|
import { IEditorOption } from '../../../../interface/Editor'
|
||||||
|
import { IElement, IElementPosition } from '../../../../interface/Element'
|
||||||
|
import {
|
||||||
|
ISearchResult,
|
||||||
|
ISearchResultRestArgs
|
||||||
|
} from '../../../../interface/Search'
|
||||||
|
import { Draw } from '../../Draw'
|
||||||
|
import { Control } from '../Control'
|
||||||
|
|
||||||
|
type IHighlightMatchResult = (ISearchResult & IControlHighlightRule)[]
|
||||||
|
|
||||||
|
export class ControlSearch {
|
||||||
|
private draw: Draw
|
||||||
|
private options: DeepRequired<IEditorOption>
|
||||||
|
private highlightList: IControlHighlight[]
|
||||||
|
private highlightMatchResult: IHighlightMatchResult
|
||||||
|
|
||||||
|
constructor(control: Control) {
|
||||||
|
this.draw = control.getDraw()
|
||||||
|
this.options = this.draw.getOptions()
|
||||||
|
|
||||||
|
this.highlightList = []
|
||||||
|
this.highlightMatchResult = []
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHighlightMatchResult(): IHighlightMatchResult {
|
||||||
|
return this.highlightMatchResult
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHighlightList(): IControlHighlight[] {
|
||||||
|
return this.highlightList
|
||||||
|
}
|
||||||
|
|
||||||
|
public setHighlightList(payload: IControlHighlight[]) {
|
||||||
|
this.highlightList = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
public computeHighlightList() {
|
||||||
|
const search = this.draw.getSearch()
|
||||||
|
const computeHighlight = (
|
||||||
|
elementList: IElement[],
|
||||||
|
restArgs?: ISearchResultRestArgs
|
||||||
|
) => {
|
||||||
|
let i = 0
|
||||||
|
while (i < elementList.length) {
|
||||||
|
const element = elementList[i]
|
||||||
|
i++
|
||||||
|
// 表格下钻处理
|
||||||
|
if (element.type === ElementType.TABLE) {
|
||||||
|
const trList = element.trList!
|
||||||
|
for (let r = 0; r < trList.length; r++) {
|
||||||
|
const tr = trList[r]
|
||||||
|
for (let d = 0; d < tr.tdList.length; d++) {
|
||||||
|
const td = tr.tdList[d]
|
||||||
|
const restArgs: ISearchResultRestArgs = {
|
||||||
|
tableId: element.id,
|
||||||
|
tableIndex: i - 1,
|
||||||
|
trIndex: r,
|
||||||
|
tdIndex: d,
|
||||||
|
tdId: td.id
|
||||||
|
}
|
||||||
|
computeHighlight(td.value, restArgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const controlConceptId = element?.control?.conceptId
|
||||||
|
if (!controlConceptId) continue
|
||||||
|
const highlightIndex = this.highlightList.findIndex(
|
||||||
|
highlight => highlight.conceptId === controlConceptId
|
||||||
|
)
|
||||||
|
if (!~highlightIndex) continue
|
||||||
|
// 搜索后控件结束索引
|
||||||
|
const startIndex = i
|
||||||
|
let newEndIndex = i
|
||||||
|
while (newEndIndex < elementList.length) {
|
||||||
|
const nextElement = elementList[newEndIndex]
|
||||||
|
if (nextElement.controlId !== element.controlId) break
|
||||||
|
newEndIndex++
|
||||||
|
}
|
||||||
|
i = newEndIndex
|
||||||
|
// 高亮信息
|
||||||
|
const controlElementList = elementList.slice(startIndex, newEndIndex)
|
||||||
|
const highlight = this.highlightList[highlightIndex]
|
||||||
|
const { ruleList } = highlight
|
||||||
|
for (let r = 0; r < ruleList.length; r++) {
|
||||||
|
const rule = ruleList[r]
|
||||||
|
const searchResult = search.getMatchList(
|
||||||
|
rule.keyword,
|
||||||
|
controlElementList
|
||||||
|
)
|
||||||
|
this.highlightMatchResult.push(
|
||||||
|
...searchResult.map(result => ({
|
||||||
|
...result,
|
||||||
|
...rule,
|
||||||
|
...restArgs,
|
||||||
|
index: result.index + startIndex // 实际索引
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.highlightMatchResult = []
|
||||||
|
computeHighlight(this.draw.getOriginalMainElementList())
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderHighlightList(ctx: CanvasRenderingContext2D, pageIndex: number) {
|
||||||
|
if (!this.highlightMatchResult?.length) return
|
||||||
|
const { searchMatchAlpha, searchMatchColor } = this.options
|
||||||
|
const positionList = this.draw.getPosition().getOriginalPositionList()
|
||||||
|
const elementList = this.draw.getOriginalElementList()
|
||||||
|
ctx.save()
|
||||||
|
for (let s = 0; s < this.highlightMatchResult.length; s++) {
|
||||||
|
const searchMatch = this.highlightMatchResult[s]
|
||||||
|
let position: IElementPosition | null = null
|
||||||
|
if (searchMatch.tableId) {
|
||||||
|
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) continue
|
||||||
|
ctx.fillStyle = searchMatch.backgroundColor || searchMatchColor
|
||||||
|
ctx.globalAlpha = searchMatch.alpha || searchMatchAlpha
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -153,7 +153,10 @@ export class Search {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMatchList(payload: string): ISearchResult[] {
|
public getMatchList(
|
||||||
|
payload: string,
|
||||||
|
originalElementList: IElement[]
|
||||||
|
): ISearchResult[] {
|
||||||
const keyword = payload.toLocaleLowerCase()
|
const keyword = payload.toLocaleLowerCase()
|
||||||
const searchMatchList: ISearchResult[] = []
|
const searchMatchList: ISearchResult[] = []
|
||||||
// 分组
|
// 分组
|
||||||
@@ -162,7 +165,6 @@ export class Search {
|
|||||||
elementList: IElement[]
|
elementList: IElement[]
|
||||||
index: number
|
index: number
|
||||||
}[] = []
|
}[] = []
|
||||||
const originalElementList = this.draw.getOriginalElementList()
|
|
||||||
const originalElementListLength = originalElementList.length
|
const originalElementListLength = originalElementList.length
|
||||||
// 查找表格所在位置
|
// 查找表格所在位置
|
||||||
const tableIndexList = []
|
const tableIndexList = []
|
||||||
@@ -264,7 +266,10 @@ export class Search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public compute(payload: string) {
|
public compute(payload: string) {
|
||||||
this.searchMatchList = this.getMatchList(payload)
|
this.searchMatchList = this.getMatchList(
|
||||||
|
payload,
|
||||||
|
this.draw.getOriginalElementList()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(ctx: CanvasRenderingContext2D, pageIndex: number) {
|
public render(ctx: CanvasRenderingContext2D, pageIndex: number) {
|
||||||
|
|||||||
@@ -249,7 +249,9 @@ export class RangeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getKeywordRangeList(payload: string): IRange[] {
|
public getKeywordRangeList(payload: string): IRange[] {
|
||||||
const searchMatchList = this.draw.getSearch().getMatchList(payload)
|
const searchMatchList = this.draw
|
||||||
|
.getSearch()
|
||||||
|
.getMatchList(payload, this.draw.getOriginalElementList())
|
||||||
const searchRangeMap: Map<string, IRange> = new Map()
|
const searchRangeMap: Map<string, IRange> = new Map()
|
||||||
for (const searchMatch of searchMatchList) {
|
for (const searchMatch of searchMatchList) {
|
||||||
const searchRange = searchRangeMap.get(searchMatch.groupId)
|
const searchRange = searchRangeMap.get(searchMatch.groupId)
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ export interface IControlCheckbox {
|
|||||||
checkbox?: ICheckbox
|
checkbox?: ICheckbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IControlHighlightRule {
|
||||||
|
keyword: string
|
||||||
|
alpha?: number
|
||||||
|
backgroundColor?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IControlHighlight {
|
||||||
|
ruleList: IControlHighlightRule[]
|
||||||
|
conceptId: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface IControlRule {
|
export interface IControlRule {
|
||||||
deletable?: boolean
|
deletable?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
@@ -108,3 +119,5 @@ export interface ISetControlExtensionOption {
|
|||||||
conceptId: string
|
conceptId: string
|
||||||
extension: unknown
|
extension: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ISetControlHighlightOption = IControlHighlight[]
|
||||||
|
|||||||
Reference in New Issue
Block a user