@leafer/selector 1.0.0-alpha.9 → 1.0.0-bate
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/FindPath.ts +141 -0
- package/src/Selector.ts +43 -41
- package/src/PathFinder.ts +0 -131
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/selector",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-bate",
|
|
4
4
|
"description": "@leafer/selector",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"leaferjs"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@leafer/event": "1.0.0-
|
|
23
|
-
"@leafer/math": "1.0.0-
|
|
24
|
-
"@leafer/list": "1.0.0-
|
|
22
|
+
"@leafer/event": "1.0.0-bate",
|
|
23
|
+
"@leafer/math": "1.0.0-bate",
|
|
24
|
+
"@leafer/list": "1.0.0-bate"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@leafer/interface": "1.0.0-
|
|
27
|
+
"@leafer/interface": "1.0.0-bate"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/src/FindPath.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ILeaf, ILeafList, IPointData, IRadiusPointData, ISelectPathResult, ISelectPathOptions, ISelector } from '@leafer/interface'
|
|
2
|
+
import { BoundsHelper } from '@leafer/math'
|
|
3
|
+
import { LeafList } from '@leafer/list'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const { hitRadiusPoint } = BoundsHelper
|
|
7
|
+
|
|
8
|
+
export class FindPath {
|
|
9
|
+
|
|
10
|
+
protected target: ILeaf
|
|
11
|
+
protected selector: ISelector
|
|
12
|
+
|
|
13
|
+
protected findList: ILeaf[]
|
|
14
|
+
protected exclude: ILeafList
|
|
15
|
+
|
|
16
|
+
protected point: IRadiusPointData
|
|
17
|
+
|
|
18
|
+
constructor(target: ILeaf, selector: ISelector) {
|
|
19
|
+
this.target = target
|
|
20
|
+
this.selector = selector
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public getByPoint(hitPoint: IPointData, hitRadius: number, options?: ISelectPathOptions): ISelectPathResult {
|
|
24
|
+
if (!hitRadius) hitRadius = 0
|
|
25
|
+
if (!options) options = {}
|
|
26
|
+
|
|
27
|
+
const through = options.through || false
|
|
28
|
+
const ignoreHittable = options.ignoreHittable || false
|
|
29
|
+
this.exclude = options.exclude || null
|
|
30
|
+
|
|
31
|
+
this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius }
|
|
32
|
+
this.findList = []
|
|
33
|
+
|
|
34
|
+
// path
|
|
35
|
+
this.eachFind(this.target.children, this.target.__onlyHitMask)
|
|
36
|
+
|
|
37
|
+
const list = this.findList
|
|
38
|
+
const leaf = this.getBestMatchLeaf()
|
|
39
|
+
const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf)
|
|
40
|
+
|
|
41
|
+
this.clear()
|
|
42
|
+
|
|
43
|
+
return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public getBestMatchLeaf(): ILeaf {
|
|
47
|
+
const { findList: targets } = this
|
|
48
|
+
if (targets.length > 1) {
|
|
49
|
+
let find: ILeaf
|
|
50
|
+
this.findList = []
|
|
51
|
+
const { x, y } = this.point
|
|
52
|
+
const point = { x, y, radiusX: 0, radiusY: 0 }
|
|
53
|
+
for (let i = 0, len = targets.length; i < len; i++) {
|
|
54
|
+
find = targets[i]
|
|
55
|
+
this.hitChild(find, point)
|
|
56
|
+
if (this.findList.length) return this.findList[0]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return targets[0]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public getPath(leaf: ILeaf): LeafList {
|
|
63
|
+
const path = new LeafList()
|
|
64
|
+
while (leaf) {
|
|
65
|
+
path.push(leaf)
|
|
66
|
+
leaf = leaf.parent
|
|
67
|
+
}
|
|
68
|
+
path.push(this.target)
|
|
69
|
+
return path
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public getHitablePath(leaf: ILeaf): LeafList {
|
|
73
|
+
const path = this.getPath(leaf)
|
|
74
|
+
let item: ILeaf, hittablePath = new LeafList()
|
|
75
|
+
for (let i = path.list.length - 1; i > -1; i--) {
|
|
76
|
+
item = path.list[i]
|
|
77
|
+
if (!item.__.hittable) break
|
|
78
|
+
hittablePath.unshift(item)
|
|
79
|
+
if (!item.__.hitChildren) break
|
|
80
|
+
}
|
|
81
|
+
return hittablePath
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public getThroughPath(list: ILeaf[]): LeafList {
|
|
85
|
+
const throughPath = new LeafList()
|
|
86
|
+
const pathList: ILeafList[] = []
|
|
87
|
+
|
|
88
|
+
for (let i = list.length - 1; i > -1; i--) {
|
|
89
|
+
pathList.push(this.getPath(list[i]))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let path: ILeafList, nextPath: ILeafList, leaf: ILeaf
|
|
93
|
+
for (let i = 0, len = pathList.length; i < len; i++) {
|
|
94
|
+
path = pathList[i], nextPath = pathList[i + 1]
|
|
95
|
+
for (let j = 0, jLen = path.length; j < jLen; j++) {
|
|
96
|
+
leaf = path.list[j]
|
|
97
|
+
if (nextPath && nextPath.has(leaf)) break
|
|
98
|
+
throughPath.push(leaf)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return throughPath
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
protected eachFind(children: Array<ILeaf>, hitMask: boolean): void {
|
|
107
|
+
let child: ILeaf, hit: boolean
|
|
108
|
+
const { point } = this, len = children.length
|
|
109
|
+
for (let i = len - 1; i > -1; i--) {
|
|
110
|
+
child = children[i]
|
|
111
|
+
if (hitMask && !child.isMask) continue
|
|
112
|
+
hit = hitRadiusPoint(child.__world, point)
|
|
113
|
+
|
|
114
|
+
if (child.isBranch) {
|
|
115
|
+
if (hit || child.__ignoreHitWorld) {
|
|
116
|
+
this.eachFind(child.children, child.__onlyHitMask)
|
|
117
|
+
if (child.isBranchLeaf && !this.findList.length) this.hitChild(child, point) // like frame
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
if (hit) this.hitChild(child, point)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
protected hitChild(child: ILeaf, point: IRadiusPointData): void {
|
|
126
|
+
if (this.exclude && this.exclude.has(child)) return
|
|
127
|
+
if (child.__hitWorld(point)) this.findList.push(child)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
protected clear(): void {
|
|
131
|
+
this.point = null
|
|
132
|
+
this.findList = null
|
|
133
|
+
this.exclude = null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public destroy(): void {
|
|
137
|
+
this.target = null
|
|
138
|
+
this.selector = null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
package/src/Selector.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ILeaf, ILeafArrayMap, ILeafMap, ISelector, ISelectPathResult, ISelectPathOptions, IPointData,
|
|
2
|
-
import { ChildEvent } from '@leafer/event'
|
|
3
|
-
import {
|
|
1
|
+
import { ILeaf, ILeafArrayMap, ILeafMap, ISelector, ISelectPathResult, ISelectPathOptions, IPointData, IEventListenerId, ISelectorConfig } from '@leafer/interface'
|
|
2
|
+
import { ChildEvent, LayoutEvent } from '@leafer/event'
|
|
3
|
+
import { DataHelper } from '@leafer/data'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { FindPath } from './FindPath'
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
interface IFind {
|
|
@@ -13,45 +13,30 @@ interface IFind {
|
|
|
13
13
|
export class Selector implements ISelector {
|
|
14
14
|
|
|
15
15
|
public target: ILeaf
|
|
16
|
-
protected pathFinder: PathFinder
|
|
17
16
|
|
|
18
|
-
public
|
|
17
|
+
public config: ISelectorConfig = {}
|
|
19
18
|
|
|
20
|
-
protected
|
|
19
|
+
protected findPath: FindPath
|
|
21
20
|
|
|
22
21
|
protected innerIdList: ILeafMap = {}
|
|
23
22
|
protected idList: ILeafMap = {}
|
|
24
23
|
protected classNameList: ILeafArrayMap = {}
|
|
25
24
|
protected tagNameList: ILeafArrayMap = {}
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
this.target = target
|
|
29
|
-
this.defaultPath = new LeafList(target)
|
|
30
|
-
this.pathFinder = new PathFinder(target, this)
|
|
31
|
-
this.listenEvents()
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
protected listenEvents(): void {
|
|
35
|
-
this.eventIds = [
|
|
36
|
-
this.target.on__(ChildEvent.REMOVE, this.onRemoveChild, this)
|
|
37
|
-
]
|
|
38
|
-
}
|
|
26
|
+
protected __eventIds: IEventListenerId[]
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
this.target
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const target = event.target as ILeaf
|
|
46
|
-
if (this.idList[target.id]) this.idList[target.id] = undefined
|
|
47
|
-
if (this.innerIdList[target.id]) this.innerIdList[target.innerId] = undefined
|
|
28
|
+
constructor(target: ILeaf, userConfig?: ISelectorConfig) {
|
|
29
|
+
this.target = target
|
|
30
|
+
if (userConfig) this.config = DataHelper.default(userConfig, this.config)
|
|
31
|
+
this.findPath = new FindPath(target, this)
|
|
32
|
+
this.__listenEvents()
|
|
48
33
|
}
|
|
49
34
|
|
|
50
|
-
public
|
|
51
|
-
|
|
35
|
+
public getByPoint(hitPoint: IPointData, hitRadius: number, options?: ISelectPathOptions): ISelectPathResult {
|
|
36
|
+
this.target.emit(LayoutEvent.CHECK_UPDATE)
|
|
37
|
+
return this.findPath.getByPoint(hitPoint, hitRadius, options)
|
|
52
38
|
}
|
|
53
39
|
|
|
54
|
-
|
|
55
40
|
public find(name: number | string, branch?: ILeaf): ILeaf | ILeaf[] {
|
|
56
41
|
if (typeof name === 'number') {
|
|
57
42
|
return this.getByInnerId(name, branch)
|
|
@@ -112,7 +97,7 @@ export class Selector implements ISelector {
|
|
|
112
97
|
if (!branch) branch = this.target
|
|
113
98
|
let find: Array<ILeaf | ILeaf> = []
|
|
114
99
|
this.loopFind(branch, (leaf) => {
|
|
115
|
-
if (leaf.
|
|
100
|
+
if (leaf.__tag === name) find.push(leaf)
|
|
116
101
|
return false
|
|
117
102
|
})
|
|
118
103
|
return find
|
|
@@ -124,21 +109,38 @@ export class Selector implements ISelector {
|
|
|
124
109
|
for (let i = 0, len = children.length; i < len; i++) {
|
|
125
110
|
branch = children[i] as ILeaf
|
|
126
111
|
if (find(branch)) return
|
|
127
|
-
if (branch.
|
|
112
|
+
if (branch.isBranch) this.loopFind(branch, find)
|
|
128
113
|
}
|
|
129
114
|
}
|
|
130
115
|
|
|
116
|
+
protected __onRemoveChild(event: ChildEvent): void {
|
|
117
|
+
const target = event.target as ILeaf
|
|
118
|
+
if (this.idList[target.id]) this.idList[target.id] = null
|
|
119
|
+
if (this.innerIdList[target.id]) this.innerIdList[target.innerId] = null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
protected __listenEvents(): void {
|
|
124
|
+
this.__eventIds = [
|
|
125
|
+
this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this)
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
protected __removeListenEvents(): void {
|
|
130
|
+
this.target.off_(this.__eventIds)
|
|
131
|
+
}
|
|
132
|
+
|
|
131
133
|
public destroy(): void {
|
|
132
134
|
if (this.target) {
|
|
133
|
-
this.
|
|
134
|
-
this.
|
|
135
|
-
|
|
136
|
-
this.target =
|
|
137
|
-
this.
|
|
138
|
-
this.innerIdList =
|
|
139
|
-
this.idList =
|
|
140
|
-
this.classNameList =
|
|
141
|
-
this.tagNameList =
|
|
135
|
+
this.__removeListenEvents()
|
|
136
|
+
this.findPath.destroy()
|
|
137
|
+
|
|
138
|
+
this.target = null
|
|
139
|
+
this.findPath = null
|
|
140
|
+
this.innerIdList = null
|
|
141
|
+
this.idList = null
|
|
142
|
+
this.classNameList = null
|
|
143
|
+
this.tagNameList = null
|
|
142
144
|
}
|
|
143
145
|
}
|
|
144
146
|
|
package/src/PathFinder.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { ILeaf, ILeafList, IPointData, IRadiusPointData, ISelectPathResult, ISelectPathOptions, ISelector } from '@leafer/interface'
|
|
2
|
-
import { BoundsHelper } from '@leafer/math'
|
|
3
|
-
import { LeafList } from '@leafer/list'
|
|
4
|
-
|
|
5
|
-
const { hitRadiusPoint } = BoundsHelper
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export class PathFinder {
|
|
9
|
-
|
|
10
|
-
protected target: ILeaf
|
|
11
|
-
protected selector: ISelector
|
|
12
|
-
|
|
13
|
-
protected leaf?: ILeaf
|
|
14
|
-
protected throughPath: ILeafList
|
|
15
|
-
protected exclude: ILeafList
|
|
16
|
-
|
|
17
|
-
protected point: IRadiusPointData
|
|
18
|
-
protected isStop: boolean
|
|
19
|
-
|
|
20
|
-
constructor(target: ILeaf, selector: ISelector) {
|
|
21
|
-
this.target = target
|
|
22
|
-
this.selector = selector
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public getHitPointPath(hitPoint: IPointData, hitRadius: number, options?: ISelectPathOptions): ISelectPathResult {
|
|
26
|
-
const through = options ? options.through : false
|
|
27
|
-
this.exclude = options ? options.exclude : undefined
|
|
28
|
-
|
|
29
|
-
this.isStop = false
|
|
30
|
-
this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius }
|
|
31
|
-
|
|
32
|
-
// path
|
|
33
|
-
this.eachFind(this.target.children)
|
|
34
|
-
|
|
35
|
-
const { leaf } = this
|
|
36
|
-
const { defaultPath } = this.selector
|
|
37
|
-
const path = this.getPath(leaf)
|
|
38
|
-
path.pushList(defaultPath.list)
|
|
39
|
-
|
|
40
|
-
let result: ISelectPathResult
|
|
41
|
-
|
|
42
|
-
// throughPath
|
|
43
|
-
if (through) {
|
|
44
|
-
const throughPath = this.throughPath = new LeafList()
|
|
45
|
-
this.eachThroughFind(this.target.children)
|
|
46
|
-
throughPath.pushList(defaultPath.list)
|
|
47
|
-
result = { path, leaf, throughPath }
|
|
48
|
-
} else {
|
|
49
|
-
result = { path, leaf }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.clear()
|
|
53
|
-
|
|
54
|
-
return result
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public getPath(leaf: ILeaf): LeafList {
|
|
59
|
-
const list: LeafList = new LeafList()
|
|
60
|
-
while (leaf) {
|
|
61
|
-
list.push(leaf)
|
|
62
|
-
leaf = leaf.parent
|
|
63
|
-
}
|
|
64
|
-
return list
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
protected eachThroughFind(children: Array<ILeaf>): void {
|
|
68
|
-
let child: ILeaf
|
|
69
|
-
const { point } = this, len = children.length
|
|
70
|
-
for (let i = len - 1; i > -1; i--) {
|
|
71
|
-
child = children[i]
|
|
72
|
-
if (child.__interactionOff) continue
|
|
73
|
-
|
|
74
|
-
if (hitRadiusPoint(child.__world, point)) {
|
|
75
|
-
if (child.__isBranch) {
|
|
76
|
-
child.__childrenInteractionOff || this.eachThroughFind(child.children)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (this.exclude && this.exclude.has(child)) continue
|
|
80
|
-
if (child.__hitWorld(point)) this.throughPath.push(child)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
protected eachFind(children: Array<ILeaf>): void {
|
|
87
|
-
let child: ILeaf
|
|
88
|
-
const { point } = this, len = children.length
|
|
89
|
-
for (let i = len - 1; i > -1; i--) {
|
|
90
|
-
child = children[i]
|
|
91
|
-
if (child.__interactionOff) continue
|
|
92
|
-
|
|
93
|
-
if (hitRadiusPoint(child.__world, point)) {
|
|
94
|
-
if (child.__isBranch) {
|
|
95
|
-
|
|
96
|
-
child.__childrenInteractionOff || this.eachFind(child.children)
|
|
97
|
-
|
|
98
|
-
if (child.__isBranchLeaf) { // 填充了背景色的Group, 如画板/Frame元素
|
|
99
|
-
if (!this.isStop) this.hitChild(child, point)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
} else {
|
|
103
|
-
this.hitChild(child, point)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (this.isStop) break
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
protected hitChild(child: ILeaf, point: IRadiusPointData): void {
|
|
112
|
-
if (this.exclude && this.exclude.has(child)) return
|
|
113
|
-
if (child.__hitWorld(point)) {
|
|
114
|
-
this.leaf = child
|
|
115
|
-
this.isStop = true
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
protected clear(): void {
|
|
120
|
-
this.point = undefined
|
|
121
|
-
this.leaf = undefined
|
|
122
|
-
this.throughPath = undefined
|
|
123
|
-
this.exclude = undefined
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
public destroy(): void {
|
|
127
|
-
this.target = undefined
|
|
128
|
-
this.selector = undefined
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
}
|