experiments with glb objects and data based diagrams.

This commit is contained in:
Michael Mainguy 2023-12-23 06:21:58 -06:00
parent dcd5a8835c
commit a1adbf5bd9
22 changed files with 479 additions and 65 deletions

View File

@ -109,9 +109,8 @@
<script src='/niceware.js'></script> <script src='/niceware.js'></script>
</head> </head>
<body> <body>
<!--<div id="questLaunch"><a href="https://www.oculus.com/open_url/?url=https://www.deepdiagram.com/" target="_blank">Launch
On Quest</a> <!--
</div>
<div id="download"><a href="#" id="downloadLink">Download Model</a></div> <div id="download"><a href="#" id="downloadLink">Download Model</a></div>
--> -->
<script> <script>

Binary file not shown.

63
public/data/data.json Normal file
View File

@ -0,0 +1,63 @@
{
"name": "Chart 1",
"series": [
{
"name": "series 1",
"values": [
{
"id": "1",
"start": "2015-01-01",
"end": "2015-12-31",
"value": 1
},
{
"id": "2",
"start": "2016-01-01",
"end": "2016-12-31",
"value": 2
},
{
"id": "3",
"start": "2017-01-01",
"end": "2017-12-31",
"value": 3
},
{
"id": "4",
"start": "2018-01-01",
"end": "2018-12-31",
"value": 4
}
]
},
{
"name": "series 2",
"values": [
{
"id": "1",
"start": "2015-01-01",
"end": "2015-12-31",
"value": 5
},
{
"id": "2",
"start": "2016-01-01",
"end": "2016-12-31",
"value": 6
},
{
"id": "3",
"start": "2017-01-01",
"end": "2017-12-31",
"value": 7
},
{
"id": "4",
"start": "2018-01-01",
"end": "2018-12-31",
"value": 8
}
]
}
]
}

View File

@ -21,7 +21,7 @@ export class Rigplatform {
private readonly xr: WebXRDefaultExperience; private readonly xr: WebXRDefaultExperience;
private yRotation: number = 0; private yRotation: number = 0;
public rigMesh: Mesh; public rigMesh: Mesh;
public flyMode: boolean = true;
private turning: boolean = false; private turning: boolean = false;
private velocity: Vector3 = Vector3.Zero(); private velocity: Vector3 = Vector3.Zero();
private turnVelocity: number = 0; private turnVelocity: number = 0;
@ -43,6 +43,7 @@ export class Rigplatform {
this.fixRotation(); this.fixRotation();
this.initializeControllers(); this.initializeControllers();
this.registerVelocityObserver(); this.registerVelocityObserver();
} }
public forwardback(val: number) { public forwardback(val: number) {
this.velocity.z = (val * this.velocityArray[this.velocityIndex])*-1; this.velocity.z = (val * this.velocityArray[this.velocityIndex])*-1;

View File

@ -1,4 +1,4 @@
import {DiagramEntity} from "../types/diagramEntity"; import {DiagramEntity, DiagramEntityType} from "../types/diagramEntity";
import {AbstractMesh, InstancedMesh, Mesh, Quaternion, Scene, Vector3} from "@babylonjs/core"; import {AbstractMesh, InstancedMesh, Mesh, Quaternion, Scene, Vector3} from "@babylonjs/core";
import {DiagramConnection} from "../diagramConnection"; import {DiagramConnection} from "../diagramConnection";
import {TextLabel} from "../../objects/textLabel"; import {TextLabel} from "../../objects/textLabel";
@ -13,9 +13,19 @@ export function buildMeshFromDiagramEntity(entity: DiagramEntity, scene: Scene):
logger.error("buildMeshFromDiagramEntity: entity is null"); logger.error("buildMeshFromDiagramEntity: entity is null");
return null; return null;
} }
if (!entity.id) { switch (entity.type) {
entity.id = "id" + uuidv4(); case DiagramEntityType.USER:
logger.debug("buildMeshFromDiagramEntity: entity is user");
break;
default:
} }
generateId(entity);
const newMesh: AbstractMesh = createNewInstanceIfNecessary(entity, scene);
return mapMetadata(entity, newMesh, scene);
}
function createNewInstanceIfNecessary(entity: DiagramEntity, scene: Scene): AbstractMesh {
const oldMesh: AbstractMesh = scene.getMeshById(entity.id); const oldMesh: AbstractMesh = scene.getMeshById(entity.id);
let newMesh: AbstractMesh; let newMesh: AbstractMesh;
if (oldMesh) { if (oldMesh) {
@ -33,10 +43,20 @@ export function buildMeshFromDiagramEntity(entity: DiagramEntity, scene: Scene):
newMesh.metadata = {template: entity.template, exportable: true, tool: false}; newMesh.metadata = {template: entity.template, exportable: true, tool: false};
} else { } else {
logger.warn('no tool mesh found for ' + entity.template + "-" + entity.color); logger.warn('no tool mesh found for ' + entity.template + "-" + entity.color);
} }
} }
} }
return newMesh;
}
function generateId(entity: DiagramEntity) {
if (!entity.id) {
entity.id = "id" + uuidv4();
}
}
function mapMetadata(entity: DiagramEntity, newMesh: AbstractMesh, scene: Scene): AbstractMesh {
if (newMesh) { if (newMesh) {
if (entity.position) { if (entity.position) {
newMesh.position = xyztovec(entity.position); newMesh.position = xyztovec(entity.position);
@ -73,8 +93,6 @@ export function buildMeshFromDiagramEntity(entity: DiagramEntity, scene: Scene):
} }
return newMesh; return newMesh;
} }
function xyztovec(xyz: { x, y, z }): Vector3 { function xyztovec(xyz: { x, y, z }): Vector3 {
return new Vector3(xyz.x, xyz.y, xyz.z); return new Vector3(xyz.x, xyz.y, xyz.z);
} }

View File

@ -25,7 +25,15 @@ export function toDiagramEntity(mesh: AbstractMesh): DiagramEntity {
entity.to = mesh?.metadata?.to; entity.to = mesh?.metadata?.to;
entity.scale = vectoxys(mesh.scaling); entity.scale = vectoxys(mesh.scaling);
if (mesh.material) { if (mesh.material) {
switch (mesh.material.getClassName()) {
case "StandardMaterial":
entity.color = (mesh.material as any).diffuseColor.toHexString(); entity.color = (mesh.material as any).diffuseColor.toHexString();
break;
case "PBRMaterial":
entity.color = (mesh.material as any).albedoColor.toHexString();
break;
}
} else { } else {
if (entity.template != "#object-template") { if (entity.template != "#object-template") {
logger.error("toDiagramEntity: mesh.material is null"); logger.error("toDiagramEntity: mesh.material is null");

View File

@ -13,6 +13,10 @@ export enum DiagramEventType {
RESET RESET
} }
export enum DiagramEntityType {
USER = "user"
}
export enum DiagramEventMask { export enum DiagramEventMask {
LOCAL = 1, LOCAL = 1,
REMOTE = 2, REMOTE = 2,
@ -37,6 +41,7 @@ export type DiagramEntity = {
position?: { x: number, y: number, z: number }; position?: { x: number, y: number, z: number };
rotation?: { x: number, y: number, z: number }; rotation?: { x: number, y: number, z: number };
template?: string; template?: string;
type?: DiagramEntityType;
text?: string; text?: string;
scale?: { x: number, y: number, z: number }; scale?: { x: number, y: number, z: number };
parent?: string; parent?: string;

87
src/objects/avatar.ts Normal file
View File

@ -0,0 +1,87 @@
import {
AssetContainer,
Mesh,
MeshBuilder,
Observable,
PhysicsAggregate,
PhysicsMotionType,
PhysicsShapeType,
Scene,
SceneLoader,
Vector3
} from "@babylonjs/core";
export function buildAvatar(scene: Scene) {
const objectObservable = new Observable<AssetContainer>();
objectObservable.add((container) => {
try {
const data = container.instantiateModelsToScene(undefined, false, {doNotInstantiate: true});
const mesh = (data.rootNodes[0] as Mesh);
const body = scene.getMeshByName("Clone of avaturn_body");
/*body.simplify(
[
{quality: .7, distance: 5},
{quality: .1, distance: 10},
],
true,
SimplificationType.QUADRATIC,
function() {
const skel = scene.getSkeletonById("Clone of Armature");
body.parent.getChildMeshes().forEach((m) => {
if (m.name.indexOf("ecimated") > -1) {
m.skeleton = skel;
}
});
console.log("simplification done");
}
)
*/
const bounds = mesh.getHierarchyBoundingVectors(true);
console.log(bounds);
const size = bounds.max.subtract(bounds.min);
const top = MeshBuilder.CreateBox("container", {width: size.x, height: size.y, depth: size.z}, scene);
top.position.y = 1.6;
top.metadata = {grabbable: true};
mesh.parent = top;
mesh.position.y = -size.y / 2;
top.position = new Vector3(-.6, size.y / 2 + 1, 0);
//top.scaling = new Vector3(.1, .1, .1);
top.visibility = 0;
//top.physicsBody = new PhysicsBody(top, PhysicsMotionType.DYNAMIC, false, this.scene);
data.animationGroups[0].play(true);
const physicsAggregate = new PhysicsAggregate(top,
PhysicsShapeType.BOX, {mass: 100, restitution: .02, friction: .3}, scene);
physicsAggregate.body.setMotionType(PhysicsMotionType.DYNAMIC);
physicsAggregate.body.setGravityFactor(1);
} catch (err) {
console.log(err);
}
//physicsAggregate.body.setAngularDamping(.5);
//top.physicsBody.setLinearVelocity(Vector3.Up().scale(100));
//mesh.parent = top.physicsBody.transformNode;
});
loadObject(scene, objectObservable);
}
function loadObject(scene: Scene, observable: Observable<AssetContainer>) {
SceneLoader.LoadAssetContainer("/assets/models/",
"model.glb",
scene,
(container: AssetContainer) => {
observable.notifyObservers(container);
});
}

View File

@ -23,7 +23,7 @@ export class TextLabel {
} }
//Set font //Set font
const height = 0.125; const height = 0.05;
const font_size = 24; const font_size = 24;
const font = "bold " + font_size + "px Arial"; const font = "bold " + font_size + "px Arial";
//Set height for dynamic texture //Set height for dynamic texture
@ -65,10 +65,11 @@ export class TextLabel {
const yOffset = mesh.getBoundingInfo().boundingSphere.maximum.y; const yOffset = mesh.getBoundingInfo().boundingSphere.maximum.y;
plane.parent = mesh; plane.parent = mesh;
plane.position.y = yOffset + height;
//plane.scaling.y = mesh.scaling.y; plane.scaling.y = (1 / mesh.scaling.y);
//plane.scaling.x = mesh.scaling.x; plane.scaling.x = (1 / mesh.scaling.x);
//plane.scaling.z = mesh.scaling.z; plane.scaling.z = (1 / mesh.scaling.z);
plane.position.y = yOffset + (height * plane.scaling.y);
return plane; return plane;
} }
} }

View File

@ -1,15 +1,21 @@
import {Color3, MeshBuilder, Observable, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core"; import {Color3, MeshBuilder, Observable, PBRMaterial, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {enumKeys} from "../../util/functions/enumKeys"; import {enumKeys} from "../../util/functions/enumKeys";
import {ToolType} from "../types/toolType"; import {ToolType} from "../types/toolType";
import {buildTool} from "./buildTool"; import {buildTool} from "./buildTool";
import {AdvancedDynamicTexture, ColorPicker} from "@babylonjs/gui"; import {AdvancedDynamicTexture, ColorPicker} from "@babylonjs/gui";
import {MarbleProceduralTexture} from "@babylonjs/procedural-textures";
export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number, export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number,
colorChangeObservable: Observable<{ oldColor: string, newColor: string }>) { colorChangeObservable: Observable<{ oldColor: string, newColor: string }>) {
const width = 1; const width = 1;
const depth = .2; const depth = .2;
const material = new StandardMaterial("material-" + color.toHexString(), scene); const material = new PBRMaterial("material-" + color.toHexString(), scene);
material.diffuseColor = color;
//const material = new StandardMaterial("material-" + color.toHexString(), scene);
material.albedoColor = color;
material.metallic = 1;
material.bumpTexture = new MarbleProceduralTexture("marble", 1024, scene);
material.bumpTexture.level = 5;
const mesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), { const mesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), {
width: width, width: width,
height: .01, height: .01,
@ -42,9 +48,9 @@ export function buildColor(color: Color3, scene: Scene, parent: TransformNode, i
colorPicker.scaleX = 5; colorPicker.scaleX = 5;
colorPicker.value = color; colorPicker.value = color;
colorPicker.onValueChangedObservable.add((value) => { colorPicker.onValueChangedObservable.add((value) => {
const oldColor = material.diffuseColor.clone(); const oldColor = material.albedoColor.clone();
const newColor = value.clone(); const newColor = value.clone();
material.diffuseColor = newColor; material.albedoColor = newColor;
const newColorHex = newColor.toHexString(); const newColorHex = newColor.toHexString();
material.id = "material-" + newColorHex; material.id = "material-" + newColorHex;
material.name = "material-" + newColorHex; material.name = "material-" + newColorHex;

View File

@ -1,11 +1,23 @@
import {AbstractMesh, Color3, InstancedMesh, StandardMaterial, Vector3} from "@babylonjs/core"; import {AbstractMesh, Color3, InstancedMesh, PBRMaterial, StandardMaterial, Vector3} from "@babylonjs/core";
import {ToolType} from "../types/toolType"; import {ToolType} from "../types/toolType";
import {buildMesh} from "./buildMesh"; import {buildMesh} from "./buildMesh";
const WIDGET_SIZE = .1; const WIDGET_SIZE = .1;
export function buildTool(tool: ToolType, parent: AbstractMesh) { export function buildTool(tool: ToolType, parent: AbstractMesh) {
const id = toolId(tool, (parent.material as StandardMaterial).diffuseColor); let id = "ID";
switch (parent.material.getClassName()) {
case "StandardMaterial":
id = toolId(tool, (parent.material as StandardMaterial).diffuseColor);
break;
case "PBRMaterial":
id = toolId(tool, (parent.material as PBRMaterial).albedoColor);
break;
default:
this.logger.warn("buildTool: parent.material is null");
}
const newItem = buildMesh(tool, `tool-${id}`, parent.getScene()); const newItem = buildMesh(tool, `tool-${id}`, parent.getScene());
if (!newItem) { if (!newItem) {

View File

@ -1,14 +1,4 @@
import { import {AssetContainer, Color3, Mesh, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
AssetContainer,
Color3,
Mesh,
MeshBuilder,
Observable,
Scene,
SceneLoader,
TransformNode,
Vector3
} from "@babylonjs/core";
import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui"; import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui";
import {ControllerEventType, Controllers} from "../controllers/controllers"; import {ControllerEventType, Controllers} from "../controllers/controllers";
@ -81,25 +71,8 @@ export class Toolbox {
this.addPanel.node.scaling = new Vector3(.1, .1, .1); this.addPanel.node.scaling = new Vector3(.1, .1, .1);
this.addPanel.position = new Vector3(-.25, 0, 0); this.addPanel.position = new Vector3(-.25, 0, 0);
//@TODO: move this somewhere else, just to prototype loading objects. //@TODO: move this somewhere else, just to prototype loading objects.
//loadObject(this.scene, this.objectObservable);
this.objectObservable.add((container) => {
this.logger.debug("loaded object");
const data = container.instantiateModelsToScene(undefined, false, {doNotInstantiate: true});
const mesh = (data.rootNodes[0] as Mesh);
const bounds = data.rootNodes[0].getHierarchyBoundingVectors(true);
console.log(bounds);
const size = bounds.max.subtract(bounds.min);
const top = MeshBuilder.CreateBox("container", {width: size.x, height: size.y, depth: size.z}, this.scene);
top.position.y = 1.5;
top.metadata = {template: "#object-template", grabbable: true, tool: true};
mesh.parent = top;
mesh.position.y = -size.y / 2;
top.position = new Vector3(-.6, .2, 0);
//top.scaling = new Vector3(.1, .1, .1);
top.visibility = 0;
console.log(data.rootNodes.length);
});
addButton.onPointerClickObservable.add(() => { addButton.onPointerClickObservable.add(() => {
buildColor(Color3.Random(), this.scene, this.node, this.index++, this.colorChangeObservable); buildColor(Color3.Random(), this.scene, this.node, this.index++, this.colorChangeObservable);
}); });
@ -111,16 +84,7 @@ export class Toolbox {
} }
} }
function loadObject(scene: Scene, observable: Observable<AssetContainer>) {
SceneLoader.LoadAssetContainer("/assets/models/",
"server_racking_system.glb",
scene,
(container: AssetContainer) => {
observable.notifyObservers(container);
});
}
function createButton(): Button3D { function createButton(): Button3D {
const addButton = new Button3D("add-button"); const addButton = new Button3D("add-button");
const text = new TextBlock("add-button-text", "Add Color"); const text = new TextBlock("add-button-text", "Add Color");

View File

@ -103,7 +103,7 @@ export class CustomEnvironment {
ground.material = groundMaterial; ground.material = groundMaterial;
new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, scene); new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, scene);
//buildAvatar(scene);
return ground; return ground;
} }
} }

View File

@ -0,0 +1,16 @@
export function buildQuestLink() {
/*
<div id="questLaunch"><a href="https://www.oculus.com/open_url/?url=https://www.deepdiagram.com/" target="_blank">Launch
On Quest</a>
</div>
*/
const div = document.createElement("div");
div.id = "questLaunch";
const a = document.createElement("a");
a.href = "https://www.oculus.com/open_url/?url=" + window.location.href;
a.target = "_blank";
a.innerText = "Launch On Quest";
div.appendChild(a);
document.body.appendChild(div);
}

View File

@ -0,0 +1,6 @@
import {TimeseriesType} from "./timeseriesType";
export type ChartDataType = {
name: string;
series: TimeseriesType[];
}

View File

@ -0,0 +1,22 @@
import {Color3, Mesh, MeshBuilder, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core";
export function buildContainer(parent: TransformNode, size: Vector3) {
const scene = parent.getScene();
if (!scene) {
return;
}
const material = new StandardMaterial("container-material", scene);
material.diffuseColor = new Color3(.5, .5, .5);
const floor = MeshBuilder.CreatePlane("floor", {width: size.x, height: size.z, sideOrientation: Mesh.DOUBLESIDE}, scene);
const left = MeshBuilder.CreatePlane("left", {width: size.z, height: size.y, sideOrientation: Mesh.DOUBLESIDE}, scene);
const back = MeshBuilder.CreatePlane("back", {width: size.x, height: size.y, sideOrientation: Mesh.DOUBLESIDE}, scene);
[floor, left, back].forEach((mesh) => {
mesh.material = material;
mesh.parent = parent;
});
left.position = new Vector3(size.x / 2, size.y / 2, 0);
back.position = new Vector3(0, size.y / 2, -size.z / 2);
left.rotation.y = Math.PI / 2;
floor.rotation.x = Math.PI / 2;
}

View File

@ -0,0 +1,17 @@
import {AbstractMesh, Mesh, MeshBuilder, TransformNode} from "@babylonjs/core";
const LABEL_HEIGHT = .1;
export function buildLabel(name: string, parent: TransformNode, labelWidth: number): void {
const scene = parent.getScene();
const seriesLabel = MeshBuilder.CreatePlane(name + "-label", {
width: labelWidth,
height: LABEL_HEIGHT,
sideOrientation: Mesh.DOUBLESIDE
}, scene);
seriesLabel.parent = parent;
seriesLabel.position.z = LABEL_HEIGHT / 2;
seriesLabel.position.y = .5;
seriesLabel.rotation.x = Math.PI / 2;
seriesLabel.material = (parent as AbstractMesh).material;
}

View File

@ -0,0 +1,62 @@
import {
AbstractMesh,
Color3,
InstancedMesh,
Mesh,
MeshBuilder,
StandardMaterial,
TransformNode,
Vector3
} from "@babylonjs/core";
import {buildLabel} from "./buildLabel";
import {TimeseriesType} from "../timeseriesType";
export function buildSeries(parent: TransformNode, series: TimeseriesType, index: number, count: number, scale: number): void {
const scene = parent.getScene();
if (!scene) {
return;
}
const labelWidth = 1 / count * .8;
const material = new StandardMaterial(series.name + "-material", scene);
const seriesMesh = MeshBuilder.CreatePlane(series.name, {width: labelWidth, height: 1, sideOrientation: Mesh.DOUBLESIDE}, scene);
seriesMesh.material = material;
seriesMesh.parent = parent;
seriesMesh.position.x = .5 - (index / count) - (1 / count / 2);
seriesMesh.position.y = .001;
seriesMesh.rotation.x = Math.PI / 2;
material.diffuseColor = Color3.Random();
buildLabel(series.name, seriesMesh, labelWidth);
buildValues(seriesMesh, series, scale);
}
function buildValues(parent: TransformNode, series: TimeseriesType, scale: number): void {
const scene = parent.getScene();
if (!scene) {
return;
}
const valueCount = series.values.length;
const valueStep = 1 / valueCount;
let lastValue = null;
const linepoints: Vector3[] = [];
const basepoint = MeshBuilder.CreatePlane(series.name + "-value-base", {height: .003, width: .01}, scene);
basepoint.parent = parent;
basepoint.material = (parent as AbstractMesh).material;
basepoint.visibility = .5;
series.values.forEach((value, index) => {
//const point = MeshBuilder.CreateSphere(series.name + "-value-" + index, {diameter: .01}, scene);
const point = new InstancedMesh(series.name + "-value-" + index, basepoint);
point.parent = parent;
//point.rotation.x = Math.PI/2;
point.position.z = .5 - index * valueStep;
point.position.y = value.value * scale;
point.billboardMode = Mesh.BILLBOARDMODE_Y;
linepoints.push(point.position.clone());
});
const line = MeshBuilder.CreateLines(series.name + "-line", {points: linepoints}, scene);
line.color = ((parent as AbstractMesh).material as StandardMaterial).diffuseColor;
line.parent = parent;
line.isPickable = false;
line.rotation.x = -Math.PI / 2;
}

View File

@ -0,0 +1,58 @@
import {ChartDataType} from "../chartDataType";
import {TimepointType, TimeseriesType} from "../timeseriesType";
export function genData(): ChartDataType {
return {
name: "test",
series: [
testDataSeries("series1"),
testDataSeries("series2"),
testDataSeries("series3"),
testDataSeries("series4"),
testDataSeries("series5"),
testDataSeries("series6"),
testDataSeries("series7"),
testDataSeries("series8"),
testDataSeries("series9"),
testDataSeries("series10"),
testDataSeries("series11"),
testDataSeries("series12"),
testDataSeries("series13"),
testDataSeries("series14"),
testDataSeries("series15"),
testDataSeries("series16"),
testDataSeries("series17"),
testDataSeries("series18"),
testDataSeries("series19"),
testDataSeries("series20"),
]
}
}
function testDataSeries(name: string): TimeseriesType {
const data = {
name: name,
values: getValues()
};
return data;
}
function getValues(): TimepointType[] {
const data: TimepointType[] = [];
const count = 150;
let val = Math.random() * 50 + 25;
for (let i = 0; i < count; i++) {
let rand = (Math.random() * 4 - 2);
if (Math.abs(rand) < .15) {
rand = (Math.random() * 10 - 5);
}
data.push({
start: i,
end: i + 1,
value: val += rand
});
}
return data;
}

View File

@ -0,0 +1,46 @@
import {TransformNode, Vector3} from "@babylonjs/core";
import {TimeseriesType} from "./timeseriesType";
import {buildContainer} from "./functions/buildContainer";
import {ChartDataType} from "./chartDataType";
import {buildSeries} from "./functions/buildSeries";
export class Timeseries {
private parent: TransformNode;
private data: ChartDataType;
private size: Vector3 = new Vector3(1, 1, 1);
constructor(parent: TransformNode) {
this.parent = parent;
this.parent.onDisposeObservable.add(() => {
this.parent = null;
});
}
public setData(data: ChartDataType) {
this.data = data;
if (this.parent) {
this.build();
}
}
public fetchData(url: string) {
fetch(url)
.then(response => response.json())
.then(data => {
this.setData((data as ChartDataType));
});
}
build() {
const scene = this.parent.getScene();
if (!scene || !this.data) {
return;
}
buildContainer(this.parent, this.size);
const seriesCount = this.data.series.length;
this.data.series.forEach((series: TimeseriesType, index: number) => {
buildSeries(this.parent, series, index, seriesCount, .01);
});
this.parent.scaling = new Vector3(5, 5, 5);
}
}

View File

@ -0,0 +1,10 @@
export type TimeseriesType = {
name: string;
values: TimepointType[];
}
export type TimepointType = {
id?: string,
start?: string | number;
end: string | number;
value: number;
}

View File

@ -13,6 +13,7 @@ import {addSceneInspector} from "./util/functions/sceneInspctor";
import {groundMeshObserver} from "./util/functions/groundMeshObserver"; import {groundMeshObserver} from "./util/functions/groundMeshObserver";
import {MainMenu} from "./menus/mainMenu"; import {MainMenu} from "./menus/mainMenu";
import {Introduction} from "./tutorial/introduction"; import {Introduction} from "./tutorial/introduction";
import {buildQuestLink} from "./util/functions/buildQuestLink";
export class VrApp { export class VrApp {
private scene: Scene; private scene: Scene;
@ -63,11 +64,12 @@ export class VrApp {
await db.initialize(); await db.initialize();
const environment = new CustomEnvironment(scene, "default", config);
const camera: FreeCamera = new FreeCamera("Main Camera", const camera: FreeCamera = new FreeCamera("Main Camera",
new Vector3(0, 1.6, 0), scene); new Vector3(0, 1.6, 0), scene);
//camera.setTarget(new Vector3(0, 1.6, -3)); //camera.setTarget(new Vector3(0, 1.6, -3));
scene.setActiveCameraByName("Main Camera"); scene.setActiveCameraByName("Main Camera");
const environment = new CustomEnvironment(scene, "default", config);
environment.groundMeshObservable.add((ground) => { environment.groundMeshObservable.add((ground) => {
groundMeshObserver(ground, scene, diagramManager, controllers, spinner); groundMeshObserver(ground, scene, diagramManager, controllers, spinner);
}, -1, false, this); }, -1, false, this);
@ -103,13 +105,24 @@ export class VrApp {
*/ */
addSceneInspector(scene); addSceneInspector(scene);
const mainMenu = new MainMenu(scene); const mainMenu = new MainMenu(scene);
//const zero = MeshBuilder.CreateSphere('target', {diameter: 1.6}, scene);
// zero.position = new Vector3(0, .8, 0); /*
const base = new TransformNode("chart");
base.position.y = .25;
base.position.z = -5;
const chart = new Timeseries(base);
chart.setData(genData());
*/
//const newRelic = new NewRelicQuery(scene); //const newRelic = new NewRelicQuery(scene);
//newRelic.getSales(); //newRelic.getSales();
this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer'); this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer');
let i = 0;
this.engine.runRenderLoop(() => { this.engine.runRenderLoop(() => {
this.scene.render(); this.scene.render();
if (i++ % 60 == 0) {
// console.log(this.engine.getFps());
}
}); });
this.logger.info('Render loop started'); this.logger.info('Render loop started');
@ -123,7 +136,7 @@ export class VrApp {
const vrApp = new VrApp(); const vrApp = new VrApp();
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement); const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
vrApp.initialize(canvas).then(() => { vrApp.initialize(canvas).then(() => {
buildQuestLink();
}); });