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 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.

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>
<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>
* {
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/useWindowDimensions.js
import { ref, onBeforeUnmount } from "vue";

function useWindowDimensions() {
const width = ref(window.innerWidth);
const height = ref(window.innerHeight);

const listener = () => {
width.value = window.innerWidth;
height.value = window.innerHeight;
};

window.addEventListener("resize", listener, false);
onBeforeUnmount(() => {
window.removeEventListener("resize", listener, false);
});
return { width, height };
}
export { useWindowDimensions };
src/5.tagging/ModeController.vue
<template>
<nav class="navbar fixed-bottom navbar-light bg-light">
<div class="container-fluid justify-content-center">
<div class="btn-group">
<button
:class="
state.mode == 'Panorama'
? 'btn btn-primary active'
: 'btn btn-primary'
"
@click="() => setState({ mode: Five.Mode.Panorama })"
>
Panorama roaming
</button>
<button
:class="
state.mode == 'Panorama'
? 'btn btn-primary'
: 'btn btn-primary active'
"
@click="() => setState({ mode: Five.Mode.Floorplan })"
>
Space overview
</button>
</div>
</div>
</nav>
</template>

<script setup>
import { useFiveCurrentState } from "@realsee/five/vue";
import { Five } from "@realsee/five";

const [state, setState] = useFiveCurrentState();
</script>
src/5.tagging/App.vue
<template>
<FiveProvider :work="work">
<FiveCanvas :width="width" :height="height" />
<ModeController />
</FiveProvider>
</template>

<script setup>
import { FiveProvider, FiveCanvas } from "@realsee/five/vue";
import { parseWork } from "@realsee/five";
import { ref } from "vue";
import { useWindowDimensions } from "./useWindowDimensions";
import ModeController from "./ModeController.vue";

const work = ref();
const workURL =
"https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

fetch(workURL)
.then((response) => response.text())
.then((text) => (work.value = parseWork(text)));
const { width, height } = useWindowDimensions();
</script>
src/5.tagging/index.js
import { createApp, h } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

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

useFiveProject2d Description

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

useFiveProject2d(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 tag locations and text with tags Vue Reactive
  3. Save the currently created tag with newTag Vue Ref.
  4. Listen to the intersectionOnModelUpdate event to place the newly created tab in the mouse position.
  5. Call useProject2 with a tag project2 method (intagElement ) to get the screen canvas coordinates and render them by changing styles.
  6. Add Tag Style (Style is not required, only for tags)
src/5.tagging/TaggingController.vue
<template>
<div class="card position-fixed m-2 top-0 start-0">
<button class="btn btn-primary" @click="addTag">Tag</button>
</div>
<div v-for="(tag, index) in tags" class="tag" :style="tagStyle(tag)">
<div class="tag-pannel">
<span class="tag-content">{{ tag.label }}</span>
</div>
</div>
<div class="tag" :style="newTagStyle(newTag)">
<div class="tag-pannel">
<span class="tag-content">{{ newTag?.label }}</span>
</div>
</div>
</template>
<script setup>
import { useFiveEventCallback, useFiveProject2d } from "@realsee/five/vue";
import { ref, reactive } from "vue";
import { Vector3 } from "three";

let newTag = ref(null);
let tags = reactive([]);
const project2d = useFiveProject2d();

const intersectPoint = ref(new Vector3(0, 0, 0));

useFiveEventCallback("intersectionOnModelUpdate", (intersect) => {
// 更新三维点
if (newTag.value) {
intersectPoint.value = intersect.point;
newTag.value.position = intersect.point;
}
});

// 点击更新数组
useFiveEventCallback("wantsTapGesture", () => {
if (newTag.value && newTag.value.position) {
tags.push(newTag.value);
newTag.value = null;
return false;
}
});

const addTag = () => {
if (!newTag.value) {
newTag.value = {
label: window.prompt("添加标签", "") || "未命名",
position: new Vector3(0, 0, 0),
};
}
};

const tagStyle = (tag) => {
return {
left: project2d(tag.position, false).value?.x + "px",
top: project2d(tag.position, false).value?.y + "px",
};
};

const newTagStyle = (tag) => {
if (tag) {
return {
left: project2d(tag.position, false).value?.x + "px",
top: project2d(tag.position, false).value?.y + "px",
display: "block",
};
}
return {
display: "none",
};
};
</script>
<style>
.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>

Use Tag Component

Insert into App file GiveProvider

src/5.taging/App.vue
<template>
<FiveProvider :work="work">
<FiveCanvas :width="width" :height="height" />
<ModeController />
<TaggingController />
</FiveProvider>
</template>

<script setup>
import { FiveProvider, FiveCanvas } from "@realsee/five/vue";
import { parseWork } from "@realsee/five";
import { ref } from "vue";
import { useWindowDimensions } from "./useWindowDimensions";
import ModeController from "./ModeController.vue";
import TaggingController from "./TaggingController.vue";

const work = ref();
const workURL =
"https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

fetch(workURL)
.then((response) => response.text())
.then((text) => (work.value = parseWork(text)));
const { width, height } = useWindowDimensions();
</script>

Returning to your browser for viewing will find tabs in the upper left corner of your page, click on, fill in the tag name, move the mouse, click in the position you need and place the tag.

Well, it is a functional feature: partying_face: