• three.js通过canvas实现球体世界平面地图


    概况如下:

    1、SphereGeometry实现自转的地球;

    2、THREE.CatmullRomCurve3实现球体线条地图点确定;

    3、THREE.Math.degToRadMath.sinMath.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.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);

    通过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.fillRect(0, 0, w, h);
    13     // canvas中绘制地图方法
    14     function canvasLineFun (childrenPosition) {
    15         context.fillStyle = earthBallPlaneColor;
    16         context.moveTo(centerX + childrenPosition[0][0] * average, centerY - childrenPosition[0][1] * average);
    17         childrenPosition.forEach(function (posItem) {
    18             context.lineTo(centerX + posItem[0] * average, centerY - posItem[1] * average);
    19         })
    20         context.closePath();
    21         context.fill();
    22     }
    23     worldPos.forEach(function (item) {
    24         canvasLineFun(item);
    25     })
    26     return canvas;
    27 }

    定义地球及其材质,地球通过SphereGeometry来实现,通过THREE.CanvasTexture来引入canvas创建的贴图。

    1 // 创建地球
    2 earthBall = new THREE.Mesh(new THREE.SphereGeometry(earthBallSize, 50, 50), new THREE.MeshBasicMaterial({
    3     map: new THREE.CanvasTexture(createCanvas(2048, 1024, worldGeometry)),
    4     side: THREE.FrontSide
    5 }));
    6 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 }

    绘制世界地图线条方法

     1 // 绘制世界地图线条函数
     2 var drawWorldLine = function (pos, identify) {
     3     var posArray = [];
     4     pos.forEach(function (item) {
     5         var pointPosition = getPosition(item[0] + 90, item[1], earthBallSize);
     6         posArray.push(new THREE.Vector3(pointPosition.x, pointPosition.y, pointPosition.z));
     7     })
     8     // 绘制的线条需要关闭,第二个参数默认为false,表示不关闭
     9     var curve = new THREE.CatmullRomCurve3(posArray, true);
    10     var points = curve.getPoints(500);
    11     var geometry = new THREE.Geometry().setFromPoints(points);
    12     // 定义线条
    13     var line = new MeshLine();
    14     line.setGeometry(geometry);
    15     // 定义线条材质
    16     var material = new MeshLineMaterial({
    17         color: worldLineColor,
    18         lineWidth: worldLineWidth
    19     })
    20     // 绘制地图
    21     lineGeometryObj['lineGeometry' + identify] = new THREE.Mesh(line.geometry, material);
    22     // 将地图加入场景
    23     scene.add(lineGeometryObj['lineGeometry' + identify])
    24 }

    获取世界地图经纬度信息及计算绘制球体地图参数方法

     1 // 获取世界经纬度信息函数
     2 var getWorldGeometry = function () {
     3     $.ajax({ 
     4          type : "GET", //提交方式 
     5          url : "./code/world.json",
     6          async: false,
     7          success : function(response) {//返回数据根据结果进行相应的处理 
     8              worldGeometry = [];
     9              // 绘制世界地图
    10             response.features.forEach(function (worldItem, worldItemIndex) {
    11                 var length = worldItem.geometry.coordinates.length;
    12                 var multipleBool = length > 1 ? true : false;
    13                 worldItem.geometry.coordinates.forEach(function (worldChildItem, worldChildItemIndex) {
    14                     if (multipleBool) {
    15                         // 值界可以使用的经纬度信息
    16                         if (worldChildItem.length && worldChildItem[0].length == 2) {
    17                             worldGeometry.push(worldChildItem);
    18                         }
    19                         // 需要转换才可以使用的经纬度信息
    20                         if (worldChildItem.length && worldChildItem[0].length > 2) {
    21                             worldChildItem.forEach(function (countryItem, countryItenIndex) {
    22                                 worldGeometry.push(countryItem);
    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.push(countryPos);
    34                         }
    35                     }
    36                 })
    37             })
    38          } 
    39     })
    40 }

    球体地图线条通过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 }
  • 相关阅读:
    重启sqlserver服务命令
    k8s学习
    collection包1.1.0都升级了什么功能
    Golang项目的测试实践
    一个让业务开发效率提高10倍的golang库
    GopherChina第二天小结
    GopherChina第一天小结
    slice是什么时候决定要扩张?
    史上最快的后台搭建框架
    gorm的日志模块源码解析
  • 原文地址:https://www.cnblogs.com/gaozhiqiang/p/11470441.html
Copyright © 2020-2023  润新知