大家好,我是王大傻。最近一直在学光哥的Nest,想着是学完后搭配Three自己写一个可视化的完整项目,但看到很多小伙伴不知道可视化项目怎么构造,大傻就按照自己的理解给大家举几个可视化的例子。
前期准备
在文章开始大傻首先列举下此次文章主要完成的效果以及使用的技术栈,另代码的地址也会双手给大家呈上,整体效果展示(PS:大傻的GPU配置不太好,看起来不太流畅)
效果展示
- 3D驾驶舱效果
- svg线条动画
- 楼层展开收起效果
本文示例使用的技术栈
- Three
- Vue
- Vite
- gsap
项目地址以及目录结构
项目地址在Github上。
目录结构如下:
我们整体设计为在Src下面建立一个three目录,在three目录下对初始化的内容进行拆分,如:动画、场景、相机等。如下图所示:
中期开发
3D驾驶舱效果
首先是我们的驾驶舱效果
如上图所示,我们的驾驶舱是有3D场景以及我们的操作面板组成的,那么是如何结合到一块的呢?且听大傻娓娓道来。
首先我们是两个页面:
这样大家都知道了,是用CSS的定位,将3D场景置于底层,然后我们通过对操作页面的定位使其悬浮到表层,在这我们需要注意的是
样式调整
首先我们的样式方面,CSS在划分层后,我们的首层操作区域因为在最高层,从而会导致我们的3D区域出现无法拖动,无法响应事件的操作,这是我们需要加上一个很重要的CSS属性 pointer-events: none; 这个属性将会使得我们操作界面的所有事件失效,这样我们便可以操作我们的3D场景的拖动等效果,当然,如果全局设置了这个属性,也会使我们操作界面的内容无法正确执行。这时候我们需要
在我们需要执行事件的地方进行放开pointer-events属性,这样我们就可以正常操作我们的操作面板区域
通讯问题
我们操作面板和我们的3D场景分属于两个不同的页面,那么我们当然需要一个中间桥梁进行通讯操作,因为大傻这里使用的是Vue,所以
这里我们用了Mitt进行中间通讯,他的使用也很简单,首先我们在3D场景中的将某些变化封装为一个函数,并将这个函数暴露出来:
eventHub.on('showFloor1', (data) => {
---
})
比如我们将这个精灵点击事件暴露,同样的我们需要在操作面板通过emit去接受。
const showFloor1 = () => {
camera.position.set(100, 100, 100);
camera.updateMatrix()
eventHub.emit("showFloor1");
};
这样我们就能通过操作面板进行3D场景的数据、视图改变
Svg线条动画
我们前端如果想要页面酷炫,那必定动画少不了。在此大傻就介绍几个Svg的动画,如下所示
此处我们有两个svg的效果,其一我们导航下面有个线条,从中间开始向两边扩散,其二是我们左边的logo,细看有一个个小点不断地重构新的颜色。那么我们先说第一个:
<svg xmlns="http://www.w3.org/2000/svg" :width="size.width + 'rem'" height="100%" version="1.1">
<defs>
<radialGradient id="grad1" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" style="stop-color: pink; stop-opacity: 1" />
<stop offset="100%" style="stop-color: #1cd; stop-opacity: 0.2" />
</radialGradient>
</defs>
<symbol id="linePathSymbol">
<path stroke-width="3" ref="path" fill="transparent" :d="path_content" />
<path stroke-width="3" fill="transparent" :d="path_content1" />
<path stroke="#e7c80e" fill="transparent" :d="path_content2" />
<path stroke="#e7c80e" fill="transparent" :d="path_content3" />
</symbol>
<g>
<use xlink:href="#linePathSymbol" class="path"></use>
<circle x="0" y="0" r="6" fill="url(#grad1)">
<animateMotion :path="path_content" dur="5" begin="0s" fill="freeze" retate="auto" repeatDur="indefinite" />
</circle>
<circle x="0" y="0" r="6" fill="url(#grad1)">
<animateMotion :path="path_content1" dur="5" begin="0s" fill="freeze" retate="auto" repeatDur="indefinite" />
</circle>
</g>
</svg>
这里简单介绍下,defs标签是为了包裹一些图形的复用,正如我们这里的radialGradient是个圆形元素,然后在Svg中id也是必不可少的,我们可以在g标签里面通过fill来规定填充的是那个元素,而path标签则是对路径的描述。
接下来我们再来看一段代码:
这里出现了很多标签,那他们究竟代表什么呢
- M 代表 MoveTo 移动到 两个参数 x,y x代表x 坐标 y代表y 坐标
- L 代表 LineTo 划线到 两个参数x,y x代表x坐标 y 代表y坐标
- H 代表 HorizonTo 代表水平位置 一个参数 代表水平位置
- V 代表 VerticalTo 代表垂直方向 一个参数 代表垂直位置
因此我们再看这个svg动画,其实用语言描述下来就是,从中间出发,在2.9的时候记录一个位置,然后由这个位置向上移动12个单位接下来我们在通过H变化为水平移动,在4的位置继续打点,向上移动。最后我们通过H来定义最终移动到的距离。其次在animateMotion标签上我们通过dur 以及begin 来约束我们的小球跟随运动并且开始以及持续时间。看到这大家是不是豁然开朗。接下来我们再说下logo的动画
.path1 {
stroke: #f5f5f5;
stroke-width: 6px;
stroke-dashoffset: 7%;
stroke-dasharray: 0 35%;
fill: transparent;
animation: animation 15s ease-in-out infinite;
}
@keyframes animation {
0% {
stroke-dashoffset: 7%;
stroke-dasharray: 0 35%;
fill: transparent;
}
50% {
stroke-dasharray: 7% 7%;
stroke-dashoffset: 7%;
fill: #fff;
}
100% {
stroke-dashoffset: 7%;
stroke-dasharray: 0 35%;
fill: transparent;
}
}
logo主要是通过CSS进行变动,在这,我们用到了svg特有的 stroke-dashoffset 和 stroke-dasharray属性,其中
- stroke-dashoffset:这个属性是相对于起始点的偏移,正数偏移x值的时候,相当于往左移动了x个长度单位,负数偏移x的时候,相当于往右移动了x个长度单位。需要注意的是,不管偏移的方向是哪边,要记得dasharray 是循环的,也就是 虚线-间隔-虚线-间隔。 这个属性要搭配stroke-dashoffset才能看得出来效果,非虚线的话,是无法看出偏移的。
- stroke-dasharray:这个属性用于创建虚线,之所以后面跟的是array的,是因为值其实是数组
也就是我们上面写法,我们可以用实际的宽高px 也可以用百分比去控制。至此我们的简单的Svg动画也已经完成
楼层展开收起效果
楼层的展开收起效果其实这个需要看我们的3D模型是怎么设计,根据设计的不同实现起来也不同,如果我们在模型里面做好了动画,那么就可以通过在载入模型时候遍历出来他的动画进行运动,在此,大傻使用的是三个模型,因此需要手动改变。
举例说明,这里我们通过visible属性使得其他的隐藏,然后通过模型的position改变呈现给我们展开收起的效果。
结语
相信大家通过看了这篇文章后,也可以自己写一下可视化大屏的页面,当然很多细节例如适配问题这些大家可以通过google自行解决,其次还有如果写的是类似地图的页面:
如上所示,大家可以采用geoJson拿到地理位置信息,在通过echarts的gl板块进行渲染,如果是更为复杂的地理信息,建议可以使用cesium进行开发。