@leafer/selector 1.0.0-rc.1 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leafer/selector",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.10",
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.1"
25
+ "@leafer/core": "1.0.0-rc.10"
26
26
  },
27
27
  "devDependencies": {
28
- "@leafer/interface": "1.0.0-rc.1"
28
+ "@leafer/interface": "1.0.0-rc.10"
29
29
  }
30
30
  }
@@ -1,10 +1,10 @@
1
- import { ILeaf, ILeafList, IPointData, IRadiusPointData, ISelectPathResult, ISelectPathOptions, ISelector } from '@leafer/interface'
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 FindPath {
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?: ISelectPathOptions): ISelectPathResult {
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(this.target.children, this.target.__onlyHitMask)
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,10 +64,10 @@ export class FindPath {
63
64
  public getPath(leaf: ILeaf): LeafList {
64
65
  const path = new LeafList()
65
66
  while (leaf) {
66
- path.push(leaf)
67
+ path.add(leaf)
67
68
  leaf = leaf.parent
68
69
  }
69
- path.push(this.target)
70
+ path.add(this.target)
70
71
  return path
71
72
  }
72
73
 
@@ -76,7 +77,7 @@ export class FindPath {
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.unshift(item)
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.push(leaf)
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: Array<ILeaf>, hitMask: boolean): void {
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.__.isMask)) continue
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, ILeafArrayMap, ILeafMap, ISelector, ISelectPathResult, ISelectPathOptions, IPointData, IEventListenerId, ISelectorConfig } from '@leafer/interface'
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 { FindPath } from './FindPath'
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 findPath: FindPath
19
+ protected picker: Picker
20
+
21
+ protected innerIdMap: ILeafMap = {}
22
+ protected idMap: ILeafMap = {}
19
23
 
20
- protected innerIdList: ILeafMap = {}
21
- protected idList: ILeafMap = {}
22
- protected classNameList: ILeafArrayMap = {}
23
- protected tagNameList: ILeafArrayMap = {}
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.findPath = new FindPath(target, this)
39
+ this.picker = new Picker(target, this)
31
40
  this.__listenEvents()
32
41
  }
33
42
 
34
- public getByPoint(hitPoint: IPointData, hitRadius: number, options?: ISelectPathOptions): ISelectPathResult {
35
- if (Platform.name === 'node') this.target.emit(LayoutEvent.CHECK_UPDATE)
36
- return this.findPath.getByPoint(hitPoint, hitRadius, options)
37
- }
38
-
39
- public find(name: number | string, branch?: ILeaf): ILeaf | ILeaf[] {
40
- if (typeof name === 'number') {
41
- return this.getByInnerId(name, branch)
42
- } else if (name.startsWith('#')) {
43
- return this.getById(name.substring(1), branch)
44
- } else if (name.startsWith('.')) {
45
- return this.getByClassName(name.substring(1), branch)
46
- } else {
47
- return this.getByTagName(name, branch)
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 getByInnerId(name: number, branch?: ILeaf): ILeaf {
52
- let cache = this.innerIdList[name]
53
- if (cache) return cache
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 getById(name: string, branch?: ILeaf): ILeaf {
69
- let cache = this.idList[name]
68
+ public getByInnerId(innerId: number, branch?: ILeaf): ILeaf {
69
+ const cache = this.innerIdMap[innerId]
70
70
  if (cache) return cache
71
- if (!branch) branch = this.target
72
- let find: ILeaf
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 getByClassName(name: string, branch?: ILeaf): ILeaf[] {
86
- if (!branch) branch = this.target
87
- let find: Array<ILeaf | ILeaf> = []
88
- this.loopFind(branch, (leaf) => {
89
- if (leaf.className === name) find.push(leaf)
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 getByTagName(name: string, branch?: ILeaf): ILeaf[] {
96
- if (!branch) branch = this.target
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
- protected loopFind(branch: ILeaf, find: IFind): void {
106
- if (find(branch)) return
107
- const { children } = branch
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
- branch = children[i] as ILeaf
110
- if (find(branch)) return
111
- if (branch.isBranch) this.loopFind(branch, find)
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 target = event.target as ILeaf
117
- if (this.idList[target.id]) this.idList[target.id] = null
118
- if (this.innerIdList[target.id]) this.innerIdList[target.innerId] = null
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.findPath.destroy()
137
- this.innerIdList = {}
138
- this.idList = {}
139
- this.classNameList = {}
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, ISelectPathOptions, ISelectPathResult, ISelectorConfig, ILeafMap, ILeafArrayMap, IEventListenerId } from '@leafer/interface';
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 FindPath {
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?: ISelectPathOptions): ISelectPathResult;
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: Array<ILeaf>, hitMask: boolean): void;
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 findPath: FindPath;
29
- protected innerIdList: ILeafMap;
30
- protected idList: ILeafMap;
31
- protected classNameList: ILeafArrayMap;
32
- protected tagNameList: ILeafArrayMap;
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
- getByPoint(hitPoint: IPointData, hitRadius: number, options?: ISelectPathOptions): ISelectPathResult;
36
- find(name: number | string, branch?: ILeaf): ILeaf | ILeaf[];
37
- getByInnerId(name: number, branch?: ILeaf): ILeaf;
38
- getById(name: string, branch?: ILeaf): ILeaf;
39
- getByClassName(name: string, branch?: ILeaf): ILeaf[];
40
- getByTagName(name: string, branch?: ILeaf): ILeaf[];
41
- protected loopFind(branch: ILeaf, find: IFind): void;
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;