Fixed up text entry for immersive and xr emulation.

This commit is contained in:
Michael Mainguy 2023-07-27 11:46:52 -05:00
parent c74dc62654
commit 06b2989f3a
3 changed files with 155 additions and 95 deletions

View File

@ -52,6 +52,7 @@ export class Right extends Base {
if (abutton) {
abutton.onButtonStateChangedObservable.add((value) => {
if (value.pressed) {
log.getLogger("right").debug("a-button pressed");
Controllers.controllerObserver.notifyObservers({type: 'menu'});
}
});

View File

@ -1,5 +1,14 @@
import {DiagramEntity} from "./diagramEntity";
import {AbstractMesh, Color3, InstancedMesh, Mesh, Scene, StandardMaterial} from "@babylonjs/core";
import {
AbstractMesh,
Color3,
DynamicTexture,
InstancedMesh,
Mesh,
MeshBuilder,
Scene,
StandardMaterial
} from "@babylonjs/core";
import {v4 as uuidv4} from 'uuid';
import {Toolbox} from "../toolbox/toolbox";
import log from "loglevel";
@ -57,6 +66,7 @@ export class MeshConverter {
mesh.metadata = {template: entity.template};
if (entity.text) {
mesh.metadata.text = entity.text;
this.updateTextNode(mesh, entity.text);
}
if (entity.position) {
mesh.position = entity.position;
@ -82,4 +92,50 @@ export class MeshConverter {
}
public static updateTextNode(mesh: AbstractMesh, text: string) {
let textNode = (mesh.getChildren((node) => {
return node.name == 'text'
})[0] as Mesh);
if (textNode) {
textNode.dispose(false, true);
}
//Set font
const height = 0.125;
const font_size = 24;
const font = "bold " + font_size + "px Arial";
//Set height for dynamic texture
const DTHeight = 1.5 * font_size; //or set as wished
//Calc Ratio
const ratio = height / DTHeight;
//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 tmpctx = temp.getContext();
tmpctx.font = font;
const DTWidth = tmpctx.measureText(text).width + 8;
//Calculate width the plane has to be
const planeWidth = DTWidth * ratio;
//Create dynamic texture and write the text
const dynamicTexture = new DynamicTexture("DynamicTexture", {
width: DTWidth,
height: DTHeight
}, mesh.getScene(), false);
const mat = new StandardMaterial("mat", mesh.getScene());
mat.diffuseTexture = dynamicTexture;
dynamicTexture.drawText(text, null, null, font, "#000000", "#ffffff", true);
//Create plane and set dynamic texture as material
const plane = MeshBuilder.CreatePlane("text", {width: planeWidth, height: height}, mesh.getScene());
plane.material = mat;
plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
//textNode = this.updateTextNode(mesh, entity.text);
plane.parent = mesh;
log.getLogger('bmenu').debug("max y", mesh.getBoundingInfo().boundingBox.maximum.y);
plane.position.y = .5+ (height / 2);
return plane;
}
}

View File

@ -2,6 +2,7 @@ import {
AbstractMesh,
GizmoManager,
PointerEventTypes,
PointerInfo,
Scene,
Vector3,
WebXRExperienceHelper
@ -40,21 +41,27 @@ export class Bmenu {
case PointerEventTypes.POINTERPICK:
if (pointerInfo.pickInfo?.pickedMesh?.metadata?.template &&
pointerInfo.pickInfo?.pickedMesh?.parent?.parent?.id != "toolbox") {
if (this.textInput) {
this.textInput.blur();
this.textInput.remove();
this.textInput = null;
}
if (this.textView) {
this.textView.dispose().then(() => {
log.getLogger("bmenu").debug("disposed");
this.cleanup()
.then(() => {
log.getLogger("bmenu").debug("cleaned up");
})
.catch((e) => {
log.getLogger("bmenu").error(e);
});
this.handleEventStateAction(pointerInfo).then(() => {
log.getLogger("bmenu").debug("handled");
}).catch((e) => {
log.getLogger("bmenu").error(e);
});
this.textView = null;
}
switch (this.state) {
break;
}
}
});
}
private async handleEventStateAction(pointerInfo: PointerInfo) {
switch (this.state) {
case BmenuState.REMOVING:
log.debug("removing " + pointerInfo.pickInfo.pickedMesh.id);
const event: DiagramEvent = {
@ -82,15 +89,11 @@ export class Bmenu {
log.debug(mesh.scaling);
});
}
}
break;
case BmenuState.LABELING:
const mesh = pointerInfo.pickInfo.pickedMesh;
log.debug("labeling " + mesh.id);
const textInput = document.createElement("input");
textInput.type = "text";
document.body.appendChild(textInput);
@ -106,41 +109,40 @@ export class Bmenu {
log.debug(event);
});
const textView = new InputTextView(this.scene, this.xr, mesh)
textView.show(textInput.value);
await textView.show(textInput.value);
textInput.addEventListener('keydown', (event) => {
if (event.key == "Enter") {
log.getLogger('bmenu').debug("enter");
MeshConverter.updateTextNode(mesh, textInput.value);
this.persist(mesh, textInput.value);
textInput.blur();
textInput.remove();
this.textView.dispose();
this.textView = null;
this.textInput = null;
this.cleanup();
} else {
textView.updateText(textInput.value);
MeshConverter.updateTextNode(mesh, textInput.value);
}
});
this.textView = textView;
} else {
textInput.addEventListener('keydown', (event)=> {
log.debug(event);
if (event.key == "Enter") {
textInput.addEventListener('blur', () => {
log.getLogger('bmenu').debug("blur");
MeshConverter.updateTextNode(mesh, textInput.value);
this.persist(mesh, textInput.value);
textInput.blur();
textInput.remove();
this.textInput = null;
this.textView = null;
}
this.cleanup();
});
}
this.textInput = textInput;
break;
}
break;
}
}
});
private async cleanup() {
if (this.textInput) {
this.textInput.blur();
this.textInput.remove();
}
this.textInput = null;
this.textView && await this.textView.dispose();
this.textView = null;
}
private persist(mesh: AbstractMesh, text: string) {
if (mesh.metadata) {
@ -153,6 +155,7 @@ export class Bmenu {
entity: MeshConverter.toDiagramEntity(mesh),
});
}
makeButton(name: string, id: string) {
const button = new Button3D(name);
button.scaling = new Vector3(.1, .1, .1);