ThingJS 架构
场景搭建
- 圈地
- 添加自定义建筑
- 设置参考图及其比例(可前置为第一步)
- 设置建筑外立面
- 自定义属性
- 场景导出
场景加载
```javascript // 线上 const app = new Thing.App({ url: “线上场景 URL”, }); // 本地 const app = new Thing.App({
});
<a name="Flibf"></a>
## UI 元素创建及引入
<a name="XcMXx"></a>
### ThingJS 界面体系
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1016618/1661825028318-42246508-aa82-4391-bfb8-648c5e858a8a.png#clientId=u14ff5ce6-3738-4&from=paste&height=675&id=u4a4032c2&originHeight=675&originWidth=1408&originalType=binary&ratio=1&rotation=0&showTitle=false&size=213439&status=done&style=none&taskId=u39e46356-2a39-49c3-b193-17e67e61d1f&title=&width=1408)
<a name="XeASG"></a>
#### 3D 容器外的 UI 引入方式
<a name="LmChE"></a>
##### `iframe` 方式引入
通过 `document.body.appendChild` 将 `iframe` 嵌入页面(需要对 `iframe` 进行 `position` 定位 )
<a name="rwik9"></a>
##### `app.domElement.appendChild` 方式引入
通过 `app.domElement.appendChild` 方式引入创建的 `element` 元素(需要对其进行 `position` 定位)
<a name="qWWyV"></a>
#### 3D 容器内的 UI 引入方式
<a name="xpeHV"></a>
##### 通过 `UIAnchor` 类型创建
```javascript
class CreateUIAnchor {
constructor() {
this.ui = null;
this.init();
}
// 初始化 UI
init() {
const template = `
<div class="bubble" id="uianchor">
<span>小车</span>
</div>
`;
const uiElem = document.createElement("template");
uiElem.innerHTML = template;
document.querySelector("#div3d").append(uiElem.content.childNodes);
this.createUI();
}
// 创建 UIAnchor
createUI() {
this.ui = app.create({
type: "UIAnchor",
parent: app.query("car02")[0],
element: this.createElement(),
localPosition: [0, 2, 0],
pivot: [0.5, 1], // UI 元素定位中心, [0, 0] 左上角, [1, 1] 右下角
});
},
// 创建元素
createElement() {
const originElem = document.querySelector("#uianchor");
const newElem = originElem.cloneNode(true);
newElem.style.display = "block";
app.domElement.insertBefore(newElem, originElem);
return newElem;
},
}
通过 Maker
类型创建
class CreateMarker {
constructor() {
this.ui = null;
this.init();
}
// 初始化 UI
init() {
const template = `
<div class="bubble" id="marker">
<span>小车</span>
</div>
`;
const uiElem = document.createElement("template");
uiElem.innerHTML = template;
document.querySelector("#div3d").append(uiElem.content.childNodes);
this.createUI();
}
// 创建 UIAnchor
createUI() {
this.ui = app.create({
type: "Marker",
parent: app.query("car02")[0],
element: document,querySelector("#marker"),
localPosition: [0, 2, 0],
size: 2,
});
}
}
注意:
- 3D容器外的2D界面布局需使用
position
定位; - 3D容器内的顶牌,使用绑定
element
对象方式创建顶牌时,注意样式编写:- 样式不能写为模块/组件样式,需写为全局样式;
- 顶牌 DOM 元素需要隐藏;
UIAnchor
和Marker
的区别是,前者不能被 app 实例管理操作;但销毁方式都是使用destory
方法。⭐创建物体
参考 《创建/销毁物体》 章节。扩展知识
坐标点位采集
通过监听园区的点击事件,获取点击处的坐标点位。app.on("click", (e) => {
console.log(e.pickedPosition);
});
创建物体并添加控件
通过app.create
创建的物体,可以通过obj.addControl
方法添加由new THING.AxisTransformControl(obj, type, options, tag)
创建的操作控件,也能通过obj.removeControl(tag)
移除已添加的控件。 ```javascript // 单击 app.on(“singleClick”, (ev) => { // 创建物体 app.create({ type: “Thing”, url: “”, localPosition: ev.pickedPosition, // 物体的初始位置为点击的点位(父级的坐标系) scale: [3, 3, 3], // 物体缩放 parent: app.level.current, // 父对象为当前层级对象 complete() { // 物体添加位置移动控件 obj.addControl(createTransCtrl(this, “transform”)); // 物体添加角度调整控件 obj.addControl(createTransCtrl(this, “rotate”)); } }); });
// 创建操作控件
function createTransCtrl(obj, type) {
const tag = ${type}Control
;
return new THING.AxisTransformControl(obj, type, {
changeStart() {
console.log(start ${type}
);
},
changeEnd() {
console.log(${type} end
, type === “transform” ? obj.position : obj.angle);
// 物体移除操作控件
obj.removeControl(tag);
},
}, tag);
}
<a name="DZvJZ"></a>
## 物体效果设置
- 颜色 `obj.style.color = <hex-color> | rgba() | <named-color> | null`
- 透明度 `obj.style.opacity = <number>`
- 勾边/轮廓 `obj.style.outlineColor = <hex-color> | rgba() | <named-color> | null`
- 发光/阴影
- 向外 `obj.style.glow = <boolean>`
- 向内 `obj.style.innerGlow = <boolean>`
- 缩放
- 瞬时 `obj.style.scale = [x, y, z]`
- 逐渐缩放 `obj.style.scaleTo = [x, y, z]`
- 停止缩放 `obj.style.stopScaling()`
- ⭐移动
```javascript
// 移动到目标点
obj.moveTo({
position: [x, y, z],
time: 1000,
delayTime: 1000,
orientToPath: true, // 移动时朝向移动路径
lerpType: null, // 插值方式,默认线性(与 css 的 transition-time-funtion 类似)
loopType: THING.loopType.Repeat, // 重复
complete(e) {},
});
// 按路径移动
const path = [[0, 0, 0], [1, 2, 3] ...];
obj.movePath({
path, // 移动路径,非 position 目标点
// ....
});
扩展知识
⭐自定义类管理设备状态
// 定义类
// 自定义安全帽类继承物体类
class SafetyHelmet extends THING.Thing {
contructor(app) {
super(app);
},
// 添加自定义属性
alarmed: flase,
// 添加自定义方法
alarm() {
this.alarmed = true;
}
}
// 注册类,参数是(类型名, 构造函数)
THING.factory.registerClass("SafetyHelmet", SafetyHelmet);
// 通过自定义类创建物体
const sh = app.create({
type: "SafetyHelmet",
name: "安全帽001",
url: "",
position: [],
// ...
});
// 查询自定义物体
const shs = app.query(".SafetyHelmet");
// 给自定义物体注册事件,并调用其方法
app.on("click", ".SafetyHelmet", (e) => {
e.object.alarm();
console.log(e.object.alarmed);
});
事件绑定与顶牌控制
事件绑定
ThingJS 中内置的事件有:鼠标事件,键盘事件,层级变化事件等。主要分为全局事件和局部事件;
- 全局事件
app.on(eventName, callback, tagName?)
app.on(eventName, condition, callback, tagName?)
其中condition
可为一种或多种类型,如".Thing"
或".Car || .SafetyHelmet"
局部事件
Marker
- 图片
- canvas
- Element
- TextRegion 文本
- WebView: 3D 内嵌页面
- UIAnchor: 2D 界面(不能设置大小和近大远小
size, keepSize
,不能通过query
查询,无法被程序管理) - Widget: 2D 快捷界面库
层级切换
ThingJS 提供了 SenseLevel 模块,可以通过app.level
控制层级。
常用的 API 有:
app.level.chang(obj) |
层级切换到指定对象 |
---|---|
app.level.back() |
回到上一层级 |
app.level.current |
当前层级对象 |
app.level.previous |
前一个层级对象 |
EnterLevel | 进入层级事件,内含 4 个响应: - THING.EventTag.LevelSenseOperation 进入层级时的场景控制- THING.EventTag.LevelFly 进入层级时的飞行控制- THING.EventTag.LevelSetBackground 进入层级时的天空背景控制- THING.EventTag.LevelPickedResultFun 进入层级时的 Pick 对象设置 |
LeaveLevel | 退出层级事件,内含 1 个响应: - THING.EventTag.LevelSenseOperation 进入层级时的场景控制 |
LevelFlyEnd | 层级切换后相机飞行结束事件 |
⭐相机
相机常用 API
app.camera.position |
摄像机位置 |
---|---|
app.camera.target |
摄像机目标 |
app.camera.up |
摄像机 UP 方向 默认值为 [0,1,0] |
app.camera.lookAt(<position> | <object> | null) |
摄像机“盯”住某一物体 |
app.camera.fit() |
摄像机自动调整最佳位置(无回调) |
app.camera.flyTo(<position> | <object>) |
设置摄像机飞行 |
app.camera.flying() |
返回 <boolean> 类型的摄像机飞行状态 |
app.camera.stopFlying() |
设置摄像机停止飞行 |
app.camera.rotateAround(<position> | <object>) |
设置摄像机环绕某点/物体飞行 |
app.camera.followObject(<object>) |
设置摄像机跟随某一物体移动 |
app.camera.stopFollowObject() |
设置摄像机停止跟随物体 |
相机交互控制
app.camera.inputEnable |
是否允许相机交互 |
---|---|
app.camera.enablePan |
是否允许相机平移 |
app.camera.enableRotate |
是否允许相机旋转 |
app.camera.enableZoom |
是否允许相机缩放 |
app.camera.mousePanSpeed = 0.1 |
鼠标平移速度 |
app.camera.keyPanSpeed = 0.1 |
键盘平移速度 |
app.camera.yAngleLimitRange = [0, 360] |
相机水平角度范围 |
app.camera.xAngleLimitRange = [0, 360] |
相机垂直角度范围 |
app.camera.viewMode = "" |
相机模式 - THING.CameraView.TopView 顶视图- THING.CameraView.Normal 3D 视图(默认) |
数据对接
- Ajax
- JSONP
- Axios
- Websocket