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