概况如下:
1、SphereGeometry
实现自转的地球;
2、THREE.Math.degToRad
,Math.sin
,Math.cos
实现地图经纬度与三位坐标x,y,z之间的转换;
3、ImageUtils
加载球体贴图;
4、THREE.CubicBezierCurve3
创建标记立体轨迹,调用getPoints
将轨迹分成需要的段数;
5、轨迹中根据分段数与相应国家gdp值来实现标记。
效果图如下:
预览地址:three.js实现球体地球2018年全球GDP前十国际标记
初始化场景、相机、渲染器,设置相机位置,初始化光源,光源采用HemisphereLight
,设置光源位置为场景中心位置,并将光源加入场景中。
1 // 初始化场景 2 var scene = new THREE.Scene(); 3 // 初始化相机,第一个参数为摄像机视锥体垂直视野角度,第二个参数为摄像机视锥体长宽比, 4 // 第三个参数为摄像机视锥体近端面,第四个参数为摄像机视锥体远端面 5 var camera = new THREE.PerspectiveCamera(20, dom.clientWidth / dom.clientHeight, 1, 100000); 6 // 设置相机位置,对应参数分别表示x,y,z位置 7 camera.position.set(0, 0, 200); 8 var renderer = new THREE.WebGLRenderer({ 9 alpha: true, 10 antialias: true 11 }); 12 // 设置光照 13 scene.add(new THREE.HemisphereLight('#ffffff', '#ffffff', 1));
设置场景窗口尺寸,并且初始化控制器,窗口尺寸默认与浏览器窗口尺寸保持一致,最后将渲染器加载到dom中。
1 // 设置窗口尺寸,第一个参数为宽度,第二个参数为高度 2 renderer.setSize(dom.clientWidth, dom.clientHeight); 3 // 初始化控制器 4 var orbitcontrols = new THREE.OrbitControls(camera,renderer.domElement); 5 // 将渲染器加载到dom中 6 dom.appendChild(renderer.domElement);
定义地球及其材质,地球通过SphereGeometry
来实现,通过ImageUtils
来导入贴图。
1 // 定义地球材质,earthImg表示地图贴图地址 2 var earthTexture = THREE.ImageUtils.loadTexture(earthImg, {}, function () { 3 renderer.render(scene, camera); 4 }); 5 // 创建地球 6 earthBall = new THREE.Mesh(new THREE.SphereGeometry(earthBallSize, 50, 50), new THREE.MeshBasicMaterial({ 7 map: earthTexture 8 })); 9 scene.add(earthBall);
标记地点经纬度坐标与三维x,y,z坐标转换方法。
1 // 经纬度转换函数,longitude表示经度,latitude表示唯独,radius表示球体半径 2 var getPosition = function (longitude, latitude, radius) { 3 // 将经度,纬度转换为rad坐标 4 var lg = THREE.Math.degToRad(longitude); 5 var lt = THREE.Math.degToRad(latitude); 6 var temp = radius * Math.cos(lt); 7 // 获取x,y,z坐标 8 var x = temp * Math.sin(lg); 9 var y = radius * Math.sin(lt); 10 var z = temp * Math.cos(lg); 11 return { 12 x: x, 13 y: y, 14 z: z 15 } 16 }
标记分段通过THREE.Group
来将多个分段节点集合成一个,通过getPosition
将标记点的经纬度转换为三维x,y,z坐标。
1 // 标记函数,marking表示需要标记地点的经纬度信息,标记值 2 var markingPoint = function (marking) { 3 // 将经纬度信息转换为三维x,y,z坐标 4 var pos = getPosition(marking.pos[0] + 90, marking.pos[1], earthBallSize); 5 var _pos = getPosition(marking.pos[0] + 90, marking.pos[1], earthBallSize + marking.value); 6 // 根据转换的信息通过三次贝塞尔曲线实现轨迹 7 var curve = new THREE.CubicBezierCurve3(pos, pos, _pos, _pos); 8 // 在轨迹中分出100各节点 9 var points = curve.getPoints(100); 10 // 创建一个集合,用于存放分段的节点信息 11 var aGroup = new THREE.Group(); 12 points.forEach(function (pointItem, index) { 13 var radius = 0.5 - index * 0.005; 14 // 创建分段节点处的类 15 var aGeo = new THREE.SphereGeometry(radius, 5, 5); 16 // 创建分段节点处类的材质 17 var aMater = new THREE.MeshPhongMaterial({ 18 color: marking.color, 19 transparent: true, 20 opacity: 1 - index * 0.01 21 }) 22 var aMesh = new THREE.Mesh(aGeo, aMater); 23 // 根据计算出的经纬度信息确认分段节点的位置 24 aMesh.position.set(pointItem.x, pointItem.y, pointItem.z); 25 aGroup.add(aMesh); 26 }) 27 markingGroup.add(aGroup); 28 }
标记地点通过position
值来实现位置的确认,动画使用requestAnimationFrame
来实现。
1 // 执行函数 2 var render = function () { 3 scene.rotation.y -= 0.01; 4 renderer.render(scene, camera); 5 orbitcontrols.update(); 6 requestAnimationFrame(render); 7 }