概况如下:
1、SphereGeometry
实现自转的地球;
2、THREE.CatmullRomCurve3
实现球体线条地图点确定;
3、THREE.Math.degToRad
,Math.sin
,Math.cos
实现地图经纬度与三位坐标x,y,z之间的转换;
4、MeshLine
用于绘制线条;
5、canvas
用于绘制球体世界地图贴图,通过THREE.CanvasTexture
引入。
效果图如下:
预览地址:three.js通过canvas实现球体世界平面地图
初始化场景、相机、渲染器,设置相机位置,初始化光源,光源采用HemisphereLight
,设置光源位置为场景中心位置,并将光源加入场景中。
1 // 初始化场景 2 var scene = new THREE.Scene); 3 // 初始化相机,第一个参数为摄像机视锥体垂直视野角度,第二个参数为摄像机视锥体长宽比, 4 // 第三个参数为摄像机视锥体近端面,第四个参数为摄像机视锥体远端面 5 var camera = new THREE.PerspectiveCamera20, dom.clientWidth / dom.clientHeight, 1, 100000); 6 // 设置相机位置,对应参数分别表示x,y,z位置 7 camera.position.set0, 0, 200); 8 var renderer = new THREE.WebGLRenderer{ 9 alpha: true, 10 antialias: true 11 }); 12 // 设置光照 13 scene.addnew THREE.HemisphereLight'#ffffff', '#ffffff', 1));
设置场景窗口尺寸,并且初始化控制器,窗口尺寸默认与浏览器窗口尺寸保持一致,最后将渲染器加载到dom中。
1 // 设置窗口尺寸,第一个参数为宽度,第二个参数为高度 2 renderer.setSizedom.clientWidth, dom.clientHeight); 3 // 初始化控制器 4 var orbitcontrols = new THREE.OrbitControlscamera,renderer.domElement); 5 // 将渲染器加载到dom中 6 dom.appendChildrenderer.domElement);
通过canvas
定义地球材质。
1 // canvas画地图函数,因为性能问题,线条不再canvas中实现,w表示宽度,h表示高度,worldPos表示世界地图经纬度信息 2 var createCanvas = function w, h, worldPos) { 3 var canvas = document.createElement'canvas'); 4 canvas.width = w; 5 canvas.height = h; 6 var context = canvas.getContext'2d'); 7 var centerX = w / 2; 8 var centerY = h / 2; 9 var average = w / 360; 10 // 绘制背景颜色 11 context.fillStyle = earthBallColor; 12 context.fillRect0, 0, w, h); 13 // canvas中绘制地图方法 14 function canvasLineFun childrenPosition) { 15 context.fillStyle = earthBallPlaneColor; 16 context.moveTocenterX + childrenPosition[0][0] * average, centerY - childrenPosition[0][1] * average); 17 childrenPosition.forEachfunction posItem) { 18 context.lineTocenterX + posItem[0] * average, centerY - posItem[1] * average); 19 }) 20 context.closePath); 21 context.fill); 22 } 23 worldPos.forEachfunction item) { 24 canvasLineFunitem); 25 }) 26 return canvas; 27 }
定义地球及其材质,地球通过SphereGeometry
来实现,通过THREE.CanvasTexture
来引入canvas
创建的贴图。
1 // 创建地球 2 earthBall = new THREE.Meshnew THREE.SphereGeometryearthBallSize, 50, 50), new THREE.MeshBasicMaterial{ 3 map: new THREE.CanvasTexturecreateCanvas2048, 1024, worldGeometry)), 4 side: THREE.FrontSide 5 })); 6 scene.addearthBall);
标记地点经纬度坐标与三维x,y,z坐标转换方法。
1 // 经纬度转换函数,longitude表示经度,latitude表示唯独,radius表示球体半径 2 var getPosition = function longitude, latitude, radius) { 3 // 将经度,纬度转换为rad坐标 4 var lg = THREE.Math.degToRadlongitude); 5 var lt = THREE.Math.degToRadlatitude); 6 var temp = radius * Math.coslt); 7 // 获取x,y,z坐标 8 var x = temp * Math.sinlg); 9 var y = radius * Math.sinlt); 10 var z = temp * Math.coslg); 11 return { 12 x: x, 13 y: y, 14 z: z 15 } 16 }
绘制世界地图线条方法
1 // 绘制世界地图线条函数 2 var drawWorldLine = function pos, identify) { 3 var posArray = []; 4 pos.forEachfunction item) { 5 var pointPosition = getPositionitem[0] + 90, item[1], earthBallSize); 6 posArray.pushnew THREE.Vector3pointPosition.x, pointPosition.y, pointPosition.z)); 7 }) 8 // 绘制的线条需要关闭,第二个参数默认为false,表示不关闭 9 var curve = new THREE.CatmullRomCurve3posArray, true); 10 var points = curve.getPoints500); 11 var geometry = new THREE.Geometry).setFromPointspoints); 12 // 定义线条 13 var line = new MeshLine); 14 line.setGeometrygeometry); 15 // 定义线条材质 16 var material = new MeshLineMaterial{ 17 color: worldLineColor, 18 lineWidth: worldLineWidth 19 }) 20 // 绘制地图 21 lineGeometryObj['lineGeometry' + identify] = new THREE.Meshline.geometry, material); 22 // 将地图加入场景 23 scene.addlineGeometryObj['lineGeometry' + identify]) 24 }
获取世界地图经纬度信息及计算绘制球体地图参数方法
1 // 获取世界经纬度信息函数 2 var getWorldGeometry = function ) { 3 $.ajax{ 4 type : "GET", //提交方式 5 url : "./code/world.json", 6 async: false, 7 success : functionresponse) {//返回数据根据结果进行相应的处理 8 worldGeometry = []; 9 // 绘制世界地图 10 response.features.forEachfunction worldItem, worldItemIndex) { 11 var length = worldItem.geometry.coordinates.length; 12 var multipleBool = length > 1 ? true : false; 13 worldItem.geometry.coordinates.forEachfunction worldChildItem, worldChildItemIndex) { 14 if multipleBool) { 15 // 值界可以使用的经纬度信息 16 if worldChildItem.length && worldChildItem[0].length == 2) { 17 worldGeometry.pushworldChildItem); 18 } 19 // 需要转换才可以使用的经纬度信息 20 if worldChildItem.length && worldChildItem[0].length > 2) { 21 worldChildItem.forEachfunction countryItem, countryItenIndex) { 22 worldGeometry.pushcountryItem); 23 }) 24 } 25 } else { 26 var countryPos = null; 27 if worldChildItem.length > 1) { 28 countryPos = worldChildItem; 29 } else { 30 countryPos = worldChildItem[0]; 31 } 32 if countryPos) { 33 worldGeometry.pushcountryPos); 34 } 35 } 36 }) 37 }) 38 } 39 }) 40 }
球体地图线条通过position
值来实现位置的确认,动画使用requestAnimationFrame
来实现。
1 // 执行函数 2 var render = function ) { 3 scene.rotation.y -= 0.01; 4 renderer.renderscene, camera); 5 orbitcontrols.update); 6 requestAnimationFramerender); 7 }