Updated click menu to use Html Button. Added Scale feature.

This commit is contained in:
Michael Mainguy 2024-04-20 06:56:42 -05:00
parent ea5b8789c0
commit b2c5c85d7e
6 changed files with 206 additions and 168 deletions

14
package-lock.json generated
View File

@ -26,7 +26,7 @@
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.6.8",
"babylon-html": "0.0.1",
"babylon-html": "^0.0.2",
"dom-to-image-more": "^3.3.0",
"earcut": "^2.2.4",
"events": "^3.3.0",
@ -55,7 +55,8 @@
}
},
"../babylon-html": {
"version": "0.0.1",
"version": "0.0.2",
"extraneous": true,
"license": "MIT",
"dependencies": {
"@babylonjs/core": "^7.1.0",
@ -1107,8 +1108,13 @@
}
},
"node_modules/babylon-html": {
"resolved": "../babylon-html",
"link": true
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/babylon-html/-/babylon-html-0.0.2.tgz",
"integrity": "sha512-bcdLgMmnjvLrysZq5VFzc71TkDT0b6coCv3ZoFzTxJDhXtZF96FFaRMba9rxMHp1TM3rX9u6yW8N/sJodA/qVg==",
"dependencies": {
"@babylonjs/core": "^7.1.0",
"dom-to-image-more": "^3.3.0"
}
},
"node_modules/babylonjs-gltf2interface": {
"version": "7.1.0",

View File

@ -34,7 +34,7 @@
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.6.8",
"babylon-html": "0.0.1",
"babylon-html": "^0.0.2",
"dom-to-image-more": "^3.3.0",
"earcut": "^2.2.4",
"events": "^3.3.0",

View File

@ -14,6 +14,7 @@ import {buildEntityActionManager} from "./functions/buildEntityActionManager";
import {isDiagramEntity} from "./functions/isDiagramEntity";
import {InputTextView} from "../information/inputTextView";
import {DefaultScene} from "../defaultScene";
import {ScaleMenu} from "../menus/scaleMenu";
export class DiagramManager {
@ -21,7 +22,7 @@ export class DiagramManager {
private readonly _controllers: Controllers;
private readonly diagramEntityActionManager: ActionManager;
private readonly inputTextView: InputTextView;
public readonly scaleMenu: ScaleMenu;
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
private readonly logger = log.getLogger('DiagramManager');
private readonly toolbox: Toolbox;
@ -48,6 +49,17 @@ export class DiagramManager {
});
this.toolbox = new Toolbox();
this.scaleMenu = new ScaleMenu();
this.scaleMenu.onScaleChangeObservable.add((mesh: AbstractMesh) => {
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.MODIFY,
entity: toDiagramEntity(mesh),
}, -1);
const position = mesh.absolutePosition.clone();
position.y = mesh.getBoundingInfo().boundingBox.maximumWorld.y + .1;
this.scaleMenu.changePosition(position);
});
//this.presentationManager = new PresentationManager(this._scene);
this.diagramEntityActionManager = buildEntityActionManager(this._controllers);

View File

@ -1,55 +1,76 @@
import {GUI3DManager, PlanePanel} from "@babylonjs/gui";
import {AbstractMesh, Tools, TransformNode, Vector3} from "@babylonjs/core";
import {AbstractMesh, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
import {toDiagramEntity} from "../diagram/functions/toDiagramEntity";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramConnection} from "../diagram/diagramConnection";
import {isDiagramEntity} from "../diagram/functions/isDiagramEntity";
import {makeButton} from "./functions/makeButton";
import {HtmlButton} from "babylon-html";
export class ClickMenu {
private static readonly sounds;
private readonly entity: AbstractMesh;
private readonly manager: GUI3DManager;
private readonly _mesh: AbstractMesh;
private readonly transform: TransformNode;
private readonly diagramManager: DiagramManager;
private utilityPosition: Vector3;
private connection: DiagramConnection = null;
constructor(entity: AbstractMesh, diagramManager: DiagramManager, grip: TransformNode) {
this.entity = entity;
constructor(mesh: AbstractMesh, diagramManager: DiagramManager, grip: TransformNode) {
this._mesh = mesh;
this.diagramManager = diagramManager;
const scene = entity.getScene();
const manager = new GUI3DManager(scene);
manager.onPickingObservable.add((mesh) => {
if (mesh) {
this.utilityPosition = mesh.getAbsolutePosition();
const scene = mesh.getScene();
this.transform = new TransformNode("transform", scene);
let x = -.54 / 2;
const removeButton: HtmlButton = this.makeNewButton("Remove", "remove", scene, x += .11);
removeButton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
const event: DiagramEvent = {
type: DiagramEventType.REMOVE,
entity:
toDiagramEntity(this._mesh)
}
});
const transform = new TransformNode("transform", scene);
const panel = new PlanePanel();
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
this.dispose();
}
}, -1, false, this, false);
panel.orientation = PlanePanel.FACEFORWARD_ORIENTATION;
panel.columns = 4;
panel.margin = .1;
manager.addControl(panel);
panel.linkToTransformNode(transform);
const labelButton: HtmlButton = this.makeNewButton("Label", "label", scene, x += .11);
labelButton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
this.diagramManager.editText(this._mesh);
this.dispose();
}
}, -1, false, this, false);
panel.addControl(this.makeButton("Remove", "remove", grip));
panel.addControl(this.makeButton("Label", "label", grip));
panel.addControl(this.makeButton("Connect", "connect", grip));
panel.addControl(this.makeButton("Close", "close", grip));
const connectButton: HtmlButton = this.makeNewButton("Connect", "connect", scene, x += .11);
connectButton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
this.createMeshConnection(this._mesh, grip, eventData.additionalData.pickedPoint.clone());
}
}, -1, false, this, false);
manager.controlScaling = .1;
panel.updateLayout();
this.transform = transform;
this.manager = manager;
Tools.SetImmediate(() => {
transform.position = entity.absolutePosition.clone();
transform.position.y = entity.getBoundingInfo().boundingBox.maximumWorld.y + .1;
transform.billboardMode = TransformNode.BILLBOARDMODE_Y;
});
const closeButton: HtmlButton = this.makeNewButton("Close", "close", scene, x += .11);
closeButton.onPointerObservable.add((eventData) => {
eventData.sourceEvent.type == "pointerup" && this.dispose();
}, -1, false, this, false);
const sizeButton: HtmlButton = this.makeNewButton("Size", "size", scene, x += .11);
sizeButton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
this.diagramManager.scaleMenu.show(this._mesh);
}
}, -1, false, this, false);
this.transform.position = mesh.absolutePosition.clone();
this.transform.position.y = mesh.getBoundingInfo().boundingBox.maximumWorld.y + .1;
this.transform.billboardMode = TransformNode.BILLBOARDMODE_Y;
}
private makeNewButton(name: string, id: string, scene: Scene, x: number): HtmlButton {
const button = new HtmlButton(name, id, scene, null, {html: null, image: {width: 268, height: 268}});
button.transform.parent = this.transform;
button.transform.rotation.y = Math.PI;
button.transform.position.x = x;
return button;
}
public get isConnecting() {
@ -74,40 +95,12 @@ export class ClickMenu {
}
}
private makeButton(name: string, id: string, grip: TransformNode) {
const button = makeButton(id, name);
button.onPointerClickObservable.add(() => {
switch (id) {
case "close":
this.dispose();
break;
case "remove":
const event: DiagramEvent = {
type: DiagramEventType.REMOVE,
entity:
toDiagramEntity(this.entity)
}
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
this.dispose();
break;
case "label":
this.diagramManager.editText(this.entity);
this.dispose();
break;
case "connect":
this.createMeshConnection(this.entity, grip);
}
}, -1, false, this, true);
return button;
}
private createMeshConnection(mesh: AbstractMesh, grip: TransformNode) {
this.connection = new DiagramConnection(mesh.id, null, null, this.transform.getScene(), grip, this.utilityPosition);
private createMeshConnection(mesh: AbstractMesh, grip: TransformNode, utilityPosition: Vector3) {
this.connection = new DiagramConnection(mesh.id, null, null, this.transform.getScene(), grip, utilityPosition);
}
private dispose() {
this.manager.onPickingObservable.clear();
this.manager.dispose();
this.transform.dispose();
this.diagramManager.scaleMenu.hide();
this.transform.dispose(false, true);
}
}

View File

@ -1,103 +1,131 @@
import {AbstractMesh, TransformNode, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
import {DefaultScene} from "../defaultScene";
import {HtmlButton, HtmlMeshBuilder} from "babylon-html";
import {AbstractMesh, Observable, TransformNode, Vector3} from "@babylonjs/core";
import {Controllers} from "../controllers/controllers";
import {DiaSounds} from "../util/diaSounds";
import {AbstractMenu} from "./abstractMenu";
import {GUI3DManager, Slider3D} from "@babylonjs/gui";
export class ScaleMenu extends AbstractMenu {
private sounds: DiaSounds;
private mesh: AbstractMesh;
private xSlider: Slider3D;
private ySlider: Slider3D;
private zSlider: Slider3D;
private transformNode: TransformNode;
private xTransformNode: TransformNode;
private yTransformNode: TransformNode;
private zTransformNode: TransformNode;
constructor(xr: WebXRDefaultExperience, controllers: Controllers) {
super(xr, controllers);
this.transformNode = new TransformNode("scaleMenu", this.scene);
this.xTransformNode = new TransformNode("xTransformNode", this.scene);
this.xTransformNode.parent = this.transformNode;
this.yTransformNode = new TransformNode("yTransformNode", this.scene);
this.yTransformNode.parent = this.transformNode;
this.zTransformNode = new TransformNode("zTransformNode", this.scene);
this.zTransformNode.parent = this.transformNode;
//super.createHandle(this.transformNode);
this.transformNode.position.y = 0;
this.transformNode.position.z = 0;
this.transformNode.position.x = 0;
this.buildMenu();
//this.transformNode.position.y = 2;
export class ScaleMenu {
private static Sizes = [
.025, .05, .1, .25, .5, 1.0, 2.0, 3.0, 4.0, 5.0
]
public readonly onScaleChangeObservable: Observable<AbstractMesh> = new Observable<AbstractMesh>();
private readonly transform;
private _mesh: AbstractMesh;
constructor() {
this.transform = new TransformNode("scaleMenu", DefaultScene.Scene);
this.transform.scaling = new Vector3(.5, .5, .5);
this.build();
}
public changeMesh(mesh: AbstractMesh) {
this.mesh = mesh;
this.xSlider.value = mesh.scaling.x;
this.ySlider.value = mesh.scaling.y;
this.zSlider.value = mesh.scaling.z;
const two = new Vector3(2, 2, 2);
this.transformNode.position = this.mesh.absolutePosition.clone();
this.transformNode.rotation = this.mesh.absoluteRotationQuaternion.toEulerAngles();
public changePosition(position: Vector3) {
this.transform.position = position.clone();
}
private buildMenu() {
const manager = new GUI3DManager(this.scene);
//manager.rootContainer.position.y = 2;
//manager.rootContainer.node.position.y = 2;
this.xSlider = new Slider3D("xslider");
this.ySlider = new Slider3D("yslider");
this.zSlider = new Slider3D("zslider");
manager.addControl(this.xSlider);
manager.addControl(this.ySlider);
manager.addControl(this.zSlider);
this.xSlider.linkToTransformNode(this.xTransformNode);
this.ySlider.linkToTransformNode(this.yTransformNode);
this.zSlider.linkToTransformNode(this.zTransformNode);
this.xTransformNode.position = new Vector3(0, 0, .6);
this.xTransformNode.rotation.y = Math.PI;
this.yTransformNode.position = new Vector3(.6, .6, .6);
this.yTransformNode.rotation.z = Math.PI / 2;
this.zTransformNode.position = new Vector3(.6, .6, 0);
this.zTransformNode.rotation.y = Math.PI / 2;
setValues(this.xSlider);
setValues(this.ySlider);
setValues(this.zSlider);
this.xSlider.onValueChangedObservable.add((value) => {
if (this.mesh) {
this.mesh.scaling.x = value;
}
});
this.ySlider.onValueChangedObservable.add((value) => {
if (this.mesh) {
this.mesh.scaling.y = value;
}
});
this.zSlider.onValueChangedObservable.add((value) => {
if (this.mesh) {
this.mesh.scaling.z = value;
}
});
this.transformNode.scaling.x = .5;
this.transformNode.scaling.y = .5;
this.transformNode.scaling.z = .5;
public show(mesh: AbstractMesh) {
this.transform.position = mesh.absolutePosition.clone();
this.transform.position.y = mesh.getBoundingInfo().boundingBox.maximumWorld.y + .1;
//this.transform.billboardMode = TransformNode.BILLBOARDMODE_Y;
this.transform.setEnabled(true);
this._mesh = mesh;
}
}
function setValues(slider: Slider3D) {
slider.minimum = .1;
slider.maximum = 1;
slider.step = .1;
slider.value = .1;
public hide() {
this.transform.setEnabled(false);
this._mesh = null;
}
private async build() {
let x = .12;
const xParent = new TransformNode("xParent", DefaultScene.Scene);
xParent.parent = this.transform;
const yParent = new TransformNode("yParent", DefaultScene.Scene);
yParent.parent = this.transform;
const zParent = new TransformNode("zParent", DefaultScene.Scene);
zParent.parent = this.transform;
xParent.rotation.x = Math.PI / 2;
yParent.rotation.z = Math.PI / 2;
yParent.billboardMode = TransformNode.BILLBOARDMODE_Y;
zParent.rotation.y = Math.PI / 2;
zParent.rotation.x = Math.PI / 2;
for (const size of ScaleMenu.Sizes) {
const xbutton = this.makeButton(size.toString(), x, 0, xParent);
xbutton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
this.scaleX(size)
}
}, -1, false, this, false);
const ybutton = this.makeButton(size.toString(), x, Math.PI / 2, yParent);
ybutton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
this.scaleY(size)
}
}, -1, false, this, false);
const zbutton = this.makeButton(size.toString(), x, -Math.PI / 2, zParent);
zbutton.onPointerObservable.add((eventData) => {
if (eventData.sourceEvent.type == "pointerup") {
this.scaleZ(size)
}
}, -1, false, this, false);
x += .11;
}
// const labelX = await this.createLabel('X Size', .3);
// const labelY = await this.createLabel('Y Size', .2);
// const labelZ = await this.createLabel('Z Size', .1);
this.transform.position.y = 1;
this.transform.rotation.y = Math.PI;
this.transform.setEnabled(false);
}
private makeButton(name: string, x: number, y: number, parent: TransformNode = null) {
const button = new HtmlButton(name, name, DefaultScene.Scene);
button.transform.parent = parent;
button.transform.position.x = x;
//button.transform.position.y = y;
button.transform.rotation.z = y;
button.transform.rotation.y = Math.PI;
return button;
}
private scaleX(size: number) {
if (this._mesh) {
this._mesh.scaling.x = size;
this.scaleChanged();
}
}
private scaleY(size: number) {
if (this._mesh) {
this._mesh.scaling.y = size;
this.scaleChanged();
}
}
private scaleZ(size: number) {
if (this._mesh) {
this._mesh.scaling.z = size;
this.scaleChanged();
}
}
private scaleChanged() {
if (this._mesh) {
this.onScaleChangeObservable.notifyObservers(this._mesh);
}
}
private async createLabel(name: string, y: number) {
const label = await HtmlMeshBuilder.CreatePlane(`${name}-label`,
{
html: `<div style='margin: 0; padding-top: 40px; font-size: 32px; text-align: center; color:#ffffff; background: #000000; width: 128px; height: 128px'>${name}</div>`,
height: .1, image: {width: 128, height: 128}
},
DefaultScene.Scene);
label.parent = this.transform;
label.position.y = y;
label.position.x = -.42;
return label;
}
}

View File

@ -52,7 +52,6 @@ export class VrApp {
*/
addSceneInspector();
//const mainMenu = new MainMenu(scene);
const el = document.querySelector('#download');
if (el) {
el.addEventListener('click', () => {