Added diagram import from drawio.
This commit is contained in:
parent
a7997608c2
commit
c62aa59923
@ -26,6 +26,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="loader">Loading...</div>
|
||||
<div id="graphContainer"></div>
|
||||
<script type="module" src="./src/app.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
45
package-lock.json
generated
45
package-lock.json
generated
@ -8,14 +8,17 @@
|
||||
"name": "immersive",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@babylonjs/core": "^6.14.0",
|
||||
"@babylonjs/gui": "^6.14.0",
|
||||
"@babylonjs/core": "^6.15.0",
|
||||
"@babylonjs/gui": "^6.15.0",
|
||||
"@babylonjs/havok": "1.1.1",
|
||||
"@babylonjs/inspector": "^6.14.0",
|
||||
"@babylonjs/inspector": "^6.15.0",
|
||||
"@babylonjs/serializers": "^6.15.0",
|
||||
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
|
||||
"dexie": "^3.2.4",
|
||||
"dexie-observable": "^4.0.1-beta.13",
|
||||
"earcut": "^2.2.4",
|
||||
"loglevel": "^1.8.1",
|
||||
"mxgraph": "^4.2.2",
|
||||
"p2p-data-channel": "^1.10.7",
|
||||
"query-string": "^8.1.0",
|
||||
"ring-client-api": "11.7.7",
|
||||
@ -41,14 +44,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babylonjs/core": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.14.0.tgz",
|
||||
"integrity": "sha512-ciIfWMMtV5jsnqxqTn+v/CS65yji6CXTP2drmvLlzk+k+IZjE8RfkpMqZgZozN/KNkOmIVn2Li7qRMjg4ZUGlw=="
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.15.0.tgz",
|
||||
"integrity": "sha512-eoeJ3RB6xYC63ZuGGuceF7rrVA1OFIlO3cvBvAxsoBIzxTSLxyhmG4wwktEvCAePxZ7W7CDYNtA061edGWhxUw=="
|
||||
},
|
||||
"node_modules/@babylonjs/gui": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.14.0.tgz",
|
||||
"integrity": "sha512-rkqPEVDaeza4agyd5xSLSjnWgI1spqcNI/kmNke4gREmweEcZZFxNxjGQd5m/JQMbx7qrj9jtEp8COZ7wNSiWw==",
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.15.0.tgz",
|
||||
"integrity": "sha512-WkR/r8wLbKyzUuXUgcWVaTZO5drxQ8YjkstDRz/ZrhfOTIEFDpidd7onDhaQ9wmekQEpFHcKJejJ1/MLXYLwAg==",
|
||||
"peerDependencies": {
|
||||
"@babylonjs/core": "^6.0.0"
|
||||
}
|
||||
@ -74,9 +77,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babylonjs/inspector": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.14.0.tgz",
|
||||
"integrity": "sha512-8wntNbVb9Yhj0q8Ll4kFGDDJPHk7IeosqVwXTPToTfDYC67pwkVQFXFViEXr1R0HrG0l1FmZzPVLY6szbFSwrw==",
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.15.0.tgz",
|
||||
"integrity": "sha512-wN1jVC+gxQDcLL/dyuIMbedPZpxTHNW9gto82jvgyjXLIUKOWiQUVJS7moaLhTM27BMWBrHMfG+K4RnsnKEW9A==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.0.0",
|
||||
@ -113,10 +116,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babylonjs/serializers": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.8.0.tgz",
|
||||
"integrity": "sha512-/deOpTX3Lnll3PM9Um7l+e33mVPe65BgAOlgskrcH6XmT5BaltedYwQktTyblrZs8nQEs90elPpdOb0bsoY4HA==",
|
||||
"peer": true,
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.15.0.tgz",
|
||||
"integrity": "sha512-qUKqMe18wlEQpyh5cAa/u/B4xMZ2tKh5K1CurnN9TXaM6i8wImRL4mmXqlwy/Tq18zUGmfmPyU1p1qPuD1ytcg==",
|
||||
"peerDependencies": {
|
||||
"@babylonjs/core": "^6.0.0",
|
||||
"babylonjs-gltf2interface": "^6.0.0"
|
||||
@ -901,6 +903,11 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typed-mxgraph/typed-mxgraph": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@typed-mxgraph/typed-mxgraph/-/typed-mxgraph-1.0.8.tgz",
|
||||
"integrity": "sha512-rzTbmD/XofRq0YZMY/BU9cjbCTw9q8rpIvWRhQO0DcgCx3+rpHTsVOk3pfuhcnUigUYNFkljmDkRuVjbl7zZoQ=="
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
@ -2826,6 +2833,12 @@
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||
},
|
||||
"node_modules/mxgraph": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/mxgraph/-/mxgraph-4.2.2.tgz",
|
||||
"integrity": "sha512-FrJc5AxzXSqiQNF+8CyJk6VxuKO4UVPgw32FZuFZ3X9W+JqOAQBTokZhh0ZkEqGpEOyp3z778ssmBTvdrTAdqw==",
|
||||
"deprecated": "Package no longer supported. Use at your own risk"
|
||||
},
|
||||
"node_modules/nano-time": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz",
|
||||
|
||||
@ -11,15 +11,18 @@
|
||||
"havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babylonjs/core": "^6.14.0",
|
||||
"@babylonjs/gui": "^6.14.0",
|
||||
"@babylonjs/core": "^6.15.0",
|
||||
"@babylonjs/gui": "^6.15.0",
|
||||
"@babylonjs/havok": "1.1.1",
|
||||
"@babylonjs/inspector": "^6.14.0",
|
||||
"@babylonjs/inspector": "^6.15.0",
|
||||
"@babylonjs/serializers": "^6.15.0",
|
||||
"ring-client-api": "11.7.7",
|
||||
"dexie": "^3.2.4",
|
||||
"dexie-observable": "^4.0.1-beta.13",
|
||||
"query-string": "^8.1.0",
|
||||
"loglevel": "^1.8.1",
|
||||
"mxgraph": "^4.2.2",
|
||||
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
|
||||
"round": "^2.0.1",
|
||||
"earcut": "^2.2.4",
|
||||
"uuid": "^9.0.0",
|
||||
|
||||
17
src/app.ts
17
src/app.ts
@ -17,18 +17,22 @@ import {PeerjsNetworkConnection} from "./integration/peerjsNetworkConnection";
|
||||
import {InputTextView} from "./information/inputTextView";
|
||||
import {GamepadManager} from "./controllers/gamepadManager";
|
||||
import {CustomEnvironment} from "./util/customEnvironment";
|
||||
import {DrawioManager} from "./integration/drawioManager";
|
||||
|
||||
export class App {
|
||||
//preTasks = [havokModule];
|
||||
constructor() {
|
||||
const config = AppConfig.config;
|
||||
const logger = log.getLogger('App');
|
||||
log.setLevel('info');
|
||||
log.getLogger('App').setLevel('info');
|
||||
log.getLogger('IndexdbPersistenceManager').setLevel('info');
|
||||
log.getLogger('DiagramManager').setLevel('info');
|
||||
log.disableAll();
|
||||
log.setDefaultLevel('info');
|
||||
|
||||
log.getLogger('DiagramConnection').setLevel('debug');
|
||||
log.getLogger('App').setLevel('info');
|
||||
//log.getLogger('IndexdbPersistenceManager').setLevel('info');
|
||||
//log.getLogger('DiagramManager').setLevel('info');
|
||||
|
||||
//log.getLogger('DiagramConnection').setLevel('debug');
|
||||
log.getLogger('DrawioManager').setLevel('debug');
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.style.width = "100%";
|
||||
canvas.style.height = "100%";
|
||||
@ -41,6 +45,7 @@ export class App {
|
||||
}
|
||||
|
||||
async initialize(canvas) {
|
||||
|
||||
const logger = log.getLogger('App');
|
||||
const engine = new Engine(canvas, true);
|
||||
const scene = new Scene(engine);
|
||||
@ -69,6 +74,7 @@ export class App {
|
||||
camera.radius = 0;
|
||||
camera.attachControl(canvas, true);
|
||||
new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
|
||||
|
||||
environment.groundMeshObservable.add(async (ground) => {
|
||||
const xr = await WebXRDefaultExperience.CreateAsync(scene, {
|
||||
floorMeshes: [ground],
|
||||
@ -99,6 +105,7 @@ export class App {
|
||||
const diagramManager = new DiagramManager(scene, xr.baseExperience);
|
||||
const rig = new Rigplatform(scene, xr, diagramManager);
|
||||
const toolbox = new Toolbox(scene, xr.baseExperience, diagramManager);
|
||||
const dioManager = new DrawioManager(scene, diagramManager);
|
||||
import ('./integration/indexdbPersistenceManager').then((module) => {
|
||||
const persistenceManager = new module.IndexdbPersistenceManager("diagram");
|
||||
diagramManager.setPersistenceManager(persistenceManager);
|
||||
|
||||
@ -20,6 +20,7 @@ import {EditMenu} from "../menus/editMenu";
|
||||
import {Controllers} from "./controllers";
|
||||
import log from "loglevel";
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
import {AppConfig} from "../util/appConfig";
|
||||
|
||||
|
||||
export class Rigplatform {
|
||||
@ -35,6 +36,7 @@ export class Rigplatform {
|
||||
private camera: Camera;
|
||||
private turning: boolean = false;
|
||||
private velocity: Vector3 = Vector3.Zero();
|
||||
private turnVelocity: number = 0;
|
||||
private logger = log.getLogger('Rigplatform');
|
||||
private readonly diagramManager: DiagramManager;
|
||||
|
||||
@ -92,12 +94,13 @@ export class Rigplatform {
|
||||
this.velocity.y = (val * this.velocityArray[this.velocityIndex])*-1;
|
||||
}
|
||||
public turn(val: number) {
|
||||
const snap = true;
|
||||
if (snap) {
|
||||
const snap = AppConfig.config.currentTurnSnap.value;
|
||||
|
||||
if (snap > 0) {
|
||||
if (!this.turning) {
|
||||
if (Math.abs(val) > .1) {
|
||||
this.turning = true;
|
||||
this.yRotation += Angle.FromDegrees(Math.sign(val) * 22.5).radians();
|
||||
this.yRotation += Angle.FromDegrees(Math.sign(val) * snap).radians();
|
||||
}
|
||||
} else {
|
||||
if (Math.abs(val) < .1) {
|
||||
@ -106,9 +109,9 @@ export class Rigplatform {
|
||||
}
|
||||
} else {
|
||||
if (Math.abs(val) > .1) {
|
||||
this.body.setAngularVelocity(Vector3.Up().scale(val));
|
||||
this.turnVelocity = val;
|
||||
} else {
|
||||
this.body.setAngularVelocity(Vector3.Zero());
|
||||
this.turnVelocity = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,6 +172,7 @@ export class Rigplatform {
|
||||
}
|
||||
private fixRotation() {
|
||||
this.scene.registerBeforeRender(() => {
|
||||
if (AppConfig?.config?.currentTurnSnap?.value > 0) {
|
||||
const q = this.rigMesh.rotationQuaternion;
|
||||
this.body.setAngularVelocity(Vector3.Zero());
|
||||
if (q) {
|
||||
@ -176,6 +180,10 @@ export class Rigplatform {
|
||||
e.y += this.yRotation;
|
||||
q.copyFrom(Quaternion.FromEulerAngles(0, e.y, 0));
|
||||
}
|
||||
} else {
|
||||
this.body.setAngularVelocity(Vector3.Up().scale(this.turnVelocity));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -136,6 +136,20 @@ export class DiagramManager {
|
||||
if (entity) {
|
||||
mesh = this.scene.getMeshById(entity.id);
|
||||
}
|
||||
if (!mesh) {
|
||||
const toolMesh = this.scene.getMeshById("tool-" + event.entity.template + "-" + event.entity.color);
|
||||
if (!toolMesh) {
|
||||
log.debug('no mesh found for ' + event.entity.template + "-" + event.entity.color, 'adding it');
|
||||
this.onDiagramEventObservable.notifyObservers({
|
||||
type: DiagramEventType.CHANGECOLOR,
|
||||
entity: event.entity
|
||||
});
|
||||
}
|
||||
|
||||
mesh = MeshConverter.fromDiagramEntity(event.entity, this.scene);
|
||||
mesh.actionManager = this.actionManager;
|
||||
DiagramShapePhysics.applyPhysics(mesh, this.scene, PhysicsMotionType.DYNAMIC);
|
||||
}
|
||||
switch (event.type) {
|
||||
case DiagramEventType.CLEAR:
|
||||
break;
|
||||
|
||||
235
src/integration/drawioManager.ts
Normal file
235
src/integration/drawioManager.ts
Normal file
@ -0,0 +1,235 @@
|
||||
import log from "loglevel";
|
||||
import {
|
||||
AbstractMesh,
|
||||
Axis,
|
||||
Color3,
|
||||
DynamicTexture,
|
||||
MeshBuilder,
|
||||
Scene,
|
||||
Space,
|
||||
StandardMaterial,
|
||||
TransformNode,
|
||||
Vector3
|
||||
} from "@babylonjs/core";
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
import {DiagramEventType} from "../diagram/diagramEntity";
|
||||
|
||||
export class DrawioManager {
|
||||
private diagramManager: DiagramManager;
|
||||
private readonly zdepth: Map<string, number> = new Map<string, number>();
|
||||
private scene: Scene;
|
||||
private readonly logger = log.getLogger('DrawioManager');
|
||||
private minY = 0;
|
||||
private minX = 0;
|
||||
private maxX = 0;
|
||||
private maxY = 0;
|
||||
|
||||
constructor(scene: Scene, diagramManager: DiagramManager) {
|
||||
this.scene = scene;
|
||||
this.diagramManager = diagramManager;
|
||||
this.getGraph();
|
||||
}
|
||||
|
||||
public static updateTextNode(mesh: AbstractMesh, text: string): AbstractMesh {
|
||||
//Set font
|
||||
const height = 0.1;
|
||||
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", 32, 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;
|
||||
plane.parent = mesh;
|
||||
plane.position.z = .51;
|
||||
plane.scaling.y = 1 / mesh.scaling.y;
|
||||
plane.scaling.x = 1 / mesh.scaling.x;
|
||||
plane.scaling.z = 1 / mesh.scaling.z;
|
||||
plane.rotate(Axis.Z, Math.PI, Space.LOCAL);
|
||||
plane.rotate(Axis.Y, Math.PI, Space.LOCAL);
|
||||
//plane.rotate(Axis.X, Math.PI, Space.LOCAL);
|
||||
|
||||
return plane;
|
||||
}
|
||||
|
||||
private async getGraph() {
|
||||
this.logger.debug("starting to get graph");
|
||||
const entities: Array<{ text: string, id: string, geometry: { x: number, y: number, width: number, height: number } }>
|
||||
= new Array<{ text: string; id: string, geometry: { x: number; y: number; width: number; height: number } }>();
|
||||
|
||||
const graph = await fetch('/arch_demo.xml');
|
||||
this.logger.debug('got graph');
|
||||
const graphXml = await graph.text();
|
||||
const doc = new DOMParser().parseFromString(graphXml, 'text/html');
|
||||
//this.logger.debug(doc);
|
||||
const firstDiagram = doc.querySelectorAll('diagram')[0];
|
||||
const mxDiagram = firstDiagram.querySelector('mxGraphModel');
|
||||
const width = mxDiagram.getAttribute('pageWidth');
|
||||
const height = mxDiagram.getAttribute('pageHeight');
|
||||
this.logger.debug('begin parse');
|
||||
mxDiagram.querySelectorAll('mxCell').forEach((cell) => {
|
||||
|
||||
const value = cell.getAttribute('value');
|
||||
if (!value) {
|
||||
//this.logger.warn('no value for :' , cell);
|
||||
} else {
|
||||
const ent = new DOMParser().parseFromString(value, 'text/html');
|
||||
const errorNode = ent.querySelector("parsererror");
|
||||
this.logger.debug(value);
|
||||
if (errorNode) {
|
||||
//this.logger.debug(value);
|
||||
} else {
|
||||
const text = this.getText(ent, '');
|
||||
const id = cell.getAttribute('id');
|
||||
const parent = cell.getAttribute('parent');
|
||||
if (this.zdepth.has(parent)) {
|
||||
this.zdepth.set(id, this.zdepth.get(parent) + .2);
|
||||
} else {
|
||||
this.zdepth.set(cell.getAttribute('id'), 0);
|
||||
}
|
||||
const geo = cell.querySelector('mxGeometry');
|
||||
const geometry = {
|
||||
x: geo.getAttribute('x'),
|
||||
y: geo.getAttribute('y'),
|
||||
width: geo.getAttribute('width'),
|
||||
height: geo.getAttribute('height'),
|
||||
}
|
||||
entities.push({text: text, id: id, geometry: this.fixMinMax(geometry)});
|
||||
if (text) {
|
||||
this.logger.debug('Text' + text);
|
||||
this.logger.debug('Geometry' + JSON.stringify(geometry));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.debug('done parsing');
|
||||
|
||||
this.logger.debug('MinX' + this.minX);
|
||||
this.logger.debug('MinY' + this.minY);
|
||||
this.logger.debug('MaxX' + this.maxX);
|
||||
this.logger.debug('MaxY' + this.maxY);
|
||||
const diagramWidth = this.maxX - this.minX;
|
||||
const diagramHeight = this.maxY - this.minY;
|
||||
let scale = 1;
|
||||
if (diagramHeight > diagramWidth) {
|
||||
scale = 20 / diagramHeight;
|
||||
} else {
|
||||
scale = 20 / diagramWidth;
|
||||
}
|
||||
const anchor = new TransformNode('anchor', this.scene);
|
||||
|
||||
if (entities.length > 0) {
|
||||
//const basebox = MeshBuilder.CreateBox("box", {
|
||||
// height: 1,
|
||||
// width: 1, depth: 1
|
||||
//}, this.scene);
|
||||
|
||||
//const material: StandardMaterial = new StandardMaterial("mat", this.scene);
|
||||
//material.diffuseColor = new Color3(0.5, 0.5, 0.5);
|
||||
//material.alpha = .4;
|
||||
//basebox.material = material;
|
||||
entities.forEach((entity) => {
|
||||
/* const box = new InstancedMesh("box", basebox);
|
||||
box.scaling.z = .1;
|
||||
box.scaling.y = entity.geometry.height * scale;
|
||||
box.scaling.x = entity.geometry.width * scale;
|
||||
box.position.x = (entity.geometry.x - this.minX) * scale + (entity.geometry.width * scale / 2);
|
||||
box.position.y = (entity.geometry.y - this.minY) * scale + (entity.geometry.height * scale / 2);
|
||||
box.position.z = 2 + this.zdepth.get(entity.id); */
|
||||
this.diagramManager.onDiagramEventObservable.notifyObservers(
|
||||
{
|
||||
type: DiagramEventType.ADD,
|
||||
entity: {
|
||||
text: entity.text,
|
||||
id: entity.id,
|
||||
position: new Vector3((entity.geometry.x - this.minX) * scale + (entity.geometry.width * scale / 2),
|
||||
(entity.geometry.y - this.minY) * scale + (entity.geometry.height * scale / 2),
|
||||
2 + this.zdepth.get(entity.id)),
|
||||
scale: new Vector3(entity.geometry.width * scale, entity.geometry.height * scale, .1),
|
||||
color: Color3.Blue().toHexString(),
|
||||
template: '#box-template'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//box.metadata = {text: entity.text};
|
||||
//box.setParent(anchor);
|
||||
//DrawioManager.updateTextNode(box, entity.text);
|
||||
});
|
||||
anchor.position.y = 20;
|
||||
anchor.rotation.x = Math.PI;
|
||||
|
||||
}
|
||||
|
||||
this.logger.debug('Scale' + scale);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fixMinMax(geometry: { x: string; y: string; width: string; height: string; }):
|
||||
{ x: number, y: number, width: number, height: number } {
|
||||
let x = 0;
|
||||
if (geometry.x) {
|
||||
x = parseFloat(geometry.x);
|
||||
if (x < this.minX) {
|
||||
this.minX = x;
|
||||
}
|
||||
if (x > this.maxX) {
|
||||
this.maxX = x;
|
||||
}
|
||||
}
|
||||
let y = 0;
|
||||
if (geometry.y) {
|
||||
y = parseFloat(geometry.y);
|
||||
if (y < this.minY) {
|
||||
this.minY = y;
|
||||
}
|
||||
if (y > this.maxY) {
|
||||
this.maxY = y;
|
||||
}
|
||||
}
|
||||
return ({x: x, y: y, width: parseFloat(geometry.width), height: parseFloat(geometry.height)});
|
||||
}
|
||||
|
||||
private getText(obj: Node, text: string): string {
|
||||
if (obj.nodeType == Node.TEXT_NODE) {
|
||||
if (obj.textContent) {
|
||||
return obj.textContent.trim();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
if (obj.childNodes) {
|
||||
let t = '';
|
||||
obj.childNodes.forEach((child) => {
|
||||
t += ' ' + this.getText(child, '');
|
||||
});
|
||||
return text.trim() + ' ' + t.trim();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,22 +30,24 @@ export class ConfigMenu {
|
||||
}
|
||||
DiaSounds.instance.enter.play();
|
||||
const width = .25;
|
||||
const height = .55;
|
||||
const height = .75;
|
||||
const res = 256;
|
||||
const heightPixels = Math.round((height / width) * res);
|
||||
this.configPlane = MeshBuilder
|
||||
.CreatePlane("gridSizePlane",
|
||||
{
|
||||
width: .25,
|
||||
height: .5
|
||||
height: .75
|
||||
}, this.scene);
|
||||
const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, res, heightPixels);
|
||||
configTexture.background = "white";
|
||||
const selectionPanel = new SelectionPanel("selectionPanel");
|
||||
configTexture.addControl(selectionPanel)
|
||||
this.buildGridSizeControl(selectionPanel);
|
||||
this.buildRotationSnapControl(selectionPanel);
|
||||
this.buildCreateScaleControl(selectionPanel);
|
||||
this.buildRotationSnapControl(selectionPanel);
|
||||
this.buildTurnSnapControl(selectionPanel);
|
||||
|
||||
CameraHelper.setMenuPosition(this.configPlane, this.scene);
|
||||
}
|
||||
|
||||
@ -85,11 +87,26 @@ export class ConfigMenu {
|
||||
return radio;
|
||||
}
|
||||
|
||||
private buildTurnSnapControl(selectionPanel: SelectionPanel): RadioGroup {
|
||||
const radio = new RadioGroup("Turn Snap");
|
||||
selectionPanel.addGroup(radio);
|
||||
for (const [index, snap] of AppConfig.config.turnSnaps().entries()) {
|
||||
const selected = AppConfig.config.currentTurnSnapIndex == index;
|
||||
radio.addRadio(snap.label, this.turnVal, selected);
|
||||
}
|
||||
return radio;
|
||||
}
|
||||
|
||||
private rotateVal(value) {
|
||||
AppConfig.config.currentRotateSnapIndex = value;
|
||||
log.debug("configMenu", "rotate Snap", value);
|
||||
}
|
||||
|
||||
private turnVal(value) {
|
||||
AppConfig.config.currentTurnSnapIndex = value;
|
||||
log.debug("configMenu", "turn Snap", value);
|
||||
}
|
||||
|
||||
private gridVal(value) {
|
||||
AppConfig.config.currentGridSnapIndex = value;
|
||||
log.debug("configMenu", "grid Snap", value);
|
||||
|
||||
@ -18,6 +18,7 @@ import {DiaSounds} from "../util/diaSounds";
|
||||
import {CameraHelper} from "../util/cameraHelper";
|
||||
import {TextLabel} from "../diagram/textLabel";
|
||||
import {DiagramConnection} from "../diagram/diagramConnection";
|
||||
import {GLTF2Export} from "@babylonjs/serializers";
|
||||
|
||||
export class EditMenu {
|
||||
private state: EditMenuState = EditMenuState.NONE;
|
||||
@ -44,14 +45,17 @@ export class EditMenu {
|
||||
this.scene.onPointerObservable.add((pointerInfo) => {
|
||||
switch (pointerInfo.type) {
|
||||
case PointerEventTypes.POINTERPICK:
|
||||
if (pointerInfo.pickInfo?.pickedMesh?.metadata?.template &&
|
||||
pointerInfo.pickInfo?.pickedMesh?.parent?.parent?.id != "toolbox") {
|
||||
const pickedMesh = pointerInfo.pickInfo?.pickedMesh;
|
||||
if (pickedMesh.metadata?.template &&
|
||||
pickedMesh?.parent?.parent?.id != "toolbox") {
|
||||
this.diagramEntityPicked(pointerInfo).then(() => {
|
||||
this.logger.debug("handled");
|
||||
}).catch((e) => {
|
||||
this.logger.error(e);
|
||||
});
|
||||
break;
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -72,6 +76,7 @@ export class EditMenu {
|
||||
panel.addControl(this.makeButton("Add Label", "label"));
|
||||
panel.addControl(this.makeButton("Copy", "copy"));
|
||||
panel.addControl(this.makeButton("Connect", "connect"));
|
||||
panel.addControl(this.makeButton("Export", "export"));
|
||||
|
||||
//panel.addControl(this.makeButton("Add Ring Cameras", "addRingCameras"));
|
||||
this.manager.controlScaling = .5;
|
||||
@ -211,9 +216,23 @@ export class EditMenu {
|
||||
case "connect":
|
||||
this.state = EditMenuState.CONNECTING;
|
||||
break;
|
||||
case "export":
|
||||
GLTF2Export.GLTFAsync(this.scene, 'diagram.gltf', {
|
||||
shouldExportNode: function (node) {
|
||||
if (node?.metadata?.template) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}).then((gltf) => {
|
||||
gltf.downloadFiles();
|
||||
});
|
||||
default:
|
||||
this.logger.error("Unknown button");
|
||||
return;
|
||||
|
||||
}
|
||||
this.manager.dispose();
|
||||
this.manager = null;
|
||||
|
||||
@ -13,6 +13,7 @@ export type SnapValue = {
|
||||
export class AppConfig {
|
||||
private readonly logger = log.getLogger('AppConfig');
|
||||
private gridSnap = 1;
|
||||
private _turnSnap = 0;
|
||||
private rotateSnap = 0;
|
||||
private createSnap = 0;
|
||||
_physicsEnabled = false;
|
||||
@ -35,6 +36,11 @@ export class AppConfig {
|
||||
{value: 22.5, label: "22.5 Degrees"},
|
||||
{value: 45, label: "45 Degrees"},
|
||||
{value: 90, label: "90 Degrees"}];
|
||||
private turnSnapArray: SnapValue[] =
|
||||
[{value: 0, label: "Off"},
|
||||
{value: 22.5, label: "22.5 Degrees"},
|
||||
{value: 45, label: "45 Degrees"},
|
||||
{value: 90, label: "90 Degrees"}];
|
||||
|
||||
public get currentGridSnap(): SnapValue {
|
||||
return this.gridSnapArray[this.gridSnap];
|
||||
@ -66,10 +72,19 @@ export class AppConfig {
|
||||
return this.createSnapArray[this.createSnap];
|
||||
}
|
||||
|
||||
public get currentTurnSnap(): SnapValue {
|
||||
return this.turnSnapArray[this._turnSnap];
|
||||
}
|
||||
|
||||
public get currentGridSnapIndex(): number {
|
||||
return this.gridSnap;
|
||||
}
|
||||
|
||||
public set currentTurnSnapIndex(val: number) {
|
||||
this._turnSnap = val;
|
||||
this.save();
|
||||
}
|
||||
|
||||
public set currentGridSnapIndex(val: number) {
|
||||
this.gridSnap = val;
|
||||
this.save();
|
||||
@ -110,6 +125,10 @@ export class AppConfig {
|
||||
return this.gridSnapArray;
|
||||
}
|
||||
|
||||
public turnSnaps(): SnapValue[] {
|
||||
return this.turnSnapArray;
|
||||
}
|
||||
|
||||
public createSnaps(): SnapValue[] {
|
||||
return this.createSnapArray;
|
||||
}
|
||||
@ -153,6 +172,7 @@ export class AppConfig {
|
||||
gridSnap: this.currentGridSnap.value,
|
||||
rotateSnap: this.currentRotateSnap.value,
|
||||
createSnap: this.currentCreateSnap.value,
|
||||
turnSnap: this.currentTurnSnap.value,
|
||||
physicsEnabled: this._physicsEnabled
|
||||
});
|
||||
}
|
||||
@ -167,7 +187,10 @@ export class AppConfig {
|
||||
config.gridSnap != this.currentGridSnap.value ||
|
||||
config.rotateSnap != this.currentRotateSnap.value) {
|
||||
this.logger.debug("Config changed", config);
|
||||
|
||||
this._turnSnap = this.turnSnapArray.findIndex((snap) => snap.value == config.turnSnap);
|
||||
if (!this._turnSnap || this._turnSnap == -1) {
|
||||
this._turnSnap = 0;
|
||||
}
|
||||
this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap);
|
||||
this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap);
|
||||
const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap);
|
||||
|
||||
@ -3,5 +3,6 @@ export type AppConfigType = {
|
||||
gridSnap: number,
|
||||
rotateSnap: number,
|
||||
createSnap: number,
|
||||
turnSnap: number,
|
||||
physicsEnabled: boolean
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user