@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.
- package/package.json +19 -0
- package/src/ArrayUtils.ts +65 -0
- package/src/AsyncTask.ts +72 -0
- package/src/Category.ts +119 -0
- package/src/Color.ts +111 -0
- package/src/Engine.ts +101 -0
- package/src/Generate.ts +40 -0
- package/src/InputSystem.ts +108 -0
- package/src/Listener.ts +59 -0
- package/src/ObjectPool.ts +84 -0
- package/src/ObjectUtils.ts +49 -0
- package/src/Scriptable.ts +27 -0
- package/src/Serialization.ts +49 -0
- package/src/Traverser.ts +39 -0
- package/src/actor/Actor.ts +28 -0
- package/src/actor/AnimationUnitActor.ts +289 -0
- package/src/actor/DivActor.ts +70 -0
- package/src/actor/FragmentActor.ts +56 -0
- package/src/actor/HTMActor.ts +166 -0
- package/src/actor/HTMServiceActor.ts +57 -0
- package/src/actor/HTMTransformControllerActor.ts +404 -0
- package/src/actor/StyleActor.ts +96 -0
- package/src/actor/index.ts +8 -0
- package/src/asset/Asset.ts +271 -0
- package/src/asset/AssetGraph.ts +246 -0
- package/src/asset/index.ts +2 -0
- package/src/descriptor/AnimationUnitDescriptor.ts +65 -0
- package/src/descriptor/CameraDescriptor.ts +12 -0
- package/src/descriptor/ControllerDescriptor.ts +16 -0
- package/src/descriptor/DatasetDescriptor.ts +92 -0
- package/src/descriptor/Descriptor.ts +415 -0
- package/src/descriptor/DivDescriptor.ts +18 -0
- package/src/descriptor/DynamicDescriptor.ts +27 -0
- package/src/descriptor/HTMLDescriptor.ts +87 -0
- package/src/descriptor/HTMLServiceDescriptor.ts +19 -0
- package/src/descriptor/HTMLTransformControllerDescriptor.ts +34 -0
- package/src/descriptor/NodeDescriptor.ts +32 -0
- package/src/descriptor/PrefabDescriptor.ts +53 -0
- package/src/descriptor/PrefabInstanceDescriptor.ts +32 -0
- package/src/descriptor/RoutineDescriptor.ts +54 -0
- package/src/descriptor/ServiceDescriptor.ts +32 -0
- package/src/descriptor/ServiceSchedulerDescriptor.ts +32 -0
- package/src/descriptor/StyleDescriptor.ts +213 -0
- package/src/descriptor/index.ts +17 -0
- package/src/graphics/Collection.ts +25 -0
- package/src/graphics/Compilation.ts +82 -0
- package/src/graphics/Graphics.ts +475 -0
- package/src/graphics/Observer.ts +36 -0
- package/src/graphics/Unit.ts +83 -0
- package/src/graphics/VariableProxy.ts +92 -0
- package/src/graphics/index.ts +5 -0
- package/src/index.ts +26 -0
- package/src/interpreter/AnimationUnitInterpreter.ts +53 -0
- package/src/interpreter/DatasetInterpreter.ts +11 -0
- package/src/interpreter/DivInterpreter.ts +44 -0
- package/src/interpreter/DynamicInterpreter.ts +207 -0
- package/src/interpreter/FragmentInterpreter.ts +34 -0
- package/src/interpreter/HTMLServiceInterpreter.ts +47 -0
- package/src/interpreter/HTMLTransformControllerInterpreter.ts +40 -0
- package/src/interpreter/Interpreter.ts +69 -0
- package/src/interpreter/PrefaInterpreter.ts +11 -0
- package/src/interpreter/PrefabInstanceInterpreter.ts +12 -0
- package/src/interpreter/RoutineInterpreter.ts +88 -0
- package/src/interpreter/ServiceInterpreter.ts +24 -0
- package/src/interpreter/ServiceSchedulerInterpreter.ts +42 -0
- package/src/interpreter/StyleInterpreter.ts +66 -0
- package/src/interpreter/index.ts +14 -0
- package/src/locale/Language.ts +10 -0
- package/src/locale/LanguageProvider.ts +48 -0
- package/src/locale/index.ts +2 -0
- package/src/math/Euler.ts +303 -0
- package/src/math/Matrix4.ts +1123 -0
- package/src/math/Quaternion.ts +737 -0
- package/src/math/Vector2.ts +680 -0
- package/src/math/Vector3.ts +1062 -0
- package/src/math/index.ts +5 -0
- package/src/math/utils.ts +17 -0
- package/src/preset/execute/dataset/index.ts +1 -0
- package/src/preset/execute/dataset/update.ts +52 -0
- package/src/preset/execute/graphics/index.ts +1 -0
- package/src/preset/execute/graphics/invoke.ts +49 -0
- package/src/preset/execute/index.ts +4 -0
- package/src/preset/execute/net/index.ts +1 -0
- package/src/preset/execute/net/request.ts +103 -0
- package/src/preset/execute/scheduler/index.ts +1 -0
- package/src/preset/execute/scheduler/switch.ts +46 -0
- package/src/preset/index.ts +7 -0
- package/src/preset/routine/graphics/index.ts +1 -0
- package/src/preset/routine/graphics/invoke.ts +27 -0
- package/src/preset/routine/index.ts +2 -0
- package/src/preset/routine/scheduler/index.ts +1 -0
- package/src/preset/routine/scheduler/switch.ts +27 -0
- package/src/setup/index.ts +17 -0
- package/src/utils/AssetProvider.ts +72 -0
- 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
|
+
}
|