改变视角
上一章回顾: 展示三维空间
- 你了解什么是 Work, 以及如何获取和加载。
- 如何展示三维空间,并且再次基础上开发组件来控制三维空间。
本章你可以学习到
- 了解什么是 State。
- 如何改变三维空间观察的方向 / 位置。
- 了解上一章的代码,比如
useCurrentState
及其他响应的是如何工作的。 - 通过 State 完成了自动环视的功能。
准备工作
和上一章节一样,我们新建一个目录(src/2.knowing-state
)以及对应的 html 文件 以及 jsx 或 tsx 文件。
jsx 或 tsx 文件可以先拷贝上一章节的内容。
<!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>改变视角 | Knowing state</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>
- JavaScript
- TypeScript
import { useState, useEffect } from "react";
import { parseWork } from "@realsee/five";
/**
* React Hook: 通过 work.json 的地址 获取 work 对象
* @param url work.json 的数据地址
* @returns work 对象,如果获取中,返回 null
*/
function useFetchWork(url) {
const [work, setWork] = useState(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
export { useFetchWork };
src/2.knowing-state/useWindowDimensions.js
import { useState, useEffect } from "react";
/**
* 获取当前窗口的尺寸
*/
function getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
/**
* React Hook: 获取当前窗口的尺寸
*/
function useWindowDimensions() {
const [size, setSize] = useState(getWindowDimensions);
useEffect(() => {
const listener = () => setSize(getWindowDimensions());
window.addEventListener("resize", listener, false);
return () => window.removeEventListener("resize", listener, false);
});
return size;
}
export { useWindowDimensions };
src/2.knowing-state/ModeController.jsx
import React from "react";
import { Five } from "@realsee/five";
import { useFiveCurrentState } from "@realsee/five/react";
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";
/**
* React Component: 模态控制
*/
const ModeController = () => {
const [state, setState] = useFiveCurrentState();
return <Paper sx={{ position: "fixed", bottom: 0, left: 0, right: 0 }}>
<BottomNavigation
showLabels
value={state.mode}
onChange={(_, newValue) => {
setState({ mode: newValue });
}}
>
<BottomNavigationAction label="全景漫游" icon={<DirectionsWalkIcon/>} value={Five.Mode.Panorama}/>
<BottomNavigationAction label="空间总览" icon={<ViewInArIcon/>} value={Five.Mode.Floorplan}/>
</BottomNavigation>
</Paper>;
}
export { ModeController };
src/2.knowing-state/App.jsx
import React from "react";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { useFetchWork } from "./useFetchWork";
import { useWindowDimensions } from "./useWindowDimensions";
import { ModeController } from "./ModeController";
/** work.json 的数据 URL */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
const FiveProvider = createFiveProvider();
const App = () => {
const work = useFetchWork(workURL);
const size = useWindowDimensions();
return work && <FiveProvider initialWork={work}>
<FiveCanvas {...size}/>
<ModeController/>
</FiveProvider>;
};
export { App };
src/2.knowing-state/index.jsx
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};
import { useState, useEffect } from "react";
import { Work, parseWork } from "@realsee/five";
/**
* React Hook: 通过 work.json 的地址 获取 work 对象
* @param url work.json 的数据地址
* @returns work 对象,如果获取中,返回 null
*/
function useFetchWork(url: string) {
const [work, setWork] = useState<Work | null>(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
export { useFetchWork };
src/2.knowing-state/useWindowDimensions.ts
import { useState, useEffect } from "react";
/**
* 获取当前窗口的尺寸
*/
function getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
/**
* React Hook: 获取当前窗口的尺寸
*/
function useWindowDimensions() {
const [size, setSize] = useState(getWindowDimensions);
useEffect(() => {
const listener = () => setSize(getWindowDimensions());
window.addEventListener("resize", listener, false);
return () => window.removeEventListener("resize", listener, false);
});
return size;
}
export { useWindowDimensions };
src/2.knowing-state/ModeController.tsx
import React, { FC } from "react";
import { Five, Mode } from "@realsee/five";
import { useFiveCurrentState } from "@realsee/five/react";
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";
/**
* React Component: 模态控制
*/
const ModeController: FC = () => {
const [state, setState] = useFiveCurrentState();
return <Paper sx={{ position: "fixed", bottom: 0, left: 0, right: 0 }}>
<BottomNavigation
showLabels
value={state.mode}
onChange={(_, newValue: Mode) => {
setState({ mode: newValue });
}}
>
<BottomNavigationAction label="全景漫游" icon={<DirectionsWalkIcon/>} value={Five.Mode.Panorama}/>
<BottomNavigationAction label="空间总览" icon={<ViewInArIcon/>} value={Five.Mode.Floorplan}/>
</BottomNavigation>
</Paper>;
}
export { ModeController };
src/2.knowing-state/App.tsx
import React, { FC } from "react";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { useFetchWork } from "./useFetchWork";
import { useWindowDimensions } from "./useWindowDimensions";
/** work.json 的数据 URL */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
const FiveProvider = createFiveProvider();
const App: FC = () => {
const work = useFetchWork(workURL);
const size = useWindowDimensions();
return work && <FiveProvider initialWork={work}>
<FiveCanvas {...size}/>
</FiveProvider>;
};
export { App };
src/2.knowing-state/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};
启动服务 npm run dev
。 并跳转到当前页面 "http://localhost:3000/src/2.knowing-state/index.html"。
信息
请查看你的控制台,端口号会因为你的配置以及当前端口占用情况变更,请已控制台输出的为准。 如果你使用其他开发构建工具,请按照自己的开发构建工具的要求启动服务。
什么是 State
又来了解概念了,我保证这你是现阶段需要了解的最后一个理论知识了。