Added Image upload component.
This commit is contained in:
parent
eb4281ac30
commit
d82df88296
@ -156,7 +156,7 @@ h1 {
|
|||||||
#tutorial {
|
#tutorial {
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
left: 100px;
|
left: 100px;
|
||||||
top: 560px;
|
top: 750px;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
height: 210px;
|
height: 210px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {AbstractMesh, ActionManager, InstancedMesh, Mesh, Observable, Scene, TransformNode} from "@babylonjs/core";
|
import {AbstractMesh, ActionManager, InstancedMesh, Mesh, Observable, Scene, TransformNode} from "@babylonjs/core";
|
||||||
import {DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {Controllers} from "../controllers/controllers";
|
import {Controllers} from "../controllers/controllers";
|
||||||
import {AppConfig} from "../util/appConfig";
|
import {AppConfig} from "../util/appConfig";
|
||||||
@ -43,6 +43,27 @@ export class DiagramManager {
|
|||||||
this.cleanupOrphanConnections(mesh)
|
this.cleanupOrphanConnections(mesh)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
document.addEventListener('uploadImage', (event: CustomEvent) => {
|
||||||
|
const diagramEntity: DiagramEntity = {
|
||||||
|
template: '#image-template',
|
||||||
|
image: event.detail.data,
|
||||||
|
text: event.detail.name,
|
||||||
|
position: {x: 0, y: 1.6, z: 0},
|
||||||
|
rotation: {x: 0, y: Math.PI, z: 0},
|
||||||
|
scale: {x: 1, y: 1, z: 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(diagramEntity);
|
||||||
|
//const newMesh = buildMeshFromDiagramEntity(diagramEntity, this._scene);
|
||||||
|
if (this.onDiagramEventObservable) {
|
||||||
|
this.onDiagramEventObservable.notifyObservers({
|
||||||
|
type: DiagramEventType.ADD,
|
||||||
|
entity: diagramEntity
|
||||||
|
}, DiagramEventObserverMask.ALL);
|
||||||
|
|
||||||
|
//this.onDiagramEventObservable.notifyObservers({type: DiagramEventType.ADD, entity: diagramEntity}, DiagramEventObserverMask.FROM_DB);
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public get diagramMenuManager(): DiagramMenuManager {
|
public get diagramMenuManager(): DiagramMenuManager {
|
||||||
|
|||||||
15
src/diagram/functions/buildImage.ts
Normal file
15
src/diagram/functions/buildImage.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import log from "loglevel";
|
||||||
|
import {AbstractMesh, MeshBuilder, StandardMaterial, Texture} from "@babylonjs/core";
|
||||||
|
import {DefaultScene} from "../../defaultScene";
|
||||||
|
import {DiagramEntity} from "../types/diagramEntity";
|
||||||
|
|
||||||
|
export function buildImage(entity: DiagramEntity): AbstractMesh {
|
||||||
|
const logger = log.getLogger('buildImage');
|
||||||
|
logger.debug("buildImage: entity is image");
|
||||||
|
const scene = DefaultScene.Scene;
|
||||||
|
const plane = MeshBuilder.CreatePlane("plane", {size: 1}, scene);
|
||||||
|
const material = new StandardMaterial("planeMaterial", scene);
|
||||||
|
const texture = new Texture(entity.image, scene);
|
||||||
|
material.emissiveTexture = texture;
|
||||||
|
return plane;
|
||||||
|
}
|
||||||
@ -1,12 +1,21 @@
|
|||||||
import {DiagramEntity, DiagramEntityType} from "../types/diagramEntity";
|
import {DiagramEntity, DiagramEntityType, DiagramTemplates} from "../types/diagramEntity";
|
||||||
import {AbstractMesh, InstancedMesh, Mesh, Quaternion, Scene, Vector3} from "@babylonjs/core";
|
import {
|
||||||
|
AbstractMesh,
|
||||||
|
InstancedMesh,
|
||||||
|
Mesh,
|
||||||
|
MeshBuilder,
|
||||||
|
Quaternion,
|
||||||
|
Scene,
|
||||||
|
StandardMaterial,
|
||||||
|
Texture,
|
||||||
|
Vector3
|
||||||
|
} from "@babylonjs/core";
|
||||||
import {DiagramConnection} from "../diagramConnection";
|
import {DiagramConnection} from "../diagramConnection";
|
||||||
import {updateTextNode} from "../../util/functions/updateTextNode";
|
import {updateTextNode} from "../../util/functions/updateTextNode";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import {v4 as uuidv4} from 'uuid';
|
||||||
import {buildStandardMaterial} from "../../materials/functions/buildStandardMaterial";
|
import {buildStandardMaterial} from "../../materials/functions/buildStandardMaterial";
|
||||||
|
|
||||||
|
|
||||||
export function buildMeshFromDiagramEntity(entity: DiagramEntity, scene: Scene): AbstractMesh {
|
export function buildMeshFromDiagramEntity(entity: DiagramEntity, scene: Scene): AbstractMesh {
|
||||||
const logger = log.getLogger('buildMeshFromDiagramEntity');
|
const logger = log.getLogger('buildMeshFromDiagramEntity');
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
@ -33,25 +42,58 @@ function createNewInstanceIfNecessary(entity: DiagramEntity, scene: Scene): Abst
|
|||||||
logger.debug(`mesh ${oldMesh.id} already exists`);
|
logger.debug(`mesh ${oldMesh.id} already exists`);
|
||||||
newMesh = oldMesh;
|
newMesh = oldMesh;
|
||||||
} else {
|
} else {
|
||||||
if (entity.template == "#connection-template") {
|
switch (entity.template) {
|
||||||
|
case DiagramTemplates.CONNECTION:
|
||||||
const connection: DiagramConnection = new DiagramConnection(entity.from, entity.to, entity.id, scene);
|
const connection: DiagramConnection = new DiagramConnection(entity.from, entity.to, entity.id, scene);
|
||||||
|
|
||||||
logger.debug(`connection.mesh = ${connection.mesh.id}`);
|
logger.debug(`connection.mesh = ${connection.mesh.id}`);
|
||||||
newMesh = connection.mesh;
|
newMesh = connection.mesh;
|
||||||
} else {
|
break;
|
||||||
|
case DiagramTemplates.USER:
|
||||||
|
break;
|
||||||
|
case DiagramTemplates.IMAGE:
|
||||||
|
newMesh = buildImage(entity, scene);
|
||||||
|
newMesh.metadata = {template: entity.template, exportable: true, tool: false}
|
||||||
|
break;
|
||||||
|
case DiagramTemplates.BOX:
|
||||||
|
case DiagramTemplates.SPHERE:
|
||||||
|
case DiagramTemplates.CYLINDER:
|
||||||
|
case DiagramTemplates.CONE:
|
||||||
|
case DiagramTemplates.PLANE:
|
||||||
const toolMesh = scene.getMeshById("tool-" + entity.template + "-" + entity.color);
|
const toolMesh = scene.getMeshById("tool-" + entity.template + "-" + entity.color);
|
||||||
if (toolMesh && !oldMesh) {
|
if (toolMesh && !oldMesh) {
|
||||||
newMesh = new InstancedMesh(entity.id, (toolMesh as Mesh));
|
newMesh = new InstancedMesh(entity.id, (toolMesh as Mesh));
|
||||||
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);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.warn('no tool mesh found for ' + entity.template + "-" + entity.color);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return newMesh;
|
return newMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildImage(entity: DiagramEntity, scene: Scene): AbstractMesh {
|
||||||
|
const logger = log.getLogger('buildImage');
|
||||||
|
logger.debug("buildImage: entity is image");
|
||||||
|
const plane = MeshBuilder.CreatePlane(entity.id, {size: 1}, scene);
|
||||||
|
const material = new StandardMaterial("planeMaterial", scene);
|
||||||
|
const image = new Image();
|
||||||
|
image.src = entity.image;
|
||||||
|
const texture = new Texture(entity.image, scene);
|
||||||
|
material.emissiveTexture = texture;
|
||||||
|
material.backFaceCulling = false;
|
||||||
|
material.disableLighting = true;
|
||||||
|
plane.material = material;
|
||||||
|
image.decode().then(() => {
|
||||||
|
plane.scaling.x = image.width / image.height;
|
||||||
|
});
|
||||||
|
return plane;
|
||||||
|
}
|
||||||
|
|
||||||
function generateId(entity: DiagramEntity) {
|
function generateId(entity: DiagramEntity) {
|
||||||
if (!entity.id) {
|
if (!entity.id) {
|
||||||
entity.id = "id" + uuidv4();
|
entity.id = "id" + uuidv4();
|
||||||
@ -104,6 +146,7 @@ function mapMetadata(entity: DiagramEntity, newMesh: AbstractMesh, 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);
|
||||||
}
|
}
|
||||||
@ -21,6 +21,16 @@ export enum DiagramEventMask {
|
|||||||
REMOTE = 2,
|
REMOTE = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum DiagramTemplates {
|
||||||
|
CONNECTION = "#connection-template",
|
||||||
|
USER = "#user-template",
|
||||||
|
BOX = "#box-template",
|
||||||
|
SPHERE = "#sphere-template",
|
||||||
|
CYLINDER = "#cylinder-template",
|
||||||
|
CONE = "#cone-template",
|
||||||
|
IMAGE = "#image-template",
|
||||||
|
PLANE = "#plane-template",
|
||||||
|
}
|
||||||
|
|
||||||
export type DiagramEvent = {
|
export type DiagramEvent = {
|
||||||
type: DiagramEventType;
|
type: DiagramEventType;
|
||||||
@ -34,6 +44,7 @@ export type DiagramEntity = {
|
|||||||
id?: string;
|
id?: string;
|
||||||
from?: string;
|
from?: string;
|
||||||
to?: string;
|
to?: string;
|
||||||
|
image?: string;
|
||||||
last_seen?: Date;
|
last_seen?: Date;
|
||||||
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 };
|
||||||
|
|||||||
43
src/react/functions/uploadImage.ts
Normal file
43
src/react/functions/uploadImage.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const uploadImage = async (evt) => {
|
||||||
|
|
||||||
|
const file = (evt.target as HTMLInputElement).files[0];
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
//formData.append('requireSignedURLs', 'true');
|
||||||
|
const formInitData = new FormData();
|
||||||
|
formInitData.append('requireSignedURLs', 'true');
|
||||||
|
|
||||||
|
const initialUpload = await fetch('/api/images', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formInitData
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const initialData = await initialUpload.json();
|
||||||
|
if (initialData.success == true) {
|
||||||
|
const upload = await fetch(initialData.result.uploadURL, {
|
||||||
|
method: 'POST', mode: 'cors', body:
|
||||||
|
formData
|
||||||
|
});
|
||||||
|
const uploadData = await upload.json();
|
||||||
|
console.log(uploadData)
|
||||||
|
for (let variant of uploadData.result.variants) {
|
||||||
|
if (variant.indexOf('fullhd') > -1) {
|
||||||
|
const uploadEvent = new CustomEvent('uploadImage', {
|
||||||
|
detail: {
|
||||||
|
name: file.name,
|
||||||
|
data: variant
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.dispatchEvent(uploadEvent);
|
||||||
|
evt.target.remove();
|
||||||
|
console.log(variant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export {uploadImage};
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
|
import {uploadImage} from "./functions/uploadImage";
|
||||||
|
|
||||||
function MainMenu({onClick}) {
|
function MainMenu({onClick}) {
|
||||||
return (
|
return (
|
||||||
@ -7,6 +8,7 @@ function MainMenu({onClick}) {
|
|||||||
<div id="enterXR" className="inactive"><a href="#" id="enterVRLink">Enter VR</a></div>
|
<div id="enterXR" className="inactive"><a href="#" id="enterVRLink">Enter VR</a></div>
|
||||||
<QuestLink/>
|
<QuestLink/>
|
||||||
<div id="diagrams"><a href="#" id="diagramsLink" onClick={onClick}>Diagrams</a></div>
|
<div id="diagrams"><a href="#" id="diagramsLink" onClick={onClick}>Diagrams</a></div>
|
||||||
|
<div id="imageUpload"><a href="#" id="imageUploadLink" onClick={onClick}>Upload Image</a></div>
|
||||||
<div id="download"><a href="#" id="downloadLink">Download Model</a></div>
|
<div id="download"><a href="#" id="downloadLink">Download Model</a></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -113,8 +115,20 @@ function Menu() {
|
|||||||
|
|
||||||
function handleDiagramListClick(evt: React.MouseEvent<HTMLAnchorElement>) {
|
function handleDiagramListClick(evt: React.MouseEvent<HTMLAnchorElement>) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
switch (evt.target.id) {
|
||||||
|
case 'imageUploadLink':
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = 'image/*';
|
||||||
|
input.onchange = uploadImage;
|
||||||
|
|
||||||
|
document.body.appendChild(input);
|
||||||
|
input.click();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
setDiagramListState(diagramListState == 'none' ? 'block' : 'none');
|
setDiagramListState(diagramListState == 'none' ? 'block' : 'none');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -134,49 +148,3 @@ export default function WebApp() {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
const create = document.querySelector('#startCreateLink');
|
|
||||||
if (create) {
|
|
||||||
create.addEventListener('click', function (evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
document.querySelector('#main').style.display = 'none';
|
|
||||||
document.querySelector('#create').style.display = 'block';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const cancel = document.querySelector('#cancelCreateLink');
|
|
||||||
if (cancel) {
|
|
||||||
cancel.addEventListener('click', function (evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
document.querySelector('#main').style.display = 'block';
|
|
||||||
document.querySelector('#create').style.display = 'none';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const close = document.querySelector('#closekey a');
|
|
||||||
if (close) {
|
|
||||||
close.addEventListener('click', function (evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
document.querySelector('#keyboardHelp').style.display = 'none';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const desktopTutorial = document.querySelector('#desktopLink');
|
|
||||||
if (desktopTutorial) {
|
|
||||||
desktopTutorial.addEventListener('click', function (evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
// document.querySelector('#tutorial').style.display = 'none';
|
|
||||||
document.querySelector('#keyboardHelp').style.display = 'block';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const createAction = document.querySelector('#createActionLink');
|
|
||||||
if (createAction) {
|
|
||||||
createAction.addEventListener('click', function (evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
const value = document.querySelector('#createName').value;
|
|
||||||
if (value && value.length > 4) {
|
|
||||||
document.location.href = '/db/' + value;
|
|
||||||
} else {
|
|
||||||
window.alert('Name must be longer than 4 characters');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
@ -22,7 +22,11 @@ export default defineConfig({
|
|||||||
'^/create-db': {
|
'^/create-db': {
|
||||||
target: 'https://www.deepdiagram.com/',
|
target: 'https://www.deepdiagram.com/',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
}
|
},
|
||||||
|
'^/api/images': {
|
||||||
|
target: 'https://www.deepdiagram.com/',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
base: "/"
|
base: "/"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user