Skip to main content

Tag

Previous chapter recalls: points in three dimensions
you understand the Live SDK event system and try to develop a small app to get a point of three-dimensional location by clicking on the event.

This chapter can learn to

Set labels in three-dimensional space.

Preparatory work

We create a new directory (src/5.taggingand corresponding htm files and jsx or tsx files. The State code with the previous chapter is too onerous, and we show the base development of the contents of the three-dimensional space chapter from .

src/5.tagging/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tag | Tagging</title>
<style>
* { margin: 0; padding: 0; }
html, body #app { width: 100%; height: 100%; overflow: hidden; }
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index"></script>
</body>
</html>
src/5.tagging/withFetchWork.jsx
import React, { Component } from "react";
import { parseWork } from "@realsee/five";

/**
* React HOC fetch work
* @param url address of work.json
*/
function withFetchWork(url) {
return function(Compnent) {
return class extends Component {
state = { work: null };
componentDidMount() {
fetch(url).then(res => res.json()).then(json => {
this.setState({ work: parseWork(json) });
});
}
render() {
if (this.state.work === null) return null;
return <Compnent work={this.state.work} {...this.props}/>;
}
}
}
}

export { withFetchWork };
src/5.tagging/withWindowDimensions.jsx
import React, { Component } from "react";

/**
* React HOC: Get the size of the current window
*/
function withWindowDimensions() {
return function(Compnent) {
return class extends Component {
state = this.getWindowDimensions();
resizeListener = () => {
this.setState(this.getWindowDimensions());
};
getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
componentDidMount() {
window.addEventListener("resize", this.resizeListener, false);
}
componentWillUnmount() {
window.removeEventListener("resize", this.resizeListener, false);
}
render() {
const dimensions = { width: this.state.width, height: this.state.height };
return <Compnent windowDimensions={dimensions} {...this.props}/>;
}
}
}
}

export { withWindowDimensions };
src/5.tagging/ModeController.jsx
import React, { Component } from "react";
import { Five } from "@realsee/five";
import { withFive, createFiveFeature } from "@realsee/five/react";
import { compose } from "@wordpress/compose";
import BottomNavigation from "@mui/material/BottomNavigation";
import BottomNavigationAction from "@mui/material/BottomNavigationAction";
import Paper from "@mui/material/Paper";
import DirectionsWalkIcon from "@mui/icons-material/DirectionsWalk";
import ViewInArIcon from "@mui/icons-material/ViewInAr";

const FEATURES = createFiveFeature("currentState", "setState");

/**
* React Component: Modal Control
*/
const ModeController = compose(
withFive(FEATURES)
)(class extends Component {
render() {
return <Paper sx={{ position: "fixed", bottom: 0, left: 0, right: 0 }}>
<BottomNavigation
showLabels
value={this.props.$five.currentState.mode}
onChange={(_, newValue) => {
this.props.$five.setState({ mode: newValue });
}}
>
<BottomNavigationAction label="Panorama roaming" icon={<DirectionsWalkIcon/>} value={Five.Mode.Panorama}/>
<BottomNavigationAction label="Space overview" icon={<ViewInArIcon/>} value={Five.Mode.Floorplan}/>
</BottomNavigation>
</Paper>;
}
})

export { ModeController };
src/5.tagging/App.jsx
import React, { Component } from "react";
import { compose } from "@wordpress/compose";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { withFetchWork } from "./withFetchWork";
import { withWindowDimensions } from "./withWindowDimensions";
import { ModeController } from "./ModeController";

/** Data URL of work.json */
const workURL = "https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

const FiveProvider = createFiveProvider();

const App = compose(
withFetchWork(workURL),
withWindowDimensions()
)(class extends Component {
render() {
const { work, windowDimensions } = this.props;
return <FiveProvider initialWork={work}>
<FiveCanvas width={windowDimensions.width} height={windowDimensions.height}/>
<ModeController/>;
</FiveProvider>;
}
});

export { App };
src/5.tagging/index.jsx
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";

ReactDOM.render(<App/>, document.querySelector("#app"));

export {};

Start service npm run dev and jump to the current page "http://localhost:3000/src/5.tagging/index.html".

info

Please see your console. The port number will change due to your configuration and current port occupancy, please check the console output. If you use another development build tool, please start the service as required by your own development build tool.

Developing Tag Features

Add Tag Style

Add a tag style to the html.

Style is not necessary, it is only for better labels.

src/5.tagging/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tag | Tagging</title>
<style>
* { margin: 0; padding: 0; }
html, body #app { width: 100%; height: 100%; overflow: hidden; }
.tag { position: absolute; width: 0; height: 0; transform: translateZ(0); }
.tag-pannel { position: absolute; width: 100px; min-height: 20px; transform: translate(-50%, 0); left: 50%; bottom: 10px; background: #333; color: #fff; border-radius: 2px; text-align: center; line-height: 20px; padding: 8px; font-size: 14px;}
.tag-pannel:after { content: ""; display: block; position: absolute; width: 10px; height: 10px; left: 50%; bottom: -5px; transform: translate(-50%, 0) rotate(45deg); background: #333; pointer-events: none; }
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index"></script>
</body>
</html>

useFiveProject2d Description

This chapter will use the useFiveProject2d method.He can match the three-dimensional coordinates to the screen.

$five.project2d(vector: THREE.Vector3, testModel: boolean): THREE.Vector2 | null

  1. Incoming a three-dimensional coordinates to get a 2D coordinates of the screen, starting at the top of the left in pixels.Can be used as { left: returnValue.x + "px", top: returnValue.y + "px" } etc.
  2. If three-dimensional coordinates cannot be calculated in the screen (e.g. behind or blocked), then return null.
  3. The second parameter testModel is calculated if the model collided, i.e. if the coordinate blocked by the model is null.

Write TaggingController

  1. Add a TaggingController file to write components.
  2. Store labels and text with tags React state
  3. Store newly created tags with newTag React state
  4. Listen to the intersectionOnModelUpdate event to place the newly created tab in the mouse position.
  5. Call $five.project2 method (tagElement method) to get screen canvas coordinates and render by changing styles.
src/5.tagging/TaggingController.jsx
import React, { Component } from "react";
import { compose } from "@wordpress/compose";
import { withFive, createFiveFeature } from "@realsee/five/react";
import Button from "@mui/material/Button";
import Paper from "@mui/material/Paper";

const FEATURES = createFiveFeature("project2d", "currentState", "on", "off");

/**
* React Component: Tag
*/
const TaggingController = compose(
withFive(FEATURES)
)(class extends Component {

state = { tags: [], newTag: null };

addTag = ( ) => {
this.setState({ newTag: { label: window.prompt("Add Tag", "") || "Untitled" } });
}

tagElement(tag, key) {
const position = tag.position && this.props.$five.project2d(tag.position, true);
const style = position ? { left: position.x, top: position.y } : { display: "none" };
return <div className="tag" style={style} key={key}>
<div className="tag-pannel"><span className="tag-content">{tag.label}</span></div>
</div>
}

onIntersectionUpdate = intersect => {
if (this.state.newTag) this.setState({ newTag: { position: intersect.point, label: this.state.newTag.label } });
};

onTapGesture = () => {
if (this.state.newTag && this.state.newTag.position) {
this.setState({
tags: this.state.tags.concat(this.state.newTag),
newTag: null
});
return false;
}
};

componentDidMount() {
this.props.$five.on("intersectionOnModelUpdate", this.onIntersectionUpdate);
this.props.$five.on("wantsTapGesture", this.onTapGesture);
}

componentWillUnmount() {
this.props.$five.off("intersectionOnModelUpdate", this.onIntersectionUpdate);
this.props.$five.off("wantsTapGesture", this.onTapGesture);
}

render() {
return <React.Fragment>
<Paper sx={{ position: "fixed", top: 10, left: 10 }}>
<Button onClick={this.addTag}>Tag</Button>
</Paper>
{this.state.newTag && this.tagElement(this.state.newTag)}
{this.state.tags.map((tag, index) => this.tagElement(tag, index))}
</React.Fragment>;
}
});

export { TaggingController };

Use Tag Component

Insert into App file GiveProvider

src/5.tagging/App.jsx
import React, { Component } from "react";
import { compose } from "@wordpress/compose";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { withFetchWork } from "./withFetchWork";
import { withWindowDimensions } from "./withWindowDimensions";
import { ModeController } from "./ModeController";
import { TaggingController } from "./TaggingController";

/** Data URL of work.json */
const workURL = "https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

const FiveProvider = createFiveProvider();

const App = compose(
withFetchWork(workURL),
withWindowDimensions()
)(class extends Component {
render() {
const { work, windowDimensions } = this.props;
return <FiveProvider initialWork={work}>
<FiveCanvas width={windowDimensions.width} height={windowDimensions.height}/>
<ModeController/>;
<TaggingController/>;
</FiveProvider>;
}
});

export { App };

Back to your browser to view it, you will find a tabs button in the upper left corner of your page, click on, fill in the tag name, then move the mouse and click in the position you need.Tag can be placed.

Well, it is a functional feature: partying_face: