@leafer/selector 1.0.0-beta.9 → 1.0.0-rc.10
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 +8 -7
- package/src/{FindPath.ts → Picker.ts} +16 -18
- package/src/Selector.ts +100 -92
- package/types/index.d.ts +54 -0
package/package.json
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/selector",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-rc.10",
|
|
4
4
|
"description": "@leafer/selector",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
|
+
"types": "types/index.d.ts",
|
|
8
9
|
"files": [
|
|
9
|
-
"src"
|
|
10
|
+
"src",
|
|
11
|
+
"types",
|
|
12
|
+
"dist"
|
|
10
13
|
],
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
|
13
16
|
"url": "https://github.com/leaferjs/leafer.git"
|
|
14
17
|
},
|
|
15
|
-
"homepage": "https://github.com/leaferjs/leafer/tree/main/packages/selector",
|
|
18
|
+
"homepage": "https://github.com/leaferjs/leafer/tree/main/packages/partner/selector",
|
|
16
19
|
"bugs": "https://github.com/leaferjs/leafer/issues",
|
|
17
20
|
"keywords": [
|
|
18
21
|
"leafer",
|
|
19
22
|
"leaferjs"
|
|
20
23
|
],
|
|
21
24
|
"dependencies": {
|
|
22
|
-
"@leafer/
|
|
23
|
-
"@leafer/math": "1.0.0-beta.9",
|
|
24
|
-
"@leafer/list": "1.0.0-beta.9"
|
|
25
|
+
"@leafer/core": "1.0.0-rc.10"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"@leafer/interface": "1.0.0-
|
|
28
|
+
"@leafer/interface": "1.0.0-rc.10"
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { ILeaf, ILeafList, IPointData, IRadiusPointData,
|
|
2
|
-
import { BoundsHelper } from '@leafer/
|
|
3
|
-
import { LeafList } from '@leafer/list'
|
|
4
|
-
import { LeafHelper } from '@leafer/helper'
|
|
1
|
+
import { ILeaf, ILeafList, IPointData, IRadiusPointData, IPickResult, IPickOptions, ISelector } from '@leafer/interface'
|
|
2
|
+
import { BoundsHelper, LeafList, LeafHelper } from '@leafer/core'
|
|
5
3
|
|
|
6
4
|
|
|
7
5
|
const { hitRadiusPoint } = BoundsHelper
|
|
8
6
|
|
|
9
|
-
export class
|
|
7
|
+
export class Picker {
|
|
10
8
|
|
|
11
9
|
protected target: ILeaf
|
|
12
10
|
protected selector: ISelector
|
|
@@ -21,19 +19,20 @@ export class FindPath {
|
|
|
21
19
|
this.selector = selector
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
public getByPoint(hitPoint: IPointData, hitRadius: number, options?:
|
|
22
|
+
public getByPoint(hitPoint: IPointData, hitRadius: number, options?: IPickOptions): IPickResult {
|
|
25
23
|
if (!hitRadius) hitRadius = 0
|
|
26
24
|
if (!options) options = {}
|
|
27
25
|
|
|
28
26
|
const through = options.through || false
|
|
29
27
|
const ignoreHittable = options.ignoreHittable || false
|
|
28
|
+
const target = options.target || this.target
|
|
30
29
|
this.exclude = options.exclude || null
|
|
31
30
|
|
|
32
31
|
this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius }
|
|
33
|
-
this.findList = []
|
|
32
|
+
this.findList = options.findList || []
|
|
34
33
|
|
|
35
34
|
// path
|
|
36
|
-
this.eachFind(
|
|
35
|
+
if (!options.findList) this.eachFind(target.children, target.__onlyHitMask)
|
|
37
36
|
|
|
38
37
|
const list = this.findList
|
|
39
38
|
const leaf = this.getBestMatchLeaf()
|
|
@@ -41,7 +40,7 @@ export class FindPath {
|
|
|
41
40
|
|
|
42
41
|
this.clear()
|
|
43
42
|
|
|
44
|
-
return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf }
|
|
43
|
+
return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf }
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
public getBestMatchLeaf(): ILeaf {
|
|
@@ -65,10 +64,10 @@ export class FindPath {
|
|
|
65
64
|
public getPath(leaf: ILeaf): LeafList {
|
|
66
65
|
const path = new LeafList()
|
|
67
66
|
while (leaf) {
|
|
68
|
-
path.
|
|
67
|
+
path.add(leaf)
|
|
69
68
|
leaf = leaf.parent
|
|
70
69
|
}
|
|
71
|
-
path.
|
|
70
|
+
path.add(this.target)
|
|
72
71
|
return path
|
|
73
72
|
}
|
|
74
73
|
|
|
@@ -78,7 +77,7 @@ export class FindPath {
|
|
|
78
77
|
for (let i = path.list.length - 1; i > -1; i--) {
|
|
79
78
|
item = path.list[i]
|
|
80
79
|
if (!item.__.hittable) break
|
|
81
|
-
hittablePath.
|
|
80
|
+
hittablePath.addAt(item, 0)
|
|
82
81
|
if (!item.__.hitChildren) break
|
|
83
82
|
}
|
|
84
83
|
return hittablePath
|
|
@@ -98,7 +97,7 @@ export class FindPath {
|
|
|
98
97
|
for (let j = 0, jLen = path.length; j < jLen; j++) {
|
|
99
98
|
leaf = path.list[j]
|
|
100
99
|
if (nextPath && nextPath.has(leaf)) break
|
|
101
|
-
throughPath.
|
|
100
|
+
throughPath.add(leaf)
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
103
|
|
|
@@ -106,13 +105,13 @@ export class FindPath {
|
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
|
|
109
|
-
protected eachFind(children:
|
|
108
|
+
protected eachFind(children: ILeaf[], hitMask: boolean): void {
|
|
110
109
|
let child: ILeaf, hit: boolean
|
|
111
110
|
const { point } = this, len = children.length
|
|
112
111
|
for (let i = len - 1; i > -1; i--) {
|
|
113
112
|
child = children[i]
|
|
114
|
-
if (hitMask && !child.
|
|
115
|
-
hit = hitRadiusPoint(child.__world, point)
|
|
113
|
+
if (!child.__.visible || (hitMask && !child.__.mask)) continue
|
|
114
|
+
hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point)
|
|
116
115
|
|
|
117
116
|
if (child.isBranch) {
|
|
118
117
|
if (hit || child.__ignoreHitWorld) {
|
|
@@ -137,8 +136,7 @@ export class FindPath {
|
|
|
137
136
|
}
|
|
138
137
|
|
|
139
138
|
public destroy(): void {
|
|
140
|
-
this.
|
|
141
|
-
this.selector = null
|
|
139
|
+
this.clear()
|
|
142
140
|
}
|
|
143
141
|
|
|
144
142
|
}
|
package/src/Selector.ts
CHANGED
|
@@ -1,147 +1,155 @@
|
|
|
1
|
-
import { ILeaf,
|
|
2
|
-
import { ChildEvent, LayoutEvent } from '@leafer/
|
|
3
|
-
import { DataHelper } from '@leafer/data'
|
|
4
|
-
import { Platform } from '@leafer/platform'
|
|
1
|
+
import { ILeaf, ILeafMap, ISelector, ISelectorProxy, IPickResult, IPickOptions, IPointData, IEventListenerId, ISelectorConfig, IFindMethod, IAnswer } from '@leafer/interface'
|
|
2
|
+
import { ChildEvent, LayoutEvent, DataHelper, Answer, Platform, PropertyEvent, LeafHelper } from '@leafer/core'
|
|
5
3
|
|
|
6
|
-
import {
|
|
4
|
+
import { Picker } from './Picker'
|
|
7
5
|
|
|
8
6
|
|
|
9
|
-
interface IFind {
|
|
10
|
-
(leaf: ILeaf): boolean
|
|
11
|
-
}
|
|
12
7
|
|
|
13
8
|
|
|
9
|
+
const { Yes, NoAndSkip, YesAndSkip } = Answer
|
|
10
|
+
|
|
14
11
|
export class Selector implements ISelector {
|
|
15
12
|
|
|
16
13
|
public target: ILeaf
|
|
17
14
|
|
|
15
|
+
public proxy?: ISelectorProxy // editor
|
|
16
|
+
|
|
18
17
|
public config: ISelectorConfig = {}
|
|
19
18
|
|
|
20
|
-
protected
|
|
19
|
+
protected picker: Picker
|
|
20
|
+
|
|
21
|
+
protected innerIdMap: ILeafMap = {}
|
|
22
|
+
protected idMap: ILeafMap = {}
|
|
21
23
|
|
|
22
|
-
protected
|
|
23
|
-
|
|
24
|
-
protected
|
|
25
|
-
|
|
24
|
+
protected findLeaf: ILeaf
|
|
25
|
+
|
|
26
|
+
protected methods = {
|
|
27
|
+
id: (leaf: ILeaf, name: string) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
|
|
28
|
+
innerId: (leaf: ILeaf, innerId: number) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
|
|
29
|
+
className: (leaf: ILeaf, name: string) => leaf.className === name ? 1 : 0,
|
|
30
|
+
tag: (leaf: ILeaf, name: string) => leaf.__tag === name ? 1 : 0
|
|
31
|
+
}
|
|
26
32
|
|
|
27
33
|
protected __eventIds: IEventListenerId[]
|
|
28
34
|
|
|
35
|
+
|
|
29
36
|
constructor(target: ILeaf, userConfig?: ISelectorConfig) {
|
|
30
37
|
this.target = target
|
|
31
38
|
if (userConfig) this.config = DataHelper.default(userConfig, this.config)
|
|
32
|
-
this.
|
|
39
|
+
this.picker = new Picker(target, this)
|
|
33
40
|
this.__listenEvents()
|
|
34
41
|
}
|
|
35
42
|
|
|
36
|
-
public
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
public getBy(condition: number | string | IFindMethod, branch?: ILeaf, one?: boolean, options?: any): ILeaf | ILeaf[] {
|
|
44
|
+
switch (typeof condition) {
|
|
45
|
+
case 'number':
|
|
46
|
+
const leaf = this.getByInnerId(condition, branch)
|
|
47
|
+
return one ? leaf : (leaf ? [leaf] : [])
|
|
48
|
+
case 'string':
|
|
49
|
+
switch (condition[0]) {
|
|
50
|
+
case '#':
|
|
51
|
+
const leaf = this.getById(condition.substring(1), branch)
|
|
52
|
+
return one ? leaf : (leaf ? [leaf] : [])
|
|
53
|
+
case '.':
|
|
54
|
+
return this.getByMethod(this.methods.className, branch, one, condition.substring(1)) // className
|
|
55
|
+
default:
|
|
56
|
+
return this.getByMethod(this.methods.tag, branch, one, condition) // tagName
|
|
57
|
+
}
|
|
58
|
+
case 'function':
|
|
59
|
+
return this.getByMethod(condition as IFindMethod, branch, one, options)
|
|
50
60
|
}
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
public
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!branch) branch = this.target
|
|
57
|
-
let find: ILeaf
|
|
58
|
-
this.loopFind(branch, (leaf) => {
|
|
59
|
-
if (leaf.innerId === name) {
|
|
60
|
-
find = leaf
|
|
61
|
-
this.innerIdList[name] = find
|
|
62
|
-
return true
|
|
63
|
-
} else {
|
|
64
|
-
return false
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
return find
|
|
63
|
+
public getByPoint(hitPoint: IPointData, hitRadius: number, options?: IPickOptions): IPickResult {
|
|
64
|
+
if (Platform.name === 'node') this.target.emit(LayoutEvent.CHECK_UPDATE)
|
|
65
|
+
return this.picker.getByPoint(hitPoint, hitRadius, options)
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
public
|
|
71
|
-
|
|
68
|
+
public getByInnerId(innerId: number, branch?: ILeaf): ILeaf {
|
|
69
|
+
const cache = this.innerIdMap[innerId]
|
|
72
70
|
if (cache) return cache
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.loopFind(branch, (leaf) => {
|
|
76
|
-
if (leaf.id === name) {
|
|
77
|
-
find = leaf
|
|
78
|
-
this.idList[name] = find
|
|
79
|
-
return true
|
|
80
|
-
} else {
|
|
81
|
-
return false
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
return find
|
|
71
|
+
this.eachFind(this.toChildren(branch), this.methods.innerId, null, innerId)
|
|
72
|
+
return this.findLeaf
|
|
85
73
|
}
|
|
86
74
|
|
|
87
|
-
public
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.
|
|
91
|
-
|
|
92
|
-
return false
|
|
93
|
-
})
|
|
94
|
-
return find
|
|
75
|
+
public getById(id: string, branch?: ILeaf): ILeaf {
|
|
76
|
+
const cache = this.idMap[id]
|
|
77
|
+
if (cache && LeafHelper.hasParent(cache, branch || this.target)) return cache
|
|
78
|
+
this.eachFind(this.toChildren(branch), this.methods.id, null, id)
|
|
79
|
+
return this.findLeaf
|
|
95
80
|
}
|
|
96
81
|
|
|
97
|
-
public
|
|
98
|
-
|
|
99
|
-
let find: Array<ILeaf | ILeaf> = []
|
|
100
|
-
this.loopFind(branch, (leaf) => {
|
|
101
|
-
if (leaf.__tag === name) find.push(leaf)
|
|
102
|
-
return false
|
|
103
|
-
})
|
|
104
|
-
return find
|
|
82
|
+
public getByClassName(className: string, branch?: ILeaf): ILeaf[] {
|
|
83
|
+
return this.getByMethod(this.methods.className, branch, false, className) as ILeaf[]
|
|
105
84
|
}
|
|
106
85
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
86
|
+
public getByTag(tag: string, branch?: ILeaf): ILeaf[] {
|
|
87
|
+
return this.getByMethod(this.methods.tag, branch, false, tag) as ILeaf[]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public getByMethod(method: IFindMethod, branch?: ILeaf, one?: boolean, options?: any): ILeaf[] | ILeaf {
|
|
91
|
+
const list: ILeaf[] = one ? null : []
|
|
92
|
+
this.eachFind(this.toChildren(branch), method, list, options)
|
|
93
|
+
return list || this.findLeaf
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
protected eachFind(children: ILeaf[], method: IFindMethod, list?: ILeaf[], options?: any): void {
|
|
98
|
+
let child: ILeaf, result: IAnswer
|
|
110
99
|
for (let i = 0, len = children.length; i < len; i++) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (
|
|
100
|
+
child = children[i]
|
|
101
|
+
result = method(child, options)
|
|
102
|
+
if (result === Yes || result === YesAndSkip) {
|
|
103
|
+
if (list) {
|
|
104
|
+
list.push(child)
|
|
105
|
+
} else {
|
|
106
|
+
this.findLeaf = child
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (child.isBranch && result < NoAndSkip) this.eachFind(child.children, method, list, options)
|
|
114
111
|
}
|
|
115
112
|
}
|
|
116
113
|
|
|
114
|
+
protected toChildren(branch: ILeaf): ILeaf[] {
|
|
115
|
+
this.findLeaf = null
|
|
116
|
+
return [branch || this.target]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
117
120
|
protected __onRemoveChild(event: ChildEvent): void {
|
|
118
|
-
const
|
|
119
|
-
if (this.
|
|
120
|
-
if (this.
|
|
121
|
+
const { id, innerId } = event.child
|
|
122
|
+
if (this.idMap[id]) delete this.idMap[id]
|
|
123
|
+
if (this.innerIdMap[innerId]) delete this.innerIdMap[innerId]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
protected __checkIdChange(event: PropertyEvent): void {
|
|
127
|
+
if (event.attrName === 'id') {
|
|
128
|
+
const id = event.oldValue as string
|
|
129
|
+
if (this.idMap[id]) delete this.idMap[id]
|
|
130
|
+
}
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
|
|
124
134
|
protected __listenEvents(): void {
|
|
125
135
|
this.__eventIds = [
|
|
126
|
-
this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this)
|
|
136
|
+
this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this),
|
|
137
|
+
this.target.on_(PropertyEvent.CHANGE, this.__checkIdChange, this)
|
|
127
138
|
]
|
|
128
139
|
}
|
|
129
140
|
|
|
130
141
|
protected __removeListenEvents(): void {
|
|
131
142
|
this.target.off_(this.__eventIds)
|
|
143
|
+
this.__eventIds.length = 0
|
|
132
144
|
}
|
|
133
145
|
|
|
134
146
|
public destroy(): void {
|
|
135
|
-
if (this.
|
|
147
|
+
if (this.__eventIds.length) {
|
|
136
148
|
this.__removeListenEvents()
|
|
137
|
-
this.
|
|
138
|
-
|
|
139
|
-
this.
|
|
140
|
-
this.
|
|
141
|
-
this.innerIdList = null
|
|
142
|
-
this.idList = null
|
|
143
|
-
this.classNameList = null
|
|
144
|
-
this.tagNameList = null
|
|
149
|
+
this.picker.destroy()
|
|
150
|
+
this.findLeaf = null
|
|
151
|
+
this.innerIdMap = {}
|
|
152
|
+
this.idMap = {}
|
|
145
153
|
}
|
|
146
154
|
}
|
|
147
155
|
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ILeaf, ISelector, ILeafList, IRadiusPointData, IPointData, IPickOptions, IPickResult, ISelectorProxy, ISelectorConfig, ILeafMap, IEventListenerId, IFindMethod } from '@leafer/interface';
|
|
2
|
+
import { LeafList, ChildEvent, PropertyEvent } from '@leafer/core';
|
|
3
|
+
|
|
4
|
+
declare class Picker {
|
|
5
|
+
protected target: ILeaf;
|
|
6
|
+
protected selector: ISelector;
|
|
7
|
+
protected findList: ILeaf[];
|
|
8
|
+
protected exclude: ILeafList;
|
|
9
|
+
protected point: IRadiusPointData;
|
|
10
|
+
constructor(target: ILeaf, selector: ISelector);
|
|
11
|
+
getByPoint(hitPoint: IPointData, hitRadius: number, options?: IPickOptions): IPickResult;
|
|
12
|
+
getBestMatchLeaf(): ILeaf;
|
|
13
|
+
getPath(leaf: ILeaf): LeafList;
|
|
14
|
+
getHitablePath(leaf: ILeaf): LeafList;
|
|
15
|
+
getThroughPath(list: ILeaf[]): LeafList;
|
|
16
|
+
protected eachFind(children: ILeaf[], hitMask: boolean): void;
|
|
17
|
+
protected hitChild(child: ILeaf, point: IRadiusPointData): void;
|
|
18
|
+
protected clear(): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare class Selector implements ISelector {
|
|
23
|
+
target: ILeaf;
|
|
24
|
+
proxy?: ISelectorProxy;
|
|
25
|
+
config: ISelectorConfig;
|
|
26
|
+
protected picker: Picker;
|
|
27
|
+
protected innerIdMap: ILeafMap;
|
|
28
|
+
protected idMap: ILeafMap;
|
|
29
|
+
protected findLeaf: ILeaf;
|
|
30
|
+
protected methods: {
|
|
31
|
+
id: (leaf: ILeaf, name: string) => 1 | 0;
|
|
32
|
+
innerId: (leaf: ILeaf, innerId: number) => 1 | 0;
|
|
33
|
+
className: (leaf: ILeaf, name: string) => 1 | 0;
|
|
34
|
+
tag: (leaf: ILeaf, name: string) => 1 | 0;
|
|
35
|
+
};
|
|
36
|
+
protected __eventIds: IEventListenerId[];
|
|
37
|
+
constructor(target: ILeaf, userConfig?: ISelectorConfig);
|
|
38
|
+
getBy(condition: number | string | IFindMethod, branch?: ILeaf, one?: boolean, options?: any): ILeaf | ILeaf[];
|
|
39
|
+
getByPoint(hitPoint: IPointData, hitRadius: number, options?: IPickOptions): IPickResult;
|
|
40
|
+
getByInnerId(innerId: number, branch?: ILeaf): ILeaf;
|
|
41
|
+
getById(id: string, branch?: ILeaf): ILeaf;
|
|
42
|
+
getByClassName(className: string, branch?: ILeaf): ILeaf[];
|
|
43
|
+
getByTag(tag: string, branch?: ILeaf): ILeaf[];
|
|
44
|
+
getByMethod(method: IFindMethod, branch?: ILeaf, one?: boolean, options?: any): ILeaf[] | ILeaf;
|
|
45
|
+
protected eachFind(children: ILeaf[], method: IFindMethod, list?: ILeaf[], options?: any): void;
|
|
46
|
+
protected toChildren(branch: ILeaf): ILeaf[];
|
|
47
|
+
protected __onRemoveChild(event: ChildEvent): void;
|
|
48
|
+
protected __checkIdChange(event: PropertyEvent): void;
|
|
49
|
+
protected __listenEvents(): void;
|
|
50
|
+
protected __removeListenEvents(): void;
|
|
51
|
+
destroy(): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { Selector };
|