webgl test and class validator mocker
This commit is contained in:
parent
b9a89a4ba7
commit
3ff2186deb
17 changed files with 368 additions and 72 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -15,6 +15,6 @@
|
|||
"*ui": false,
|
||||
"*ui.*": false
|
||||
},
|
||||
"cSpell.words": ["antd", "fileupload", "uuidv"],
|
||||
"cSpell.words": ["antd", "fileupload", "metadatas", "uuidv"],
|
||||
"editor.rulers": [100]
|
||||
}
|
||||
|
|
|
@ -76,7 +76,9 @@ export class App {
|
|||
}
|
||||
|
||||
async loadAppDependencies() {
|
||||
await new DataBaseConnectUseCase().call();
|
||||
if ((await new DataBaseConnectUseCase().call()).isFailure()) {
|
||||
console.log("database connect error");
|
||||
}
|
||||
await new CheckAndCreateStaticFilesFolderUseCase().call();
|
||||
await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||
}
|
||||
|
|
82
server/src/core/helpers/class_validator_mocket.ts
Normal file
82
server/src/core/helpers/class_validator_mocket.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { randomBytes, randomInt, randomUUID } from "crypto";
|
||||
import { getMetadataStorage, IS_BOOLEAN, IS_MONGO_ID, IS_NUMBER, IS_STRING, IS_UUID } from "class-validator";
|
||||
import { ValidationMetadata } from "class-validator/types/metadata/ValidationMetadata";
|
||||
|
||||
type AvailableTypes = string | number | boolean | undefined;
|
||||
|
||||
export class ClassValidatorMocker {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
public static create<T>(constructor: Function, partial: Partial<T> = {}): T {
|
||||
return new ClassValidatorMocker().create(constructor, partial);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
public create<T>(constructor: Function, partial: Partial<T> = {}): T {
|
||||
const metadataStorage = getMetadataStorage();
|
||||
const targetMetadatas = metadataStorage.getTargetValidationMetadatas(constructor, "", false, false);
|
||||
const groupedMetadatas = metadataStorage.groupByPropertyName(targetMetadatas);
|
||||
// nestedValidation
|
||||
console.log(targetMetadatas);
|
||||
let randomFixture = {} as T;
|
||||
|
||||
for (const propertyName of Object.keys(groupedMetadatas)) {
|
||||
const metadatas = groupedMetadatas[propertyName];
|
||||
const value = this.generatePropertyValueFromMetadatas(metadatas);
|
||||
|
||||
if (value !== undefined) {
|
||||
randomFixture = {
|
||||
...randomFixture,
|
||||
[propertyName]: value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { ...randomFixture, ...partial };
|
||||
}
|
||||
|
||||
private generatePropertyValueFromMetadatas(metadatas: ValidationMetadata[]): AvailableTypes {
|
||||
for (const metadata of metadatas) {
|
||||
const constraints = getMetadataStorage().getTargetValidatorConstraints(metadata.constraintCls);
|
||||
|
||||
for (const constraint of constraints) {
|
||||
switch (constraint.name) {
|
||||
case IS_MONGO_ID:
|
||||
return this.randomUUID();
|
||||
case IS_STRING:
|
||||
return this.randomString();
|
||||
case IS_NUMBER:
|
||||
return this.randomNumber();
|
||||
case IS_BOOLEAN:
|
||||
return this.randomBoolean();
|
||||
case IS_UUID:
|
||||
return this.randomUUID();
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private randomString(): string {
|
||||
return randomBytes(randomInt(1, 10)).toString("hex");
|
||||
}
|
||||
|
||||
private randomNumber(): number {
|
||||
return randomInt(0, 99_999);
|
||||
}
|
||||
|
||||
private randomBoolean(): boolean {
|
||||
return randomInt(0, 1) === 1;
|
||||
}
|
||||
|
||||
private randomUUID(): string {
|
||||
if (randomUUID != null) {
|
||||
return randomUUID();
|
||||
}
|
||||
|
||||
return randomBytes(16).toString("hex");
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import { IsOptional, ValidateNested } from "class-validator";
|
|||
import { IPipeline, IProcess, StackGenerateType } from "../../../core/models/process_model";
|
||||
import { Type } from "class-transformer";
|
||||
import { ProcessModel } from "../../process/models/process_validation_model";
|
||||
import { TriggerModel } from "../../triggers/models/trigger_validation_model";
|
||||
import { TriggerModelValidationModel } from "../../triggers/models/trigger_validation_model";
|
||||
|
||||
export class PipelineModel implements IPipeline {
|
||||
@ValidateNested()
|
||||
|
@ -10,8 +10,8 @@ export class PipelineModel implements IPipeline {
|
|||
public process: IProcess;
|
||||
|
||||
@ValidateNested()
|
||||
@Type(() => TriggerModel)
|
||||
public trigger: TriggerModel;
|
||||
@Type(() => TriggerModelValidationModel)
|
||||
public trigger: TriggerModelValidationModel;
|
||||
|
||||
@IsOptional()
|
||||
public env = null;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { IsMongoId, IsOptional } from "class-validator";
|
||||
import { IProcess, StackGenerateType } from "../../../core/models/process_model";
|
||||
import { TriggerModel } from "../../triggers/models/trigger_validation_model";
|
||||
import { TriggerModelValidationModel } from "../../triggers/models/trigger_validation_model";
|
||||
|
||||
export class PipelineValidationModel {
|
||||
@IsMongoId()
|
||||
public process: IProcess;
|
||||
|
||||
@IsMongoId()
|
||||
public trigger: TriggerModel;
|
||||
public trigger: TriggerModelValidationModel;
|
||||
|
||||
@IsOptional()
|
||||
public env = null;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IsArray, IsOptional, IsEnum, IsString } from "class-validator";
|
||||
import { ITriggerModel, TriggerType } from "./trigger_database_model";
|
||||
|
||||
export class TriggerModel implements ITriggerModel {
|
||||
export class TriggerModelValidationModel implements ITriggerModel {
|
||||
@IsOptional()
|
||||
public _id: string;
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { TriggerDBModel } from "./models/trigger_database_model";
|
||||
import { TriggerModel } from "./models/trigger_validation_model";
|
||||
import { TriggerModelValidationModel as TriggerValidationMode } from "./models/trigger_validation_model";
|
||||
|
||||
export class TriggerPresentation extends CrudController<TriggerModel, typeof TriggerDBModel> {
|
||||
export class TriggerPresentation extends CrudController<TriggerValidationMode, typeof TriggerDBModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "trigger",
|
||||
validationModel: TriggerModel,
|
||||
validationModel: TriggerValidationMode,
|
||||
databaseModel: TriggerDBModel,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import { ProcessPresentation } from "./features/process/process_presentation";
|
|||
import { RealTimePresentation, pipelineRealTimeService } from "./features/realtime/realtime_presentation";
|
||||
import { extensions } from "./core/extensions/extensions";
|
||||
import { ProjectInstancePresentation } from "./features/project_instance/project_instance_presentation";
|
||||
import { NixStoreManagerPresentation as NixStoreManagerPresentation } from "./features/nix_store_manager/nix_store_manager";
|
||||
import { NixStoreManagerPresentation } from "./features/nix_store_manager/nix_store_manager";
|
||||
|
||||
extensions();
|
||||
|
||||
const httpRoutes: Routes[] = [
|
||||
export const httpRoutes: Routes[] = [
|
||||
new TriggerPresentation(),
|
||||
new ProjectsPresentation(),
|
||||
new ProcessPresentation(),
|
||||
|
|
25
server/test/helper/class_validator_mocker_test.ts
Normal file
25
server/test/helper/class_validator_mocker_test.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { Type } from "class-transformer";
|
||||
import { ClassValidatorMocker } from "../../src/core/helpers/class_validator_mocket";
|
||||
import { IsString, IsNumber, IsBoolean, IsUUID, IsMongoId, ValidateNested } from "class-validator";
|
||||
|
||||
class Foo {}
|
||||
class MyClass {
|
||||
@ValidateNested()
|
||||
@Type(() => Foo)
|
||||
model: Foo;
|
||||
|
||||
@IsNumber()
|
||||
numberProperty: number;
|
||||
|
||||
@IsBoolean()
|
||||
booleanProperty: boolean;
|
||||
|
||||
@IsUUID()
|
||||
uuidProperty: string;
|
||||
}
|
||||
|
||||
const myClassDataMock = ClassValidatorMocker.create<MyClass>(MyClass);
|
||||
|
||||
export const mainTest = () => {
|
||||
console.log(myClassDataMock);
|
||||
};
|
|
@ -1,3 +1,4 @@
|
|||
import "reflect-metadata";
|
||||
import { TestCore } from "./core/test_core";
|
||||
// import { UnitTestEnv } from "../src/core/di/env";
|
||||
import { dirname } from "path";
|
||||
|
@ -13,6 +14,7 @@ import { UpdateDataBaseModelUseCaseTest } from "./usecases/update_database_model
|
|||
import { PaginationDataBaseModelUseCaseTest } from "./usecases/pagination_database_model_usecase_test";
|
||||
import { extensions } from "../src/core/extensions/extensions";
|
||||
import { DataBaseConnectUseCase } from "../src/core/usecases/database_connect_usecase";
|
||||
import { mainTest } from "./helper/class_validator_mocker_test";
|
||||
|
||||
extensions();
|
||||
|
||||
|
@ -34,20 +36,22 @@ const init = async () => {
|
|||
};
|
||||
|
||||
const test = async () => {
|
||||
await new ExecutorProgramServiceTest(dirname__).test();
|
||||
await new FilesChangerTest(dirname__).test();
|
||||
await new StackServiceTest(dirname__ + "/context/").test();
|
||||
await new TriggerServiceTest().test();
|
||||
await new CreateDataBaseModelUseCaseTest().test();
|
||||
// await new ExecutorProgramServiceTest(dirname__).test();
|
||||
// await new FilesChangerTest(dirname__).test();
|
||||
// await new StackServiceTest(dirname__ + "/context/").test();
|
||||
// await new TriggerServiceTest().test();
|
||||
// await new CreateDataBaseModelUseCaseTest().test();
|
||||
|
||||
await new CreateDataBaseModelUseCaseTest().test();
|
||||
await new DeleteDataBaseModelUseCaseTest().test();
|
||||
await new ReadDataBaseModelUseCaseTest().test();
|
||||
await new UpdateDataBaseModelUseCaseTest().test();
|
||||
// await new PipelineRealTimeServiceTest().test()
|
||||
for await (const usecase of tests) {
|
||||
testCore.assert(await new usecase().test(), usecase.name);
|
||||
}
|
||||
// await new CreateDataBaseModelUseCaseTest().test();
|
||||
// await new DeleteDataBaseModelUseCaseTest().test();
|
||||
// await new ReadDataBaseModelUseCaseTest().test();
|
||||
// await new UpdateDataBaseModelUseCaseTest().test();
|
||||
// // await new PipelineRealTimeServiceTest().test()
|
||||
// for await (const usecase of tests) {
|
||||
// testCore.assert(await new usecase().test(), usecase.name);
|
||||
// }
|
||||
|
||||
mainTest();
|
||||
};
|
||||
const main = async () => {
|
||||
await init();
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"three": "^0.159.0",
|
||||
"typescript": "^4.9.5",
|
||||
"urdf-loader": "^0.12.1",
|
||||
"uuid": "^9.0.0",
|
||||
"uuid": "^9.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
42
ui/src/core/helper/typed_event.ts
Normal file
42
ui/src/core/helper/typed_event.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
export interface Listener<T> {
|
||||
(event: T): any;
|
||||
}
|
||||
|
||||
export interface Disposable {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class TypedEvent<T> {
|
||||
private listeners: Listener<T>[] = [];
|
||||
public listenersOnces: Listener<T>[] = [];
|
||||
|
||||
on = (listener: Listener<T>): Disposable => {
|
||||
this.listeners.push(listener);
|
||||
return {
|
||||
dispose: () => this.off(listener),
|
||||
};
|
||||
};
|
||||
|
||||
once = (listener: Listener<T>): void => {
|
||||
this.listenersOnces.push(listener);
|
||||
};
|
||||
|
||||
off = (listener: Listener<T>) => {
|
||||
const callbackIndex = this.listeners.indexOf(listener);
|
||||
if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1);
|
||||
};
|
||||
|
||||
emit = (event: T) => {
|
||||
this.listeners.forEach((listener) => listener(event));
|
||||
|
||||
if (this.listenersOnces.length > 0) {
|
||||
const toCall = this.listenersOnces;
|
||||
this.listenersOnces = [];
|
||||
toCall.forEach((listener) => listener(event));
|
||||
}
|
||||
};
|
||||
|
||||
pipe = (te: TypedEvent<T>): Disposable => {
|
||||
return this.on((e) => te.emit(e));
|
||||
};
|
||||
}
|
|
@ -12,15 +12,29 @@ import {
|
|||
Object3DEventMap,
|
||||
Box3,
|
||||
Sphere,
|
||||
LineBasicMaterial,
|
||||
EdgesGeometry,
|
||||
Raycaster,
|
||||
LineSegments,
|
||||
Vector2,
|
||||
} from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
import { BaseSceneItemModel, StaticAssetItemModel } from "../../features/scene_manager/scene_manager_store";
|
||||
import { TypedEvent } from "../helper/typed_event";
|
||||
import { Result } from "../helper/result";
|
||||
|
||||
export class CoreThereRepository {
|
||||
interface IEmissiveCache {
|
||||
status: boolean;
|
||||
object3d: Object3D<Object3DEventMap>;
|
||||
}
|
||||
export class CoreThereRepository extends TypedEvent<BaseSceneItemModel> {
|
||||
scene = new Scene();
|
||||
camera: PerspectiveCamera;
|
||||
webGlRender: WebGLRenderer;
|
||||
htmlCanvasRef: HTMLCanvasElement;
|
||||
objectEmissive = new Map<string, IEmissiveCache>();
|
||||
constructor(htmlCanvasRef: HTMLCanvasElement) {
|
||||
super();
|
||||
const renderer = new WebGLRenderer({
|
||||
canvas: htmlCanvasRef as HTMLCanvasElement,
|
||||
antialias: true,
|
||||
|
@ -32,14 +46,22 @@ export class CoreThereRepository {
|
|||
this.htmlCanvasRef = htmlCanvasRef;
|
||||
this.init();
|
||||
}
|
||||
setRayCastAndGetFirstObject(vector: Vector2): Result<void, string> {
|
||||
const raycaster = new Raycaster();
|
||||
raycaster.setFromCamera(vector, this.camera);
|
||||
const intersects = raycaster.intersectObjects(this.scene.children);
|
||||
if (intersects.length > 0) {
|
||||
return Result.ok(intersects[0].object.name);
|
||||
}
|
||||
|
||||
return Result.error(undefined);
|
||||
}
|
||||
addCube(num: number, translateTo: string = "X") {
|
||||
const geometry = new BoxGeometry(1, 1, 1);
|
||||
const material = new MeshBasicMaterial({ color: 0x00ff00 });
|
||||
const cube = new Mesh(geometry, material);
|
||||
cube.name = "Cube" + String(num);
|
||||
// cube.translateX(position.x);
|
||||
// cube.translateY(position.y);
|
||||
// cube.translateZ(position.z);
|
||||
|
||||
eval(`cube.translate${translateTo}(${num * 10})`);
|
||||
this.scene.add(cube);
|
||||
}
|
||||
|
@ -70,6 +92,9 @@ export class CoreThereRepository {
|
|||
this.webGlRender.render(this.scene, this.camera);
|
||||
});
|
||||
}
|
||||
getAllSceneModels(): BaseSceneItemModel[] {
|
||||
return this.getAllSceneNameModels().map((e) => new StaticAssetItemModel(e));
|
||||
}
|
||||
getAllSceneNameModels(): string[] {
|
||||
return this.scene.children.filter((el) => el.name !== "").map((el) => el.name);
|
||||
}
|
||||
|
@ -106,36 +131,55 @@ export class CoreThereRepository {
|
|||
orbitControls.maxDistance = cameraToFarEdge * 2;
|
||||
new OrbitControls(this.camera, this.htmlCanvasRef);
|
||||
}
|
||||
switchObjectEmissive(name: string) {
|
||||
const mesh = this.getObjectsAtName(name);
|
||||
const result = this.objectEmissive.get(mesh.name);
|
||||
if (result?.status) {
|
||||
this.scene.remove(mesh);
|
||||
this.scene.add(result.object3d);
|
||||
this.objectEmissive.set(mesh.name, {
|
||||
status: false,
|
||||
object3d: mesh,
|
||||
});
|
||||
} else {
|
||||
this.objectEmissive.set(mesh.name, {
|
||||
status: true,
|
||||
object3d: mesh,
|
||||
});
|
||||
|
||||
if (mesh instanceof Mesh) {
|
||||
const newMesh = new LineSegments(mesh.geometry, new LineBasicMaterial({ color: 0x000000 }));
|
||||
newMesh.name = mesh.name;
|
||||
newMesh.translateX(mesh.position.x);
|
||||
newMesh.translateY(mesh.position.y);
|
||||
newMesh.translateZ(mesh.position.z);
|
||||
this.scene.remove(mesh);
|
||||
this.scene.add(newMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fitSelectedObjectToScreen(objects: string[]) {
|
||||
//https://stackoverflow.com/questions/14614252/how-to-fit-camera-to-object
|
||||
|
||||
let boundBox = new Box3().setFromPoints(objects.map((el) => this.getObjectsAtName(el)).map((el) => el.position));
|
||||
let boundSphere = boundBox.getBoundingSphere(new Sphere());
|
||||
let vFoV = this.camera.getEffectiveFOV();
|
||||
let hFoV = this.camera.fov * this.camera.aspect;
|
||||
|
||||
let FoV = Math.min(vFoV, hFoV);
|
||||
let FoV2 = FoV / 2;
|
||||
|
||||
let dir = new Vector3();
|
||||
this.camera.getWorldDirection(dir);
|
||||
|
||||
let bsWorld = boundSphere.center.clone();
|
||||
|
||||
let th = (FoV2 * Math.PI) / 180.0;
|
||||
let sina = Math.sin(th);
|
||||
let R = boundSphere.radius;
|
||||
let FL = R / sina;
|
||||
|
||||
let cameraDir = new Vector3();
|
||||
|
||||
let cameraOffs = cameraDir.clone();
|
||||
console.log(cameraOffs);
|
||||
cameraOffs.multiplyScalar(-FL);
|
||||
console.log(-FL);
|
||||
|
||||
let newCameraPos = bsWorld.clone().add(cameraOffs);
|
||||
console.log(newCameraPos);
|
||||
|
||||
this.camera.translateX(newCameraPos.x);
|
||||
this.camera.translateY(newCameraPos.y);
|
||||
this.camera.translateZ(newCameraPos.z);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import * as React from "react";
|
||||
import { StaticAssetItemModel } from "../scene_manager_store";
|
||||
|
||||
export interface IStaticAssetModelViewProps {
|
||||
model: StaticAssetItemModel;
|
||||
}
|
||||
|
||||
export function StaticAssetModelView(props: IStaticAssetModelViewProps) {
|
||||
return (
|
||||
<div style={{ width: "100px", textAlignLast: "center", backgroundColor: "aqua", margin: "10px" }}>
|
||||
{props.model.name}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,43 +1,55 @@
|
|||
import * as React from "react";
|
||||
import { CoreThereRepository } from "../../core/repository/core_there_repository";
|
||||
import { SceneMangerStore, StaticAssetItemModel } from "./scene_manager_store";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { StaticAssetModelView } from "./components/static_asset_item_view";
|
||||
|
||||
const useKeyLister = (fn: Function) => {
|
||||
const pressed = new Map();
|
||||
// const useKeyLister = (fn: Function) => {
|
||||
// const pressed = new Map();
|
||||
|
||||
const registerKeyPress = React.useCallback(
|
||||
(event: KeyboardEvent, codes: string[], callBack: Function) => {
|
||||
if (codes.hasIncludeElement(event.code)) {
|
||||
pressed.addValueOrMakeCallback(event.code, event.type, (e) => {
|
||||
if (Array.from(pressed.values()).equals(["keydown", "keydown"], false)) {
|
||||
callBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
[pressed]
|
||||
);
|
||||
// const registerKeyPress = React.useCallback(
|
||||
// (event: KeyboardEvent, codes: string[], callBack: Function) => {
|
||||
// if (codes.hasIncludeElement(event.code)) {
|
||||
// pressed.addValueOrMakeCallback(event.code, event.type, (e) => {
|
||||
// if (Array.from(pressed.values()).equals(["keydown", "keydown"], false)) {
|
||||
// callBack();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// [pressed]
|
||||
// );
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener("keyup", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => fn));
|
||||
window.addEventListener("keydown", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => {}));
|
||||
}, [fn, registerKeyPress]);
|
||||
// React.useEffect(() => {
|
||||
// window.addEventListener("keyup", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => fn));
|
||||
// window.addEventListener("keydown", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => {}));
|
||||
// }, [fn, registerKeyPress]);
|
||||
|
||||
return [];
|
||||
};
|
||||
export function SceneManger() {
|
||||
// return [];
|
||||
// };
|
||||
|
||||
export const SceneManger = observer(() => {
|
||||
const canvasRef = React.useRef<HTMLCanvasElement>(null);
|
||||
let thereRepository: null | CoreThereRepository = null;
|
||||
|
||||
const [sceneMangerStore] = React.useState(() => new SceneMangerStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
thereRepository = new CoreThereRepository(canvasRef.current as HTMLCanvasElement);
|
||||
thereRepository.render();
|
||||
// thereRepository.fitSelectedObjectToScreen(thereRepository.getAllSceneNameModels());
|
||||
thereRepository.fitCameraToCenteredObject(thereRepository.getAllSceneNameModels());
|
||||
sceneMangerStore.loadGl(canvasRef.current!);
|
||||
return () => {
|
||||
sceneMangerStore.dispose();
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ position: "absolute" }}>
|
||||
{sceneMangerStore.sceneItems.map((el) => {
|
||||
if (el instanceof StaticAssetItemModel) {
|
||||
return StaticAssetModelView({ model: el });
|
||||
}
|
||||
return <></>;
|
||||
})}
|
||||
</div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
70
ui/src/features/scene_manager/scene_manager_store.ts
Normal file
70
ui/src/features/scene_manager/scene_manager_store.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/* eslint-disable array-callback-return */
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import { CoreThereRepository } from "../../core/repository/core_there_repository";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Vector2 } from "three";
|
||||
|
||||
export class BaseSceneItemModel {
|
||||
id: string;
|
||||
constructor() {
|
||||
this.id = uuidv4();
|
||||
}
|
||||
}
|
||||
|
||||
enum SceneModelsType {
|
||||
ASSET,
|
||||
}
|
||||
|
||||
export class StaticAssetItemModel extends BaseSceneItemModel {
|
||||
name: string;
|
||||
type = SceneModelsType.ASSET;
|
||||
constructor(name: string) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
export class SceneMangerStore {
|
||||
coreThereRepository: null | CoreThereRepository = null;
|
||||
sceneItems: BaseSceneItemModel[] = [];
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
loadGl(canvasRef: HTMLCanvasElement): void {
|
||||
this.coreThereRepository = new CoreThereRepository(canvasRef as HTMLCanvasElement);
|
||||
this.coreThereRepository.on(this.watcherThereObjects);
|
||||
this.coreThereRepository.render();
|
||||
this.coreThereRepository.fitCameraToCenteredObject(this.coreThereRepository.getAllSceneNameModels());
|
||||
|
||||
this.sceneItems = this.coreThereRepository.getAllSceneModels();
|
||||
|
||||
window.addEventListener("click", this.handleMouseClick);
|
||||
}
|
||||
|
||||
watcherThereObjects(sceneItemModel: BaseSceneItemModel): void {
|
||||
this.sceneItems.push(sceneItemModel);
|
||||
}
|
||||
|
||||
handleMouseClick = (event: MouseEvent) => {
|
||||
const vector = new Vector2();
|
||||
console.log("====");
|
||||
console.log(event.pageX);
|
||||
console.log(event.clientX);
|
||||
console.log(event.x);
|
||||
console.log(event.movementX);
|
||||
console.log(event.screenX);
|
||||
console.log("====");
|
||||
vector.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
vector.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
this.coreThereRepository?.setRayCastAndGetFirstObject(vector).map((el) => {
|
||||
this.coreThereRepository?.switchObjectEmissive(el);
|
||||
});
|
||||
};
|
||||
|
||||
dispose() {
|
||||
window.removeEventListener("click", this.handleMouseClick);
|
||||
}
|
||||
}
|
|
@ -14,8 +14,9 @@ const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
|||
|
||||
root.render(
|
||||
<>
|
||||
<SocketLister>
|
||||
{/* <SocketLister>
|
||||
<RouterProvider router={router} />
|
||||
</SocketLister>
|
||||
</SocketLister> */}
|
||||
<SceneManger />
|
||||
</>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue