Fixed up text entry for immersive and xr emulation.
This commit is contained in:
parent
c74dc62654
commit
06b2989f3a
@ -52,6 +52,7 @@ export class Right extends Base {
|
|||||||
if (abutton) {
|
if (abutton) {
|
||||||
abutton.onButtonStateChangedObservable.add((value) => {
|
abutton.onButtonStateChangedObservable.add((value) => {
|
||||||
if (value.pressed) {
|
if (value.pressed) {
|
||||||
|
log.getLogger("right").debug("a-button pressed");
|
||||||
Controllers.controllerObserver.notifyObservers({type: 'menu'});
|
Controllers.controllerObserver.notifyObservers({type: 'menu'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
import {DiagramEntity} from "./diagramEntity";
|
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 {v4 as uuidv4} from 'uuid';
|
||||||
import {Toolbox} from "../toolbox/toolbox";
|
import {Toolbox} from "../toolbox/toolbox";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
@ -57,6 +66,7 @@ export class MeshConverter {
|
|||||||
mesh.metadata = {template: entity.template};
|
mesh.metadata = {template: entity.template};
|
||||||
if (entity.text) {
|
if (entity.text) {
|
||||||
mesh.metadata.text = 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;
|
||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -2,6 +2,7 @@ import {
|
|||||||
AbstractMesh,
|
AbstractMesh,
|
||||||
GizmoManager,
|
GizmoManager,
|
||||||
PointerEventTypes,
|
PointerEventTypes,
|
||||||
|
PointerInfo,
|
||||||
Scene,
|
Scene,
|
||||||
Vector3,
|
Vector3,
|
||||||
WebXRExperienceHelper
|
WebXRExperienceHelper
|
||||||
@ -40,21 +41,27 @@ export class Bmenu {
|
|||||||
case PointerEventTypes.POINTERPICK:
|
case PointerEventTypes.POINTERPICK:
|
||||||
if (pointerInfo.pickInfo?.pickedMesh?.metadata?.template &&
|
if (pointerInfo.pickInfo?.pickedMesh?.metadata?.template &&
|
||||||
pointerInfo.pickInfo?.pickedMesh?.parent?.parent?.id != "toolbox") {
|
pointerInfo.pickInfo?.pickedMesh?.parent?.parent?.id != "toolbox") {
|
||||||
if (this.textInput) {
|
this.cleanup()
|
||||||
this.textInput.blur();
|
.then(() => {
|
||||||
this.textInput.remove();
|
log.getLogger("bmenu").debug("cleaned up");
|
||||||
this.textInput = null;
|
})
|
||||||
}
|
.catch((e) => {
|
||||||
if (this.textView) {
|
log.getLogger("bmenu").error(e);
|
||||||
this.textView.dispose().then(() => {
|
});
|
||||||
log.getLogger("bmenu").debug("disposed");
|
this.handleEventStateAction(pointerInfo).then(() => {
|
||||||
|
log.getLogger("bmenu").debug("handled");
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
log.getLogger("bmenu").error(e);
|
log.getLogger("bmenu").error(e);
|
||||||
});
|
});
|
||||||
this.textView = null;
|
|
||||||
}
|
|
||||||
switch (this.state) {
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleEventStateAction(pointerInfo: PointerInfo) {
|
||||||
|
switch (this.state) {
|
||||||
case BmenuState.REMOVING:
|
case BmenuState.REMOVING:
|
||||||
log.debug("removing " + pointerInfo.pickInfo.pickedMesh.id);
|
log.debug("removing " + pointerInfo.pickInfo.pickedMesh.id);
|
||||||
const event: DiagramEvent = {
|
const event: DiagramEvent = {
|
||||||
@ -82,15 +89,11 @@ export class Bmenu {
|
|||||||
log.debug(mesh.scaling);
|
log.debug(mesh.scaling);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BmenuState.LABELING:
|
case BmenuState.LABELING:
|
||||||
const mesh = pointerInfo.pickInfo.pickedMesh;
|
const mesh = pointerInfo.pickInfo.pickedMesh;
|
||||||
log.debug("labeling " + mesh.id);
|
log.debug("labeling " + mesh.id);
|
||||||
|
|
||||||
|
|
||||||
const textInput = document.createElement("input");
|
const textInput = document.createElement("input");
|
||||||
textInput.type = "text";
|
textInput.type = "text";
|
||||||
document.body.appendChild(textInput);
|
document.body.appendChild(textInput);
|
||||||
@ -106,41 +109,40 @@ export class Bmenu {
|
|||||||
log.debug(event);
|
log.debug(event);
|
||||||
});
|
});
|
||||||
const textView = new InputTextView(this.scene, this.xr, mesh)
|
const textView = new InputTextView(this.scene, this.xr, mesh)
|
||||||
textView.show(textInput.value);
|
await textView.show(textInput.value);
|
||||||
textInput.addEventListener('keydown', (event) => {
|
textInput.addEventListener('keydown', (event) => {
|
||||||
if (event.key == "Enter") {
|
if (event.key == "Enter") {
|
||||||
|
log.getLogger('bmenu').debug("enter");
|
||||||
|
MeshConverter.updateTextNode(mesh, textInput.value);
|
||||||
this.persist(mesh, textInput.value);
|
this.persist(mesh, textInput.value);
|
||||||
textInput.blur();
|
this.cleanup();
|
||||||
textInput.remove();
|
|
||||||
this.textView.dispose();
|
|
||||||
this.textView = null;
|
|
||||||
this.textInput = null;
|
|
||||||
} else {
|
} else {
|
||||||
textView.updateText(textInput.value);
|
textView.updateText(textInput.value);
|
||||||
|
MeshConverter.updateTextNode(mesh, textInput.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.textView = textView;
|
this.textView = textView;
|
||||||
} else {
|
} else {
|
||||||
textInput.addEventListener('keydown', (event)=> {
|
textInput.addEventListener('blur', () => {
|
||||||
log.debug(event);
|
log.getLogger('bmenu').debug("blur");
|
||||||
if (event.key == "Enter") {
|
MeshConverter.updateTextNode(mesh, textInput.value);
|
||||||
this.persist(mesh, textInput.value);
|
this.persist(mesh, textInput.value);
|
||||||
textInput.blur();
|
this.cleanup();
|
||||||
textInput.remove();
|
|
||||||
this.textInput = null;
|
|
||||||
this.textView = null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.textInput = textInput;
|
this.textInput = textInput;
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
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) {
|
private persist(mesh: AbstractMesh, text: string) {
|
||||||
if (mesh.metadata) {
|
if (mesh.metadata) {
|
||||||
@ -153,6 +155,7 @@ export class Bmenu {
|
|||||||
entity: MeshConverter.toDiagramEntity(mesh),
|
entity: MeshConverter.toDiagramEntity(mesh),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
makeButton(name: string, id: string) {
|
makeButton(name: string, id: string) {
|
||||||
const button = new Button3D(name);
|
const button = new Button3D(name);
|
||||||
button.scaling = new Vector3(.1, .1, .1);
|
button.scaling = new Vector3(.1, .1, .1);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user