前端3D地球的实现方式

     想到3D,我最想想到的是WebGL,但是通过对WebGL的学习了解,实现地球效果很难达到。

1、用echarts gl实现

    其次还有echarts GL,做过图表的应该知道echarts,echarts是一个不错的做图表的框架,他安装简单,使用便捷。echarts GL是echarts用来实现三维图标的工具,他是可以实现3D的效果的。

实现步骤如下:

1、从官网上下载echarts.min.js和echarts-gl.min.js文件,引入到html 页面中
<script type="text/javascript" src="js/echarts.min.js"></script>
<script type="text/javascript" src="js/echarts-gl.min.js"></script>
//后续会用到,这里先引入
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/map/js/china.js"></script>

2、为地球创建一个id为earth的div容器

3、下面就是关键的js代码实现功能了,我们先创建一个地球

var dom = document.getElementById("earth")
//关键的三步:创建一个echarts实例、设置属性option、将实例和option联动
var myChart = echarts.init(dom);
option = {
  globe:{
    show:true,
    shading:"color",
    //视角控制:
    viewControl:{
      //projection:"orthographic",
      rotateSensitivity:0, //鼠标旋转灵敏度
      zoomSensitivity:0,//鼠标缩放灵敏度
      autoRotate:true,//地球是否自传
      autoRotateAfterStill:0.001,//鼠标停止后多久恢复旋转(为0时暂停后不恢复旋转)
      //alpha:160,//视角绕 x 轴,即上下旋转的角度
      //beta:-20,//视角绕 y 轴,即左右旋转的角度。
      targetCoord: [116.46, 39.92]//定位到哪里
    }
  },
};
if (option && typeof option === "object") {
  myChart.setOption(option, true);
}

4、现在只是创建了一个球,但是没有地图信息,echarts还提供了一些地图信息,有世界地图和中国地球等,我们将这些信息绘制到地球上。现在我们有了球了,还差一个贴图,我们可以自由通过canvas绘制。

// 使用 echarts 绘制世界地图的实例作为纹理
var canvas = document.createElement('canvas');
var mapChart = echarts.init(canvas, null, {
  width: 4096, height: 2048
});
mapChart.setOption({
  series : [
    {
      type: 'map',
      map: 'world',//world是html页面引入的地图文件名字
      // 绘制完整尺寸的 echarts 实例
      top: 0, left: 0,
      right: 0, bottom: 0,
      silent:true,//图形是否不响应和触发鼠标事件,默认为 false,即响应和触发鼠标事件。
      boundingCoords: [[-180, 90], [180, -90]],
      label:{
        textStyle:{
          color:"#fff",
          fontSize:50
        }
      },
      emphasis:{
        itemStyle:{
          color:"#2038cc"
        }
      }
    }
  ]
});
5、把自己写的地图贴图效果放到地球上,完整代码如下
var dom = document.getElementById("earth")
var myChart = echarts.init(dom);

// 使用 echarts 绘制世界地图的实例作为纹理
var canvas = document.createElement('canvas');
var mapChart = echarts.init(canvas, null, {
  width: 4096, height: 2048
});
mapChart.setOption({
  series : [
    {
      type: 'map',
      map: 'world',
      // 绘制完整尺寸的 echarts 实例
      top: 0, left: 0,
      right: 0, bottom: 0,
      silent:true,//图形是否不响应和触发鼠标事件,默认为 false,即响应和触发鼠标事件。
      boundingCoords: [[-180, 90], [180, -90]],
      label:{
        textStyle:{
          color:"#fff",
          fontSize:50
        }
      },
      emphasis:{
        itemStyle:{
          color:"#2038cc"
        }
      }
    }
  ]
});

option = {
  globe:{
    show:true,
    baseTexture: mapChart,
    //heightTexture:mapChart,
      shading:"color",
    //视角控制
    viewControl:{
      //projection:"orthographic",
        /*damping:0,*/
      rotateSensitivity:0, //鼠标旋转灵敏度
      zoomSensitivity:0,//鼠标缩放灵敏度
      autoRotate:true,
      autoRotateAfterStill:0.001,//鼠标停止后多久恢复旋转(为0时暂停后不恢复旋转)
      //alpha:160,//视角绕 x 轴,即上下旋转的角度
      //beta:-20,//视角绕 y 轴,即左右旋转的角度。
      targetCoord: [116.46, 39.92]//定位到哪里
    }
  },

};
if (option && typeof option === "object") {
  myChart.setOption(option, true);
}

此时实现的效果如下:

              

2、用cesium实现

   用echarts GL实现的效果不是很满意,继续尝试,发现了cesium,cesium可以直接调用地图。

 1、cesium引入的框架相对比较繁琐,可以下载了cesium后把Build\CesiumUnminified的内容全部拷贝到你的项目里。这个时候你会发现改文件很大,不是很适合,其实里面有很大是用不到的,可以删除。(怎么保留自己有用的呢?当你功能实现后,你可以把cesium.js文件先移出项目,运行后通过控制台看找不到的文件,把这些文件移入项目,多次执行,一直都没有错误为止)。

2、开始实现功能,先在html页面引入cesium.js文件,引入Widgets/widgets.css样式,并创建一个id为cesiumEarth的div容器。

3、下面开始创建地球,cesium的优点是可以引入地图文件,这里引入了天地图

var viewer = new Cesium.Viewer( 'cesiumEarth', {
    //需要进行可视化的数据源的集合
    animation: false,  //是否显示动画控件
    homeButton : false,//是否显示Home按钮
    fullscreenButton : false,//是否显示全屏按钮
    baseLayerPicker: false, //是否显示图层选择控件
    geocoder: false, //是否显示地名查找控件
    timeline: false, //是否显示时间线控件
    sceneModePicker: false, //是否显示投影方式控件
    navigationHelpButton: false, //是否显示帮助信息控件
    infoBox: false,  //是否显示点击要素之后显示的信息
    //天地图是官方开元的地图,不需要密钥
    imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
        url: "http://{s}.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
        layer: "img",
        style: "default",
        format: "tiles",
        tileMatrixSetID: "w",
        credit:new Cesium.Credit('天地图全球影像服务'),
        subdomains:['t0',"t1","t2","t3","t4","t5","t6","t7"],
        maximumLevel:18,
        show: false
    })
} );
注:地图服务有矢量图和影像服务可以根据你的需求选择,上面引入的是影像服务,下面是矢量图服务
imageryProvider : new Cesium.WebMapTileServiceImageryProvider({
        url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
        layer: "tdtVecBasicLayer",
        style: "default",
        format: "image/jpeg",
        tileMatrixSetID: "GoogleMapsCompatible",
        show: false
    })

4、这个时候你会发现,只有一个地球,没有地名的标注,我们还需要引入中文地名标注。

//全球影像中文注记服务
viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
    url: "http://t0.tianditu.com/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg",
    layer: "tdtAnnoLayer",
    style: "default",
    format: "image/jpeg",
    tileMatrixSetID: "GoogleMapsCompatible",
    show: false
}));
//全球矢量中文标注服务
viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
    url: "http://t0.tianditu.com/cva_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg",
    layer: "tdtAnnoLayer",
    style: "default",
    format: "image/jpeg",
    tileMatrixSetID: "GoogleMapsCompatible"
}));
5、这个时候看着比较美观了。框架中有很多控件,如果不需要可以通过上面3中设置为false,就不在显示。但是左下角的logo和连接是没办法去掉的,但是可以通过修改css样式进行修改
.cesium-viewer-bottom{
            display: none;
        }
6、项目本身就有鼠标操作的事件,有时候我们会需要取消这些事件自己定义。
// 禁用默认的事件处理程序
// 如果为真,则允许用户旋转相机。如果为假,相机将锁定到当前标题。此标志仅适用于2D和3D。
scene.screenSpaceCameraController.enableRotate = false;
// 如果为true,则允许用户平移地图。如果为假,相机将保持锁定在当前位置。此标志仅适用于2D和Columbus视图模式。
scene.screenSpaceCameraController.enableTranslate = false;
// 如果为真,允许用户放大和缩小。如果为假,相机将锁定到距离椭圆体的当前距离
scene.screenSpaceCameraController.enableZoom = false;
// 如果为真,则允许用户倾斜相机。如果为假,相机将锁定到当前标题。这个标志只适用于3D和哥伦布视图。
scene.screenSpaceCameraController.enableTilt = false;
// 如果为true,则允许用户使用免费外观。如果错误,摄像机视图方向只能通过转换或旋转进行更改。此标志仅适用于3D和哥伦布视图模式。
scene.screenSpaceCameraController.enableLook = false;
//自定义鼠标事件
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
// 接收用户鼠标(手势)事件
// 处理鼠标按下事件
handler.setInputAction(function(movement) {
    // movement: 接收值为一个对象,含有鼠标单击的x,y坐标
    // 设置鼠标当前位置
    mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 处理鼠标移动事件
handler.setInputAction(function(movement) {
    // 更新鼠标位置
    mousePosition = movement.endPosition;
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 处理鼠标左键弹起事件
handler.setInputAction(function(position) {
   //此时鼠标位置position
}, Cesium.ScreenSpaceEventType.LEFT_UP);
7、控制相机运动
camera.flyTo( {
            destination : Cesium.Cartesian3.fromDegrees(nowPoint.lng, nowPoint.lat, cameraH ),//使用WGS84
            orientation : {
                heading : Cesium.Math.toRadians( 0 ),
                pitch : Cesium.Math.toRadians( -90 ),
                roll : Cesium.Math.toRadians( 0 )
            },
            duration : 3,//动画持续时间
            complete : function()//飞行完毕后执行的动作
            {
                // addEntities();
                canCont=true;
                canFly=true;
            },
            pitchAdjustHeight: -90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。
            maximumHeight:5000 // 相机最大飞行高度
        } );
8、通过点击获取位置,并将相机移动过去
function flyToPoint(point) {
    //将屏幕坐标转换为世界坐标
    var pick= new Cesium.Cartesian2(point.x,point.y);
    var cartesian = scene.globe.pick(viewer.camera.getPickRay(pick), scene);
    //世界坐标转地理坐标(弧度)
    var cartographic = scene.globe.ellipsoid.cartesianToCartographic(cartesian);
    //地理坐标(弧度)转经纬度坐标
    var nowPoint={lng:cartographic.longitude / Math.PI * 180,
                  lat:cartographic.latitude / Math.PI * 180};
    //获取当前相机高度
    var cameraH=Math.ceil(viewer.camera.positionCartographic.height);
    if(cameraH>1000000){
        cameraH=Math.ceil(cameraH/5);
    }else if(cameraH>10000){
        cameraH=Math.ceil(cameraH/4);
    }else if(cameraH>2000){
        cameraH=cameraH-2500
    }
    if(cameraH>=2000 && canFly){
        canFly=false;
        camera.flyTo( {
            destination : Cesium.Cartesian3.fromDegrees(nowPoint.lng, nowPoint.lat, cameraH ),//使用WGS84
            orientation : {
                heading : Cesium.Math.toRadians( 0 ),
                pitch : Cesium.Math.toRadians( -90 ),
                roll : Cesium.Math.toRadians( 0 )
            },
            duration : 3,//动画持续时间
            complete : function()//飞行完毕后执行的动作
            {
              
            },
            pitchAdjustHeight: -90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。
            maximumHeight:5000 // 相机最大飞行高度
        } );
    }

}
创建的3D地球效果图如下:








猜你喜欢

转载自blog.csdn.net/zhou8023ddw/article/details/80705065