第一部分:ThingJS基础入门
第一章 ThingJS概述与技术架构
1.1 ThingJS平台简介
ThingJS是优锘科技推出的面向物联网的三维可视化开发平台,基于WebGL技术构建,专注于解决物联网应用中的"最后一公里"可视化问题。该平台自2016年发布以来,已广泛应用于智慧城市、工业互联网、园区管理、电力能源等众多领域。
核心特点:
- 低代码开发:提供可视化编排工具和丰富的API,降低3D可视化开发门槛
- 跨平台支持:基于Web标准,一次开发可运行于PC、移动端及大屏设备
- 性能优化:采用层级细节(LOD)技术和智能加载机制,支持大规模场景渲染
- 生态完善:拥有模型市场、插件系统和开发者社区支持
1.2 技术架构解析
整体架构:
[应用层] ←→ [ThingJS API] ←→ [核心引擎] ←→ [渲染层]
↑ ↑
[扩展插件] [资源管理系统]
核心组件:
- 场景图系统(Scene Graph):基于树状结构管理所有3D对象
- 实体组件系统(ECS):通过组件化方式扩展对象功能
- 材质系统:支持PBR(物理渲染)和传统材质
- 动画系统:包含骨骼动画、变形动画和粒子系统
- 物理引擎:集成轻量级碰撞检测系统
1.3 开发环境配置
基础环境准备:
# 推荐开发环境
Node.js 14+ (LTS版本)
Visual Studio Code 或 WebStorm
Chrome/Firefox最新版
# 安装ThingJS CLI工具
npm install -g @thingjs/cli
# 创建新项目
thingjs create my-first-project
cd my-first-project
npm install
npm run serve
项目目录结构:
├── public/ # 静态资源
├── src/
│ ├── assets/ # 项目资源
│ ├── components/ # 自定义组件
│ ├── configs/ # 配置文件
│ ├── scenes/ # 场景脚本
│ ├── styles/ # 样式文件
│ ├── utils/ # 工具函数
│ └── main.js # 应用入口
├── thingjs.config.js # 构建配置
└── package.json
第二章 基础概念与核心API
2.1 核心对象模型
对象层次结构:
App → Scene → Camera → Controller
↑
Object3D
↑
(Mesh, Light, Helper...)
关键类说明:
- THING.App:应用入口,管理应用生命周期
- THING.Scene:场景容器,管理所有3D对象
- THING.Camera:视图控制器,决定观察视角
- THING.Object3D:所有3D对象的基类
2.2 场景创建与管理
基础场景创建:
const app = new THING.App({
background: '#000000', // 背景色
skyBox: 'SkyBox1', // 天空盒
env: 'env1' // 环境光
});
// 创建地面
const ground = app.create({
type: 'Ground',
name: 'myGround',
position: [0, 0, 0],
style: {
texture: 'gradient',
size: [100, 100]
}
});
// 加载园区场景
app.load('/scenes/building').then((scene) => {
console.log('场景加载完成');
});
场景生命周期:
app.on('load', function(ev) {
// 场景加载完成
});
app.on('update', function(ev) {
// 每帧更新
});
app.on('destroy', function(ev) {
// 场景销毁
});
2.3 对象操作基础
创建与操作3D对象:
// 创建立方体
const box = app.create({
type: 'Box',
name: 'myBox',
position: [0, 5, 0],
size: [2, 2, 2],
style: {
color: '#FF0000',
opacity: 0.8
}
});
// 对象变换
box.position = [10, 0, 5]; // 设置位置
box.scale = [1.5, 1.5, 1.5]; // 缩放
box.rotation = [0, 45, 0]; // 旋转(欧拉角)
// 动画移动
box.moveTo([15, 5, 10], {
time: 2000, // 毫秒
easing: 'Quadratic.InOut'
});
对象查询:
// 通过名称查询
const obj = app.query('myBox')[0];
// 通过类型查询
const lights = app.query(/Light/);
// 通过条件查询
const bigObjects = app.query({
type: 'Mesh',
condition: 'object.scale.x > 1.5'
});
第三章 基础开发实战
3.1 第一个ThingJS应用
完整示例:智慧园区监控:
// 初始化应用
const app = new THING.App({
background: '#F0F0F0',
skyBox: 'SkyBox1'
});
// 加载园区场景
app.load('/scenes/smart-park').then((scene) => {
// 创建监控摄像头
const camera = app.create({
type: 'Camera',
name: 'surveillance-cam',
position: [50, 20, 0],
target: [0, 0, 0]
});
// 添加设备标签
camera.addComponent({
type: 'Tag',
text: '监控点#01',
style: {
color: '#FFFFFF',
backgroundColor: '#3366FF'
}
});
// 点击事件
camera.on('click', (ev) => {
app.camera.flyTo({
target: camera,
time: 1000,
complete: function() {
showCameraFeed(camera);
}
});
});
});
function showCameraFeed(camera) {
// 显示监控画面逻辑
const panel = new THING.widget.Panel({
title: '实时监控',
width: '300px',
height: '200px'
});
panel.addString('摄像头ID', camera.name).captionStyle({
color: '#333'
});
// 模拟视频流
const video = document.createElement('video');
video.src = '/assets/videos/sample.mp4';
video.autoplay = true;
panel.addDOM(video);
}
3.2 事件系统详解
事件类型:
- 鼠标事件:click, dblclick, mouseenter, mouseleave
- 触摸事件:touchstart, touchmove, touchend
- 对象生命周期:create, destroy, show, hide
- 自定义事件:可任意定义和触发
事件绑定与解绑:
// 绑定事件
obj.on('click', function(ev) {
console.log('对象被点击', ev.object);
});
// 一次性事件
obj.once('click', function(ev) {
console.log('只会触发一次');
});
// 事件解绑
const handler = function(ev) { /*...*/ };
obj.on('click', handler);
obj.off('click', handler);
// 触发自定义事件
obj.trigger('alarm', {
level: 'high',
message: '温度过高!'
});
事件冒泡与拦截:
// 事件冒泡示例
parent.on('click', function(ev) {
console.log('父对象收到事件', ev.target);
});
child.on('click', function(ev) {
console.log('子对象事件');
ev.stopPropagation(); // 阻止冒泡
});
// 事件拦截
app.on('click', function(ev) {
if (shouldIgnore(ev)) {
ev.preventDefault(); // 阻止默认行为
}
});
3.3 基础动画实现
变换动画:
// 移动动画
obj.moveTo([x, y, z], {
time: 1000, // 持续时间(ms)
easing: 'Linear', // 缓动函数
complete: function() {
console.log('移动完成');
}
});
// 旋转动画
obj.rotateTo([x, y, z], {
time: 2000,
easing: 'Elastic.Out'
});
// 缩放动画
obj.scaleTo([x, y, z], {
time: 500
});
关键帧动画:
// 创建动画剪辑
const clip = new THING.AnimationClip({
name: 'moveAndRotate',
duration: 3000,
tracks: [
{
type: 'position',
keys: [
{ time: 0, value: [0, 0, 0] },
{ time: 1000, value: [10, 0, 0] },
{ time: 3000, value: [10, 5, 10] }
]
},
{
type: 'rotation',
keys: [
{ time: 0, value: [0, 0, 0] },
{ time: 3000, value: [0, 360, 0] }
]
}
]
});
// 播放动画
const mixer = new THING.AnimationMixer(obj);
const action = mixer.clipAction(clip);
action.play();
第二部分:ThingJS中级开发
第四章 场景设计与优化
4.1 复杂场景构建
分层加载策略:
// 分步加载大型场景
async function loadLargeScene() {
// 1. 先加载基础结构
await app.load('/scenes/base-structure');
// 2. 加载建筑外观
await app.load('/scenes/buildings-exterior');
// 3. 加载室内场景(按需)
app.on('click', '.building', (ev) => {
ev.object.load('/scenes/interior/' + ev.object.name);
});
// 4. 最后加载动态元素
loadDynamicElements();
}
场景组织技巧:
// 使用空对象作为容器
const floor1 = app.create({
type: 'Object3D',
name: 'floor1-container'
});
// 将相关对象添加到容器
const desk1 = createDesk();
const chair1 = createChair();
floor1.add(desk1);
floor1.add(chair1);
// 整体操作
floor1.position = [0, 3, 0]; // 移动整个楼层
4.2 性能优化策略
渲染性能优化:
- LOD(层级细节):
app.create({
type: 'LOD',
levels: [
{ distance: 0, object: highDetailModel },
{ distance: 50, object: mediumDetailModel },
{ distance: 100, object: lowDetailModel }
]
});
- 视锥裁剪:
// 在thingjs.config.js中配置
module.exports = {
renderer: {
frustumCulling: true, // 启用视锥裁剪
maxRenderDistance: 500 // 最大渲染距离
}
};
内存优化:
// 对象池管理
const objectPool = {
desks: [],
init(count) {
for (let i = 0; i < count; i++) {
this.desks.push(createDesk());
this.desks[i].visible = false;
}
},
getDesk() {
const desk = this.desks.find(d => !d.visible);
if (desk) {
desk.visible = true;
return desk;
}
return createDesk();
}
};
第五章 高级交互实现
5.1 复杂事件处理
手势识别:
let touchStartTime;
let startPosition;
obj.on('touchstart', (ev) => {
touchStartTime = Date.now();
startPosition = obj.position.clone();
});
obj.on('touchmove', (ev) => {
// 计算移动距离
const delta = ev.deltaPosition;
obj.position = [
startPosition[0] + delta[0],
startPosition[1],
startPosition[2] + delta[1]
];
});
obj.on('touchend', (ev) => {
// 判断快速滑动
if (Date.now() - touchStartTime < 300) {
const speed = ev.speed;
// 添加惯性移动效果
addInertiaMovement(speed);
}
});
射线检测:
app.on('click', (ev) => {
const rayCaster = new THING.Raycaster();
const ray = rayCaster.setFromCamera(ev.screenPosition, app.camera);
const intersects = rayCaster.intersectObjects(scene.children);
if (intersects.length > 0) {
console.log('击中的对象:', intersects[0].object);
}
});
5.2 UI系统集成
原生UI组件:
// 创建控制面板
const panel = new THING.widget.Panel({
title: '设备控制',
width: '300px',
height: 'auto',
position: [20, 20]
});
// 添加控件
panel.addBoolean('开启照明', false).onChange((value) => {
toggleLights(value);
});
panel.addSlider('温度调节', 22, 16, 30, 1).onChange((value) => {
setTemperature(value);
});
// 自定义HTML内容
panel.addHTML('<div class="alert">警告区域</div>');
与外部UI框架集成:
// Vue集成示例
const vueApp = new Vue({
el: '#vue-ui-container',
data: {
deviceStatus: {}
},
methods: {
handleControl(command) {
// 调用ThingJS接口
app.query(command.target).forEach(obj => {
obj[command.method](...command.args);
});
}
}
});
// ThingJS事件触发Vue更新
app.on('deviceUpdate', (ev) => {
vueApp.deviceStatus = ev.data;
});
第六章 数据可视化
6.1 数据驱动场景
数据绑定示例:
// 模拟设备数据
const devices = [
{ id: 'device1', type: 'sensor', position: [10, 2, 5], value: 25.6 },
{ id: 'device2', type: 'camera', position: [15, 3, -8], status: 'online' }
];
// 数据绑定到3D对象
function bindDataToObjects() {
devices.forEach(device => {
const obj = app.create({
type: device.type === 'sensor' ? 'Sphere' : 'Camera',
name: device.id,
position: device.position,
size: [1, 1, 1]
});
// 存储原始数据
obj.userData = device;
// 根据数据更新状态
updateObjectByData(obj);
});
}
// 数据更新处理
function onDataUpdate(newData) {
const obj = app.query(newData.id)[0];
if (obj) {
Object.assign(obj.userData, newData);
updateObjectByData(obj);
}
}
function updateObjectByData(obj) {
const data = obj.userData;
if (data.type === 'sensor') {
// 根据值改变颜色
const color = data.value > 30 ? '#FF0000' : '#00FF00';
obj.style.color = color;
// 更新标签
obj.getComponent('Tag').text = `${data.value}°C`;
}
}
6.2 高级可视化技术
热力图实现:
function createHeatmap(points, options = {}) {
const { radius = 10, max = 100 } = options;
const geometry = new THING.HeatmapGeometry({
points: points.map(p => ({
position: p.position,
intensity: p.value / max
})),
radius
});
const material = new THING.HeatmapMaterial({
gradient: {
0.0: '#0000FF',
0.5: '#00FF00',
1.0: '#FF0000'
}
});
return new THING.Mesh(geometry, material);
}
// 使用示例
const sensorData = [
{ position: [0, 0, 0], value: 30 },
{ position: [5, 0, 3], value: 45 },
// 更多数据点...
];
const heatmap = createHeatmap(sensorData, { radius: 15 });
app.scene.add(heatmap);
动态路径可视化:
class DynamicPath {
constructor(points, options = {}) {
this.options = {
width: 0.5,
color: '#00FFFF',
dash: [1, 0.5],
speed: 1,
...options
};
this.line = createLine(points);
this.animateFlow();
}
createLine(points) {
const geometry = new THING.BufferGeometry().setFromPoints(points);
const material = new THING.LineDashedMaterial({
color: this.options.color,
linewidth: this.options.width,
dashSize: this.options.dash[0],
gapSize: this.options.dash[1]
});
return new THING.Line(geometry, material);
}
animateFlow() {
let offset = 0;
app.on('update', () => {
offset += 0.01 * this.options.speed;
this.line.material.dashOffset = -offset;
});
}
}
第三部分:ThingJS高级精通
第七章 自定义扩展开发
7.1 自定义组件开发
组件开发规范:
// 温度传感器组件
THING.Component.register('TemperatureSensor', {
// 组件属性
properties: {
warningThreshold: 30,
criticalThreshold: 40,
unit: '°C'
},
// 生命周期
onAttach: function() {
// 组件附加到对象时调用
this.object.style.color = '#00FF00';
this.label = this.object.addComponent('Tag', {
text: this.getDisplayText()
});
// 定时更新
this.timer = setInterval(() => this.updateReading(), 5000);
},
onDetach: function() {
// 组件移除时清理
clearInterval(this.timer);
this.object.removeComponent(this.label);
},
// 自定义方法
updateReading: function() {
// 模拟数据更新
const newValue = 25 + Math.random() * 20;
this.object.userData.temperature = newValue;
// 更新显示
this.label.text = this.getDisplayText();
// 触发事件
if (newValue > this.warningThreshold) {
this.object.trigger('temperatureWarning', {
value: newValue,
status: newValue > this.criticalThreshold ? 'critical' : 'warning'
});
}
},
getDisplayText: function() {
return `${this.object.userData.temperature.toFixed(1)}${this.unit}`;
}
});
// 使用组件
const sensor = app.create({ type: 'Sphere' });
sensor.addComponent('TemperatureSensor', {
warningThreshold: 28,
criticalThreshold: 35
});
7.2 着色器开发
自定义材质示例:
// 创建自定义着色器材质
const customShader = {
uniforms: {
time: { value: 0 },
mainColor: { value: new THING.Color(0x00ff00) },
waveSpeed: { value: 1.0 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float time;
uniform vec3 mainColor;
uniform float waveSpeed;
varying vec2 vUv;
void main() {
float wave = sin(vUv.x * 10.0 + time * waveSpeed) * 0.5 + 0.5;
vec3 color = mix(mainColor, vec3(1.0), wave * 0.3);
gl_FragColor = vec4(color, 1.0);
}
`
};
// 使用自定义材质
const material = new THING.ShaderMaterial(customShader);
const mesh = new THING.Mesh(new THING.BoxGeometry(), material);
// 更新uniforms
app.on('update', () => {
material.uniforms.time.value += 0.01;
});
第八章 项目架构与工程化
8.1 大型项目组织
模块化架构:
src/
├── core/ # 核心模块
│ ├── app.js # 应用初始化
│ ├── scene-manager.js # 场景管理
│ └── event-bus.js # 全局事件总线
├── modules/ # 功能模块
│ ├── equipment/ # 设备管理
│ ├── monitoring/ # 监控系统
│ └── analytics/ # 分析模块
├── assets/ # 资源管理
│ ├── models/ # 3D模型
│ ├── textures/ # 纹理贴图
│ └── configs/ # 配置文件
└── utils/ # 工具函数
状态管理实现:
// 基于事件总线的状态管理
class StateManager {
constructor() {
this.state = {
devices: {},
alarms: [],
viewMode: 'default'
};
this.eventBus = new THING.EventEmitter();
}
setState(path, value) {
const parts = path.split('.');
let current = this.state;
for (let i = 0; i < parts.length - 1; i++) {
current = current[parts[i]];
}
current[parts[parts.length - 1]] = value;
this.eventBus.emit('stateChange', { path, value });
}
subscribe(path, callback) {
this.eventBus.on('stateChange', ({ path: changedPath, value }) => {
if (changedPath.startsWith(path)) {
callback(this.getState(path));
}
});
}
getState(path) {
return path.split('.').reduce((obj, key) => obj[key], this.state);
}
}
// 使用示例
const state = new StateManager();
state.setState('viewMode', 'expert');
state.subscribe('devices', (devices) => {
updateDeviceVisualization(devices);
});
8.2 性能分析与调优
性能分析工具:
class PerformanceMonitor {
constructor() {
this.stats = {
fps: 0,
renderTime: 0,
objectCount: 0
};
this.frames = 0;
this.lastTime = performance.now();
app.on('update', this.update.bind(this));
}
update() {
this.frames++;
const now = performance.now();
// 每秒计算一次FPS
if (now >= this.lastTime + 1000) {
this.stats.fps = Math.round(
(this.frames * 1000) / (now - this.lastTime)
);
this.frames = 0;
this.lastTime = now;
// 收集其他指标
this.stats.objectCount = app.scene.children.length;
this.stats.renderTime = app.renderer.info.render.time;
console.table(this.stats);
}
}
startProfiling(name) {
console.time(name);
}
endProfiling(name) {
console.timeEnd(name);
}
}
// 使用示例
const monitor = new PerformanceMonitor();
monitor.startProfiling('SceneLoad');
app.load('/scenes/large-scene').then(() => {
monitor.endProfiling('SceneLoad');
});
第九章 实战项目:智慧园区综合管理系统
9.1 项目需求分析
核心功能需求:
- 三维场景展示:完整呈现园区建筑、设施和设备的3D模型
- 设备监控:实时显示IoT设备状态和数据(温湿度、能耗等)
- 告警管理:可视化呈现设备告警及定位
- 人员管理:展示人员位置和移动轨迹
- 数据分析:多维度的数据统计和可视化
技术指标:
- 支持同时展示1000+设备对象
- 数据更新延迟<1秒
- 主流浏览器60FPS流畅运行
- 场景加载时间<5秒(首次)
9.2 系统实现
架构设计:
[前端]
├── ThingJS 3D引擎
├── Vue.js 管理后台
└── ECharts 数据可视化
[后端]
├── Node.js API网关
├── Kafka 消息队列
└── 时序数据库
核心实现代码:
// 主应用入口
class SmartCampusApp {
constructor() {
this.app = new THING.App({
background: '#F5F5F5',
skyBox: 'SkyBox2'
});
this.initModules();
this.setupEventHandlers();
}
initModules() {
this.sceneManager = new SceneManager(this.app);
this.deviceManager = new DeviceManager(this.app);
this.alarmSystem = new AlarmSystem(this.app);
this.dataAnalytics = new DataAnalytics(this.app);
}
setupEventHandlers() {
// 设备选择事件
this.app.on('click', '.device', (ev) => {
this.deviceManager.showDevicePanel(ev.object);
});
// 告警处理
this.alarmSystem.on('newAlarm', (alarm) => {
this.sceneManager.highlightObject(alarm.deviceId);
this.showAlarmNotification(alarm);
});
}
}
// 设备管理模块
class DeviceManager {
constructor(app) {
this.app = app;
this.devices = new Map();
// 从API加载设备数据
this.loadDevices();
}
async loadDevices() {
const response = await fetch('/api/devices');
const devices = await response.json();
devices.forEach(device => {
const obj = this.createDeviceObject(device);
this.devices.set(device.id, obj);
});
}
createDeviceObject(device) {
const obj = this.app.create({
type: this.getDeviceType(device),
name: device.id,
position: device.position,
userData: device
});
// 添加状态指示器
obj.addComponent('StatusIndicator', {
getStatus: () => device.status
});
return obj;
}
}
第四部分:扩展与未来
第十章 ThingJS高级主题
10.1 跨平台开发
移动端适配策略:
// 响应式设计
function setupResponsive() {
// 根据屏幕尺寸调整UI
const updateUI = () => {
const isMobile = window.innerWidth < 768;
// 调整相机位置
app.camera.position = isMobile
? [0, 50, 100]
: [0, 30, 70];
// 调整控制方式
app.camera.controller.type = isMobile
? 'Orbit'
: 'FirstPerson';
// 调整UI尺寸
panel.style.fontSize = isMobile ? '14px' : '16px';
};
window.addEventListener('resize', updateUI);
updateUI();
}
// 触摸优化
function optimizeForTouch() {
// 增大点击区域
app.query('.device').forEach(obj => {
obj.userData.clickableArea = 1.5;
});
// 简化交互
app.camera.controller.touchZoomSensitivity = 0.5;
}
10.2 与GIS系统集成
地理坐标转换:
class GISConverter {
constructor(origin, scale = 1) {
this.origin = origin; // 地理坐标系原点
this.scale = scale; // 单位换算比例
}
// WGS84转场景坐标
project(lng, lat) {
// 简化的墨卡托投影
const x = (lng - this.origin.lng) * this.scale;
const y = (lat - this.origin.lat) * this.scale;
return [x, 0, -y]; // Z轴取反
}
// 场景坐标转WGS84
unproject(x, z) {
const lng = x / this.scale + this.origin.lng;
const lat = -z / this.scale + this.origin.lat;
return { lng, lat };
}
}
// 使用示例
const converter = new GISConverter(
{ lng: 116.404, lat: 39.915 }, // 天安门坐标
1000 // 1度=1000单位
);
const scenePos = converter.project(116.408, 39.916);
const obj = app.create({
type: 'Flag',
position: scenePos
});
第十一章 最佳实践与常见问题
11.1 性能优化清单
关键优化策略:
资源优化:
- 使用压缩纹理(.ktx2格式)
- 模型面数控制在5万面以内
- 使用Draco压缩的GLB模型
渲染优化:
// thingjs.config.js module.exports = { renderer: { antialias: true, shadowMap: { enabled: true, type: 'PCFSoft' // 柔和阴影 }, precision: 'mediump' // 移动端使用 } };
内存管理:
// 释放不再使用的资源 function cleanup() { // 销毁对象 obj.destroy(); // 释放纹理 texture.dispose(); // 清理几何体 geometry.dispose(); }
11.2 常见问题解决方案
典型问题与解决:
场景加载慢:
- 使用
THING.LoadingManager
显示进度 - 实现分块加载
- 预加载关键资源
- 使用
内存泄漏:
// 错误示例(会导致内存泄漏) app.on('update', function() { // 频繁创建对象 const temp = new THING.Object3D(); }); // 正确做法 const reusableObjects = []; function getTempObject() { return reusableObjects.pop() || new THING.Object3D(); }
点击事件不触发:
- 检查对象
visible
和pickable
属性 - 确认没有其他对象遮挡
- 检查事件冒泡是否被阻止
- 检查对象