change from always add to also update in persistenceManager.ts

This commit is contained in:
Michael Mainguy 2023-07-28 13:04:08 -05:00
parent b375005b33
commit 156d0858d8
8 changed files with 115 additions and 48 deletions

View File

@ -32,6 +32,7 @@ export class App {
//preTasks = [havokModule]; //preTasks = [havokModule];
private logger = log.getLogger('App'); private logger = log.getLogger('App');
private scene: Scene; private scene: Scene;
private xr: WebXRDefaultExperience; private xr: WebXRDefaultExperience;
private rig: Rigplatform; private rig: Rigplatform;
@ -40,6 +41,9 @@ export class App {
const config = AppConfig.config; const config = AppConfig.config;
log.setLevel('info'); log.setLevel('info');
log.getLogger('AppConfig').setLevel('debug');
log.getLogger('IndexdbPersistenceManager').setLevel('debug');
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
canvas.style.width = "100%"; canvas.style.width = "100%";
canvas.style.height = "100%"; canvas.style.height = "100%";

View File

@ -105,7 +105,11 @@ export class Base {
newMesh.material = mesh.material; newMesh.material = mesh.material;
newMesh.metadata = mesh.metadata; newMesh.metadata = mesh.metadata;
newMesh && newMesh.setParent(this.controller.motionController.rootMesh); newMesh && newMesh.setParent(this.controller.motionController.rootMesh);
const event: DiagramEvent = {
type: DiagramEventType.ADD,
entity: MeshConverter.toDiagramEntity(newMesh)
}
this.diagramManager.onDiagramEventObservable.notifyObservers(event);
this.grabbedMesh = newMesh; this.grabbedMesh = newMesh;
this.previousParent = null; this.previousParent = null;
} }

View File

@ -56,12 +56,14 @@ export class DiagramManager {
case DiagramEventType.DROPPED: case DiagramEventType.DROPPED:
break; break;
case DiagramEventType.DROP: case DiagramEventType.DROP:
this.getPersistenceManager()?.add(mesh) this.getPersistenceManager()?.modify(mesh);
MeshConverter.updateTextNode(mesh, entity.text);
break; break;
case DiagramEventType.ADD: case DiagramEventType.ADD:
this.getPersistenceManager()?.add(mesh);
break; break;
case DiagramEventType.MODIFY: case DiagramEventType.MODIFY:
this.getPersistenceManager()?.modify(mesh) this.getPersistenceManager()?.modify(mesh);
break; break;
case DiagramEventType.CHANGECOLOR: case DiagramEventType.CHANGECOLOR:
this.getPersistenceManager()?.changeColor(event.oldColor, event.newColor); this.getPersistenceManager()?.changeColor(event.oldColor, event.newColor);

View File

@ -4,17 +4,24 @@ import {DiagramEntity} from "./diagramEntity";
import Dexie from "dexie"; import Dexie from "dexie";
import {MeshConverter} from "./meshConverter"; import {MeshConverter} from "./meshConverter";
import log from "loglevel"; import log from "loglevel";
import {AppConfigType} from "../util/appConfig";
export class IndexdbPersistenceManager implements IPersistenceManager { export class IndexdbPersistenceManager implements IPersistenceManager {
private readonly logger = log.getLogger('IndexdbPersistenceManager'); private readonly logger = log.getLogger('IndexdbPersistenceManager');
public updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>(); public readonly updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
public readonly configObserver: Observable<AppConfigType> = new Observable<AppConfigType>();
private db: Dexie; private db: Dexie;
constructor(name: string) { constructor(name: string) {
this.db = new Dexie(name); this.db = new Dexie(name);
this.db.version(1).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"}); const version = 2;
this.db.version(2).stores({config: "id,gridSnap,rotateSnap,createSnap"});
this.db.version(2).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"});
this.logger.debug("IndexdbPersistenceManager constructed"); this.logger.debug("IndexdbPersistenceManager constructed");
} }
public add(mesh: AbstractMesh) { public add(mesh: AbstractMesh) {
if (!mesh) { if (!mesh) {
this.logger.error("Adding null mesh, early return"); this.logger.error("Adding null mesh, early return");
@ -24,27 +31,35 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
entity.position = this.vectoxys(mesh.position); entity.position = this.vectoxys(mesh.position);
entity.rotation = this.vectoxys(mesh.rotation); entity.rotation = this.vectoxys(mesh.rotation);
entity.scale = this.vectoxys(mesh.scaling); entity.scale = this.vectoxys(mesh.scaling);
this.db["entities"].add(entity); this.db["entities"].add(entity);
this.logger.debug('add', mesh, entity); this.logger.debug('add', mesh, entity);
} }
public remove(mesh: AbstractMesh) { public remove(mesh: AbstractMesh) {
if (!mesh) {
this.logger.error("Removing null mesh, early return");
return;
}
this.db["entities"].delete(mesh.id); this.db["entities"].delete(mesh.id);
} }
public getConfig(): any { public setConfig(config: AppConfigType) {
this.logger.warn('getConfig not implemented'); config.id = 1;
//@todo implement this.db["config"].put(config);
} this.logger.debug('setConfig', config);
this.configObserver.notifyObservers(config);
public setConfig(config: any) {
this.logger.warn('setConfig not implemented, value not persisted', config);
//@todo implement
} }
public modify(mesh) { public modify(mesh) {
if (!mesh) {
this.logger.error("Modifying null mesh, early return");
return;
}
const entity = <any>MeshConverter.toDiagramEntity(mesh); const entity = <any>MeshConverter.toDiagramEntity(mesh);
if (!entity) {
this.logger.error("Modifying null mesh, early return");
return;
}
entity.position = this.vectoxys(mesh.position); entity.position = this.vectoxys(mesh.position);
entity.rotation = this.vectoxys(mesh.rotation); entity.rotation = this.vectoxys(mesh.rotation);
entity.scale = this.vectoxys(mesh.scaling); entity.scale = this.vectoxys(mesh.scaling);
@ -61,10 +76,17 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
this.logger.debug('adding', e); this.logger.debug('adding', e);
this.updateObserver.notifyObservers(e); this.updateObserver.notifyObservers(e);
}); });
this.db['config'].each((c) => {
this.configObserver.notifyObservers(c);
});
this.logger.info("initialize finished"); this.logger.info("initialize finished");
} }
public changeColor(oldColor, newColor) { public changeColor(oldColor, newColor) {
if (!oldColor || !newColor) {
this.logger.error("changeColor called with null color, early return");
return;
}
this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`); this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`);
this.db['entities'].where('color').equals(oldColor.toHexString()).modify({color: newColor.toHexString()}); this.db['entities'].where('color').equals(oldColor.toHexString()).modify({color: newColor.toHexString()});
} }

View File

@ -15,7 +15,12 @@ import log from "loglevel";
export class MeshConverter { export class MeshConverter {
private static logger = log.getLogger('MeshConverter');
public static toDiagramEntity(mesh: AbstractMesh): DiagramEntity { public static toDiagramEntity(mesh: AbstractMesh): DiagramEntity {
if (!mesh) {
this.logger.error("toDiagramEntity: mesh is null");
return null;
}
const entity = <DiagramEntity>{}; const entity = <DiagramEntity>{};
if ("new" == mesh?.id) { if ("new" == mesh?.id) {
mesh.id = "id" + uuidv4(); mesh.id = "id" + uuidv4();
@ -29,11 +34,17 @@ export class MeshConverter {
entity.scale = mesh.scaling; entity.scale = mesh.scaling;
if (mesh.material) { if (mesh.material) {
entity.color = (mesh.material as any).diffuseColor.toHexString(); entity.color = (mesh.material as any).diffuseColor.toHexString();
} else {
this.logger.error("toDiagramEntity: mesh.material is null");
} }
return entity; return entity;
} }
public static fromDiagramEntity(entity: DiagramEntity, scene: Scene): AbstractMesh { public static fromDiagramEntity(entity: DiagramEntity, scene: Scene): AbstractMesh {
if (!entity) {
this.logger.error("fromDiagramEntity: entity is null");
return null;
}
if (!entity.id) { if (!entity.id) {
entity.id = "id" + uuidv4(); entity.id = "id" + uuidv4();
} }
@ -64,10 +75,7 @@ export class MeshConverter {
if (mesh) { if (mesh) {
mesh.metadata = {template: entity.template}; mesh.metadata = {template: entity.template};
if (entity.text) {
mesh.metadata.text = entity.text;
this.updateTextNode(mesh, entity.text);
}
if (entity.position) { if (entity.position) {
mesh.position = entity.position; mesh.position = entity.position;
} }
@ -85,7 +93,12 @@ export class MeshConverter {
material.diffuseColor = Color3.FromHexString(entity.color); material.diffuseColor = Color3.FromHexString(entity.color);
mesh.material = material; mesh.material = material;
} }
if (entity.text) {
mesh.metadata.text = entity.text;
this.updateTextNode(mesh, entity.text);
}
} else {
this.logger.error("fromDiagramEntity: mesh is null after it should have been created");
} }
return mesh; return mesh;
@ -93,12 +106,19 @@ export class MeshConverter {
} }
public static updateTextNode(mesh: AbstractMesh, text: string) { public static updateTextNode(mesh: AbstractMesh, text: string) {
if (!mesh) {
this.logger.error("updateTextNode: mesh is null");
return null;
}
let textNode = (mesh.getChildren((node) => { let textNode = (mesh.getChildren((node) => {
return node.name == 'text' return node.name == 'text'
})[0] as Mesh); })[0] as Mesh);
if (textNode) { if (textNode) {
textNode.dispose(false, true); textNode.dispose(false, true);
} }
if (!text) {
return null;
}
//Set font //Set font
const height = 0.125; const height = 0.125;
@ -110,7 +130,7 @@ export class MeshConverter {
const ratio = height / DTHeight; const ratio = height / DTHeight;
//Use a temporary dynamic texture to calculate the length of the text on the dynamic texture canvas //Use a temporary dynamic texture to calculate the length of the text on the dynamic texture canvas
const temp = new DynamicTexture("DynamicTexture", 64, mesh.getScene()); const temp = new DynamicTexture("DynamicTexture", 32, mesh.getScene());
const tmpctx = temp.getContext(); const tmpctx = temp.getContext();
tmpctx.font = font; tmpctx.font = font;
const DTWidth = tmpctx.measureText(text).width + 8; const DTWidth = tmpctx.measureText(text).width + 8;
@ -133,9 +153,7 @@ export class MeshConverter {
plane.billboardMode = Mesh.BILLBOARDMODE_ALL; plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
//textNode = this.updateTextNode(mesh, entity.text); //textNode = this.updateTextNode(mesh, entity.text);
plane.parent = mesh; plane.parent = mesh;
log.getLogger('bmenu').debug("max y", mesh.getBoundingInfo().boundingBox.maximum.y); plane.position.y = .5 + (.125 / 2);
plane.position.y = .5+ (height / 2);
return plane; return plane;
} }
} }

View File

@ -11,12 +11,11 @@ export interface IPersistenceManager {
initialize(); initialize();
getConfig(): AppConfigType;
setConfig(config: AppConfigType); setConfig(config: AppConfigType);
changeColor(oldColor: Color3, newColor: Color3) changeColor(oldColor: Color3, newColor: Color3)
updateObserver: Observable<DiagramEntity>; updateObserver: Observable<DiagramEntity>;
configObserver: Observable<AppConfigType>;
} }

View File

@ -26,21 +26,24 @@ export class ConfigMenu {
this.configPlane = null; this.configPlane = null;
return; return;
} }
const width = .25;
const height = .55;
const res = 256;
const heightPixels = Math.round((height / width) * res);
this.configPlane = MeshBuilder this.configPlane = MeshBuilder
.CreatePlane("gridSizePlane", .CreatePlane("gridSizePlane",
{ {
width: .25, width: .25,
height: .5 height: .5
}, this.scene); }, this.scene);
const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, 256, 512); const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, res, heightPixels);
configTexture.background = "white"; configTexture.background = "white";
const selectionPanel = new SelectionPanel("selectionPanel"); const selectionPanel = new SelectionPanel("selectionPanel");
selectionPanel.fontSize = "24px";
selectionPanel.height = "100%";
configTexture.addControl(selectionPanel) configTexture.addControl(selectionPanel)
selectionPanel.addGroup(this.buildGridSizeControl()); this.buildGridSizeControl(selectionPanel);
selectionPanel.addGroup(this.buildRotationSnapControl()); this.buildRotationSnapControl(selectionPanel);
selectionPanel.addGroup(this.buildCreateScaleControl()); this.buildCreateScaleControl(selectionPanel);
this.configPlane.position = CameraHelper.getFrontPosition(2, this.scene); this.configPlane.position = CameraHelper.getFrontPosition(2, this.scene);
this.configPlane.rotation.y = Angle.FromDegrees(180).radians(); this.configPlane.rotation.y = Angle.FromDegrees(180).radians();
} }
@ -50,8 +53,10 @@ export class ConfigMenu {
log.debug("configMenu", "create Snap", value); log.debug("configMenu", "create Snap", value);
} }
private buildCreateScaleControl(): RadioGroup { private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Create Scale"); const radio = new RadioGroup("Create Scale");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.createSnaps().entries()) { for (const [index, snap] of AppConfig.config.createSnaps().entries()) {
const selected = AppConfig.config.currentCreateSnapIndex == index; const selected = AppConfig.config.currentCreateSnapIndex == index;
radio.addRadio(snap.label, this.createVal, selected); radio.addRadio(snap.label, this.createVal, selected);
@ -59,8 +64,9 @@ export class ConfigMenu {
return radio; return radio;
} }
private buildRotationSnapControl(): RadioGroup { private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Rotation Snap"); const radio = new RadioGroup("Rotation Snap");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.rotateSnaps().entries()) { for (const [index, snap] of AppConfig.config.rotateSnaps().entries()) {
const selected = AppConfig.config.currentRotateSnapIndex == index; const selected = AppConfig.config.currentRotateSnapIndex == index;
radio.addRadio(snap.label, this.rotateVal, selected); radio.addRadio(snap.label, this.rotateVal, selected);
@ -68,8 +74,9 @@ export class ConfigMenu {
return radio; return radio;
} }
private buildGridSizeControl(): RadioGroup { private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Grid Snap"); const radio = new RadioGroup("Grid Snap");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.gridSnaps().entries()) { for (const [index, snap] of AppConfig.config.gridSnaps().entries()) {
const selected = AppConfig.config.currentGridSnapIndex == index; const selected = AppConfig.config.currentGridSnapIndex == index;
radio.addRadio(snap.label, this.gridVal, selected); radio.addRadio(snap.label, this.gridVal, selected);

View File

@ -8,13 +8,15 @@ export type SnapValue = {
label: string label: string
} }
export type AppConfigType = { export type AppConfigType = {
id?: number,
gridSnap: number, gridSnap: number,
rotateSnap: number, rotateSnap: number,
createSnap: number createSnap: number
} }
export class AppConfig { export class AppConfig {
private gridSnap = 0; private readonly logger = log.getLogger('AppConfig');
private gridSnap = 1;
private rotateSnap = 0; private rotateSnap = 0;
private createSnap = 0; private createSnap = 0;
private readonly defaultGridSnapIndex = 1; private readonly defaultGridSnapIndex = 1;
@ -75,7 +77,7 @@ export class AppConfig {
this.createSnap = val; this.createSnap = val;
if (this.currentGridSnapIndex == this.defaultGridSnapIndex) { if (this.currentGridSnapIndex == this.defaultGridSnapIndex) {
this.currentGridSnap.value = this.currentCreateSnap.value / 2; this.currentGridSnap.value = this.currentCreateSnap.value / 2;
log.getLogger('AppConfig').debug("Set grid snap to " + this.currentGridSnap.value); this.logger.debug("Set grid snap to " + this.currentGridSnap.value);
} }
this.save(); this.save();
} }
@ -95,7 +97,7 @@ export class AppConfig {
public setPersistenceManager(persistenceManager: IPersistenceManager) { public setPersistenceManager(persistenceManager: IPersistenceManager) {
this.persistenceManager = persistenceManager; this.persistenceManager = persistenceManager;
this.load(); this.persistenceManager.configObserver.add(this.configObserver, -1, false, this);
} }
public gridSnaps(): SnapValue[] { public gridSnaps(): SnapValue[] {
@ -141,9 +143,13 @@ export class AppConfig {
}); });
} }
private load() { private configObserver(config: AppConfigType) {
const config = this.persistenceManager.getConfig();
if (config) { if (config) {
if (config.createSnap != this.currentCreateSnap.value ||
config.gridSnap != this.currentGridSnap.value ||
config.rotateSnap != this.currentRotateSnap.value) {
this.logger.debug("Config changed", config);
this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap); this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap);
this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap); this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap);
const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap); const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap);
@ -151,13 +157,18 @@ export class AppConfig {
this.gridSnap = this.defaultGridSnapIndex; this.gridSnap = this.defaultGridSnapIndex;
this.currentGridSnap.value = config.gridSnap; this.currentGridSnap.value = config.gridSnap;
} }
} else {
this.logger.debug("Config unchanged", config);
}
} else {
this.logger.debug("Config not set");
} }
} }
private snapAngle(val: number): number { private snapAngle(val: number): number {
const deg = Angle.FromRadians(val).degrees(); const deg = Angle.FromRadians(val).degrees();
const snappedDegrees = round(deg, this.currentRotateSnap.value); const snappedDegrees = round(deg, this.currentRotateSnap.value);
log.getLogger('AppConfig').debug("deg", val, deg, snappedDegrees, this.currentRotateSnap.value); this.logger.debug("deg", val, deg, snappedDegrees, this.currentRotateSnap.value);
return Angle.FromDegrees(snappedDegrees).radians(); return Angle.FromDegrees(snappedDegrees).radians();
} }
} }