背景
前不久参与了公司的客户大会项目中,其中就有一个需求是要绘制一副关于北京市怀柔区的地图,和本篇文章所用的例子虽不同,但是开发过程都是一样的。在项目中,我用的是Echarts图表库进行开发,最后实现的效果算是满意。因为Echarts详细的文档,丰富的API,和良好的社区环境,易于上手等优点,让我在客户大会开发过程中因需求紧,开发周期短对窘境下,依然可以完成对地图的开发。
Echarts底层依赖矢量图形库ZRender ,ZRender它提供Canvas,SVG,VML等多种渲染方式,因此Echarts就可以提供直观,交互丰富,可高度个性化定制的数据可视化图表。因为ZRender是一个二维引擎,所以Echarts实现三维图表就要引入基于WebGL的Echarts GL js库,这样就可以跟使用 ECharts 普通组件一样轻松的使用 ECharts GL 绘制出三维的地球,建筑群,人口分布的柱状图等三维图表!
上文中可以得知Echarts要实现三维效果需要额外引入基于三维渲染引擎的js库,那么有没有是不需要额外引入其他js库的就可以实现3D效果的可视化库呢?答案是肯定的!这个可视化库就是Three.js。
之前在工作群中有看到部门总监提出让开发学习如何绘制“3D汽车模型”,同时Three.js可以实现[物联网3D可视化](http://www.yanhuangxueyuan.com/3D/liangcang/index.html)、[产品720在线预览](http://app.xuanke3d.com/apps/trayton/#/show)、[数据可视化](http://www.yanhuangxueyuan.com/3D/geojsonChina/index.html)、[WebVR](http://www.yanhuangxueyuan.com/3D/houseDesign/index.html)等场景功能。这让身处用户体验部可视化小组的我慢慢的产生了学习Three.js的兴趣。
认识Three.js
WebGL是在浏览器中实现三维效果的一套规范,而最初使用WebGL原生的API来写3D程序是一件非常痛苦的事情,所以就有了非常优秀的WebGl开源框架three.js的出现。
Three.js可以这样理解:Three表示3D的意思,js表示JavaScript的意思。那么合起来,就是使用JavaScript来写3D程序的意思。
如果我们需要使用Three.js来绘图,只需要创建一个最小的绘图环境即可。Threejs在底层其实还是调用html5中的canvas api来实现绘图的。但和我们一般绘制2D图像不同,Threejs在底层使用的是canvas的webgl context来实现3D 绘图。webgl context本身更多是直接对GPU的操作,用起来相当不直观,为此Three.js在顶层对3D绘图所需的各种元素进行封装。
Three.js三大组件
- 场景(Scene): 场景是用来容纳图形元素,包含所有需要显示的3D物体以及其他相关元素的容器。
- 相机(Camera):相机的作用是决定3D场景如何投影到2D画布之上,定义可视区域,确定哪些图形元素是可见的。
- 渲染器(Renderer):渲染器则负责用如何渲染出图像,是使用WebGL还是Canvas,用于最后绘制的画笔。
场景Scene
在Threejs中场景就只有一种,用THREE.Scene来表示,要构件一个场景也很简单,只要new一个对象就可以了。
var scene = new THREE.Scene()
相机Camera
相机决定了场景中那个角度的景色会显示出来。场景只有一种,但是相机却有很多种。和生活中的相机不同,Threejs中的相机只要设置不同的相机参数,就能够产生不一样的效果。
定义一个相机的代码:
var camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight, 0.1, 1000)
three.js有几种相机,这里使用的是PerspectiveCamera(透视摄像机)。第一个参数是视野角度(Fov),视野角度 就是无论在什么时候,所能在显示器上看到的场景的范围,它的值是角度单位。第二个参数是长宽比。接下来两个参数是近截面(near)和远截面(far)。当物体某些部分比摄像机当远截面远或者比近截面近的时候,将这些部分不渲染到场景中。
渲染器Renderer
渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。定义一个WebRenderer渲染器:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的尺寸。比如说,我们可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满我们的应用程序。因此,我们可以将渲染器宽高设置为浏览器窗口宽高。对于性能比较敏感的应用程序来说,你可以使用setSize传入一个较小的值,例如window.innerWidth/2和window.innerHeight/2,这将使得应用程序在渲染时,以一半的长宽尺寸渲染场景。
渲染器renderer的domElement元素,表示渲染器中画布,所有的渲染都画在domElement上的,所以这里的appendChild表示将这个domElement挂载在body下面,这样渲染的结果就能够在页面中显示出来。
通过例子来深入讲解
接下来对上述例子进行详细解析:
如何获得three.min.js文件
- git clone https://github.com/mrdoob/three.js.git
- cd ./three.js
- npm install
- npm run build
该文件就在three.js/build/three.min.js下
部分代码分析
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
- 要创建一个立方体,我们需要一个BoxGeometry(立方体)对象,这个对象包含了一个立方体中所有的顶点(vertices)和面(faces)。
- 对于这个立方体,需要给它一个材质让它有颜色。MeshBasicMaterial就是自带的几种材质之一,这里只简单设置了一个颜色属性。
- 需要一个Mesh(网格),网格包含一个几何体以及作用在此几何体上的材质,然后将网格对象放入到我们到场景中,并让它在场景中自由移动。
- 默认情况下,当我们调用scene.add()的时候,物体将会被添加到(0,0,0)坐标,但将使得摄像机和立方体彼此在一起。为了防止这种情况发生,就需要将摄像机稍微向外移动一点距离,这里是5。
var animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
如果将前面的代码复制到HTML文件中页面是不会看到任何东西。这是因为没有对它进行真正到渲染。我们还需要一个叫做“渲染循环”(render loop)或者“动画循环”(animate loop)的东西。在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制对循环,这里不用setInterval而用requestAnimationFrame最重要对一点或许是当用户切换到其他标签页时,会暂停,因此不会浪费用户处理器资源和损耗电池寿命。
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
进行真正的渲染后,可以看到是一个绿色的方块。而上面的代码就是让它旋转起来。这段代码每帧都会执行(正常情况下是60次/秒),这就让立方体有一个看起来很不错的旋转动画。
用Three.js制作一个世界地图
Three.js可以实现3D效果,同样也可以实现2D效果,只需要把一些组件参数进行配置完好就行。
在线编辑例子
关于Three.js的其他技巧学习可以参考官方文档:Three.js
用Echarts绘制世界地图
上述我们用Three.js实现了一个二维可以通过鼠标进行缩放的世界地图,接下来我们用Echarts同样实现一个世界地图。
总结
Echarts 是一个基于JS的数据可视化的图表工具。可将数据以地图、直方图、折线图、点状图、饼状图等方式展现出来,并且效果非常炫酷。Three.js更倾向于制作3D方面的效果,如之前很火的微信小程序游戏-跳一跳就是用Three.js开发的。在前面所提及的世界地图的例子中,用Three.js开发入门略微复杂,要对Three.js文档有一定对熟悉程度;用Echarts就无需对文档过于熟悉,只需要对某个图表对配置项进行学习进行配置就好。比如我们需求是要绘制一个饼图,那么我们就只需要在官方文档找到饼图对配置信息进行学习并完成配置,配置信息也是通俗易懂。所以我们平时做可视化前端需求对时候,如果需求开发周期过于短,我们可以考虑易上手对Echarts;如果开发周期长且需要高度定制化的图表,我们可以好好研究一下Three.js,并用以完成开发。
写这篇文章并非要揪出一个可视化图库的好坏,存在即合理。纯粹作为一个开发者,想让自身技术得以提升,毕竟兴趣是最好的老师,入门了一下Three.js让我有很浓厚的兴致继续学习下去。