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.
Set labels in three-dimensional space.
Preparatory work
We create a new directory (src/5.tagging
and corresponding htm files and js or ts 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 .
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>points in 3d</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
html, body, #app { width: 100%; height: 100%; overflow: hidden; }
</style>
</head>
<body>
<div id="app"></div>
<! - Mode switch -->
<nav class="navbar fixed-bottom navbar-light bg-light">
<div class="container-fluid justify-content-center">
<div class="btn-group">
<button class="btn btn-primary active js-Panorama">Panoramic roaming</button>
<button class="btn btn-primary js-Floorplan">Overview of space</button>
</div>
</div>
</nav>
<script type="module" src="./index"></script>
</body>
</html>
- JavaScript
- TypeScript
import { Five, parseWork } from "@realsee/five";
const workURL = "https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
const five = new Five();
five.appendTo(document.querySelector("#app"));
fetch(workURL).then(res => res.json()).then((json) => {
const work = parseWork(json);
five.load(work);
});
window.addEventListener("resize", () => five.refresh(), false);
{// === mode switching ===
const buttons = {
"Panorama": document.querySelector(".js-Panorama"),
"Floorplan": document.querySelector(".js-Floorplan")
};
for (const [modeName, element] of Object.entries(buttons)) {
element.addEventListener("click", () => {
five.setState({ mode: modeName });
}, false);
}
five.on("stateChange", state => {
for (const [modeName, element] of Object.entries(buttons)) {
if (modeName === state.mode) {
element.classList.add("active");
} else {
element.classList.remove("active");
}
};
});
}
export {};
import { Five, Mode, parseWork } from "@realsee/five";
const workURL = "https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
const five = new Five();
five.appendTo(document.querySelector("#app")!);
fetch(workURL).then(res => res.json()).then((json) => {
const work = parseWork(json);
five.load(work);
});
window.addEventListener("resize", () => five.refresh(), false);
{// === mode switching ===
const buttons: Partial<Record<Mode, Element>> = {
"Panorama": document.querySelector(".js-Panorama")!,
"Floorplan": document.querySelector(".js-Floorplan")!
};
for (const [modeName, element] of Object.entries(buttons)) {
element.addEventListener("click", () => {
five.setState({ mode: modeName as Mode });
}, false);
}
five.on("stateChange", state => {
for (const [modeName, element] of Object.entries(buttons)) {
if (modeName === state.mode) {
element.classList.add("active");
} else {
element.classList.remove("active");
}
};
});
}
export {};
Start service npm run dev
and jump to the current page "http://localhost:3000/src/5.tagging/index.html".
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.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>展示空间 | Displaying work</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
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>
<!-- 模式切换 -->
<nav class="navbar fixed-bottom navbar-light bg-light">
<div class="container-fluid justify-content-center">
<div class="btn-group">
<button class="btn btn-primary active js-Panorama">Panorama roaming</button>
<button class="btn btn-primary js-Floorplan">Space overview</button>
</div>
</div>
</nav>
<!-- 打标签 -->
<div class="card position-fixed m-2 top-0 start-0">
<button class="btn btn-primary js-add-tag">打标签</button>
</div>
<script type="module" src="./index"></script>
</body>
</html>
Project2d Description
This chapter will use the method to project2
.He can match the three-dimensional coordinates to the screen.
five.project2d (vector: THREE.Vector3, testModel: boolean): THREE.Vector2 | null
- 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. - If three-dimensional coordinates cannot be calculated in the screen (e.g. behind or blocked), then return
null
. - The second parameter testModel is calculated if the model collided, i.e. if the coordinate blocked by the model is
null
.
Write Logical Code
newTag
is a tag in a new state that needs to follow the cursor position schedule.Tags
have fixed labels to follow the camera.tagToElement
Store tag corresponding DOM structure.- Camera movement triggers
CameraUpdate
Events, in callback functions, call by tabs$five.project2
method to get screen canvasses and then render them by changing styles.
Add:after the code of mode switch
- JavaScript
- TypeScript
{ // === 打标签 ===
const app = document.querySelector("#app");
const addButton = document.querySelector("). s-add-tag");
let newTag = null;
let tags = [];
const tagToElement = new WeakMap();
const createTagElement = tag ==> Google
const div = document. createElement("div");
div.className = "tag";
div.style.display = "none";
div.innerHTML = `<div class="tag-pannel"><span class="tag-content">${tag.label}</span></div>`;
app. ppendChild(div);
return div;
};
const renderTags = () => FREE
for (const tag of [newTag, ... ags]) {
if (!tag) continue;
if (!tag. osition) continue;
const element = tagToElement. et(tag);
if (!element) continue;
const position = five. roject2d(tag.position, true);
if (position === null) {
element. tyle.display = "none";
} else {
element.style. isplay = "";
element.style. eft = position.x + "px";
element. tyle.top = position. + "px";
}
}
};
addButton. ddEventListener("click", () => File
newTag = 56 label: window.prompt("Add Label", "") || "Unnamed" };
tagToElement. et(newtag, createTagElement(newTag));
}, false);
five. n("intersectionOnModelUpdate", intersect => {
if (newTag) newTag. Position = intersect.point;
renderTags();
});
five. n("wantsTapGesture", () => {
if (newTag && newTag.position) {
tags. ush(newTag);
newTag = null;
renderTags();
return false;
}
});
five. n("cameraUpdate", renderTags);
}
{ // === tag ===
type Tag = { position?: THREE.Vector3, label: string };
const app = document.querySelector("#app")!;
const addButton = document.querySelector(".js-add-tag")!;
let newTag: Tag | null = null;
let tags: Tag[] = [];
const tagToElement = new WeakMap<Tag, HTMLElement>();
const createTagElement = (tag: Tag) => {
const div = document.createElement("div");
div.className = "tag";
div.style.display = "none";
div.innerHTML = `<div class="tag-pannel"><span class="tag-content">${tag.label}</span></div>`;
app.appendChild(div);
return div;
};
const renderTags = () => {
for (const tag of [newTag, ...tags]) {
if (!tag) continue;
if (!tag.position) continue;
const element = tagToElement.get(tag);
if (!element) continue;
const position = five.project2d(tag.position, true);
if (position === null) {
element.style.display = "none";
} else {
element.style.display = "";
element.style.left = position.x + "px";
element.style.top = position.y + "px";
}
}
};
addButton.addEventListener("click", () => {
newTag = { label: window.prompt("Add Label", "") || "Unnamed" };
tagToElement.set(newTag, createTagElement(newTag));
}, false);
five.on("intersectionOnModelUpdate", intersect => {
if (newTag) newTag.position = intersect.point;
renderTags();
});
five.on("wantsTapGesture", () => {
if (newTag && newTag.position) {
tags.push(newTag);
newTag = null;
renderTags();
return false;
}
});
five.on("cameraUpdate", renderTags);
}
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: