@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 CHANGED
@@ -1,29 +1,30 @@
1
1
  {
2
2
  "name": "@leafer/selector",
3
- "version": "1.0.0-beta.9",
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/event": "1.0.0-beta.9",
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-beta.9"
28
+ "@leafer/interface": "1.0.0-rc.10"
28
29
  }
29
30
  }
@@ -1,12 +1,10 @@
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
- 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 FindPath {
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?: ISelectPathOptions): ISelectPathResult {
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(this.target.children, this.target.__onlyHitMask)
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.push(leaf)
67
+ path.add(leaf)
69
68
  leaf = leaf.parent
70
69
  }
71
- path.push(this.target)
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.unshift(item)
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.push(leaf)
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: Array<ILeaf>, hitMask: boolean): void {
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.isMask) continue
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.target = null
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, 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
- 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 { FindPath } from './FindPath'
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 findPath: FindPath
19
+ protected picker: Picker
20
+
21
+ protected innerIdMap: ILeafMap = {}
22
+ protected idMap: ILeafMap = {}
21
23
 
22
- protected innerIdList: ILeafMap = {}
23
- protected idList: ILeafMap = {}
24
- protected classNameList: ILeafArrayMap = {}
25
- 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
+ }
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.findPath = new FindPath(target, this)
39
+ this.picker = new Picker(target, this)
33
40
  this.__listenEvents()
34
41
  }
35
42
 
36
- public getByPoint(hitPoint: IPointData, hitRadius: number, options?: ISelectPathOptions): ISelectPathResult {
37
- if (Platform.name === 'node') this.target.emit(LayoutEvent.CHECK_UPDATE)
38
- return this.findPath.getByPoint(hitPoint, hitRadius, options)
39
- }
40
-
41
- public find(name: number | string, branch?: ILeaf): ILeaf | ILeaf[] {
42
- if (typeof name === 'number') {
43
- return this.getByInnerId(name, branch)
44
- } else if (name.startsWith('#')) {
45
- return this.getById(name.substring(1), branch)
46
- } else if (name.startsWith('.')) {
47
- return this.getByClassName(name.substring(1), branch)
48
- } else {
49
- 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)
50
60
  }
51
61
  }
52
62
 
53
- public getByInnerId(name: number, branch?: ILeaf): ILeaf {
54
- let cache = this.innerIdList[name]
55
- if (cache) return cache
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 getById(name: string, branch?: ILeaf): ILeaf {
71
- let cache = this.idList[name]
68
+ public getByInnerId(innerId: number, branch?: ILeaf): ILeaf {
69
+ const cache = this.innerIdMap[innerId]
72
70
  if (cache) return cache
73
- if (!branch) branch = this.target
74
- let find: ILeaf
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 getByClassName(name: string, branch?: ILeaf): ILeaf[] {
88
- if (!branch) branch = this.target
89
- let find: Array<ILeaf | ILeaf> = []
90
- this.loopFind(branch, (leaf) => {
91
- if (leaf.className === name) find.push(leaf)
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 getByTagName(name: string, branch?: ILeaf): ILeaf[] {
98
- if (!branch) branch = this.target
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
- protected loopFind(branch: ILeaf, find: IFind): void {
108
- if (find(branch)) return
109
- 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
110
99
  for (let i = 0, len = children.length; i < len; i++) {
111
- branch = children[i] as ILeaf
112
- if (find(branch)) return
113
- 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)
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 target = event.target as ILeaf
119
- if (this.idList[target.id]) this.idList[target.id] = null
120
- 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
+ }
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.target) {
147
+ if (this.__eventIds.length) {
136
148
  this.__removeListenEvents()
137
- this.findPath.destroy()
138
-
139
- this.target = null
140
- this.findPath = null
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
 
@@ -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 };