Added babylon-html, updated db to save values correctly in local storage.

This commit is contained in:
Michael Mainguy 2024-04-19 10:36:35 -05:00
parent 2387fe53ef
commit ea5b8789c0
8 changed files with 121 additions and 196 deletions

View File

@ -40,6 +40,7 @@
*/
</script>
<div class="webApp" id="webApp">

43
package-lock.json generated
View File

@ -20,11 +20,14 @@
"@picovoice/eagle-web": "^1.0.0",
"@picovoice/web-voice-processor": "^4.0.9",
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
"@types/dom-to-image": "^2.6.7",
"@types/file-saver": "^2.0.6",
"@types/node": "^18.14.0",
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.6.8",
"babylon-html": "0.0.1",
"dom-to-image-more": "^3.3.0",
"earcut": "^2.2.4",
"events": "^3.3.0",
"file-saver": "^2.0.5",
@ -41,8 +44,9 @@
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/dom-to-image": "^2.6.7",
"typescript": "^4.9.5",
"vite": "^5.2.6",
"vite": "^5.2.9",
"vite-plugin-cp": "^1.0.0",
"vitest": "^1.4.0"
},
@ -50,6 +54,20 @@
"node": ">=18.0.0"
}
},
"../babylon-html": {
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"@babylonjs/core": "^7.1.0",
"dom-to-image-more": "^3.3.0"
},
"devDependencies": {
"@types/dom-to-image": "^2.6.7",
"ts-node": "^10.9.2",
"tsup": "^8.0.2",
"typescript": "^5.4.5"
}
},
"node_modules/@babylonjs/core": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.1.0.tgz",
@ -878,6 +896,12 @@
"resolved": "https://registry.npmjs.org/@typed-mxgraph/typed-mxgraph/-/typed-mxgraph-1.0.8.tgz",
"integrity": "sha512-rzTbmD/XofRq0YZMY/BU9cjbCTw9q8rpIvWRhQO0DcgCx3+rpHTsVOk3pfuhcnUigUYNFkljmDkRuVjbl7zZoQ=="
},
"node_modules/@types/dom-to-image": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/@types/dom-to-image/-/dom-to-image-2.6.7.tgz",
"integrity": "sha512-me5VbCv+fcXozblWwG13krNBvuEOm6kA5xoa4RrjDJCNFOZSWR3/QLtOXimBHk1Fisq69Gx3JtOoXtg1N1tijg==",
"dev": true
},
"node_modules/@types/emscripten": {
"version": "1.39.6",
"resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.6.tgz",
@ -1082,6 +1106,10 @@
"proxy-from-env": "^1.1.0"
}
},
"node_modules/babylon-html": {
"resolved": "../babylon-html",
"link": true
},
"node_modules/babylonjs-gltf2interface": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.1.0.tgz",
@ -1320,6 +1348,11 @@
"node": ">=8"
}
},
"node_modules/dom-to-image-more": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.3.0.tgz",
"integrity": "sha512-4k0oxVfQ4Nrv4/Iva6FpsXTAtPCp5JnZNO/n/hsuOpe3ANlMiK50URZDQKzJslthQD8k76z9vHS3usIzmJoFVw=="
},
"node_modules/double-ended-queue": {
"version": "2.1.0-0",
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
@ -2990,13 +3023,13 @@
}
},
"node_modules/vite": {
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz",
"integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==",
"version": "5.2.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz",
"integrity": "sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw==",
"dev": true,
"dependencies": {
"esbuild": "^0.20.1",
"postcss": "^8.4.36",
"postcss": "^8.4.38",
"rollup": "^4.13.0"
},
"bin": {

View File

@ -7,7 +7,7 @@
"node": ">=18.0.0"
},
"scripts": {
"dev": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps && vite",
"dev": "vite",
"test": "vitest",
"build": "vite build",
"preview": "vite preview",
@ -16,7 +16,6 @@
"havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
},
"dependencies": {
"axios": "^1.6.8",
"@babylonjs/core": "^7.1.0",
"@babylonjs/gui": "^7.1.0",
"@babylonjs/havok": "1.3.1",
@ -25,33 +24,38 @@
"@babylonjs/materials": "^7.1.0",
"@babylonjs/procedural-textures": "^7.1.0",
"@babylonjs/serializers": "^7.1.0",
"events": "^3.3.0",
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
"@types/node": "^18.14.0",
"earcut": "^2.2.4",
"file-saver": "^2.0.5",
"@types/file-saver": "^2.0.6",
"@picovoice/cobra-web": "^2.0.3",
"@picovoice/eagle-web": "^1.0.0",
"@picovoice/web-voice-processor": "^4.0.9",
"@picovoice/cobra-web": "^2.0.3",
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
"@types/dom-to-image": "^2.6.7",
"@types/file-saver": "^2.0.6",
"@types/node": "^18.14.0",
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.6.8",
"babylon-html": "0.0.1",
"dom-to-image-more": "^3.3.0",
"earcut": "^2.2.4",
"events": "^3.3.0",
"file-saver": "^2.0.5",
"hls.js": "^1.1.4",
"loglevel": "^1.9.1",
"niceware": "^4.0.0",
"pouchdb": "^8.0.1",
"pouchdb-find": "^8.0.1",
"query-string": "^8.1.0",
"recordrtc": "^5.6.0",
"react-dom": "^18.2.0",
"recordrtc": "^5.6.0",
"rfc4648": "^1.5.3",
"@types/react-dom": "^18.2.22",
"@types/react": "^18.2.72",
"round": "^2.0.1",
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/dom-to-image": "^2.6.7",
"typescript": "^4.9.5",
"vite": "^5.2.6",
"vitest": "^1.4.0",
"vite-plugin-cp": "^1.0.0"
"vite": "^5.2.9",
"vite-plugin-cp": "^1.0.0",
"vitest": "^1.4.0"
}
}

View File

@ -1,26 +1,21 @@
import PouchDB from 'pouchdb';
import {DiagramEntity, DiagramEventType} from "../diagram/types/diagramEntity";
import {Color3, Observable} from "@babylonjs/core";
import {AppConfigType} from "../util/appConfigType";
import {v4 as uuidv4} from 'uuid';
import axios from "axios";
import {DiagramManager} from "../diagram/diagramManager";
import log, {Logger} from "loglevel";
const logger: Logger = log.getLogger('PouchdbPersistenceManager');
export class PouchdbPersistenceManager {
configObserver: Observable<AppConfigType> = new Observable<AppConfigType>();
updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
removeObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
private db: PouchDB;
private remote: PouchDB;
private diagramListings: PouchDB;
private user: string;
constructor() {
this.diagramListings = new PouchDB("diagramListings");
}
public setDiagramManager(diagramManager: DiagramManager) {
@ -58,23 +53,6 @@ export class PouchdbPersistenceManager {
});
}
private _currentDiagramId: string;
public get currentDiagramId(): string {
return this._currentDiagramId;
}
public set currentDiagramId(value: string) {
this._currentDiagramId = value;
try {
const listing = this.diagramListings.get(value);
} catch (err) {
this.diagramListings.put({_id: value, name: "New Diagram"});
}
this.db = new PouchDB(value);
this.db.sync(this.remote, {live: true});
}
public async add(entity: DiagramEntity) {
if (!entity) {
return;
@ -121,63 +99,26 @@ export class PouchdbPersistenceManager {
return data;
}
public async setConfig(config: AppConfigType, initial: boolean = false) {
if (!initial) {
localStorage.setItem('config', JSON.stringify(config));
} else {
localStorage.setItem('config', JSON.stringify(config));
}
}
public getConfig(): AppConfigType {
return JSON.parse(localStorage.getItem('config')) as AppConfigType;
}
public async initialize() {
try {
let current = this.getPath();
const configString = localStorage.getItem('config');
const config = JSON.parse(configString) as AppConfigType;
if (!current && config.currentDiagramId) {
this.db = new PouchDB(config.currentDiagramId);
await this.beginSync(config.currentDiagramId);
} else {
if (current) {
config.currentDiagramId = current;
this.db = new PouchDB(current);
} else {
config.currentDiagramId = uuidv4();
current = 'public';
this.db = new PouchDB(current);
}
this.db = new PouchDB(config.currentDiagramId);
await this.beginSync(config.currentDiagramId);
localStorage.setItem('config', JSON.stringify(config));
}
this.configObserver.notifyObservers(config);
} catch (err) {
const defaultConfig = {
_id: '1',
demoCompleted: false,
gridSnap: 1,
rotateSnap: 0,
createSnap: 0,
turnSnap: 0,
flyMode: true,
currentDiagramId: 'public'
}
try {
await this.setConfig(defaultConfig, true);
await this.beginSync(current);
} catch (err) {
logger.error(err);
}
this.diagramListings.put({_id: defaultConfig.currentDiagramId, name: "New Diagram"});
this.db = new PouchDB(defaultConfig.currentDiagramId);
await this.beginSync(defaultConfig.currentDiagramId);
this.configObserver.notifyObservers(defaultConfig);
logger.error('cannot initialize pouchdb for sync');
return;
}
try {
const all = await this.db.allDocs({include_docs: true});
for (const entity of all.rows) {
logger.debug(entity.doc);
this.updateObserver.notifyObservers(entity.doc, 1);
@ -258,7 +199,6 @@ export class PouchdbPersistenceManager {
} else {
return;
}
}
const userEndpoint: string = import.meta.env.VITE_USER_ENDPOINT
logger.debug(userEndpoint);

View File

@ -4,9 +4,7 @@ import {AppConfigType} from "./appConfigType";
export class AppConfig {
public readonly onConfigChangedObservable = new Observable<AppConfigType>();
private _currentConfig: AppConfigType;
constructor() {
this._currentConfig = {
public readonly defaultConfig: AppConfigType = {
id: 1,
gridSnap: .1,
rotateSnap: 90,
@ -17,7 +15,20 @@ export class AppConfig {
physicsEnabled: false,
demoCompleted: false,
flyMode: true
};
}
constructor() {
this._currentConfig = this.defaultConfig;
try {
const config = JSON.parse(localStorage.getItem('appConfig'));
if (config) {
this._currentConfig = config;
} else {
localStorage.setItem('appConfig', JSON.stringify(this._currentConfig));
}
} catch (err) {
console.error(err);
}
this.onConfigChangedObservable.add((config) => {
this._currentConfig = config;
}, -1);
@ -27,55 +38,49 @@ export class AppConfig {
return this._currentConfig;
}
public set current(config: AppConfigType) {
this._currentConfig = config;
localStorage.setItem('appConfig', JSON.stringify(this._currentConfig));
this.onConfigChangedObservable.notifyObservers(this._currentConfig, -1);
}
public setRotateSnap(value: number) {
this._currentConfig.rotateSnap = value;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
public setFlyMode(value: boolean) {
this._currentConfig.flyMode = value;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
public setCreateSnap(value: number) {
this._currentConfig.createSnap = value;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
public setTurnSnap(value: number) {
this._currentConfig.turnSnap = value;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
public setGridSnap(value: number) {
this._currentConfig.gridSnap = value;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
}
public set current(config: AppConfigType) {
this._currentConfig = config;
this.onConfigChangedObservable.notifyObservers(config, 2);
}
public load(config: AppConfigType) {
this._currentConfig = config;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 1);
}
public setPassphrase(passphrase: string) {
this._currentConfig.passphrase = passphrase;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
public setPhysicsEnabled(physicsEnabled: boolean) {
this._currentConfig.physicsEnabled = physicsEnabled;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
public setDemoCompleted(demoCompleted: boolean) {
this._currentConfig.demoCompleted = demoCompleted;
this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2);
this.save();
}
private save() {
localStorage.setItem('appConfig', JSON.stringify(this._currentConfig));
this.onConfigChangedObservable.notifyObservers(this._currentConfig, -1);
}
}

View File

@ -75,7 +75,7 @@ export async function groundMeshObserver(ground: AbstractMesh,
diagramManager.config.onConfigChangedObservable.add((config) => {
rig.flyMode = config.flyMode;
rig.turnSnap = config.turnSnap;
});
}, -1, false, this);
const config = new ConfigMenu(xr, diagramManager.controllers, diagramManager.config);
const webController = new WebController(ground.getScene(), rig, diagramManager, diagramManager.controllers);

View File

@ -1,14 +1,4 @@
import {
AbstractMesh,
Color3,
DynamicTexture,
Material,
Mesh,
MeshBuilder,
Scene,
StandardMaterial,
Vector3
} from "@babylonjs/core";
import {AbstractMesh, Color3, DynamicTexture, Material, MeshBuilder, StandardMaterial} from "@babylonjs/core";
import log from "loglevel";
@ -61,29 +51,26 @@ export function updateTextNode(mesh: AbstractMesh, text: string) {
const mat = new StandardMaterial("mat", mesh.getScene());
mat.diffuseColor = Color3.Black();
mat.disableLighting = true;
mat.backFaceCulling = true;
mat.backFaceCulling = false;
mat.emissiveTexture = dynamicTexture;
mat.freeze();
//mat.emissiveColor = Color3.White();
//Create plane and set dynamic texture as material
//const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, mesh.getScene());
const plane1 = createPlane(mat, mesh, text, planeWidth, height);
const plane2 = createPlane(mat, mesh, text, planeWidth, height);
plane2.rotation.y = Math.PI;
//const plane2 = createPlane(mat, mesh, text, planeWidth, height);
//plane2.rotation.y = Math.PI;
}
function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth: number, height: number): AbstractMesh {
const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, mesh.getScene());
const yOffset = mesh.getBoundingInfo().boundingSphere.maximum.y;
plane.parent = mesh;
plane.parent = mesh;
plane.scaling.y = (1 / mesh.scaling.y);
plane.scaling.x = (1 / mesh.scaling.x);
plane.scaling.z = (1 / mesh.scaling.z);
plane.material = mat;
//plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
plane.metadata = {exportable: true, label: true};
if (mesh.metadata?.template == "#connection-template") {
plane.billboardMode = AbstractMesh.BILLBOARDMODE_Y;
plane.position.y = mesh.position.y + .1;
@ -91,22 +78,7 @@ function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth
} else {
plane.position.y = yOffset + (height * plane.scaling.y);
}
//plane.addLODLevel(5, getDistantPlane(mesh.getScene(), plane.scaling, planeWidth, height));
plane.addLODLevel(3, null);
return plane;
}
let distantPlane = null;
function getDistantPlane(scene: Scene, scaling: Vector3, planeWidth: number, planeHeight: number): Mesh {
//if (distantPlane == null) {
distantPlane = MeshBuilder.CreatePlane("distantPlane", {width: planeWidth, height: planeHeight}, scene);
distantPlane.scaling = scaling;
//distantPlane.scaling.y = distantPlane.scaling.y /4;
const material = new StandardMaterial("distantPlaneMaterial", scene);
material.emissiveColor = Color3.White()
material.freeze()
distantPlane.material = material;
// }
return distantPlane;
}

View File

@ -35,17 +35,6 @@ export class VrApp {
const diagramManager = new DiagramManager();
const db = new PouchdbPersistenceManager();
db.setDiagramManager(diagramManager);
db.configObserver.add((newConfig) => {
if (!newConfig.demoCompleted) {
const main = document.querySelector('#main');
} else {
const create = document.querySelector('#create');
}
diagramManager.config.onConfigChangedObservable.notifyObservers(newConfig, 1);
});
diagramManager.config.onConfigChangedObservable.add((newConfig) => {
db.setConfig(newConfig);
}, 2, false, this);
await db.initialize();
const camera: FreeCamera = new FreeCamera("Main Camera",
@ -71,24 +60,8 @@ export class VrApp {
})
}
this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer');
/*
const textGen = new TextMeshGenerator();
let y = .1;
for (let i = 0; i < 1000; i++) {
const text = textGen.generateCharMesh("hijklmnop Hello World");
text.position.y = y;
text.position.z = -5;
text.rotation.y = Math.PI;
y+=.1;
}
*/
let i = 0;
this.engine.runRenderLoop(() => {
scene.render();
if (i++ % 60 == 0) {
}
});
this.logger.info('Render loop started');
@ -103,14 +76,11 @@ export class VrApp {
this.engine = new Engine(canvas, true);
}
//this.engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
this.engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
//window.onresize = () => {
// this.engine.resize();
// }
/*window.setInterval(() => {
console.log(this.engine.performanceMonitor.instantaneousFPS.toFixed(2) + " fps");
}, 1000);*/
window.onresize = () => {
this.engine.resize();
}
const scene = new Scene(this.engine);
scene.ambientColor = new Color3(.1, .1, .1);
DefaultScene.Scene = scene;