@vived/app 2.6.0 → 2.8.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/README.md +1 -151
- package/lib/Core/BaseApp/UseCase.js +1 -1
- package/lib/Entities/Babylon.d.ts +31 -0
- package/lib/Entities/Babylon.js +99 -0
- package/lib/Entities/BaseApp.d.ts +7 -0
- package/lib/Entities/BaseApp.js +27 -0
- package/lib/Entities/Color.d.ts +20 -0
- package/lib/Entities/Color.js +59 -0
- package/lib/Entities/DevicePreview.d.ts +11 -0
- package/lib/Entities/DevicePreview.js +44 -0
- package/lib/Entities/KeyboardInput.d.ts +14 -0
- package/lib/Entities/KeyboardInput.js +76 -0
- package/lib/Entities/LineSegment2D.d.ts +11 -0
- package/lib/Entities/LineSegment2D.js +70 -0
- package/lib/Entities/MemoizedBoolean.d.ts +7 -0
- package/lib/Entities/MemoizedBoolean.js +19 -0
- package/lib/Entities/MemoizedNumber.d.ts +7 -0
- package/lib/Entities/MemoizedNumber.js +19 -0
- package/lib/Entities/MemoizedString.d.ts +7 -0
- package/lib/Entities/MemoizedString.js +19 -0
- package/lib/Entities/MemoizedVector2.d.ts +12 -0
- package/lib/Entities/MemoizedVector2.js +37 -0
- package/lib/Entities/MemoizedVector3.d.ts +14 -0
- package/lib/Entities/MemoizedVector3.js +46 -0
- package/lib/Entities/MouseInput.d.ts +15 -0
- package/lib/Entities/MouseInput.js +109 -0
- package/lib/Entities/MouseSceneInput.d.ts +15 -0
- package/lib/Entities/MouseSceneInput.js +109 -0
- package/lib/Entities/ObserverList.d.ts +6 -0
- package/lib/Entities/ObserverList.js +23 -0
- package/lib/Entities/OrbitCamera.d.ts +17 -0
- package/lib/Entities/OrbitCamera.js +74 -0
- package/lib/Entities/ParametricLine.d.ts +29 -0
- package/lib/Entities/ParametricLine.js +79 -0
- package/lib/Entities/ParametricPlane.d.ts +20 -0
- package/lib/Entities/ParametricPlane.js +63 -0
- package/lib/Entities/StateMachine.d.ts +25 -0
- package/lib/Entities/StateMachine.js +81 -0
- package/lib/Entities/UndoRedo.d.ts +22 -0
- package/lib/Entities/UndoRedo.js +61 -0
- package/lib/Entities/Vector2.d.ts +21 -0
- package/lib/Entities/Vector2.js +83 -0
- package/lib/Entities/Vector3.d.ts +19 -0
- package/lib/Entities/Vector3.js +75 -0
- package/lib/Entities/index.d.ts +20 -0
- package/lib/Entities/index.js +32 -0
- package/lib/PresentationManagers/DevicePreviewPM.d.ts +13 -0
- package/lib/PresentationManagers/DevicePreviewPM.js +25 -0
- package/lib/PresentationManagers/HasRedoPM.d.ts +9 -0
- package/lib/PresentationManagers/HasRedoPM.js +22 -0
- package/lib/PresentationManagers/HasUndoPM.d.ts +9 -0
- package/lib/PresentationManagers/HasUndoPM.js +22 -0
- package/lib/PresentationManagers/IsAuthoringPM.d.ts +9 -0
- package/lib/PresentationManagers/IsAuthoringPM.js +22 -0
- package/lib/PresentationManagers/OrbitCameraPM.d.ts +14 -0
- package/lib/PresentationManagers/OrbitCameraPM.js +31 -0
- package/lib/PresentationManagers/ShowBabylonInspectorPM.d.ts +9 -0
- package/lib/PresentationManagers/ShowBabylonInspectorPM.js +22 -0
- package/lib/PresentationManagers/index.d.ts +6 -0
- package/lib/PresentationManagers/index.js +18 -0
- package/lib/UseCases/LerpOrbitCamera.d.ts +36 -0
- package/lib/UseCases/LerpOrbitCamera.js +71 -0
- package/lib/UseCases/SerializeCamera.d.ts +21 -0
- package/lib/UseCases/SerializeCamera.js +59 -0
- package/lib/UseCases/SerializeOrbitCamera.d.ts +21 -0
- package/lib/UseCases/SerializeOrbitCamera.js +59 -0
- package/lib/UseCases/SerializedCamDemo.d.ts +0 -0
- package/lib/UseCases/SerializedCamDemo.js +1 -0
- package/lib/UseCases/index.d.ts +3 -0
- package/lib/UseCases/index.js +15 -0
- package/lib/UseCases/setDevicePreview.d.ts +2 -0
- package/lib/UseCases/setDevicePreview.js +14 -0
- package/lib/Utilities/degreesToRadians.d.ts +1 -0
- package/lib/Utilities/degreesToRadians.js +7 -0
- package/lib/Utilities/index.d.ts +1 -0
- package/lib/Utilities/index.js +13 -0
- package/lib/index.d.ts +7 -2
- package/lib/index.js +8 -2
- package/package.json +1 -2
- package/CHANGELOG.md +0 -58
package/README.md
CHANGED
|
@@ -1,151 +1 @@
|
|
|
1
|
-
|
|
2
|
-
This package is intended to hold all the common logic used by VIVED Slide Apps.
|
|
3
|
-
|
|
4
|
-
## Use Case
|
|
5
|
-
You will need to instantiate the baseAppUC by calling makeBaseAppUC(). Typically this is done in your Main script when everything is starting up.
|
|
6
|
-
|
|
7
|
-
### Functions
|
|
8
|
-
#### getIsAuthoring():boolean
|
|
9
|
-
Gets the flag to see if the app is currently in an authoring state
|
|
10
|
-
|
|
11
|
-
#### setIsAuthoring(isAuthoring:boolean):void
|
|
12
|
-
Sets the is authoring flag. If there is a change this will notify all observers
|
|
13
|
-
|
|
14
|
-
#### getShowBabylonInspector():boolean
|
|
15
|
-
Gets the flag to see if the babylon inspector should be show
|
|
16
|
-
|
|
17
|
-
#### setShowBabylonInspector(showInspector: boolean):void
|
|
18
|
-
Sets if the Babylon Inspector should be shown. If there is a change this will notify all observers.
|
|
19
|
-
|
|
20
|
-
#### addObserver(observer: BaseAppStateObserver): void;
|
|
21
|
-
Adds an observer to the Use Case. The observer will be notified if anything in the use case changes
|
|
22
|
-
|
|
23
|
-
#### removeObserver(observer: BaseAppStateObserver): void;
|
|
24
|
-
Removes an observer so it will no longer be notified of changes in the Use Case
|
|
25
|
-
|
|
26
|
-
#### getSerializedState(): SerializedStates;
|
|
27
|
-
Get the current serialized state of the App. See the Serilization section below
|
|
28
|
-
|
|
29
|
-
#### setSerializedState(state: SerializedStates): void;
|
|
30
|
-
Sets the state of the app to a Serialized State. See the Serilization section below
|
|
31
|
-
|
|
32
|
-
#### registerSerializableSystem(serializedSystem: SerializableSystem):void;
|
|
33
|
-
Registers a Serializable System. This is likely a system in your App which has states that need to be saved and applied. See the Serilization section below
|
|
34
|
-
|
|
35
|
-
#### setHostHandler(handler: Handler):void;
|
|
36
|
-
When an App is mounted it is passed the Host Handler. This is the Handler to which the Use Case will dispatch all requests. This needs to be set when the app Main is constructed. See the App - Host Communication section below
|
|
37
|
-
|
|
38
|
-
#### hasHostHandler():boolean;
|
|
39
|
-
This checks to see if a host handler has been set. This is useful for avoiding nasty errors
|
|
40
|
-
|
|
41
|
-
#### dispatchOnStateChange(stateObject: object):void;
|
|
42
|
-
When authoring the Host should be notified whenever something in the serializable state has changed. Calling this will let the host know that the state has changed and pass along the new state.
|
|
43
|
-
|
|
44
|
-
#### dispatchOnStateComplete():void
|
|
45
|
-
Calling this will let the Host know that the user has completed their required task and the Host can move on to the next state.
|
|
46
|
-
|
|
47
|
-
#### dispatchSubmitResults(results:object):void;
|
|
48
|
-
If a user has completed a task and there are results to submit the app can pass these results to the Host via this call.
|
|
49
|
-
|
|
50
|
-
#### dispatchGetAppAssetsURL():string
|
|
51
|
-
Many Apps require Assets such as GLBs or images. These are expected to be stored in the public/assets folder (assuming the app was built with Create React App). However once the App has been published, the path to this folder will be different. The Host should know this path so calling this will ask the host for the path to the assets folder.
|
|
52
|
-
|
|
53
|
-
#### setDevicePreview(x: number, y: number): void;
|
|
54
|
-
At some point the User may opt to view the Activity in a way the previews a specific hardware device. This decision is handled by the host but the App will be notified. This function is used to set the desired x and y resolution
|
|
55
|
-
|
|
56
|
-
#### clearDevicePreview():void;
|
|
57
|
-
Calling this will clear any preview device resoltions.
|
|
58
|
-
|
|
59
|
-
#### getUseDevicePreview(): boolean;
|
|
60
|
-
This will return a true if the Host has set a device resolution to preview. Otherwise it will return false
|
|
61
|
-
|
|
62
|
-
#### getDevicePreviewSize(): {x: number, y:number}
|
|
63
|
-
This will return the requested preview device x and y resolution. If no device has been set or the previewed device has been cleared, these will both be -1.
|
|
64
|
-
|
|
65
|
-
### Observers
|
|
66
|
-
If you want to be notified when something changes in the Use Case you will need to create an observer class the implements BaseAppStateObserver and then registers itself with the use case via addObserver. If you observer is getting destroyed it needs to call removeObserver on the Use Case
|
|
67
|
-
|
|
68
|
-
### Serilization
|
|
69
|
-
The Serilization system is designed to handle all the heavy lifting of serializing and desrializing the state of your app.
|
|
70
|
-
|
|
71
|
-
#### Serializable System
|
|
72
|
-
You app will likey have one or my systems that have data which needs to be stored in the state. For each of these systems you are expected to write a class that implements SerializableSystem and then register this class with the Base App Use Case by calling registerSerializableSystem.
|
|
73
|
-
|
|
74
|
-
This implementation requires your class to setup four items:
|
|
75
|
-
##### Name
|
|
76
|
-
This is the name of your system. Not this name must be unique across all the serialized systems in your App. In other words you cannot register two different Serializable Systems with the same name. Also, this name should not be modified down the road is it is how the Use Case will determine what Class to send stored activity data to. This name will never be seen by a user.
|
|
77
|
-
|
|
78
|
-
##### Serilization Version
|
|
79
|
-
This is an integer that is stored with the data and written into an activity file. This is intended to allow the system state data to be changed over time while giving developers the opportunity to be backwards compatable. For example, lets say after a few months the system is improved to include another statable variable. The devloper would iterate the serilizationVersion from 1 to 2. From now on, any new saved states will be saved with version number 2. When the System is asked to apply some saved state data it can check to see if this state data was version 1 or 2 and handle it appropriatetly.
|
|
80
|
-
|
|
81
|
-
##### getSerializedObject():object
|
|
82
|
-
The Serilization Use Case will trigger this function when it needs to store the current state. The Class is expected to form up an object however they see fit and return it as a vanilla object.
|
|
83
|
-
|
|
84
|
-
##### applySerializedObject(state: object, version: number):void
|
|
85
|
-
This function will be called when the Serilization Use Case want to apply a state to a system. It will pass in a vanilla object as well as the serilization version that was set when this object was formed. The Class is expected to handle the versions and apply the object appropriatetly.
|
|
86
|
-
|
|
87
|
-
### App - Host Communication
|
|
88
|
-
The boundary between the Host and the App has been intentionally designed to allow the the host and the apps to be completely independent of each other while allowing communication between the two.
|
|
89
|
-
|
|
90
|
-
#### Request
|
|
91
|
-
All messages passed between the Host and the App are called requests. All Requests are strongly typed and versioned in the @vived/app-host-boundary package.
|
|
92
|
-
|
|
93
|
-
#### Dispatcher
|
|
94
|
-
When an App needs to send a request to the Host all it needs to do is trigger a dispatch action in the Use Case. This package will take care of correctly forming the Request and sending it to the Host.
|
|
95
|
-
|
|
96
|
-
#### Handler
|
|
97
|
-
When the Host sends a request to the App it must be handled, which is the responsibility of the App Handler. You app is expected to provide a list of AppHandlerFunctions when it creates the App Handler during the construction of the App. This allows allows the App to unpack the request and then call one of these functions, allowing your App to handle it however it wants.
|
|
98
|
-
|
|
99
|
-
## Presenter Models
|
|
100
|
-
Presenter Models are intented to update a view whenenver a something specific changes in the Use Case. The Presenter Model will either pass the View a specific parameter or a View Model of parameters. Ideally the View will be able to just consume the View Model or the parameter without needing any logic or refactoring.
|
|
101
|
-
|
|
102
|
-
To use Presenter Model your View (or Hook) will need to instantiate the Presenter Model, passing in the baseAppUC and a callback function. The callback function will be triggered when the Presenter Moder is initiated and then whenever an update is available. It is important to call Dispose on the Presetner Model if your view or hook is being destroyed in order to remove it's observer from the Use Case.
|
|
103
|
-
|
|
104
|
-
### DevicePreviewPM
|
|
105
|
-
This PM will update it's view whenever something with the Device Preview changes. It returns a View Model with the following parameters
|
|
106
|
-
- isPreviewingDevice: a boolean letting you know if the render canvas should be scaled
|
|
107
|
-
- x: is the pixel width to scale to if isPreviewingDevice. This will be -1 if there is no device to preview
|
|
108
|
-
- y: is the pixel height to scale to if isPreviewingDevice. This will be -1 if there is no device
|
|
109
|
-
|
|
110
|
-
### IsAuthoringPM
|
|
111
|
-
This PM will update the view whenever the Is Authoring flag changes, passing back the current isAuthor value.
|
|
112
|
-
|
|
113
|
-
### ShowBabylonInspectorPM
|
|
114
|
-
This PM will update the view whenever the Show Babylon Inspector flag changes, passing back the current value.
|
|
115
|
-
|
|
116
|
-
## Controllers
|
|
117
|
-
### defaultAppHandlerFunctions
|
|
118
|
-
The function creates all the default app handler functions. These include:
|
|
119
|
-
- showBabylonInspector: (show: boolean) => void;
|
|
120
|
-
- setIsAuthoring: (isAuthoring: boolean) => void;
|
|
121
|
-
- disposeApp: () => void;
|
|
122
|
-
- stopApp: () => void;
|
|
123
|
-
- startApp: (container: HTMLElement) => void;
|
|
124
|
-
- setState: (finalState: string, duration?: number) => void;
|
|
125
|
-
- setDevicePreview: (x: number, y: number) => void;
|
|
126
|
-
|
|
127
|
-
Your App will likely need to handle one or more of these functions differently so the intent is that you use this function to create all the default functions and then replace the appropriate functions with your custom function before creating the App Handler
|
|
128
|
-
|
|
129
|
-
### dispatchStateChange()
|
|
130
|
-
This function is created with the factory makeDispatchStateChange. It first gets the latest serialized state and then dispatches that state to the Host
|
|
131
|
-
|
|
132
|
-
### makeAppHandler(functions: AppHandlerFunctions): Handler
|
|
133
|
-
This function is used to create the App Handler. It takes in the App Handler Functions and returns a generic Handler, which is passed to the Host. The host can then dispatch a request to this Handler. The App Handler is responsible for reading the request and triggering the appropriate App Handler Function
|
|
134
|
-
|
|
135
|
-
### setDevicePreview(x: number, y: number)
|
|
136
|
-
This function is created with the makeSetDevicePreview factory. If either x or y are negative this function will clear the selected device in the baseAppUC. Otherwise it will set the x and y value of the selected device in the Use Case.
|
|
137
|
-
|
|
138
|
-
### setIsAuthoring(isAuthoring: boolean)
|
|
139
|
-
This function is created with the makeSetIsAuthoring factory and will apply the isAuthoring flag to the use case. It will also dispatch a state change if the is Authorin is set to true. This allows the Host to know the initial state when the user start authoring.
|
|
140
|
-
|
|
141
|
-
### setState(state: string, duration?: number)
|
|
142
|
-
This function is created with the makeSetState facory. It is responsible for recieving a desired state from the Host and applying it locally. You will note that the setState function in this package does not use the duration parameter. This function simply sets the state hard, without any transition. You App will probably what to implement it's own setState function that support nice interpolations for your systems.
|
|
143
|
-
|
|
144
|
-
### showBabylonInspector(showInspector:boolean)
|
|
145
|
-
This function is created with the makeShowBabylonInspector factory. It will set the show babylon inspector flag in the Use Case.
|
|
146
|
-
|
|
147
|
-
### startApp(container: HTMLElement)
|
|
148
|
-
This function is created with the makeStartApp factory. It is reponsible for starting up all the renderings of the App. This could include the App's react components as well as the Babylon Engine.
|
|
149
|
-
|
|
150
|
-
### stopApp()
|
|
151
|
-
This function is created with the makeStopApp factory. It is reponsible for stopping up all the renderings of the App. This could include the App's react components as well as the Babylon Engine. It also ensures that the isAuthoring flag is set to false.
|
|
1
|
+
//Todo
|
|
@@ -214,7 +214,7 @@ class BaseAppUCImp {
|
|
|
214
214
|
this.appState.isTransitioning = true;
|
|
215
215
|
const durationInMS = duration * 1000;
|
|
216
216
|
let chrono = 0;
|
|
217
|
-
const transitionDelta =
|
|
217
|
+
const transitionDelta = 10;
|
|
218
218
|
this.currentInterval = setInterval(() => {
|
|
219
219
|
chrono = chrono + transitionDelta;
|
|
220
220
|
let normalizedTime = chrono / durationInMS;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ParametricLine, Vector3 } from ".";
|
|
2
|
+
import { Vector2 } from "./Vector2";
|
|
3
|
+
export declare type OnBabylonChange = () => void;
|
|
4
|
+
export interface ScenePick {
|
|
5
|
+
mouseRay: ParametricLine;
|
|
6
|
+
hit: boolean;
|
|
7
|
+
worldPickPoint?: Vector3;
|
|
8
|
+
objectPickMeta?: object;
|
|
9
|
+
}
|
|
10
|
+
export declare type ScenePicker = (pixelPos: Vector2) => ScenePick;
|
|
11
|
+
export declare type SceneRayer = (pixelPos: Vector2) => ParametricLine;
|
|
12
|
+
export interface Babylon {
|
|
13
|
+
engine: unknown;
|
|
14
|
+
scene: unknown;
|
|
15
|
+
workingCanvas?: HTMLCanvasElement;
|
|
16
|
+
showInspector: boolean;
|
|
17
|
+
renderCanvas?: HTMLCanvasElement;
|
|
18
|
+
scenePick: (pixelPos: Vector2) => ScenePick;
|
|
19
|
+
sceneRay: (pixelPos: Vector2) => ParametricLine;
|
|
20
|
+
updateCanvasSize: () => void;
|
|
21
|
+
submitRenderCanvas: (canvas: HTMLCanvasElement) => void;
|
|
22
|
+
clearRenderCanvas: () => void;
|
|
23
|
+
registerResizeEnging: (resizeEngine: () => void) => void;
|
|
24
|
+
registerStartRendering: (startRendering: (canvas: HTMLCanvasElement) => void) => void;
|
|
25
|
+
registerStopRendering: (stopRendering: (canvas: HTMLCanvasElement) => void) => void;
|
|
26
|
+
registerScenePicker: (picker: ScenePicker) => void;
|
|
27
|
+
registerSceneRayer: (rayer: SceneRayer) => void;
|
|
28
|
+
addObserver: (observer: OnBabylonChange) => void;
|
|
29
|
+
removeObserver: (observer: OnBabylonChange) => void;
|
|
30
|
+
}
|
|
31
|
+
export declare function makeBabylon(): Babylon;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeBabylon = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
const MemoizedBoolean_1 = require("./MemoizedBoolean");
|
|
6
|
+
const MemoizedVector2_1 = require("./MemoizedVector2");
|
|
7
|
+
const ObserverList_1 = require("./ObserverList");
|
|
8
|
+
const Vector2_1 = require("./Vector2");
|
|
9
|
+
function makeBabylon() {
|
|
10
|
+
return new BabylonImp();
|
|
11
|
+
}
|
|
12
|
+
exports.makeBabylon = makeBabylon;
|
|
13
|
+
class BabylonImp {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.scenePick = () => {
|
|
16
|
+
console.warn("orignal scene picker");
|
|
17
|
+
return {
|
|
18
|
+
mouseRay: _1.ParametricLine.Forward(),
|
|
19
|
+
hit: false,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
this.sceneRay = () => {
|
|
23
|
+
console.warn("orignal scene ray");
|
|
24
|
+
return _1.ParametricLine.Forward();
|
|
25
|
+
};
|
|
26
|
+
this.observers = new ObserverList_1.ObserverList();
|
|
27
|
+
this.updateCanvasSize = () => {
|
|
28
|
+
if (!this.workingCanvas)
|
|
29
|
+
return;
|
|
30
|
+
if (!this._renderCanvas)
|
|
31
|
+
return;
|
|
32
|
+
if (this.resizeEngine) {
|
|
33
|
+
this.resizeEngine();
|
|
34
|
+
}
|
|
35
|
+
this.workingCanvas.height = this._renderCanvas.height;
|
|
36
|
+
this.workingCanvas.width = this._renderCanvas.width;
|
|
37
|
+
};
|
|
38
|
+
this.submitRenderCanvas = (canvas) => {
|
|
39
|
+
if (canvas === this._renderCanvas)
|
|
40
|
+
return;
|
|
41
|
+
if (this._renderCanvas && this.stopRendering) {
|
|
42
|
+
this.stopRendering(this._renderCanvas);
|
|
43
|
+
}
|
|
44
|
+
this._renderCanvas = canvas;
|
|
45
|
+
this.updateCanvasSize();
|
|
46
|
+
if (this.startRendering) {
|
|
47
|
+
this.startRendering(canvas);
|
|
48
|
+
}
|
|
49
|
+
this.observers.notify();
|
|
50
|
+
};
|
|
51
|
+
this.clearRenderCanvas = () => {
|
|
52
|
+
if (!this._renderCanvas)
|
|
53
|
+
return;
|
|
54
|
+
if (this.stopRendering) {
|
|
55
|
+
this.stopRendering(this._renderCanvas);
|
|
56
|
+
}
|
|
57
|
+
this._renderCanvas = undefined;
|
|
58
|
+
this.observers.notify();
|
|
59
|
+
};
|
|
60
|
+
this.registerResizeEnging = (resizeEngine) => {
|
|
61
|
+
this.resizeEngine = resizeEngine;
|
|
62
|
+
};
|
|
63
|
+
this.registerStartRendering = (startRendering) => {
|
|
64
|
+
this.startRendering = startRendering;
|
|
65
|
+
};
|
|
66
|
+
this.registerStopRendering = (stopRendering) => {
|
|
67
|
+
this.stopRendering = stopRendering;
|
|
68
|
+
};
|
|
69
|
+
this.addObserver = (observer) => {
|
|
70
|
+
this.observers.add(observer);
|
|
71
|
+
};
|
|
72
|
+
this.removeObserver = (observer) => {
|
|
73
|
+
this.observers.remove(observer);
|
|
74
|
+
};
|
|
75
|
+
this.registerScenePicker = (picker) => {
|
|
76
|
+
this.scenePick = picker;
|
|
77
|
+
};
|
|
78
|
+
this.registerSceneRayer = (rayer) => {
|
|
79
|
+
this.sceneRay = rayer;
|
|
80
|
+
};
|
|
81
|
+
this.memoizedShowInspector = new MemoizedBoolean_1.MemoizedBoolean(false, this.observers.notify);
|
|
82
|
+
this.memoizedCanvasSize = new MemoizedVector2_1.MemoizedVector2(Vector2_1.Vector2.One(), this.observers.notify);
|
|
83
|
+
}
|
|
84
|
+
get showInspector() {
|
|
85
|
+
return this.memoizedShowInspector.val;
|
|
86
|
+
}
|
|
87
|
+
set showInspector(val) {
|
|
88
|
+
this.memoizedShowInspector.val = val;
|
|
89
|
+
}
|
|
90
|
+
get renderCanvas() {
|
|
91
|
+
return this._renderCanvas;
|
|
92
|
+
}
|
|
93
|
+
get canvasSize() {
|
|
94
|
+
return this.memoizedCanvasSize.getVector();
|
|
95
|
+
}
|
|
96
|
+
set canvasSize(val) {
|
|
97
|
+
this.memoizedCanvasSize.setVector(val);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeBaseApp = void 0;
|
|
4
|
+
const MemoizedBoolean_1 = require("./MemoizedBoolean");
|
|
5
|
+
const ObserverList_1 = require("./ObserverList");
|
|
6
|
+
function makeBaseApp() {
|
|
7
|
+
return new BaseAppImp();
|
|
8
|
+
}
|
|
9
|
+
exports.makeBaseApp = makeBaseApp;
|
|
10
|
+
class BaseAppImp {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.observers = new ObserverList_1.ObserverList();
|
|
13
|
+
this.memoizedIsAuthoring = new MemoizedBoolean_1.MemoizedBoolean(false, this.observers.notify);
|
|
14
|
+
this.addObserver = (observer) => {
|
|
15
|
+
this.observers.add(observer);
|
|
16
|
+
};
|
|
17
|
+
this.removeObserver = (observer) => {
|
|
18
|
+
this.observers.remove(observer);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
get isAuthoring() {
|
|
22
|
+
return this.memoizedIsAuthoring.val;
|
|
23
|
+
}
|
|
24
|
+
set isAuthoring(val) {
|
|
25
|
+
this.memoizedIsAuthoring.val = val;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare class Color {
|
|
2
|
+
static White(): Color;
|
|
3
|
+
static Black(): Color;
|
|
4
|
+
static Red(): Color;
|
|
5
|
+
static Green(): Color;
|
|
6
|
+
static Blue(): Color;
|
|
7
|
+
static Yellow(): Color;
|
|
8
|
+
static Gray(): Color;
|
|
9
|
+
r: number;
|
|
10
|
+
g: number;
|
|
11
|
+
b: number;
|
|
12
|
+
a: number;
|
|
13
|
+
get rPercent(): number;
|
|
14
|
+
get gPercent(): number;
|
|
15
|
+
get bPercent(): number;
|
|
16
|
+
get aPercent(): number;
|
|
17
|
+
equal: (otherColor: Color) => boolean;
|
|
18
|
+
copy: () => Color;
|
|
19
|
+
constructor(r: number, g: number, b: number, a?: number);
|
|
20
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Color = void 0;
|
|
4
|
+
class Color {
|
|
5
|
+
constructor(r, g, b, a = 255) {
|
|
6
|
+
this.equal = (otherColor) => {
|
|
7
|
+
if (otherColor.r === this.r &&
|
|
8
|
+
otherColor.g === this.g &&
|
|
9
|
+
otherColor.b === this.b &&
|
|
10
|
+
otherColor.a === this.a) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
this.copy = () => {
|
|
18
|
+
return new Color(this.r, this.g, this.b, this.a);
|
|
19
|
+
};
|
|
20
|
+
this.r = r;
|
|
21
|
+
this.g = g;
|
|
22
|
+
this.b = b;
|
|
23
|
+
this.a = a;
|
|
24
|
+
}
|
|
25
|
+
static White() {
|
|
26
|
+
return new Color(255, 255, 255, 255);
|
|
27
|
+
}
|
|
28
|
+
static Black() {
|
|
29
|
+
return new Color(0, 0, 0, 255);
|
|
30
|
+
}
|
|
31
|
+
static Red() {
|
|
32
|
+
return new Color(255, 0, 0, 255);
|
|
33
|
+
}
|
|
34
|
+
static Green() {
|
|
35
|
+
return new Color(0, 255, 0, 255);
|
|
36
|
+
}
|
|
37
|
+
static Blue() {
|
|
38
|
+
return new Color(0, 0, 255, 255);
|
|
39
|
+
}
|
|
40
|
+
static Yellow() {
|
|
41
|
+
return new Color(255, 0, 255, 255);
|
|
42
|
+
}
|
|
43
|
+
static Gray() {
|
|
44
|
+
return new Color(192, 192, 192, 255);
|
|
45
|
+
}
|
|
46
|
+
get rPercent() {
|
|
47
|
+
return this.r / 255;
|
|
48
|
+
}
|
|
49
|
+
get gPercent() {
|
|
50
|
+
return this.g / 255;
|
|
51
|
+
}
|
|
52
|
+
get bPercent() {
|
|
53
|
+
return this.b / 255;
|
|
54
|
+
}
|
|
55
|
+
get aPercent() {
|
|
56
|
+
return this.a / 255;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.Color = Color;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Vector2 } from ".";
|
|
2
|
+
export declare type OnDevicePreviewChange = () => void;
|
|
3
|
+
export interface DevicePreview {
|
|
4
|
+
useDevicePreview: boolean;
|
|
5
|
+
previewSize: Vector2;
|
|
6
|
+
setDevicePreview(x: number, y: number): void;
|
|
7
|
+
clearDevicePreview(): void;
|
|
8
|
+
addObserver(observer: OnDevicePreviewChange): void;
|
|
9
|
+
removeObserver(observer: OnDevicePreviewChange): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function makeDevicePreview(): DevicePreview;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeDevicePreview = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
function makeDevicePreview() {
|
|
6
|
+
return new DevicePreviewImp();
|
|
7
|
+
}
|
|
8
|
+
exports.makeDevicePreview = makeDevicePreview;
|
|
9
|
+
class DevicePreviewImp {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.observers = new _1.ObserverList();
|
|
12
|
+
this._usePreview = false;
|
|
13
|
+
this._previewSize = _1.Vector2.Zero();
|
|
14
|
+
this.setDevicePreview = (x, y) => {
|
|
15
|
+
if (this._usePreview &&
|
|
16
|
+
this._previewSize.x === x &&
|
|
17
|
+
this._previewSize.y === y)
|
|
18
|
+
return;
|
|
19
|
+
this._usePreview = true;
|
|
20
|
+
this._previewSize.x = x;
|
|
21
|
+
this._previewSize.y = y;
|
|
22
|
+
this.observers.notify();
|
|
23
|
+
};
|
|
24
|
+
this.clearDevicePreview = () => {
|
|
25
|
+
if (!this._usePreview)
|
|
26
|
+
return;
|
|
27
|
+
this._previewSize = _1.Vector2.Zero();
|
|
28
|
+
this._usePreview = false;
|
|
29
|
+
this.observers.notify();
|
|
30
|
+
};
|
|
31
|
+
this.addObserver = (observer) => {
|
|
32
|
+
this.observers.add(observer);
|
|
33
|
+
};
|
|
34
|
+
this.removeObserver = (observer) => {
|
|
35
|
+
this.observers.remove(observer);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
get useDevicePreview() {
|
|
39
|
+
return this._usePreview;
|
|
40
|
+
}
|
|
41
|
+
get previewSize() {
|
|
42
|
+
return this._previewSize.copy();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare type OnKeyDown = (key: string) => void;
|
|
2
|
+
export declare type OnKeyUp = (key: string) => void;
|
|
3
|
+
export interface KeyboardInput {
|
|
4
|
+
eventElement: HTMLElement | undefined;
|
|
5
|
+
setEventElement: (eventElement: HTMLElement) => void;
|
|
6
|
+
removeEventElement: (eventElement: HTMLElement) => void;
|
|
7
|
+
clearInputElement: () => void;
|
|
8
|
+
isKeyPressed: (key: string) => boolean;
|
|
9
|
+
addKeyDownObserver: (observer: OnKeyDown) => void;
|
|
10
|
+
removeKeyDownObserver: (observer: OnKeyDown) => void;
|
|
11
|
+
addKeyUpObserver: (observer: OnKeyUp) => void;
|
|
12
|
+
removeKeyUpObserver: (observer: OnKeyUp) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function makeKeyboardInput(): KeyboardInput;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeKeyboardInput = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
function makeKeyboardInput() {
|
|
6
|
+
return new KeyboardInputImp();
|
|
7
|
+
}
|
|
8
|
+
exports.makeKeyboardInput = makeKeyboardInput;
|
|
9
|
+
class KeyboardInputImp {
|
|
10
|
+
constructor() {
|
|
11
|
+
this._eventElement = undefined;
|
|
12
|
+
this.setEventElement = (element) => {
|
|
13
|
+
if (this._eventElement) {
|
|
14
|
+
this._eventElement.onkeydown = null;
|
|
15
|
+
this._eventElement.onkeyup = null;
|
|
16
|
+
}
|
|
17
|
+
element.onkeydown = (e) => {
|
|
18
|
+
this.submitKeyDown(e.code);
|
|
19
|
+
};
|
|
20
|
+
element.onkeyup = (e) => {
|
|
21
|
+
this.submitKeyUp(e.code);
|
|
22
|
+
};
|
|
23
|
+
this._eventElement = element;
|
|
24
|
+
};
|
|
25
|
+
this.removeEventElement = (eventElement) => {
|
|
26
|
+
if (this._eventElement !== eventElement)
|
|
27
|
+
return;
|
|
28
|
+
this._eventElement.onkeydown = null;
|
|
29
|
+
this._eventElement.onkeyup = null;
|
|
30
|
+
this._eventElement = undefined;
|
|
31
|
+
};
|
|
32
|
+
this.clearInputElement = () => {
|
|
33
|
+
if (!this._eventElement)
|
|
34
|
+
return;
|
|
35
|
+
this._eventElement.onkeydown = null;
|
|
36
|
+
this._eventElement.onkeyup = null;
|
|
37
|
+
this._eventElement = undefined;
|
|
38
|
+
};
|
|
39
|
+
this.downObservers = new _1.ObserverList();
|
|
40
|
+
this.upObservers = new _1.ObserverList();
|
|
41
|
+
this.pressedKeys = [];
|
|
42
|
+
this.submitKeyDown = (key) => {
|
|
43
|
+
if (this.pressedKeys.includes(key))
|
|
44
|
+
return;
|
|
45
|
+
this.pressedKeys.push(key);
|
|
46
|
+
this.downObservers.notify(key);
|
|
47
|
+
};
|
|
48
|
+
this.submitKeyUp = (key) => {
|
|
49
|
+
if (!this.pressedKeys.includes(key))
|
|
50
|
+
return;
|
|
51
|
+
const index = this.pressedKeys.indexOf(key);
|
|
52
|
+
if (index >= 0) {
|
|
53
|
+
this.pressedKeys.splice(index, 1);
|
|
54
|
+
}
|
|
55
|
+
this.upObservers.notify(key);
|
|
56
|
+
};
|
|
57
|
+
this.isKeyPressed = (key) => {
|
|
58
|
+
return this.pressedKeys.includes(key);
|
|
59
|
+
};
|
|
60
|
+
this.addKeyDownObserver = (observer) => {
|
|
61
|
+
this.downObservers.add(observer);
|
|
62
|
+
};
|
|
63
|
+
this.removeKeyDownObserver = (observer) => {
|
|
64
|
+
this.downObservers.remove(observer);
|
|
65
|
+
};
|
|
66
|
+
this.addKeyUpObserver = (observer) => {
|
|
67
|
+
this.upObservers.add(observer);
|
|
68
|
+
};
|
|
69
|
+
this.removeKeyUpObserver = (observer) => {
|
|
70
|
+
this.upObservers.remove(observer);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
get eventElement() {
|
|
74
|
+
return this._eventElement;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Vector2 } from "./Vector2";
|
|
2
|
+
export declare class LineSegment2D {
|
|
3
|
+
start: Vector2;
|
|
4
|
+
end: Vector2;
|
|
5
|
+
get length(): number;
|
|
6
|
+
get direction(): Vector2;
|
|
7
|
+
getPositionAtPercent(percent: number): Vector2;
|
|
8
|
+
closestPointOnLine(point: Vector2): Vector2;
|
|
9
|
+
intersect(otherLine: LineSegment2D, tolerance?: number): Vector2 | undefined;
|
|
10
|
+
constructor(start: Vector2, end: Vector2);
|
|
11
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LineSegment2D = void 0;
|
|
4
|
+
const Vector2_1 = require("./Vector2");
|
|
5
|
+
class LineSegment2D {
|
|
6
|
+
constructor(start, end) {
|
|
7
|
+
this.start = start;
|
|
8
|
+
this.end = end;
|
|
9
|
+
}
|
|
10
|
+
get length() {
|
|
11
|
+
return this.end.subtract(this.start).magnitued;
|
|
12
|
+
}
|
|
13
|
+
get direction() {
|
|
14
|
+
return this.end.subtract(this.start).unit;
|
|
15
|
+
}
|
|
16
|
+
getPositionAtPercent(percent) {
|
|
17
|
+
const dir = this.direction;
|
|
18
|
+
const length = percent * this.length;
|
|
19
|
+
dir.setLength(length);
|
|
20
|
+
return this.start.add(dir);
|
|
21
|
+
}
|
|
22
|
+
closestPointOnLine(point) {
|
|
23
|
+
// see https://monkeyproofsolutions.nl/wordpress/how-to-calculate-the-shortest-distance-between-a-point-and-a-line/
|
|
24
|
+
const direction = this.end.subtract(this.start);
|
|
25
|
+
const tNumerator = direction.dot(point.subtract(this.start));
|
|
26
|
+
const tDenominator = direction.dot(direction);
|
|
27
|
+
const t = tNumerator / tDenominator;
|
|
28
|
+
if (t < 0) {
|
|
29
|
+
return this.start.copy();
|
|
30
|
+
}
|
|
31
|
+
else if (t > 1) {
|
|
32
|
+
return this.end.copy();
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const length = t * direction.magnitued;
|
|
36
|
+
direction.setLength(length);
|
|
37
|
+
return this.start.add(direction);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
intersect(otherLine, tolerance = 0) {
|
|
41
|
+
// See https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
|
|
42
|
+
const x1 = this.start.x;
|
|
43
|
+
const y1 = this.start.y;
|
|
44
|
+
const x2 = this.end.x;
|
|
45
|
+
const y2 = this.end.y;
|
|
46
|
+
const x3 = otherLine.start.x;
|
|
47
|
+
const y3 = otherLine.start.y;
|
|
48
|
+
const x4 = otherLine.end.x;
|
|
49
|
+
const y4 = otherLine.end.y;
|
|
50
|
+
const denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
|
51
|
+
if (denominator === 0) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const tNumerator = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4);
|
|
55
|
+
const t = tNumerator / denominator;
|
|
56
|
+
const tTolearnce = tolerance / this.length;
|
|
57
|
+
if (t < -tTolearnce || t > 1 + tTolearnce) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const uNumerator = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
|
|
61
|
+
const u = uNumerator / denominator;
|
|
62
|
+
const uTolearnce = tolerance / otherLine.length;
|
|
63
|
+
if (u < -uTolearnce || u > 1 + uTolearnce)
|
|
64
|
+
return undefined;
|
|
65
|
+
const px = x1 + t * (x2 - x1);
|
|
66
|
+
const py = y1 + t * (y2 - y1);
|
|
67
|
+
return new Vector2_1.Vector2(px, py);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.LineSegment2D = LineSegment2D;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoizedBoolean = void 0;
|
|
4
|
+
class MemoizedBoolean {
|
|
5
|
+
constructor(initialValue, onChangeCallback) {
|
|
6
|
+
this._val = initialValue;
|
|
7
|
+
this.onChangeCallback = onChangeCallback;
|
|
8
|
+
}
|
|
9
|
+
get val() {
|
|
10
|
+
return this._val;
|
|
11
|
+
}
|
|
12
|
+
set val(b) {
|
|
13
|
+
if (this._val === b)
|
|
14
|
+
return;
|
|
15
|
+
this._val = b;
|
|
16
|
+
this.onChangeCallback();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.MemoizedBoolean = MemoizedBoolean;
|