概況如下:
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
,設置光源位置爲場景中心位置,並將光源加入場景中。
// 初始化場景
var scene = new THREE.Scene();
// 初始化相機,第一個參數爲攝像機視錐體垂直視野角度,第二個參數爲攝像機視錐體長寬比,
// 第三個參數爲攝像機視錐體近端面,第四個參數爲攝像機視錐體遠端面
var camera = new THREE.PerspectiveCamera(20, dom.clientWidth / dom.clientHeight, 1, 100000);
// 設置相機位置,對應參數分別表示x,y,z位置
camera.position.set(0, 0, 200);
var renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
// 設置光照
scene.add(new THREE.HemisphereLight('#ffffff', '#ffffff', 1));
設置場景窗口尺寸,並且初始化控制器,窗口尺寸默認與瀏覽器窗口尺寸保持一致,最後將渲染器加載到dom
中。
// 設置窗口尺寸,第一個參數爲寬度,第二個參數爲高度
renderer.setSize(dom.clientWidth, dom.clientHeight);
// 初始化控制器
var orbitcontrols = new THREE.OrbitControls(camera,renderer.domElement);
// 將渲染器加載到dom中
dom.appendChild(renderer.domElement);</pre>
</div>
通過canvas
定義地球材質。
// canvas畫地圖函數,因爲性能問題,線條不再canvas中實現,w表示寬度,h表示高度,worldPos表示世界地圖經緯度信息
var createCanvas = function (w, h, worldPos) {
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
var context = canvas.getContext('2d');
var centerX = w / 2;
var centerY = h / 2;
var average = w / 360;
// 繪製背景顏色
context.fillStyle = earthBallColor;
context.fillRect(0, 0, w, h);
// canvas中繪製地圖方法
function canvasLineFun (childrenPosition) {
context.fillStyle = earthBallPlaneColor;
context.moveTo(centerX + childrenPosition[0][0] * average, centerY - childrenPosition[0][1] * average);
childrenPosition.forEach(function (posItem) {
context.lineTo(centerX + posItem[0] * average, centerY - posItem[1] * average);
})
context.closePath();
context.fill();
}
worldPos.forEach(function (item) {
canvasLineFun(item);
})
return canvas;
}
定義地球及其材質,地球通過SphereGeometry
來實現,通過THREE.CanvasTexture
來引入canvas
創建的貼圖。
// 創建地球
earthBall = new THREE.Mesh(new THREE.SphereGeometry(earthBallSize, 50, 50), new THREE.MeshBasicMaterial({
map: new THREE.CanvasTexture(createCanvas(2048, 1024, worldGeometry)),
side: THREE.FrontSide
}));
scene.add(earthBall);
標記地點經緯度座標與三維x,y,z座標轉換方法。
// 經緯度轉換函數,longitude表示經度,latitude表示唯獨,radius表示球體半徑
var getPosition = function (longitude, latitude, radius) {
// 將經度,緯度轉換爲rad座標
var lg = THREE.Math.degToRad(longitude);
var lt = THREE.Math.degToRad(latitude);
var temp = radius * Math.cos(lt);
// 獲取x,y,z座標
var x = temp * Math.sin(lg);
var y = radius * Math.sin(lt);
var z = temp * Math.cos(lg);
return {
x: x,
y: y,
z: z
}
}
繪製世界地圖線條方法
// 繪製世界地圖線條函數
var drawWorldLine = function (pos, identify) {
var posArray = [];
pos.forEach(function (item) {
var pointPosition = getPosition(item[0] + 90, item[1], earthBallSize);
posArray.push(new THREE.Vector3(pointPosition.x, pointPosition.y, pointPosition.z));
})
// 繪製的線條需要關閉,第二個參數默認爲false,表示不關閉
var curve = new THREE.CatmullRomCurve3(posArray, true);
var points = curve.getPoints(500);
var geometry = new THREE.Geometry().setFromPoints(points);
// 定義線條
var line = new MeshLine();
line.setGeometry(geometry);
// 定義線條材質
var material = new MeshLineMaterial({
color: worldLineColor,
lineWidth: worldLineWidth
})
// 繪製地圖
lineGeometryObj['lineGeometry' + identify] = new THREE.Mesh(line.geometry, material);
// 將地圖加入場景
scene.add(lineGeometryObj['lineGeometry' + identify])
}
獲取世界地圖經緯度信息及計算繪製球體地圖參數方法。
// 獲取世界經緯度信息函數
var getWorldGeometry = function () {
$.ajax({
type : "GET", //提交方式
url : "./code/world.json",
async: false,
success : function(response) {//返回數據根據結果進行相應的處理
worldGeometry = [];
// 繪製世界地圖
response.features.forEach(function (worldItem, worldItemIndex) {
var length = worldItem.geometry.coordinates.length;
var multipleBool = length > 1 ? true : false;
worldItem.geometry.coordinates.forEach(function (worldChildItem, worldChildItemIndex) {
if (multipleBool) {
// 值界可以使用的經緯度信息
if (worldChildItem.length && worldChildItem[0].length == 2) {
worldGeometry.push(worldChildItem);
}
// 需要轉換纔可以使用的經緯度信息
if (worldChildItem.length && worldChildItem[0].length > 2) {
worldChildItem.forEach(function (countryItem, countryItenIndex) {
worldGeometry.push(countryItem);
})
}
} else {
var countryPos = null;
if (worldChildItem.length > 1) {
countryPos = worldChildItem;
} else {
countryPos = worldChildItem[0];
}
if (countryPos) {
worldGeometry.push(countryPos);
}
}
})
})
}
})
}
球體地圖線條通過position
值來實現位置的確認,動畫使用requestAnimationFrame
來實現。
// 執行函數
var render = function () {
scene.rotation.y -= 0.01;
renderer.render(scene, camera);
orbitcontrols.update();
requestAnimationFrame(render);
}