@leafer-ui/interaction 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023-present, Chao (Leafer) Wan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # @leafer-ui/interaction
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@leafer-ui/interaction",
3
+ "version": "1.0.0-rc.10",
4
+ "description": "@leafer-ui/interaction",
5
+ "author": "Chao (Leafer) Wan",
6
+ "license": "MIT",
7
+ "main": "src/index.ts",
8
+ "types": "types/index.d.ts",
9
+ "files": [
10
+ "src",
11
+ "types",
12
+ "dist"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/leaferjs/ui.git"
17
+ },
18
+ "homepage": "https://github.com/leaferjs/ui/tree/main/packages/interaction/interaction",
19
+ "bugs": "https://github.com/leaferjs/ui/issues",
20
+ "keywords": [
21
+ "leafer-ui",
22
+ "leaferjs"
23
+ ],
24
+ "dependencies": {
25
+ "@leafer/core": "1.0.0-rc.10",
26
+ "@leafer-ui/event": "1.0.0-rc.10"
27
+ },
28
+ "devDependencies": {
29
+ "@leafer/interface": "1.0.0-rc.10"
30
+ }
31
+ }
package/src/Cursor.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { ICursorTypeMap, ICursorType } from '@leafer/interface'
2
+
3
+
4
+ export class Cursor {
5
+
6
+ static custom: ICursorTypeMap = {}
7
+
8
+ static set(name: string, value: ICursorType | ICursorType[]): void {
9
+ this.custom[name] = value
10
+ }
11
+
12
+ static get(name: string): ICursorType | ICursorType[] {
13
+ return this.custom[name]
14
+ }
15
+
16
+ }
package/src/Dragger.ts ADDED
@@ -0,0 +1,252 @@
1
+ import { IPointerEvent, IDragEvent, ILeaf, ILeafList, ITimer, IFunction } from '@leafer/interface'
2
+ import { BoundsHelper, PointHelper, LeafHelper, LeafList } from '@leafer/core'
3
+
4
+ import { MoveEvent, DragEvent, DropEvent, PointerButton } from '@leafer-ui/event'
5
+
6
+ import { InteractionHelper } from './InteractionHelper'
7
+ import { InteractionBase } from './Interaction'
8
+
9
+
10
+ const emptyList = new LeafList()
11
+ const { getDragEventData, getDropEventData, getSwipeEventData } = InteractionHelper
12
+
13
+ export class Dragger {
14
+
15
+ protected interaction: InteractionBase
16
+
17
+ public moving: boolean
18
+ public dragging: boolean
19
+
20
+ public dragData: IDragEvent
21
+ protected downData: IPointerEvent
22
+
23
+ public dragableList: ILeafList
24
+ protected dragOverPath: ILeafList
25
+ protected dragEnterPath: ILeafList
26
+
27
+ protected autoMoveTimer: ITimer
28
+
29
+ protected canAnimate: boolean
30
+ protected animateWait: IFunction
31
+
32
+ constructor(interaction: InteractionBase) {
33
+ this.interaction = interaction
34
+ }
35
+
36
+ public setDragData(data: IPointerEvent): void { // pointer down
37
+ if (this.animateWait) this.dragEndReal()
38
+ this.downData = this.interaction.downData
39
+ this.dragData = getDragEventData(data, data, data)
40
+ }
41
+
42
+ public getList(): ILeafList {
43
+ const { proxy } = this.interaction.selector
44
+ return this.dragging && (!proxy || !proxy.list.length) ? (DragEvent.list || this.dragableList || emptyList) : emptyList
45
+ }
46
+
47
+ public checkDrag(data: IPointerEvent, canDrag: boolean): void {
48
+ const { interaction } = this
49
+
50
+ if (this.moving && data.buttons < 1) {
51
+ this.canAnimate = false // 防止dragEnd动画
52
+ interaction.pointerCancel() // 按住中键/右键拖出页面后的up事件接收不到
53
+ return
54
+ } else {
55
+ this.canAnimate = true
56
+ }
57
+
58
+ if (!this.moving && canDrag) {
59
+ if (this.moving = interaction.moveMode || interaction.isHoldRightKey) interaction.emit(MoveEvent.START, this.dragData)
60
+ }
61
+
62
+ if (!this.moving) {
63
+ this.dragStart(data, canDrag)
64
+ }
65
+
66
+ this.drag(data)
67
+ }
68
+
69
+ public dragStart(data: IPointerEvent, canDrag: boolean): void {
70
+ if (!this.dragging) {
71
+ this.dragging = canDrag && PointerButton.left(data)
72
+ if (this.dragging) {
73
+ this.interaction.emit(DragEvent.START, this.dragData)
74
+ this.getDragableList(this.dragData.path)
75
+ }
76
+ }
77
+ }
78
+
79
+ protected getDragableList(path: ILeafList): void {
80
+ let leaf: ILeaf
81
+ for (let i = 0, len = path.length; i < len; i++) {
82
+ leaf = path.list[i]
83
+ if ((leaf.__.draggable || leaf.__.editable) && leaf.__.hitSelf && !leaf.__.locked) {
84
+ this.dragableList = new LeafList(leaf)
85
+ break
86
+ }
87
+ }
88
+ }
89
+
90
+ protected drag(data: IPointerEvent): void {
91
+ const { interaction, dragData, downData } = this
92
+ const { path, throughPath } = downData
93
+ this.dragData = getDragEventData(downData, dragData, data)
94
+ if (throughPath) this.dragData.throughPath = throughPath
95
+ this.dragData.path = path
96
+
97
+ if (this.moving) {
98
+ interaction.emit(MoveEvent.BEFORE_MOVE, this.dragData)
99
+ interaction.emit(MoveEvent.MOVE, this.dragData)
100
+ } else if (this.dragging) {
101
+ this.dragReal()
102
+ interaction.emit(DragEvent.BEFORE_DRAG, this.dragData)
103
+ interaction.emit(DragEvent.DRAG, this.dragData)
104
+ }
105
+ }
106
+
107
+ protected dragReal(): void {
108
+ const { running } = this.interaction
109
+ const list = this.getList()
110
+ if (list.length && running) {
111
+ const { moveX, moveY } = this.dragData
112
+ list.forEach(leaf => LeafHelper.moveWorld(leaf, moveX, moveY))
113
+ }
114
+ }
115
+
116
+ public dragOverOrOut(data: IPointerEvent): void {
117
+ const { interaction } = this
118
+ const { dragOverPath } = this
119
+ const { path } = data
120
+
121
+ if (dragOverPath) {
122
+ if (path.indexAt(0) !== dragOverPath.indexAt(0)) {
123
+ interaction.emit(DragEvent.OUT, data, dragOverPath)
124
+ interaction.emit(DragEvent.OVER, data, path)
125
+ }
126
+ } else {
127
+ interaction.emit(DragEvent.OVER, data, path)
128
+ }
129
+ this.dragOverPath = path
130
+ }
131
+
132
+ public dragEnterOrLeave(data: IPointerEvent): void {
133
+ const { interaction } = this
134
+ const { dragEnterPath } = this
135
+ const { path } = data
136
+
137
+ interaction.emit(DragEvent.LEAVE, data, dragEnterPath, path)
138
+ interaction.emit(DragEvent.ENTER, data, path, dragEnterPath)
139
+ this.dragEnterPath = path
140
+ }
141
+
142
+ public dragEnd(data: IPointerEvent, speed?: number): void {
143
+ if (!this.dragData) return
144
+
145
+ const { moveX, moveY } = this.dragData
146
+ if (this.canAnimate && this.moving && (Math.abs(moveX) > 1 || Math.abs(moveY) > 1)) {
147
+ data = { ...data }
148
+ speed = (speed || (data.pointerType === 'touch' ? 2 : 1)) * 0.9
149
+ PointHelper.move(data, moveX * speed, moveY * speed)
150
+
151
+ this.drag(data)
152
+ this.animate(() => { this.dragEnd(data, 1) })
153
+
154
+ } else {
155
+ this.dragEndReal(data)
156
+ }
157
+ }
158
+
159
+ protected dragEndReal(data?: IPointerEvent): void {
160
+ const { interaction, downData, dragData } = this
161
+ if (!data) data = dragData
162
+ const { path, throughPath } = downData
163
+ const endDragData = getDragEventData(downData, data, data)
164
+ if (throughPath) endDragData.throughPath = throughPath
165
+ endDragData.path = path
166
+
167
+ if (this.moving) interaction.emit(MoveEvent.END, endDragData)
168
+ if (this.dragging) {
169
+ interaction.emit(DragEvent.END, endDragData)
170
+
171
+ this.swipe(data, endDragData)
172
+ this.drop(data)
173
+ }
174
+
175
+ this.autoMoveCancel()
176
+ this.dragReset()
177
+ this.animate(null, 'off')
178
+ }
179
+
180
+ protected animate(func?: IFunction, off?: 'off'): void { // dragEnd animation
181
+ const animateWait = func || this.animateWait
182
+ if (animateWait) this.interaction.target.nextRender(animateWait, off)
183
+ this.animateWait = func
184
+ }
185
+
186
+
187
+ protected swipe(data: IPointerEvent, endDragData: IDragEvent): void {
188
+ const { interaction } = this
189
+ const { downData } = interaction
190
+ if (PointHelper.getDistance(downData, data) > interaction.config.pointer.swipeDistance) {
191
+ const swipeData = getSwipeEventData(downData, this.dragData, endDragData)
192
+ this.interaction.emit(swipeData.type, swipeData)
193
+ }
194
+ }
195
+
196
+ protected drop(data: IPointerEvent): void {
197
+ const dropData = getDropEventData(data, this.getList(), DragEvent.data)
198
+ dropData.path = this.dragEnterPath
199
+ this.interaction.emit(DropEvent.DROP, dropData)
200
+ this.interaction.emit(DragEvent.LEAVE, data, this.dragEnterPath)
201
+ }
202
+
203
+ protected dragReset(): void {
204
+ DragEvent.list = DragEvent.data = this.dragableList = this.dragData = this.downData = this.dragOverPath = this.dragEnterPath = null
205
+ this.dragging = this.moving = false
206
+ }
207
+
208
+
209
+ public checkDragOut(data: IPointerEvent): void {
210
+ const { interaction } = this
211
+ this.autoMoveCancel()
212
+ if (this.dragging && !interaction.shrinkCanvasBounds.hitPoint(data)) this.autoMoveOnDragOut(data)
213
+ }
214
+
215
+
216
+ protected autoMoveOnDragOut(data: IPointerEvent): void {
217
+ const { interaction, downData } = this
218
+ const { autoDistance, dragOut } = interaction.config.move
219
+ if (!dragOut || !autoDistance) return
220
+
221
+ const bounds = interaction.shrinkCanvasBounds
222
+ const { x, y } = bounds
223
+ const right = BoundsHelper.maxX(bounds)
224
+ const bottom = BoundsHelper.maxY(bounds)
225
+
226
+ const moveX = data.x < x ? autoDistance : (right < data.x ? -autoDistance : 0)
227
+ const moveY = data.y < y ? autoDistance : (bottom < data.y ? -autoDistance : 0)
228
+ let totalX = 0, totalY = 0
229
+
230
+ this.autoMoveTimer = setInterval(() => {
231
+ totalX += moveX
232
+ totalY += moveY
233
+
234
+ PointHelper.move(downData, moveX, moveY)
235
+ PointHelper.move(this.dragData, moveX, moveY)
236
+
237
+ interaction.move({ ...data, moveX, moveY, totalX, totalY })
238
+ interaction.pointerMoveReal(data)
239
+ }, 10)
240
+ }
241
+
242
+ protected autoMoveCancel(): void {
243
+ if (this.autoMoveTimer) {
244
+ clearInterval(this.autoMoveTimer)
245
+ this.autoMoveTimer = 0
246
+ }
247
+ }
248
+
249
+ public destroy(): void {
250
+ this.dragReset()
251
+ }
252
+ }
@@ -0,0 +1,45 @@
1
+ import { IScreenSizeData, IHitCanvasManager, ILeaf, IHitCanvas, ILeafList } from '@leafer/interface'
2
+ import { CanvasManager, LeafList, Creator } from '@leafer/core'
3
+
4
+
5
+ export class HitCanvasManager extends CanvasManager implements IHitCanvasManager {
6
+
7
+ protected pathTypeList: ILeafList = new LeafList()
8
+ protected imageTypeList: ILeafList = new LeafList()
9
+
10
+ public getImageType(leaf: ILeaf, size: IScreenSizeData): IHitCanvas {
11
+ this.imageTypeList.add(leaf)
12
+ return Creator.hitCanvas(size)
13
+ }
14
+
15
+ public getPathType(leaf: ILeaf): IHitCanvas {
16
+ this.pathTypeList.add(leaf)
17
+ return Creator.hitCanvas()
18
+ }
19
+
20
+ public clearImageType(): void {
21
+ this.__clearLeafList(this.imageTypeList)
22
+ }
23
+
24
+ public clearPathType(): void {
25
+ this.__clearLeafList(this.pathTypeList)
26
+ }
27
+
28
+ protected __clearLeafList(leafList: ILeafList): void {
29
+ if (leafList.length) {
30
+ leafList.forEach(leaf => {
31
+ if (leaf.__hitCanvas) {
32
+ leaf.__hitCanvas.destroy()
33
+ leaf.__hitCanvas = null
34
+ }
35
+ })
36
+ leafList.reset()
37
+ }
38
+ }
39
+
40
+ public clear(): void {
41
+ this.clearPathType()
42
+ this.clearImageType()
43
+ }
44
+
45
+ }
@@ -0,0 +1,456 @@
1
+ import { IUIEvent, IPointerEvent, ILeaf, IInteraction, IInteractionConfig, ILeafList, IMoveEvent, IZoomEvent, IRotateEvent, ISelector, IBounds, IEventListenerId, IInteractionCanvas, ITimer, IKeepTouchData, IKeyEvent, IPickOptions, ICursorType, IBooleanMap } from '@leafer/interface'
2
+ import { LeaferEvent, ResizeEvent, LeafList, Bounds, PointHelper, DataHelper } from '@leafer/core'
3
+
4
+ import { PointerEvent, DropEvent, KeyEvent, PointerButton, Keyboard } from '@leafer-ui/event'
5
+
6
+ import { Transformer } from './Transformer'
7
+ import { Dragger } from './Dragger'
8
+ import { emit } from './emit'
9
+ import { InteractionHelper } from './InteractionHelper'
10
+ import { MultiTouchHelper } from './MultiTouchHelper'
11
+ import { config } from './config'
12
+
13
+
14
+ const { pathHasEventType, getMoveEventData, getZoomEventData, getRotateEventData } = InteractionHelper
15
+ export class InteractionBase implements IInteraction {
16
+
17
+ public target: ILeaf
18
+ public canvas: IInteractionCanvas
19
+ public selector: ISelector
20
+
21
+ public running: boolean
22
+
23
+ public get dragging(): boolean { return this.dragger.dragging }
24
+ public get isDragEmpty(): boolean { return this.config.move.dragEmpty && (this.hoverData && (this.hoverData.path.list[0] as ILeaf).isLeafer) && (!this.downData || (this.downData.path.list[0] as ILeaf).isLeafer) }
25
+ public get isHoldRightKey(): boolean { return this.config.move.holdRightKey && this.downData && PointerButton.right(this.downData) }
26
+ public get moveMode(): boolean { return this.config.move.drag || (this.config.move.holdSpaceKey && Keyboard.isHoldSpaceKey()) || (this.downData && ((this.config.move.holdMiddleKey && PointerButton.middle(this.downData)) || (this.isHoldRightKey && this.dragger.moving))) || this.isDragEmpty }
27
+
28
+ public config: IInteractionConfig = config
29
+
30
+ public cursor: ICursorType | ICursorType[]
31
+ public get hitRadius(): number { return this.config.pointer.hitRadius }
32
+
33
+ public shrinkCanvasBounds: IBounds
34
+
35
+ public downData: IPointerEvent
36
+ protected oldDownData?: IPointerEvent // 通过updateDownData强制更新下来的数据
37
+ public hoverData: IPointerEvent
38
+
39
+ public downTime: number
40
+ protected overPath: LeafList
41
+ protected enterPath: LeafList
42
+
43
+ protected waitMenuTap: boolean
44
+ protected waitTap: boolean
45
+ protected longPressTimer: ITimer
46
+ protected longPressed: boolean
47
+ protected tapCount = 0
48
+ protected tapTimer: ITimer
49
+
50
+ protected dragger: Dragger
51
+ protected transformer: Transformer
52
+
53
+ protected __eventIds: IEventListenerId[]
54
+ protected defaultPath: ILeafList
55
+
56
+ protected downKeyMap: IBooleanMap = {}
57
+
58
+ constructor(target: ILeaf, canvas: IInteractionCanvas, selector: ISelector, userConfig?: IInteractionConfig) {
59
+ this.target = target
60
+ this.canvas = canvas
61
+ this.selector = selector
62
+ this.defaultPath = new LeafList(target)
63
+
64
+ this.transformer = new Transformer(this)
65
+ this.dragger = new Dragger(this)
66
+
67
+ if (userConfig) this.config = DataHelper.default(userConfig, this.config)
68
+ this.__listenEvents()
69
+ }
70
+
71
+
72
+ public start(): void {
73
+ this.running = true
74
+ }
75
+
76
+ public stop(): void {
77
+ this.running = false
78
+ }
79
+
80
+
81
+ public receive(_event: any): void { }
82
+
83
+
84
+ public pointerDown(data?: IPointerEvent, useDefaultPath?: boolean): void {
85
+ if (!data) data = this.hoverData
86
+ if (!data) return
87
+ PointerButton.defaultLeft(data)
88
+
89
+ this.updateDownData(data)
90
+ if (useDefaultPath) data.path = this.defaultPath
91
+
92
+ this.emit(PointerEvent.BEFORE_DOWN, data)
93
+ this.emit(PointerEvent.DOWN, data)
94
+
95
+ this.downTime = Date.now()
96
+
97
+ this.dragger.setDragData(data)
98
+
99
+ if (PointerButton.left(data)) {
100
+ this.tapWait()
101
+ this.longPressWait(data)
102
+ } else if (PointerButton.right(data)) {
103
+ this.waitMenuTap = true
104
+ }
105
+
106
+ this.updateCursor(data)
107
+ }
108
+
109
+ public pointerMove(data?: IPointerEvent): void {
110
+ if (!data) data = this.hoverData
111
+ if (!data) return
112
+ if (this.downData) PointerButton.defaultLeft(data)
113
+
114
+ const hit = this.canvas.bounds.hitPoint(data)
115
+ if (hit || this.downData) {
116
+ if (hit && !this.downData && PointerButton.left(data)) this.pointerDown(data, true) // 从外部拖拽内容进入,需要先模拟down事件
117
+ this.pointerMoveReal(data)
118
+ this.dragger.checkDragOut(data)
119
+ }
120
+ }
121
+
122
+ public pointerMoveReal(data: IPointerEvent): void {
123
+ this.emit(PointerEvent.BEFORE_MOVE, data, this.defaultPath)
124
+
125
+ if (this.downData) {
126
+ const canDrag = PointHelper.getDistance(this.downData, data) > this.config.pointer.dragDistance
127
+ if (canDrag) {
128
+ if (this.waitTap) this.pointerWaitCancel()
129
+ this.waitMenuTap = false
130
+ }
131
+
132
+ this.dragger.checkDrag(data, canDrag)
133
+ }
134
+
135
+ if (!this.dragger.moving) {
136
+ this.updateHoverData(data)
137
+ this.emit(PointerEvent.MOVE, data)
138
+
139
+ this.pointerOverOrOut(data)
140
+ this.pointerEnterOrLeave(data)
141
+ if (this.dragger.dragging) {
142
+ this.dragger.dragOverOrOut(data)
143
+ this.dragger.dragEnterOrLeave(data)
144
+ }
145
+ }
146
+
147
+ this.updateCursor(this.downData || data)
148
+ }
149
+
150
+ public pointerUp(data?: IPointerEvent): void {
151
+ if (!data) data = this.downData
152
+ if (!this.downData) return
153
+ PointerButton.defaultLeft(data)
154
+
155
+ this.findPath(data)
156
+
157
+ this.emit(PointerEvent.BEFORE_UP, data)
158
+ this.emit(PointerEvent.UP, data)
159
+ if (this.oldDownData) this.emit(PointerEvent.UP, this.oldDownData, undefined, data.path) // oldDownPath必须触发up
160
+ this.emit(PointerEvent.UP, this.downData, undefined, data.path) // downPath必须触发up
161
+
162
+ this.touchLeave(data)
163
+
164
+ this.tap(data)
165
+ this.menuTap(data)
166
+
167
+ this.dragger.dragEnd(data)
168
+
169
+ this.downData = this.oldDownData = null
170
+
171
+ this.updateCursor(data)
172
+ }
173
+
174
+ public pointerCancel(): void {
175
+ this.pointerUp(this.dragger.dragData)
176
+ }
177
+
178
+
179
+ public multiTouch(data: IUIEvent, list: IKeepTouchData[]): void {
180
+ const { move, angle, scale, center } = MultiTouchHelper.getData(list)
181
+ this.rotate(getRotateEventData(center, angle, data))
182
+ this.zoom(getZoomEventData(center, scale, data))
183
+ this.move(getMoveEventData(center, move, data))
184
+ }
185
+
186
+ // context menu
187
+
188
+ public menu(data: IPointerEvent): void {
189
+ this.findPath(data)
190
+ this.emit(PointerEvent.MENU, data)
191
+ }
192
+
193
+ public menuTap(data: IPointerEvent): void {
194
+ if (this.waitMenuTap) this.emit(PointerEvent.MENU_TAP, data)
195
+ }
196
+
197
+ // window transform
198
+
199
+ public move(data: IMoveEvent): void {
200
+ this.transformer.move(data)
201
+ }
202
+
203
+ public zoom(data: IZoomEvent): void {
204
+ this.transformer.zoom(data)
205
+ }
206
+
207
+ public rotate(data: IRotateEvent): void {
208
+ this.transformer.rotate(data)
209
+ }
210
+
211
+ public transformEnd(): void {
212
+ this.transformer.transformEnd()
213
+ }
214
+
215
+
216
+ // key
217
+
218
+ public keyDown(data: IKeyEvent): void {
219
+ const { code } = data
220
+ if (!this.downKeyMap[code]) {
221
+ this.downKeyMap[code] = true
222
+ Keyboard.setDownCode(code)
223
+
224
+ this.emit(KeyEvent.HOLD, data, this.defaultPath)
225
+ if (this.moveMode) this.updateCursor()
226
+ }
227
+ this.emit(KeyEvent.DOWN, data, this.defaultPath)
228
+ }
229
+
230
+ public keyUp(data: IKeyEvent): void {
231
+ const { code } = data
232
+ this.downKeyMap[code] = false
233
+ Keyboard.setUpCode(code)
234
+
235
+ this.emit(KeyEvent.UP, data, this.defaultPath)
236
+ if (this.cursor === 'grab') this.updateCursor()
237
+ }
238
+
239
+
240
+ // helper
241
+ protected pointerOverOrOut(data: IPointerEvent): void {
242
+ if (this.dragger.moving) return
243
+ if (this.dragging && !this.config.pointer.dragHover) return
244
+
245
+ const { path } = data
246
+ if (this.overPath) {
247
+ if (path.indexAt(0) !== this.overPath.indexAt(0)) {
248
+ this.emit(PointerEvent.OUT, data, this.overPath)
249
+ this.emit(PointerEvent.OVER, data, path)
250
+ }
251
+ } else {
252
+ this.emit(PointerEvent.OVER, data, path)
253
+ }
254
+ this.overPath = path
255
+ }
256
+
257
+ protected pointerEnterOrLeave(data: IPointerEvent): void {
258
+ if (this.dragger.moving) return
259
+ if (this.dragging && !this.config.pointer.dragHover) return
260
+
261
+ const { path } = data
262
+ this.emit(PointerEvent.LEAVE, data, this.enterPath, path)
263
+ this.emit(PointerEvent.ENTER, data, path, this.enterPath)
264
+ this.enterPath = path
265
+ }
266
+
267
+ protected touchLeave(data: IPointerEvent): void {
268
+ if (data.pointerType === 'touch') {
269
+ if (this.enterPath) {
270
+ this.emit(PointerEvent.LEAVE, data)
271
+ if (this.dragger.dragging) this.emit(DropEvent.LEAVE, data)
272
+ }
273
+ }
274
+ }
275
+
276
+ protected tap(data: IPointerEvent): void {
277
+ const { pointer } = this.config
278
+
279
+ const longTap = this.longTap(data)
280
+ if (!pointer.tapMore && longTap) return
281
+
282
+ if (!this.waitTap) return
283
+ if (pointer.tapMore) this.emitTap(data)
284
+
285
+ const useTime = Date.now() - this.downTime
286
+
287
+ const hasDouble = [PointerEvent.DOUBLE_TAP, PointerEvent.DOUBLE_CLICK].some(type => pathHasEventType(data.path, type))
288
+
289
+ if (useTime < pointer.tapTime + 50 && hasDouble) {
290
+
291
+ this.tapCount++
292
+ if (this.tapCount === 2) {
293
+ this.tapWaitCancel()
294
+ this.emitDoubleTap(data)
295
+ } else {
296
+ clearTimeout(this.tapTimer)
297
+ this.tapTimer = setTimeout(() => {
298
+ if (!pointer.tapMore) {
299
+ this.tapWaitCancel()
300
+ this.emitTap(data)
301
+ }
302
+ }, pointer.tapTime)
303
+ }
304
+
305
+ } else {
306
+
307
+ if (!pointer.tapMore) {
308
+ this.tapWaitCancel()
309
+ this.emitTap(data)
310
+ }
311
+ }
312
+ }
313
+
314
+
315
+ // update
316
+ public findPath(data: IPointerEvent, options?: IPickOptions): ILeafList {
317
+ const { hitRadius, through } = this.config.pointer
318
+ const find = this.selector.getByPoint(data, hitRadius, options || { through })
319
+ if (find.throughPath) data.throughPath = find.throughPath
320
+ data.path = find.path
321
+ return find.path
322
+ }
323
+
324
+ public isDrag(leaf: ILeaf): boolean {
325
+ return this.dragger.getList().has(leaf)
326
+ }
327
+
328
+ public updateDownData(data?: IPointerEvent, options?: IPickOptions): void {
329
+ const { downData } = this
330
+ if (!data && downData) data = { ...downData }
331
+ if (!data) return
332
+ this.oldDownData = downData
333
+ this.findPath(data, options)
334
+ this.downData = data
335
+ }
336
+
337
+ public updateHoverData(data?: IPointerEvent): void {
338
+ if (!data) data = this.hoverData
339
+ if (!data) return
340
+ this.findPath(data, { exclude: this.dragger.getList(), name: PointerEvent.MOVE })
341
+ this.hoverData = data
342
+ }
343
+
344
+ public updateCursor(data?: IPointerEvent): void {
345
+ if (this.config.cursor.stop) return
346
+
347
+ if (!data) {
348
+ this.updateHoverData()
349
+ data = this.downData || this.hoverData
350
+ }
351
+
352
+ if (this.dragger.moving) {
353
+ return this.setCursor('grabbing')
354
+ } else if (this.moveMode) {
355
+ return this.setCursor(this.downData ? 'grabbing' : 'grab')
356
+ } else if (!data) return
357
+
358
+ let leaf: ILeaf
359
+ let cursor: ICursorType | ICursorType[]
360
+
361
+ const { path } = data
362
+ for (let i = 0, len = path.length; i < len; i++) {
363
+ leaf = path.list[i]
364
+ cursor = leaf.cursor
365
+ if (cursor) break
366
+ }
367
+
368
+ this.setCursor(cursor)
369
+ }
370
+
371
+ public setCursor(cursor: ICursorType | ICursorType[]): void {
372
+ this.cursor = cursor
373
+ }
374
+
375
+ protected emitTap(data: IPointerEvent) {
376
+ this.emit(PointerEvent.TAP, data)
377
+ this.emit(PointerEvent.CLICK, data)
378
+ }
379
+
380
+ protected emitDoubleTap(data: IPointerEvent) {
381
+ this.emit(PointerEvent.DOUBLE_TAP, data)
382
+ this.emit(PointerEvent.DOUBLE_CLICK, data)
383
+ }
384
+
385
+ public pointerWaitCancel(): void {
386
+ this.tapWaitCancel()
387
+ this.longPressWaitCancel()
388
+ }
389
+
390
+ protected tapWait(): void {
391
+ clearTimeout(this.tapTimer)
392
+ this.waitTap = true
393
+ }
394
+
395
+ protected tapWaitCancel(): void {
396
+ clearTimeout(this.tapTimer)
397
+ this.waitTap = false
398
+ this.tapCount = 0
399
+ }
400
+
401
+ protected longPressWait(data: IPointerEvent): void {
402
+ clearTimeout(this.longPressTimer)
403
+ this.longPressTimer = setTimeout(() => {
404
+ this.longPressed = true
405
+ this.emit(PointerEvent.LONG_PRESS, data)
406
+ }, this.config.pointer.longPressTime)
407
+ }
408
+
409
+ protected longTap(data: IPointerEvent): boolean {
410
+ let longTap
411
+ if (this.longPressed) {
412
+ this.emit(PointerEvent.LONG_TAP, data)
413
+ if (pathHasEventType(data.path, PointerEvent.LONG_TAP)) longTap = true
414
+ }
415
+ this.longPressWaitCancel()
416
+ return longTap
417
+ }
418
+
419
+ protected longPressWaitCancel(): void {
420
+ clearTimeout(this.longPressTimer)
421
+ this.longPressed = false
422
+ }
423
+
424
+ protected __onResize(): void {
425
+ this.shrinkCanvasBounds = new Bounds(this.canvas.bounds)
426
+ this.shrinkCanvasBounds.spread(-2)
427
+ }
428
+
429
+ protected __listenEvents(): void {
430
+ const { target } = this
431
+ this.__eventIds = [target.on_(ResizeEvent.RESIZE, this.__onResize, this)]
432
+ target.once(LeaferEvent.READY, () => this.__onResize())
433
+ }
434
+
435
+ protected __removeListenEvents(): void {
436
+ this.target.off_(this.__eventIds)
437
+ this.__eventIds.length = 0
438
+ }
439
+
440
+
441
+ public emit(type: string, data: IUIEvent, path?: ILeafList, excludePath?: ILeafList): void {
442
+ if (this.running) emit(type, data, path, excludePath)
443
+ }
444
+
445
+
446
+ public destroy(): void {
447
+ if (this.__eventIds.length) {
448
+ this.stop()
449
+ this.__removeListenEvents()
450
+ this.dragger.destroy()
451
+ this.transformer.destroy()
452
+ this.downData = this.overPath = this.enterPath = null
453
+ }
454
+ }
455
+
456
+ }
@@ -0,0 +1,111 @@
1
+ import { IEvent, IPointerEvent, IMoveEvent, IZoomEvent, IRotateEvent, IDragEvent, ISwipeEvent, IUIEvent, IPointData, ILeafList, IDropEvent, IObject } from '@leafer/interface'
2
+ import { PointHelper, LeafList } from '@leafer/core'
3
+
4
+ import { SwipeEvent } from '@leafer-ui/event'
5
+
6
+
7
+ export const InteractionHelper = {
8
+
9
+ getMoveEventData(center: IPointData, move: IPointData, event: IEvent): IMoveEvent {
10
+ return {
11
+ ...event,
12
+ x: center.x,
13
+ y: center.y,
14
+ moveX: move.x,
15
+ moveY: move.y
16
+ } as IMoveEvent
17
+ },
18
+
19
+ getRotateEventData(center: IPointData, angle: number, event: IEvent): IRotateEvent {
20
+ return {
21
+ ...event,
22
+ x: center.x,
23
+ y: center.y,
24
+ rotation: angle
25
+ } as IRotateEvent
26
+ },
27
+
28
+ getZoomEventData(center: IPointData, scale: number, event: IEvent): IZoomEvent {
29
+ return {
30
+ ...event,
31
+ x: center.x,
32
+ y: center.y,
33
+ scale,
34
+ } as IZoomEvent
35
+ },
36
+
37
+ getDragEventData(startPoint: IPointData, lastPoint: IPointData, event: IPointerEvent): IDragEvent {
38
+ return {
39
+ ...event,
40
+ x: event.x,
41
+ y: event.y,
42
+ moveX: event.x - lastPoint.x,
43
+ moveY: event.y - lastPoint.y,
44
+ totalX: event.x - startPoint.x,
45
+ totalY: event.y - startPoint.y,
46
+ } as IDragEvent
47
+ },
48
+
49
+ getDropEventData(event: IPointerEvent, list: ILeafList, data: IObject): IDropEvent {
50
+ return {
51
+ ...event,
52
+ list,
53
+ data
54
+ }
55
+ },
56
+
57
+ getSwipeDirection(angle: number): string {
58
+ if (angle < -45 && angle > -135) {
59
+ return SwipeEvent.UP
60
+ } else if (angle > 45 && angle < 135) {
61
+ return SwipeEvent.DOWN
62
+ } else if (angle <= 45 && angle >= -45) {
63
+ return SwipeEvent.RIGHT
64
+ } else {
65
+ return SwipeEvent.LEFT
66
+ }
67
+ },
68
+
69
+ getSwipeEventData(startPoint: IPointData, lastDragData: IDragEvent, event: IPointerEvent): ISwipeEvent {
70
+ return {
71
+ ...event,
72
+ moveX: lastDragData.moveX,
73
+ moveY: lastDragData.moveY,
74
+ totalX: event.x - startPoint.x,
75
+ totalY: event.y - startPoint.y,
76
+ type: I.getSwipeDirection(PointHelper.getAngle(startPoint, event)),
77
+ }
78
+ },
79
+
80
+
81
+ getBase(e: IObject): IUIEvent {
82
+ const pointerUpButtons = e.button === 1 ? 4 : e.button // 0: left, 1: middle, 2: right
83
+ return {
84
+ altKey: e.altKey,
85
+ ctrlKey: e.ctrlKey,
86
+ shiftKey: e.shiftKey,
87
+ metaKey: e.metaKey,
88
+ buttons: e.buttons === undefined ? 1 : (e.buttons === 0 ? pointerUpButtons : e.buttons), // touchEvent no button and buttons, set default
89
+ origin: e
90
+ } as IUIEvent
91
+ },
92
+
93
+ pathHasEventType(path: ILeafList, type: string): boolean {
94
+ const { list } = path
95
+ for (let i = 0, len = list.length; i < len; i++) {
96
+ if (list[i].hasEvent(type)) return true
97
+ }
98
+ return false
99
+ },
100
+
101
+ filterPathByEventType(path: ILeafList, type: string): ILeafList {
102
+ const find = new LeafList()
103
+ const { list } = path
104
+ for (let i = 0, len = list.length; i < len; i++) {
105
+ if (list[i].hasEvent(type)) find.add(list[i])
106
+ }
107
+ return find
108
+ }
109
+ }
110
+
111
+ const I = InteractionHelper
@@ -0,0 +1,22 @@
1
+ import { IMultiTouchData, IKeepTouchData } from '@leafer/interface'
2
+ import { PointHelper } from '@leafer/core'
3
+
4
+
5
+ export const MultiTouchHelper = {
6
+
7
+ getData(list: IKeepTouchData[]): IMultiTouchData {
8
+ const a = list[0]
9
+ const b = list[1]
10
+ const lastCenter = PointHelper.getCenter(a.from, b.from)
11
+ const center = PointHelper.getCenter(a.to, b.to)
12
+ const move = { x: center.x - lastCenter.x, y: center.y - lastCenter.y }
13
+
14
+ const lastDistance = PointHelper.getDistance(a.from, b.from)
15
+ const distance = PointHelper.getDistance(a.to, b.to)
16
+ const scale = distance / lastDistance
17
+
18
+ const angle = PointHelper.getRotation(a.from, b.from, a.to, b.to)
19
+
20
+ return { move, scale, angle, center }
21
+ }
22
+ }
@@ -0,0 +1,108 @@
1
+ import { IMoveEvent, IZoomEvent, IRotateEvent, ITimer } from '@leafer/interface'
2
+ import { MoveEvent, ZoomEvent, RotateEvent } from '@leafer-ui/event'
3
+
4
+ import { InteractionBase } from './Interaction'
5
+
6
+
7
+ export class Transformer {
8
+
9
+ protected interaction: InteractionBase
10
+ protected moveData: IMoveEvent
11
+ protected zoomData: IZoomEvent
12
+ protected rotateData: IRotateEvent
13
+ protected transformTimer: ITimer
14
+
15
+ constructor(interaction: InteractionBase) {
16
+ this.interaction = interaction
17
+ }
18
+
19
+ public move(data: IMoveEvent): void {
20
+ const { interaction } = this
21
+
22
+ if (!this.moveData) {
23
+ const { path } = interaction.selector.getByPoint(data, interaction.hitRadius)
24
+ data.path = path
25
+ this.moveData = { ...data, moveX: 0, moveY: 0 }
26
+ interaction.emit(MoveEvent.START, this.moveData)
27
+ }
28
+
29
+ data.path = this.moveData.path
30
+ interaction.emit(MoveEvent.BEFORE_MOVE, data)
31
+ interaction.emit(MoveEvent.MOVE, data)
32
+
33
+ this.transformEndWait()
34
+ }
35
+
36
+ public zoom(data: IZoomEvent): void {
37
+ const { interaction } = this
38
+
39
+ if (!this.zoomData) {
40
+ const { path } = interaction.selector.getByPoint(data, interaction.hitRadius)
41
+ data.path = path
42
+ this.zoomData = { ...data, scale: 1 }
43
+ interaction.emit(ZoomEvent.START, this.zoomData)
44
+ }
45
+
46
+ data.path = this.zoomData.path
47
+ interaction.emit(ZoomEvent.BEFORE_ZOOM, data)
48
+ interaction.emit(ZoomEvent.ZOOM, data)
49
+
50
+ this.transformEndWait()
51
+ }
52
+
53
+ public rotate(data: IRotateEvent): void {
54
+ const { interaction } = this
55
+
56
+ if (!this.rotateData) {
57
+ const { path } = interaction.selector.getByPoint(data, interaction.hitRadius)
58
+ data.path = path
59
+ this.rotateData = { ...data, rotation: 0 }
60
+ interaction.emit(RotateEvent.START, this.rotateData)
61
+ }
62
+
63
+ data.path = this.rotateData.path
64
+ interaction.emit(RotateEvent.BEFORE_ROTATE, data)
65
+ interaction.emit(RotateEvent.ROTATE, data)
66
+
67
+ this.transformEndWait()
68
+ }
69
+
70
+
71
+ protected transformEndWait(): void {
72
+ clearTimeout(this.transformTimer)
73
+ this.transformTimer = setTimeout(() => {
74
+ this.transformEnd()
75
+ }, this.interaction.config.pointer.transformTime)
76
+ }
77
+
78
+ public transformEnd(): void {
79
+ this.moveEnd()
80
+ this.zoomEnd()
81
+ this.rotateEnd()
82
+ }
83
+
84
+ protected moveEnd(): void {
85
+ if (this.moveData) {
86
+ this.interaction.emit(MoveEvent.END, this.moveData)
87
+ this.moveData = null
88
+ }
89
+ }
90
+
91
+ protected zoomEnd(): void {
92
+ if (this.zoomData) {
93
+ this.interaction.emit(ZoomEvent.END, this.zoomData)
94
+ this.zoomData = null
95
+ }
96
+ }
97
+
98
+ protected rotateEnd(): void {
99
+ if (this.rotateData) {
100
+ this.interaction.emit(RotateEvent.END, this.rotateData)
101
+ this.rotateData = null
102
+ }
103
+ }
104
+
105
+ public destroy(): void {
106
+ this.zoomData = this.moveData = this.rotateData = null
107
+ }
108
+ }
package/src/config.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { IInteractionConfig } from '@leafer/interface'
2
+
3
+ export const config: IInteractionConfig = {
4
+ wheel: {
5
+ zoomMode: false,
6
+ zoomSpeed: 0.5,
7
+ moveSpeed: 0.5,
8
+ rotateSpeed: 0.5,
9
+ delta: { x: 80 / 4, y: 8.0 }, // 基准速度(会影响zoomSpeed),可根据不同系统、浏览器细化定制
10
+ preventDefault: true
11
+ },
12
+ pointer: {
13
+ hitRadius: 5,
14
+ through: false,
15
+ tapTime: 120,
16
+ longPressTime: 800,
17
+ transformTime: 500,
18
+ dragHover: true,
19
+ dragDistance: 2,
20
+ swipeDistance: 20,
21
+ ignoreMove: false,
22
+ preventDefaultMenu: true
23
+ },
24
+ cursor: {}
25
+ }
package/src/emit.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { IUIEvent, ILeaf, ILeafList } from '@leafer/interface'
2
+ import { EventCreator, Debug } from '@leafer/core'
3
+
4
+ const debug = Debug.get('emit')
5
+
6
+ export function emit(type: string, data: IUIEvent, path?: ILeafList, excludePath?: ILeafList): void {
7
+ if (!path && !data.path) return
8
+
9
+ let leaf: ILeaf
10
+ data.type = type
11
+ if (path) {
12
+ data = { ...data, path }
13
+ } else {
14
+ path = data.path
15
+ }
16
+
17
+ data.target = path.indexAt(0)
18
+
19
+ try {
20
+
21
+ // capture
22
+ for (let i = path.length - 1; i > -1; i--) {
23
+ leaf = path.list[i]
24
+ if (emitEvent(leaf, type, data, true, excludePath)) return
25
+ if (leaf.isApp) emitAppChildren(leaf, type, data, true, excludePath) // other leafer
26
+ }
27
+
28
+ // bubble
29
+ for (let i = 0, len = path.length; i < len; i++) {
30
+ leaf = path.list[i]
31
+ if (leaf.isApp) emitAppChildren(leaf, type, data, false, excludePath) // other leafer
32
+ if (emitEvent(leaf, type, data, false, excludePath)) return
33
+ }
34
+
35
+ } catch (e) {
36
+ debug.error(e)
37
+ }
38
+ }
39
+
40
+ const allowTypes = ['move', 'zoom', 'rotate', 'key']
41
+ function emitAppChildren(leaf: ILeaf, type: string, data: IUIEvent, capture?: boolean, excludePath?: ILeafList): void {
42
+ if (allowTypes.some(name => type.startsWith(name)) && leaf.__.hitChildren && !exclude(leaf, excludePath)) {
43
+ let child: ILeaf
44
+ for (let i = 0, len = leaf.children.length; i < len; i++) {
45
+ child = leaf.children[i]
46
+ if (!data.path.has(child) && child.__.hittable) emitEvent(child, type, data, capture, excludePath) // other leafer
47
+ }
48
+ }
49
+ }
50
+
51
+ function emitEvent(leaf: ILeaf, type: string, data: IUIEvent, capture?: boolean, excludePath?: ILeafList): boolean {
52
+ if (leaf.destroyed) return true
53
+ if (leaf.__.hitSelf && leaf.hasEvent(type, capture) && !exclude(leaf, excludePath)) {
54
+ data.phase = capture ? 1 : ((leaf === data.target) ? 2 : 3)
55
+ const event = EventCreator.get(type, data)
56
+ leaf.emitEvent(event, capture)
57
+ if (event.isStop) return true
58
+ }
59
+ return false
60
+ }
61
+
62
+ function exclude(leaf: ILeaf, excludePath?: ILeafList): boolean {
63
+ return excludePath && excludePath.has(leaf)
64
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { InteractionBase } from './Interaction'
2
+ export { InteractionHelper } from './InteractionHelper'
3
+ export { MultiTouchHelper } from './MultiTouchHelper'
4
+ export { Cursor } from './Cursor'
5
+ export { HitCanvasManager } from './HitCanvasManager'
@@ -0,0 +1,163 @@
1
+ import { IMoveEvent, IZoomEvent, IRotateEvent, ITimer, IDragEvent, IPointerEvent, ILeafList, IFunction, IInteraction, ILeaf, IInteractionCanvas, ISelector, IInteractionConfig, ICursorType, IBounds, IEventListenerId, IBooleanMap, IUIEvent, IKeepTouchData, IKeyEvent, IPickOptions, IPointData, IEvent, IObject, IDropEvent, ISwipeEvent, IMultiTouchData, ICursorTypeMap, IHitCanvasManager, IScreenSizeData, IHitCanvas } from '@leafer/interface';
2
+ import { LeafList, CanvasManager } from '@leafer/core';
3
+
4
+ declare class Transformer {
5
+ protected interaction: InteractionBase;
6
+ protected moveData: IMoveEvent;
7
+ protected zoomData: IZoomEvent;
8
+ protected rotateData: IRotateEvent;
9
+ protected transformTimer: ITimer;
10
+ constructor(interaction: InteractionBase);
11
+ move(data: IMoveEvent): void;
12
+ zoom(data: IZoomEvent): void;
13
+ rotate(data: IRotateEvent): void;
14
+ protected transformEndWait(): void;
15
+ transformEnd(): void;
16
+ protected moveEnd(): void;
17
+ protected zoomEnd(): void;
18
+ protected rotateEnd(): void;
19
+ destroy(): void;
20
+ }
21
+
22
+ declare class Dragger {
23
+ protected interaction: InteractionBase;
24
+ moving: boolean;
25
+ dragging: boolean;
26
+ dragData: IDragEvent;
27
+ protected downData: IPointerEvent;
28
+ dragableList: ILeafList;
29
+ protected dragOverPath: ILeafList;
30
+ protected dragEnterPath: ILeafList;
31
+ protected autoMoveTimer: ITimer;
32
+ protected canAnimate: boolean;
33
+ protected animateWait: IFunction;
34
+ constructor(interaction: InteractionBase);
35
+ setDragData(data: IPointerEvent): void;
36
+ getList(): ILeafList;
37
+ checkDrag(data: IPointerEvent, canDrag: boolean): void;
38
+ dragStart(data: IPointerEvent, canDrag: boolean): void;
39
+ protected getDragableList(path: ILeafList): void;
40
+ protected drag(data: IPointerEvent): void;
41
+ protected dragReal(): void;
42
+ dragOverOrOut(data: IPointerEvent): void;
43
+ dragEnterOrLeave(data: IPointerEvent): void;
44
+ dragEnd(data: IPointerEvent, speed?: number): void;
45
+ protected dragEndReal(data?: IPointerEvent): void;
46
+ protected animate(func?: IFunction, off?: 'off'): void;
47
+ protected swipe(data: IPointerEvent, endDragData: IDragEvent): void;
48
+ protected drop(data: IPointerEvent): void;
49
+ protected dragReset(): void;
50
+ checkDragOut(data: IPointerEvent): void;
51
+ protected autoMoveOnDragOut(data: IPointerEvent): void;
52
+ protected autoMoveCancel(): void;
53
+ destroy(): void;
54
+ }
55
+
56
+ declare class InteractionBase implements IInteraction {
57
+ target: ILeaf;
58
+ canvas: IInteractionCanvas;
59
+ selector: ISelector;
60
+ running: boolean;
61
+ get dragging(): boolean;
62
+ get isDragEmpty(): boolean;
63
+ get isHoldRightKey(): boolean;
64
+ get moveMode(): boolean;
65
+ config: IInteractionConfig;
66
+ cursor: ICursorType | ICursorType[];
67
+ get hitRadius(): number;
68
+ shrinkCanvasBounds: IBounds;
69
+ downData: IPointerEvent;
70
+ protected oldDownData?: IPointerEvent;
71
+ hoverData: IPointerEvent;
72
+ downTime: number;
73
+ protected overPath: LeafList;
74
+ protected enterPath: LeafList;
75
+ protected waitMenuTap: boolean;
76
+ protected waitTap: boolean;
77
+ protected longPressTimer: ITimer;
78
+ protected longPressed: boolean;
79
+ protected tapCount: number;
80
+ protected tapTimer: ITimer;
81
+ protected dragger: Dragger;
82
+ protected transformer: Transformer;
83
+ protected __eventIds: IEventListenerId[];
84
+ protected defaultPath: ILeafList;
85
+ protected downKeyMap: IBooleanMap;
86
+ constructor(target: ILeaf, canvas: IInteractionCanvas, selector: ISelector, userConfig?: IInteractionConfig);
87
+ start(): void;
88
+ stop(): void;
89
+ receive(_event: any): void;
90
+ pointerDown(data?: IPointerEvent, useDefaultPath?: boolean): void;
91
+ pointerMove(data?: IPointerEvent): void;
92
+ pointerMoveReal(data: IPointerEvent): void;
93
+ pointerUp(data?: IPointerEvent): void;
94
+ pointerCancel(): void;
95
+ multiTouch(data: IUIEvent, list: IKeepTouchData[]): void;
96
+ menu(data: IPointerEvent): void;
97
+ menuTap(data: IPointerEvent): void;
98
+ move(data: IMoveEvent): void;
99
+ zoom(data: IZoomEvent): void;
100
+ rotate(data: IRotateEvent): void;
101
+ transformEnd(): void;
102
+ keyDown(data: IKeyEvent): void;
103
+ keyUp(data: IKeyEvent): void;
104
+ protected pointerOverOrOut(data: IPointerEvent): void;
105
+ protected pointerEnterOrLeave(data: IPointerEvent): void;
106
+ protected touchLeave(data: IPointerEvent): void;
107
+ protected tap(data: IPointerEvent): void;
108
+ findPath(data: IPointerEvent, options?: IPickOptions): ILeafList;
109
+ isDrag(leaf: ILeaf): boolean;
110
+ updateDownData(data?: IPointerEvent, options?: IPickOptions): void;
111
+ updateHoverData(data?: IPointerEvent): void;
112
+ updateCursor(data?: IPointerEvent): void;
113
+ setCursor(cursor: ICursorType | ICursorType[]): void;
114
+ protected emitTap(data: IPointerEvent): void;
115
+ protected emitDoubleTap(data: IPointerEvent): void;
116
+ pointerWaitCancel(): void;
117
+ protected tapWait(): void;
118
+ protected tapWaitCancel(): void;
119
+ protected longPressWait(data: IPointerEvent): void;
120
+ protected longTap(data: IPointerEvent): boolean;
121
+ protected longPressWaitCancel(): void;
122
+ protected __onResize(): void;
123
+ protected __listenEvents(): void;
124
+ protected __removeListenEvents(): void;
125
+ emit(type: string, data: IUIEvent, path?: ILeafList, excludePath?: ILeafList): void;
126
+ destroy(): void;
127
+ }
128
+
129
+ declare const InteractionHelper: {
130
+ getMoveEventData(center: IPointData, move: IPointData, event: IEvent): IMoveEvent;
131
+ getRotateEventData(center: IPointData, angle: number, event: IEvent): IRotateEvent;
132
+ getZoomEventData(center: IPointData, scale: number, event: IEvent): IZoomEvent;
133
+ getDragEventData(startPoint: IPointData, lastPoint: IPointData, event: IPointerEvent): IDragEvent;
134
+ getDropEventData(event: IPointerEvent, list: ILeafList, data: IObject): IDropEvent;
135
+ getSwipeDirection(angle: number): string;
136
+ getSwipeEventData(startPoint: IPointData, lastDragData: IDragEvent, event: IPointerEvent): ISwipeEvent;
137
+ getBase(e: IObject): IUIEvent;
138
+ pathHasEventType(path: ILeafList, type: string): boolean;
139
+ filterPathByEventType(path: ILeafList, type: string): ILeafList;
140
+ };
141
+
142
+ declare const MultiTouchHelper: {
143
+ getData(list: IKeepTouchData[]): IMultiTouchData;
144
+ };
145
+
146
+ declare class Cursor {
147
+ static custom: ICursorTypeMap;
148
+ static set(name: string, value: ICursorType | ICursorType[]): void;
149
+ static get(name: string): ICursorType | ICursorType[];
150
+ }
151
+
152
+ declare class HitCanvasManager extends CanvasManager implements IHitCanvasManager {
153
+ protected pathTypeList: ILeafList;
154
+ protected imageTypeList: ILeafList;
155
+ getImageType(leaf: ILeaf, size: IScreenSizeData): IHitCanvas;
156
+ getPathType(leaf: ILeaf): IHitCanvas;
157
+ clearImageType(): void;
158
+ clearPathType(): void;
159
+ protected __clearLeafList(leafList: ILeafList): void;
160
+ clear(): void;
161
+ }
162
+
163
+ export { Cursor, HitCanvasManager, InteractionBase, InteractionHelper, MultiTouchHelper };