使用pixi.js开发一个智慧路口(车辆轨迹追踪)项目
项目效果
项目功能:
- 位置更新、航向角计算。
- debug模式。
- 位置角度线性补帧。
- 变道、转弯、碰撞检测。
- mock轨迹数据
图片效果:
视频效果:
项目启动
项目地址
- github:(github.com/huoguozhang…)
- 线上:todo
(如果觉得项目对你有帮助的话, 可以给我一个star 和 赞,❤️)
启动demo项目
- cd
car-tracking-2d/demos/react-demo
yarn
yarn start
界面使用
debug 模式
浏览器url ?后面(search部分)加入参数debug=1
例如:http://localhost:3000/home?tunnelNo=tunnel1&debug=1
将会展示调试信息:
如图:车旁边的白色文字信息为debug模式才会展示的内容(由上到下为:里程、车id、车道id、[x,y]
、旋转角度)
实现:
技术栈:
ts
+pixi.js
+任意前端框架
(前端框架使用vue
和react
或者其他框架都可以。只需要在mounted
阶段,实例化我们暴露出来class
即可。然后在destroyed
或者unmounted
阶段destory
示例即可,后面会提到。)
pixi.js
官网介绍:
Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.
pixi.js是一个2D的WebGL的渲染库。但是没有three.js知名度高。一个原因是,我们2D的需求技术路线很多,可以是dom、svg、canvas draw api等,包括本项目也可以使用其他技术方案实现,希望通过本文,大家在实现这种频繁更新元素位置的功能,可以考虑一下pixi.js。
API快速讲解
这里只讲我们项目使用到的
Application
import * as PIXI from 'pixi.js';
const app = new PIXI.Application({
view: canvasDom // canvas dom 对象
});
Container
容器,功能为一个组。
当我们设置容器的scale(缩放)、rotation(旋转)、x、y(位置)时。里面的元素都会收到影响。
(ps:app.stage
也是一个Container
)
每个 Container
可以通过addChild
(增加子节点)、removeChild
(删除子节点),也可以设置子元素的zIndex
(和css的功能一致)。子原始的scale(缩放)、rotation(旋转)、x、y(位置)是相对于Container的。
Sprite
精灵,渲染图片对象。
carObj = Sprite.from('/car.svg')
Sprite.from(url)
,url相同的话,只会加载一次图片。纹理对象也只会创建一次。
anchor
属性其他对象也有,设置定位点,类似于css
的transform-origin
。
执行下面代码carObj.anchor.set(0.5, 0.5)
如果x = 10 y =10,carObj的中心点的坐标就是(10,10),旋转原点也是(10,10),缩放也是如此。
Graphics
绘制几何图形,圆弧,曲线、直线等都可以。也支持fill和stroke,canvas draw api支持的,Graphics都支持。
Text
文本,比较简单。字体、颜色、大小,都支持。
- 值得注意的是文本内容含有换行符时(
\n \r
),文本会换行。 - pixi提供测量文本的width height的方法非常好用。
Tick
this.app.ticker.add(() => {})
类似于requestAnimationFrame
具体实现
分三步,vue/react都一样:
1 获取canvas dom通过ref的方式。
2 创建我们封装Stage Road
3 组件销毁时,执行 stage.destroy
(注意stage是我封装的,不是pixi的。使用方不需要使用pixi.js的api)
线性插帧
当有一个对象由坐标 点a(0,0
)变换到点b(1000,1000)
,1秒内完成。
中间的变化值为:dx =1000 dy=1000
记录每帧的时间差t(当前帧距离第0帧的,单位毫秒)
所以第n帧位置信息为(0+dx / 1000 * t, 0+ dy /1000 *t)
角度变换也是这个道理。
位置坐标获取
如果直线长度为1000px
,对应的实际里程为100米。
当跑了50米,当前就是直线的中点坐标。
弯道呢,通过弧度可以推算出坐标。
可以把 Road.ts line 70的注释取消。
// 方便开发观察 绘制车道线 ---begin----
// this.mount(lane.centerLine.paint())
航向角
直线简单,通过Math.atan2
可以求出来。
弯道需要通过解析几何,计算出圆弧切线,然后推测出航向角。
转弯
可以查看我们标注的一些点
以1到7的弯道举例,相当于是从新创建一次车道,车道的点是车道1和车道7的组合。
我们通过 circle
属性配置,在创建Road
时
{
uid: '1-2',
x: 1072,
y: 1605,
circle: {
// 编号形式 车道序号-第几个点
linkId: '7-3'
}
},
这条信息表示:车道1的第2个点(uid
),有圆弧链接到车道7的第3个点(circle.linkId
)
碰撞检测
我们这个项目的特点是,前端展示,实际后端返回什么数据,我们就展示什么数据。(一般不需要前端处理)。
这里我们mock的数据就简单处理一下。判断是否存在相交的线段(当前对象的位置和将要到达的点),如果线段相交,车辆暂停移动。
来源:juejin.cn/post/7327467832866095130