@vyr/engine 0.0.1

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.
Files changed (95) hide show
  1. package/package.json +19 -0
  2. package/src/ArrayUtils.ts +65 -0
  3. package/src/AsyncTask.ts +72 -0
  4. package/src/Category.ts +119 -0
  5. package/src/Color.ts +111 -0
  6. package/src/Engine.ts +101 -0
  7. package/src/Generate.ts +40 -0
  8. package/src/InputSystem.ts +108 -0
  9. package/src/Listener.ts +59 -0
  10. package/src/ObjectPool.ts +84 -0
  11. package/src/ObjectUtils.ts +49 -0
  12. package/src/Scriptable.ts +27 -0
  13. package/src/Serialization.ts +49 -0
  14. package/src/Traverser.ts +39 -0
  15. package/src/actor/Actor.ts +28 -0
  16. package/src/actor/AnimationUnitActor.ts +289 -0
  17. package/src/actor/DivActor.ts +70 -0
  18. package/src/actor/FragmentActor.ts +56 -0
  19. package/src/actor/HTMActor.ts +166 -0
  20. package/src/actor/HTMServiceActor.ts +57 -0
  21. package/src/actor/HTMTransformControllerActor.ts +404 -0
  22. package/src/actor/StyleActor.ts +96 -0
  23. package/src/actor/index.ts +8 -0
  24. package/src/asset/Asset.ts +271 -0
  25. package/src/asset/AssetGraph.ts +246 -0
  26. package/src/asset/index.ts +2 -0
  27. package/src/descriptor/AnimationUnitDescriptor.ts +65 -0
  28. package/src/descriptor/CameraDescriptor.ts +12 -0
  29. package/src/descriptor/ControllerDescriptor.ts +16 -0
  30. package/src/descriptor/DatasetDescriptor.ts +92 -0
  31. package/src/descriptor/Descriptor.ts +415 -0
  32. package/src/descriptor/DivDescriptor.ts +18 -0
  33. package/src/descriptor/DynamicDescriptor.ts +27 -0
  34. package/src/descriptor/HTMLDescriptor.ts +87 -0
  35. package/src/descriptor/HTMLServiceDescriptor.ts +19 -0
  36. package/src/descriptor/HTMLTransformControllerDescriptor.ts +34 -0
  37. package/src/descriptor/NodeDescriptor.ts +32 -0
  38. package/src/descriptor/PrefabDescriptor.ts +53 -0
  39. package/src/descriptor/PrefabInstanceDescriptor.ts +32 -0
  40. package/src/descriptor/RoutineDescriptor.ts +54 -0
  41. package/src/descriptor/ServiceDescriptor.ts +32 -0
  42. package/src/descriptor/ServiceSchedulerDescriptor.ts +32 -0
  43. package/src/descriptor/StyleDescriptor.ts +213 -0
  44. package/src/descriptor/index.ts +17 -0
  45. package/src/graphics/Collection.ts +25 -0
  46. package/src/graphics/Compilation.ts +82 -0
  47. package/src/graphics/Graphics.ts +475 -0
  48. package/src/graphics/Observer.ts +36 -0
  49. package/src/graphics/Unit.ts +83 -0
  50. package/src/graphics/VariableProxy.ts +92 -0
  51. package/src/graphics/index.ts +5 -0
  52. package/src/index.ts +26 -0
  53. package/src/interpreter/AnimationUnitInterpreter.ts +53 -0
  54. package/src/interpreter/DatasetInterpreter.ts +11 -0
  55. package/src/interpreter/DivInterpreter.ts +44 -0
  56. package/src/interpreter/DynamicInterpreter.ts +207 -0
  57. package/src/interpreter/FragmentInterpreter.ts +34 -0
  58. package/src/interpreter/HTMLServiceInterpreter.ts +47 -0
  59. package/src/interpreter/HTMLTransformControllerInterpreter.ts +40 -0
  60. package/src/interpreter/Interpreter.ts +69 -0
  61. package/src/interpreter/PrefaInterpreter.ts +11 -0
  62. package/src/interpreter/PrefabInstanceInterpreter.ts +12 -0
  63. package/src/interpreter/RoutineInterpreter.ts +88 -0
  64. package/src/interpreter/ServiceInterpreter.ts +24 -0
  65. package/src/interpreter/ServiceSchedulerInterpreter.ts +42 -0
  66. package/src/interpreter/StyleInterpreter.ts +66 -0
  67. package/src/interpreter/index.ts +14 -0
  68. package/src/locale/Language.ts +10 -0
  69. package/src/locale/LanguageProvider.ts +48 -0
  70. package/src/locale/index.ts +2 -0
  71. package/src/math/Euler.ts +303 -0
  72. package/src/math/Matrix4.ts +1123 -0
  73. package/src/math/Quaternion.ts +737 -0
  74. package/src/math/Vector2.ts +680 -0
  75. package/src/math/Vector3.ts +1062 -0
  76. package/src/math/index.ts +5 -0
  77. package/src/math/utils.ts +17 -0
  78. package/src/preset/execute/dataset/index.ts +1 -0
  79. package/src/preset/execute/dataset/update.ts +52 -0
  80. package/src/preset/execute/graphics/index.ts +1 -0
  81. package/src/preset/execute/graphics/invoke.ts +49 -0
  82. package/src/preset/execute/index.ts +4 -0
  83. package/src/preset/execute/net/index.ts +1 -0
  84. package/src/preset/execute/net/request.ts +103 -0
  85. package/src/preset/execute/scheduler/index.ts +1 -0
  86. package/src/preset/execute/scheduler/switch.ts +46 -0
  87. package/src/preset/index.ts +7 -0
  88. package/src/preset/routine/graphics/index.ts +1 -0
  89. package/src/preset/routine/graphics/invoke.ts +27 -0
  90. package/src/preset/routine/index.ts +2 -0
  91. package/src/preset/routine/scheduler/index.ts +1 -0
  92. package/src/preset/routine/scheduler/switch.ts +27 -0
  93. package/src/setup/index.ts +17 -0
  94. package/src/utils/AssetProvider.ts +72 -0
  95. package/src/utils/index.ts +1 -0
@@ -0,0 +1,56 @@
1
+ import { Descriptor } from "../descriptor";
2
+ import { ArrayUtils } from "../ArrayUtils";
3
+ import { Actor } from "./Actor";
4
+
5
+ class FragmentActor extends Actor {
6
+ private _parent = ''
7
+ collection: Actor[] = []
8
+
9
+ bind(parent: string) {
10
+ this._parent = parent
11
+ }
12
+
13
+ unbind() {
14
+ if (this._parent === '') return
15
+ const graphics = Actor.getGraphics(this)
16
+ const parent = Descriptor.get(this._parent)
17
+ if (parent instanceof Descriptor) {
18
+ const parentActor = graphics.getActor(parent, { delta: 0 })
19
+ if (parentActor !== null) {
20
+ for (const actor of this.collection) parentActor.remove(actor)
21
+ }
22
+ }
23
+ this.collection.length = 0
24
+ this._parent = ''
25
+ }
26
+
27
+ add(actor: Actor) {
28
+ if (actor instanceof FragmentActor) return
29
+
30
+ const graphics = Actor.getGraphics(this)
31
+ const parent = Descriptor.get<Descriptor>(this._parent)
32
+
33
+ if (parent instanceof Descriptor) {
34
+ const parentActor = graphics.getActor(parent, { delta: 0 })
35
+ if (parentActor !== null) parentActor.add(actor)
36
+ }
37
+
38
+ ArrayUtils.insert(this.collection, actor)
39
+ }
40
+
41
+ remove(actor: Actor) {
42
+ if (actor instanceof FragmentActor) return
43
+
44
+ const graphics = Actor.getGraphics(this)
45
+ const parent = Descriptor.get<Descriptor>(this._parent)
46
+ if (parent instanceof Descriptor) {
47
+ const parentActor = graphics.getActor(parent, { delta: 0 })
48
+ if (parentActor !== null) parentActor.remove(actor)
49
+ }
50
+ ArrayUtils.remove(this.collection, actor)
51
+ }
52
+ }
53
+
54
+ export {
55
+ FragmentActor
56
+ }
@@ -0,0 +1,166 @@
1
+ import { Asset } from "../asset"
2
+ import { Descriptor, InteractionProperty, HTMLDescriptor, HTMLStyle, RoutineDescriptor, StyleDescriptor, UpdateArgs } from "../descriptor"
3
+ import { RoutineInterpreter } from "../interpreter";
4
+ import { Graphics } from "../graphics";
5
+ import { Actor } from "./Actor"
6
+ import { StyleActor } from "./StyleActor"
7
+
8
+ abstract class HTMLActor extends Actor {
9
+ static className = 'vyr-html-wrapper'
10
+ static uuidKey = 'data-vyr-uuid'
11
+ readonly uuid
12
+ readonly unlisteners: Array<() => void> = []
13
+ className?: string[]
14
+
15
+ constructor(uuid: string) {
16
+ super()
17
+ this.uuid = uuid
18
+ }
19
+
20
+ createDOM() {
21
+ const DOM = document.createElement('div')
22
+ DOM.setAttribute(HTMLActor.uuidKey, this.uuid)
23
+ DOM.style.width = '100%'
24
+ DOM.style.height = '100%'
25
+ DOM.style.position = 'relative'
26
+ DOM.style.backgroundSize = '100% 100%'
27
+ DOM.style.backgroundRepeat = 'no-repeat'
28
+ DOM.style.backgroundPosition = '0% 0%'
29
+ return DOM
30
+ }
31
+
32
+ getWrapperStyle(descriptor: HTMLDescriptor, args: UpdateArgs) {
33
+ const style: HTMLStyle = {}
34
+ style.pointerEvents = 'auto'
35
+ style.flexGrow = descriptor.flexGrow + ''
36
+ if (descriptor.visible === false) {
37
+ style.display = 'none'
38
+ } else {
39
+ style.display = descriptor.display
40
+ }
41
+
42
+ const width = descriptor.width
43
+ if (width < 0) {
44
+ style.width = 'auto'
45
+ } else {
46
+ style.width = `calc(${width + descriptor.wUnit} + ${descriptor.calcWidth}px)`
47
+ }
48
+
49
+ const height = descriptor.height
50
+ if (height < 0) {
51
+ style.height = 'auto'
52
+ } else {
53
+ style.height = `calc(${height + descriptor.hUnit} + ${descriptor.calcHeight}px)`
54
+ }
55
+
56
+ style.position = descriptor.position
57
+ style.transform = ''
58
+ if (descriptor.translate.x !== 0) {
59
+ style.transform += `translateX(${descriptor.translate.x}%) `
60
+ }
61
+ if (descriptor.translate.y !== 0) {
62
+ style.transform += `translateY(${descriptor.translate.y}%) `
63
+ }
64
+
65
+ const xValue = descriptor.location.x + descriptor.xUnit
66
+ if (descriptor.xAxis === 'left') {
67
+ style.left = xValue
68
+ style.right = ''
69
+ } else {
70
+ style.right = xValue
71
+ style.left = ''
72
+ }
73
+ const yValue = descriptor.location.y + descriptor.yUnit
74
+ if (descriptor.yAxis === 'top') {
75
+ style.top = yValue
76
+ style.bottom = ''
77
+ } else {
78
+ style.bottom = yValue
79
+ style.top = ''
80
+ }
81
+
82
+ style.marginLeft = descriptor.margin.left + 'px'
83
+ style.marginTop = descriptor.margin.top + 'px'
84
+ style.marginRight = descriptor.margin.right + 'px'
85
+ style.marginBottom = descriptor.margin.bottom + 'px'
86
+
87
+ return style
88
+ }
89
+
90
+ getLayoutStyle(descriptor: HTMLDescriptor, args: UpdateArgs) {
91
+ const style: HTMLStyle = {}
92
+
93
+ style.display = descriptor.display
94
+ style.flexWrap = descriptor.flexWrap
95
+ style.flexDirection = descriptor.flexDirection
96
+ style.justifyContent = descriptor.justifyContent
97
+ style.alignItems = descriptor.alignItems
98
+ style.alignContent = descriptor.alignContent
99
+ style.opacity = descriptor.opacity + ''
100
+ style.zIndex = descriptor.zIndex
101
+
102
+ return style
103
+ }
104
+
105
+ setHTMLStyle(DOM: HTMLElement, style: HTMLStyle) {
106
+ Object.assign(DOM.style, style)
107
+ }
108
+
109
+ getStyleClass(descriptor: HTMLDescriptor, args: UpdateArgs) {
110
+ const styleDescriptor = Asset.get<StyleDescriptor>(descriptor.style)
111
+ if (styleDescriptor === null) return []
112
+ const graphics = Actor.getGraphics(this)
113
+ const styleActor = graphics.getInterpreter(styleDescriptor).getActor<StyleActor>(descriptor, args)
114
+ return styleActor.getClassName()
115
+ }
116
+
117
+ setStyleClass(DOM: HTMLElement, className: string[]) {
118
+ this.clearStyleClass(DOM)
119
+ this.className = className
120
+ DOM.classList.add(...className)
121
+ }
122
+
123
+ clearStyleClass(DOM: HTMLElement) {
124
+ if (this.className === undefined) return
125
+ DOM.classList.remove(...this.className)
126
+ delete this.className
127
+ }
128
+
129
+ bindInteraction(DOM: HTMLElement, interaction: InteractionProperty, trigger: Descriptor, graphics: Graphics, args: UpdateArgs) {
130
+ const routine = Asset.get<RoutineDescriptor>(interaction.url)
131
+ const interpreter = graphics.getInterpreter<RoutineInterpreter>(routine)
132
+
133
+ const eventArgs = { ...args, trigger }
134
+ const listener = (e: Event) => {
135
+ e.stopPropagation()
136
+ interpreter.do(interaction.inputs, routine, eventArgs)
137
+ }
138
+ const eid = graphics.engine.inputSystem.listen(interaction.type as any, listener, { target: DOM })
139
+ this.unlisteners.push(() => graphics.engine.inputSystem.unlisten(eid))
140
+ }
141
+
142
+ cleanInteraction() {
143
+ for (const unlistener of this.unlisteners) unlistener()
144
+ this.unlisteners.length = 0
145
+ }
146
+
147
+ setHTMLInteraction(DOM: HTMLElement, trigger: Descriptor, args: UpdateArgs) {
148
+ this.cleanInteraction()
149
+ const graphics = HTMLActor.getGraphics(this)
150
+ for (const interaction of trigger.interactions) {
151
+ if (interaction.url) this.bindInteraction(DOM, interaction, trigger, graphics, args)
152
+ }
153
+ }
154
+
155
+ abstract add(actor: Actor): void
156
+
157
+ abstract remove(actor: Actor): void
158
+
159
+ abstract getWrapper(): HTMLElement | null
160
+
161
+ abstract update(descriptor: HTMLDescriptor, args: UpdateArgs): void
162
+ }
163
+
164
+ export {
165
+ HTMLActor
166
+ }
@@ -0,0 +1,57 @@
1
+ import { HTMLServiceDescriptor, StyleDescriptor, UpdateArgs } from "../descriptor"
2
+ import { Actor } from "./Actor"
3
+ import { HTMLActor } from "./HTMActor"
4
+
5
+ class HTMLServiceActor extends HTMLActor {
6
+ private _wrapper: HTMLElement | null = null
7
+ readonly DOM
8
+
9
+ constructor(uuid: string) {
10
+ super(uuid)
11
+ this.DOM = this.createDOM()
12
+ const wrapper = this.getWrapper()
13
+ wrapper.appendChild(this.DOM)
14
+ }
15
+
16
+ protected createWrapper() {
17
+ const wrapper = document.createElement('div')
18
+ wrapper.setAttribute('class', HTMLActor.className)
19
+ wrapper.setAttribute(HTMLActor.uuidKey, this.uuid)
20
+ return wrapper
21
+ }
22
+
23
+ getWrapper() {
24
+ if (this._wrapper === null) {
25
+ this._wrapper = this.createWrapper()
26
+ }
27
+
28
+ return this._wrapper
29
+ }
30
+
31
+ add(actor: Actor) {
32
+ if (actor instanceof HTMLActor) {
33
+ const wrapper = actor.getWrapper()
34
+ if (wrapper === null) return
35
+ if (this.DOM.contains(wrapper)) return
36
+ this.DOM.appendChild(wrapper)
37
+ }
38
+ }
39
+
40
+ remove(actor: Actor) {
41
+ if (actor instanceof HTMLActor) {
42
+ const wrapper = actor.getWrapper()
43
+ if (wrapper === null) return
44
+ if (this.DOM.contains(wrapper)) this.DOM.removeChild(wrapper)
45
+ }
46
+ }
47
+
48
+ update(descriptor: HTMLServiceDescriptor, args: UpdateArgs) {
49
+ const wrapper = this.getWrapper()
50
+ this.setHTMLStyle(wrapper, this.getWrapperStyle(descriptor, args))
51
+ const styleClass = [...this.getStyleClass(descriptor, args)]
52
+ if (descriptor.active) styleClass.push(StyleDescriptor.activeName)
53
+ this.setStyleClass(this.DOM, styleClass)
54
+ }
55
+ }
56
+
57
+ export { HTMLServiceActor }
@@ -0,0 +1,404 @@
1
+ import { Vector2 } from "../math"
2
+ import { Asset } from "../asset"
3
+ import { Descriptor, HTMLDescriptor, HTMLTransformControllerChangeArgs, HTMLTransformControllerDescriptor, UpdateArgs } from "../descriptor"
4
+ import { Scriptable } from "../Scriptable"
5
+ import { Actor } from "./Actor"
6
+ import { HTMLActor } from "./HTMActor"
7
+
8
+ class HTMLTransformState {
9
+ isDragging = false
10
+ isResizing = false
11
+ offset = new Vector2()
12
+ resizeData = {
13
+ direction: "",
14
+ startWidth: 0,
15
+ startHeight: 0,
16
+ calcHeight: 0,
17
+ calcWidth: 0,
18
+ startX: 0,
19
+ startY: 0,
20
+ }
21
+ target = {
22
+ element: document.createElement('div') as HTMLElement,
23
+ parent: null as HTMLElement | null,
24
+ initialRect: new DOMRect(),
25
+ }
26
+ }
27
+
28
+ class HTMLTransformControllerActor extends Actor {
29
+ state = new HTMLTransformState()
30
+ offset = new Vector2()
31
+ events: number[] = []
32
+ element: HTMLElement
33
+ circles: HTMLElement[]
34
+ target!: HTMLDescriptor
35
+ descriptor!: HTMLTransformControllerDescriptor
36
+
37
+ constructor() {
38
+ super()
39
+ this.element = this.createElement()
40
+ this.circles = this.createCircle()
41
+ for (const circle of this.circles) this.element.appendChild(circle)
42
+ document.body.appendChild(this.element)
43
+ }
44
+
45
+ createElement() {
46
+ const element = document.createElement('div')
47
+ element.style.width = '100px'
48
+ element.style.height = '100px'
49
+ element.style.position = 'fixed'
50
+ element.style.top = '0px'
51
+ element.style.left = '0px'
52
+ element.style.zIndex = '2147483647'
53
+ element.style.userSelect = 'none'
54
+ element.addEventListener('contextmenu', e => {
55
+ e.stopPropagation()
56
+ e.preventDefault()
57
+ this.change('contextmenu')
58
+ })
59
+
60
+ const border = document.createElement('div')
61
+ border.style.position = 'absolute'
62
+ border.style.top = '50%'
63
+ border.style.left = '50%'
64
+ border.style.transform = 'translate(-50%,-50%)'
65
+ border.style.width = '100%'
66
+ border.style.height = '100%'
67
+ border.style.border = '6px double #1b8fdfcc'
68
+ border.style.boxSizing = 'content-box'
69
+ border.style.pointerEvents = 'none'
70
+ element.appendChild(border)
71
+ return element
72
+ }
73
+
74
+ createCircle() {
75
+ const circles = []
76
+ const positions = [[0, 0], [100, 0], [100, 100], [0, 100]]
77
+ for (let i = 0; i < positions.length; i++) {
78
+ const circle = document.createElement('div')
79
+ this.setCircleStyle(circle, i, positions[i])
80
+ circles.push(circle)
81
+ }
82
+ return circles
83
+ }
84
+
85
+ setCircleStyle(circle: HTMLElement, index: number, position: number[]) {
86
+ circle.classList.add('resize-handle', index.toString())
87
+ circle.style.borderRadius = '50%'
88
+ circle.style.width = '12px'
89
+ circle.style.height = '12px'
90
+ circle.style.position = 'absolute'
91
+ circle.style.left = position[0] + '%'
92
+ circle.style.top = position[1] + '%'
93
+ circle.style.transform = 'translate(-50%,-50%)'
94
+ circle.style.border = '2px double #1b8fdfcc'
95
+ circle.style.background = '#ffffff'
96
+ circle.style.boxShadow = '0 0 4px #1b8fdfcc'
97
+ circle.style.zIndex = '99999'
98
+ circle.style.cursor = [1, 3].includes(index) ? 'nesw-resize' : 'nwse-resize'
99
+ }
100
+
101
+ listen(descriptor: HTMLTransformControllerDescriptor, args: UpdateArgs) {
102
+ this.reset()
103
+ const graphics = Actor.getGraphics(this)
104
+ const target = graphics.variableProxy.get<Descriptor>(descriptor.target, graphics, args)
105
+ if (target instanceof HTMLDescriptor) {
106
+
107
+ const targetActor = graphics.getActor<HTMLActor>(target, args)
108
+ if (targetActor === null) return
109
+
110
+ const wrapper = targetActor.getWrapper()
111
+ if (wrapper === null) return
112
+
113
+ this.descriptor = descriptor
114
+ this.target = target
115
+
116
+ this.selectTargetElement(wrapper)
117
+
118
+ this.events.push(graphics.engine.inputSystem.listen('mousedown', this.handleDragStart, { target: this.element }))
119
+ for (const circle of this.circles) {
120
+ this.events.push(graphics.engine.inputSystem.listen('mousedown', this.handleResizeStart, { target: circle }))
121
+ }
122
+ this.events.push(graphics.engine.inputSystem.listen('mousemove', this.handleMouseMove, { target: document }))
123
+ this.events.push(graphics.engine.inputSystem.listen('mouseup', this.handleMouseEnd, { target: document }))
124
+ }
125
+ }
126
+
127
+ unlisten() {
128
+ this.reset()
129
+ }
130
+
131
+ update(descriptor: HTMLTransformControllerDescriptor, args: UpdateArgs) {
132
+ this.listen(descriptor, args)
133
+ }
134
+
135
+ change = (type = 'change') => {
136
+ const scriptable = Asset.get<Scriptable>(this.descriptor.event)
137
+ if (scriptable === null) return
138
+ const graphics = Actor.getGraphics(this)
139
+ const _args: HTMLTransformControllerChangeArgs = { delta: 0, event: { type, target: this.descriptor.target } }
140
+ scriptable.execute(this.descriptor, graphics, _args)
141
+ }
142
+
143
+ reset() {
144
+ const graphics = Actor.getGraphics(this)
145
+ for (const id of this.events) graphics.engine.inputSystem.unlisten(id)
146
+ this.events.length = 0
147
+ this.element.style.display = 'none'
148
+ this.state.target.element = document.createElement('div')
149
+ this.state.target.parent = null
150
+ //@ts-ignore
151
+ this.target = undefined
152
+ }
153
+
154
+ dispose() {
155
+ this.reset()
156
+ this.element.remove()
157
+ }
158
+
159
+ // 选中目标元素
160
+ selectTargetElement = (element: HTMLElement) => {
161
+ this.state.target.element = element;
162
+ this.state.target.parent = element.parentElement;
163
+ this.state.target.initialRect = element.getBoundingClientRect();
164
+
165
+ this.updateOffset(this.state.target.initialRect)
166
+ // 显示并更新拖拽元素
167
+ this.updateDraggableElement();
168
+ this.element.style.display = 'block';
169
+ }
170
+
171
+ updateOffset(rect: DOMRect = this.state.target.initialRect) {
172
+ this.offset.set(
173
+ rect.width * (this.target.translate.x / 100),
174
+ rect.height * (this.target.translate.y / 100)
175
+ )
176
+ }
177
+
178
+ // 更新拖拽元素以匹配目标
179
+ updateDraggableElement = () => {
180
+ if (!this.state.target.element) return;
181
+
182
+ const targetRect = this.state.target.element.getBoundingClientRect();
183
+
184
+ this.element.style.left = `${targetRect.left}px`;
185
+ this.element.style.top = `${targetRect.top}px`;
186
+ this.element.style.width = `${targetRect.width}px`;
187
+ this.element.style.height = `${targetRect.height}px`;
188
+ }
189
+
190
+ // 同步更新目标元素位置
191
+ syncTargetPosition = (resize = true) => {
192
+ if (!this.state.target.element) return;
193
+ if (!this.state.target.parent) return
194
+
195
+ const draggableRect = this.element.getBoundingClientRect();
196
+ const parentRect = this.state.target.parent.getBoundingClientRect();
197
+
198
+ // 设置尺寸
199
+ if (resize) {
200
+ this.setDimension('width', draggableRect.width - this.state.resizeData.calcWidth, parentRect.width, this.target.wUnit);
201
+ this.setDimension('height', draggableRect.height - this.state.resizeData.calcHeight, parentRect.height, this.target.hUnit);
202
+ }
203
+
204
+ // 设置位置
205
+ if (this.target.position === 'fixed') {
206
+ this.setFixedPosition(draggableRect)
207
+ } else {
208
+ this.setRelativePosition(draggableRect, parentRect);
209
+ }
210
+
211
+ this.target.setNeedsUpdate()
212
+ }
213
+
214
+ // 设置元素尺寸
215
+ setDimension = (prop: string, value: number, parentSize: number, unit: string) => {
216
+ //@ts-ignore
217
+ this.target[prop] = unit === '%' ? (value / parentSize) * 100 : value
218
+ }
219
+
220
+ // 设置固定定位
221
+ setFixedPosition = (rect: DOMRect) => {
222
+ if (this.target.xAxis === 'left') {
223
+ const leftPos = rect.left - this.offset.x
224
+ this.target.location.x = this.target.xUnit === '%' ? (leftPos / window.innerWidth) * 100
225
+ : leftPos
226
+ } else {
227
+ const rightPos = window.innerWidth - rect.right + this.offset.x
228
+ this.target.location.x = this.target.xUnit === '%'
229
+ ? (rightPos / window.innerWidth) * 100
230
+ : rightPos
231
+ }
232
+
233
+ if (this.target.yAxis === 'top') {
234
+ const topPos = rect.top - this.offset.y
235
+ this.target.location.y = this.target.yUnit === '%'
236
+ ? (topPos / window.innerHeight) * 100
237
+ : topPos
238
+ } else {
239
+ const bottomPos = window.innerHeight - rect.bottom + this.offset.y
240
+ this.target.location.y = this.target.yUnit === '%'
241
+ ? (bottomPos / window.innerHeight) * 100
242
+ : bottomPos
243
+ }
244
+ }
245
+
246
+ // 设置相对/绝对定位
247
+ setRelativePosition = (draggableRect: DOMRect, parentRect: DOMRect) => {
248
+ if (this.target.xAxis === 'left') {
249
+ const leftPos = draggableRect.left - parentRect.left - this.offset.x;
250
+ this.target.location.x = this.target.xUnit === '%'
251
+ ? (leftPos / parentRect.width) * 100
252
+ : leftPos
253
+ } else {
254
+ const rightPos = parentRect.right - draggableRect.right + this.offset.x;
255
+ this.target.location.x = this.target.xUnit === '%'
256
+ ? (rightPos / parentRect.width) * 100
257
+ : rightPos
258
+ }
259
+
260
+ if (this.target.yAxis === 'top') {
261
+ const topPos = draggableRect.top - parentRect.top - this.offset.y;
262
+ this.target.location.y = this.target.yUnit === '%'
263
+ ? (topPos / parentRect.height) * 100
264
+ : topPos
265
+ } else {
266
+ const bottomPos = parentRect.bottom - draggableRect.bottom + this.offset.y;
267
+ this.target.location.y = this.target.yUnit === '%'
268
+ ? (bottomPos / parentRect.height) * 100
269
+ : bottomPos
270
+ }
271
+ }
272
+
273
+ // 拖拽开始
274
+ handleDragStart = (e: MouseEvent) => {
275
+ if (this.descriptor.enabled === false) return
276
+ if (!this.state.target.element) return
277
+ if (this.target.position === 'static' || this.target.position === 'relative') return
278
+
279
+ if (e.target instanceof HTMLElement && e.target.classList.contains('resize-handle') === false) {
280
+
281
+ this.state.isDragging = true;
282
+
283
+ const rect = this.element.getBoundingClientRect();
284
+ this.state.offset = new Vector2(e.clientX - rect.left, e.clientY - rect.top)
285
+
286
+ // 清除目标元素的过渡效果,实现更流畅的拖拽
287
+ this.state.target.element.style.transition = 'none';
288
+
289
+ e.preventDefault();
290
+
291
+ this.change('mousedown')
292
+ }
293
+
294
+ }
295
+
296
+ // 调整大小开始
297
+ handleResizeStart = (e: MouseEvent) => {
298
+ if (this.descriptor.enabled === false) return
299
+ if (!this.state.target.element) return;
300
+ if (this.target.position === 'static' || this.target.position === 'relative') return
301
+ if (e.target instanceof HTMLElement) {
302
+
303
+ this.state.isResizing = true;
304
+ this.state.resizeData.direction = e.target.classList[1];
305
+
306
+ const rect = this.element.getBoundingClientRect();
307
+ this.state.resizeData.calcWidth = this.target.calcWidth
308
+ this.state.resizeData.calcHeight = this.target.calcHeight
309
+ this.state.resizeData.startWidth = rect.width;
310
+ this.state.resizeData.startHeight = rect.height;
311
+ this.state.resizeData.startX = rect.left;
312
+ this.state.resizeData.startY = rect.top;
313
+ this.state.offset = new Vector2(e.clientX, e.clientY)
314
+
315
+ // 清除目标元素的过渡效果,实现更流畅的调整
316
+ this.state.target.element.style.transition = 'none';
317
+
318
+ e.preventDefault();
319
+
320
+ this.change('mousedown')
321
+ }
322
+ }
323
+
324
+ // 鼠标移动处理
325
+ handleMouseMove = (e: MouseEvent) => {
326
+ if (!this.state.target.element) return
327
+
328
+ if (this.state.isDragging) {
329
+ // 更新拖拽元素位置
330
+ this.element.style.left = `${e.clientX - this.state.offset.x}px`;
331
+ this.element.style.top = `${e.clientY - this.state.offset.y}px`;
332
+
333
+ // 同步更新目标元素
334
+ this.syncTargetPosition(false);
335
+ this.change()
336
+ } else if (this.state.isResizing) {
337
+ this.handleResizing(e);
338
+ this.change()
339
+ }
340
+ }
341
+
342
+ // 处理调整大小
343
+ handleResizing = (e: MouseEvent) => {
344
+ const deltaX = e.clientX - this.state.offset.x;
345
+ const deltaY = e.clientY - this.state.offset.y;
346
+ const { direction, startWidth, startHeight, startX, startY } = this.state.resizeData;
347
+
348
+ let newWidth = startWidth;
349
+ let newHeight = startHeight;
350
+ let newLeft = startX;
351
+ let newTop = startY;
352
+
353
+ // 根据调整方向计算新尺寸和位置
354
+ switch (direction) {
355
+ case '0':
356
+ newWidth = Math.max(20, startWidth - deltaX);
357
+ newHeight = Math.max(20, startHeight - deltaY);
358
+ newLeft = startX + (startWidth - newWidth);
359
+ newTop = startY + (startHeight - newHeight);
360
+ break;
361
+ case '1':
362
+ newWidth = Math.max(20, startWidth + deltaX);
363
+ newHeight = Math.max(20, startHeight - deltaY);
364
+ newTop = startY + (startHeight - newHeight);
365
+ break;
366
+ case '3':
367
+ newWidth = Math.max(20, startWidth - deltaX);
368
+ newHeight = Math.max(20, startHeight + deltaY);
369
+ newLeft = startX + (startWidth - newWidth);
370
+ break;
371
+ case '2':
372
+ newWidth = Math.max(20, startWidth + deltaX);
373
+ newHeight = Math.max(20, startHeight + deltaY);
374
+ break;
375
+ }
376
+
377
+ this.element.style.width = `${newWidth}px`;
378
+ this.element.style.height = `${newHeight}px`;
379
+ this.element.style.left = `${newLeft}px`;
380
+ this.element.style.top = `${newTop}px`;
381
+
382
+ this.updateOffset(this.element.getBoundingClientRect())
383
+
384
+ // 同步更新目标元素
385
+ this.syncTargetPosition();
386
+ }
387
+
388
+ // 鼠标释放处理
389
+ handleMouseEnd = () => {
390
+ if (!this.state.target.element) return
391
+
392
+ if (this.state.isDragging) {
393
+ this.state.isDragging = false;
394
+ } else if (this.state.isResizing) {
395
+ this.state.isResizing = false;
396
+ }
397
+
398
+ this.change('mouseup')
399
+ }
400
+ }
401
+
402
+ export {
403
+ HTMLTransformControllerActor
404
+ }