Cesium开发实践

西安小哥
English

做了大概三个月的基于cesium地图开发的应用场景和大屏;主要想从cesium基本的入门到一些简单的场景交互做一个代码分享。

Cesium是三维地图开发的一个前端gis引擎;支持wtms、影像、模型、地形、倾斜摄影的数据加载。并通过对点线面、材质、视角等图形学知识对它进行一个真实三维场景的一个复现。
包括一些最

  • 基本的创建地图、创建点位、点位聚合、数据源组、创建图层、加载gif,相机视角;
  • 加载图层、绘制点、线、面,调节情景参数;
  • 对接天地图、高德地图、百度地图;
  • 事件:点击事件、移除事件、移除事件、拖拽事件
  • 弹框:视频弹框、详情弹框、报警弹框
  • 轨迹:动态轨迹、轨迹漫游
  • 流线图:喷泉、流线图
  • 热力图
  • 场景:模拟下雪、下雨、雷达图
  • 基本工具箱:放大、缩小,定位、画线
  • kml、geojson文件转换和加载
  • 性能优化
  • 常用工具方法

    1、基本的创建地图

 viewer = new Cesium.Viewer('maps', {
                    animation: false, //是否创建动画小器件,左下角仪表
                    baseLayerPicker: false, //是否显示图层选择器
                    fullscreenButton: false, //是否显示全屏按钮
                    geocoder: false, //是否显示geocoder小器件,右上角查询按钮
                    homeButton: false, //是否显示Home按钮
                    infoBox: false, //是否显示信息框
                    sceneModePicker: false, //是否显示3D/2D选择器
                    selectionIndicator: false, //是否显示选取指示器组件
                    timeline: false, //是否显示时间轴
                    sceneMode: Cesium.SceneMode.SCENE3D, //设定3维地图的默认场景模式:Cesium.SceneMode.SCENE2D、Cesium.SceneMode.SCENE3D、Cesium.SceneMode.MORPHING
                    navigationHelpButton: false, //是否显示右上角的帮助按钮
                    scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
                    navigationInstructionsInitiallyVisible: false,
                    showRenderLoopErrors: false, //是否显示渲染错误
                    shouldAnimate: true,//允许动画 //这个得必须有!
                })
  • 创建的点位:
- layer && layer.entities.add({
                            id: item.id,
                            name: item.name,
                            type: "marker",
                            featureType: type,
                            feature: item.feature,
                            lon: item.lon,
                            lat: item.lat,
                            mapTools: tools,//地图右边按钮
                            position: Cesium.Cartesian3.fromDegrees(parseFloat(lon), parseFloat(lat), height),
                            billboard: {
                                image: new Cesium.CallbackProperty(() => {
                                    return _self.superGif.get_canvas().toDataURL("image/png");
                                }, false),
                                scale: 1,
                                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                                width: 60,
                                height: imageheight
                            },
                            label: {
                                text: type == "wrj" ? `${item.name}` : "",
                                font: '14pt 微软雅黑',
                                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                                // backgroundColor: Cesium.Color.YELLOW,
                                // showBackground: true,
                                outlineColor: new Cesium.Color.fromCssColorString("tranparent"),
                                fillColor: new Cesium.Color.fromCssColorString("#fff"),
                                outlineWidth: 5,
                                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                                pixelOffset: new Cesium.Cartesian2(-110, -25)
                            },

                        })
  • 点位聚合
    image.png

    function addPoint(Entities, featureKey, viewer,markersLayer) {
    // let markersLayer = new Cesium.CustomDataSource(featureKey.layer_name)
    
    for (let i = 0; i < Entities.length; i++) {
      let _data = Entities[i]
      // let _strokeColor = JSON.parse(featureKey.strokeColor);
      // let _fillColor = JSON.parse(featureKey.fillColor);
      let lon = _data.lon || _data.longitude,
        lat = _data.lat || _data.latitude
      let cartographic = Cesium.Cartographic.fromDegrees(lon, lat)
      let height = viewer.scene.globe.getHeight(cartographic),
        scale = 0.4
      let image = require(`@static/biz/event/event.png`)
      let width = 60,
        imageheight = 60
      if (!lon || !lat) return
      width = 47
      imageheight = 59
      switch (_data.equipmentType) {
        case 0:
          image = require(`@static/biz/type/icon-qiangji.png`)
          break
        default:
          image = require(`@static/biz/type/icon-ball.png`)
          break
      }
      markersLayer.entities.add({
        name: _data.name,
        id: 'point_' + featureKey.layer_name + '_' + _data.id,
        featureData: _data,
        type: 'marker',
        position: Cesium.Cartesian3.fromDegrees(lon, lat, height),
        _lng: lon,
        _lat: lat,
        _obj: _data,
        billboard: {
          image: image,
          scale: 0.9,
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          width: width,
          height: imageheight
        }
      })
    }
    
    var dataSourcePromise = viewer.dataSources.add(markersLayer)
    dataSourcePromise.then(function(dataSource) {
      // alert(dataSource.name);
      var pixelRange = 105
      var minimumClusterSize = 3
      var enabled = featureKey.clusters_enabled
      if (enabled === 'false') {
        enabled = false
      } else {
        enabled = true
      }
      console.log(featureKey)
      dataSource.clustering.enabled = enabled
      dataSource.clustering.pixelRange = pixelRange
      dataSource.clustering.minimumClusterSize = minimumClusterSize
    
      var removeListener
      
      // var pinBuilder = new Cesium.PinBuilder()
    
      // var singleDigitPins = new Array(8)
      // for (var i = 0; i < singleDigitPins.length; ++i) {
      //   singleDigitPins[i] = pinBuilder
      //     .fromText('' + (i + 2), Cesium.Color.fromCssColorString(featureKey.clusters_color), 48)
      //     .toDataURL()
      // }
      // var pinBuilder = new Cesium.PinBuilder();
      // var pin200 = pinBuilder.fromText('200+', Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
      // var pin50 = pinBuilder.fromText('50+', Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
      // var pin40 = pinBuilder.fromText('40+', Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
      // var pin30 = pinBuilder.fromText('30+',Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
      // var pin20 = pinBuilder.fromText('20+', Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
      // var pin10 = pinBuilder.fromText('10+', Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
      function customStyle() {
        if (Cesium.defined(removeListener)) {
          removeListener()
          removeListener = undefined
        } else {
          removeListener = dataSource.clustering.clusterEvent.addEventListener(function(clusteredEntities, cluster) {
           
            // cluster.billboard.show = false
            // cluster.billboard.id = cluster.label.id
            // cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM
            cluster.point.show= true;
            cluster.point.outlineColor= Cesium.Color.fromCssColorString(featureKey.clusters_color).withAlpha(0.2);
            cluster.point.color= Cesium.Color.fromCssColorString("#2d87f9");
            cluster.point.pixelSize= 35;
            cluster.point.outlineWidth= 5;
            cluster.label.font  = '16pt Source Han Sans CN'
            cluster.label.show = true
            cluster.label.color = Cesium.Color.fromCssColorString('#fff');
            cluster.label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER   
            // cluster.label.verticalOrigin = Cesium.verticalOrigin.CENTER; 
            cluster.label.pixelOffset = new Cesium.Cartesian2(0, 5)  
            cluster.label.eyeOffset = new Cesium.Cartesian3(0, 0,-30)  
            // cluster.point = {
            //   show: true,
            //   pixelSize: 30,
            //   outlineColor: Cesium.Color.YELLOW,
            //   outlineWidth: 10,
            //   // scaleByDistance: new Cesium.NearFarScalar(1500, 1, 20000, 0.3),
            //   // translucencyByDistance: new Cesium.NearFarScalar(1500, 1, 20000, 0.2),
            //   distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000)
            // }
            // cluster.billboard.image = pinBuilder.fromText(clusteredEntities.length + '', Cesium.Color.fromCssColorString(featureKey.clusters_color), 48).toDataURL();
            if (clusteredEntities.length >= 100) {
              // cluster.billboard.image = pin200;
              // cluster.point.color =  Cesium.Color.YELLOW
              cluster.label.text = '100+' //文本
            } else if (clusteredEntities.length >= 50) {
              // cluster.billboard.image = pin50;
              // cluster.point.color =  Cesium.Color.YELLOW
              cluster.label.text = '50+' //文本
            } else if (clusteredEntities.length >= 40) {
              // cluster.billboard.image = pin40;
              // cluster.point.color = Cesium.Color.YELLOW
              cluster.label.text = '40+' //文本
            } else if (clusteredEntities.length >= 30) {
              // cluster.billboard.image = pin30;
              // cluster.point.color = Cesium.Color.YELLOW
              cluster.label.text = '30+' //文本
            } else if (clusteredEntities.length >= 20) {
              // cluster.billboard.image = pin20;
              // cluster.point.color = Cesium.Color.YELLOW
              cluster.label.text = '20+' //文本
            } else if (clusteredEntities.length >= 10) {
              // cluster.billboard.image = pin10;
              // cluster.point.color = Cesium.Color.YELLOW
              cluster.label.text = '10+' //文本
            } else {
              // cluster.label.text = '3+' //文本
              // lboard.image = singleDigitPins[clusteredEntities.length - 2];
            }
          })
        }
        // force a re-cluster with the new styling
        var pixelRange = dataSource.clustering.pixelRange
        dataSource.clustering.pixelRange = 0
        dataSource.clustering.pixelRange = pixelRange
      }
    
      // start with custom style
      customStyle()
    })
    }
    
    export function addPointFN(_Entities, _set = {}, _viewer,markersLayer) {
    let _featureKey = {
      layer_name: 'append-layer',
      type: '', //类型
      titleKey: '', //标题
      strokeWidth: 2,
      strokeColor: '[255, 0, 0, 255]',
      fillColor: '[0, 0, 255, 255]',
      clusters_enabled: '', //聚合显示
      clusters_color: '#45deb2' //聚合颜色
    }
    for (let k in _featureKey) {
      if (_set[k]) {
        _featureKey[k] = _set[k]
      }
    }
    addPoint(_Entities, _featureKey, _viewer,markersLayer)
    }
    
  • 创建数据图层
-  markersLayer = new Cesium.CustomDataSource('marker-layer')
- viewer.dataSources.add(markersLayer)
  • 创建地图底图图层
 viewer.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({
                    url: '/static/map/worldimage.jpg'
                }));
  • 加载gif动态图片,需要引入SuperGif插件进行gif转换,再通过Cesium.CallbackProperty一帧帧获取,需要注意得加上dom元素
-  <img src="/biz/alarm.gif" width="20px" height="20px" ref="gifRef" rel:auto_play="1" rel:rubbable="1"
            style="position: absolute;z-index: -1;" />
  _self.superGif = new SuperGif({
                        gif: this.$refs.gifRef
                    });
                    _self.superGif.load(function () {
                        layer && layer.entities.add({
                            id: item.id,
                            name: item.name,
                            type: "marker",
                            featureType: type,
                            feature: item.feature,
                            lon: item.lon,
                            lat: item.lat,
                            mapTools: tools,//地图右边按钮
                            position: Cesium.Cartesian3.fromDegrees(parseFloat(lon), parseFloat(lat), height),
                            billboard: {
                                image: new Cesium.CallbackProperty(() => {
                                    return _self.superGif.get_canvas().toDataURL("image/png");
                                }, false),
                                scale: 1,
                                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                                width: 60,
                                height: imageheight
                            },
                            label: {
                                text: type == "wrj" ? `${item.name}` : "",
                                font: '14pt 微软雅黑',
                                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                                // backgroundColor: Cesium.Color.YELLOW,
                                // showBackground: true,
                                outlineColor: new Cesium.Color.fromCssColorString("tranparent"),
                                fillColor: new Cesium.Color.fromCssColorString("#fff"),
                                outlineWidth: 5,
                                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                                pixelOffset: new Cesium.Cartesian2(-110, -25)
                            },
                            _lng: lon,
                            _lat: lat,
                            _obj: item
                        })
                    });
                } 
  • 相机视角(有entity则用viewer,坐标用camera)
let heading = viewer.camera.heading, pitch = viewer.camera.pitch, roll = viewer.camera.roll;
                         viewer.flyTo(_self.pickValue, {
                                offset: {
                                    heading: 2.990358455542995, // 方向
                                    pitch: -0.5403975721607086,// 倾斜角度
                                    range: 11100
                                }
                                //定位
                let lon = list[0].lon || list[0].longitude, lat = list[0].lat || list[0].latitude;
 
                viewer.camera.flyTo(this.mapCenter, 5000);

2、加载图层、绘制点、线、面,调节情景参数

加载图层
天地图超图方式对接

let IMG_C = viewer.imageryLayers.addImageryProvider(new Cesium.TiandituImageryProvider({
                    mapStyle: Cesium.TiandituMapsStyle.IMG_C,
                    token: 'xx'
                }))
                IMG_C.show = true;
                //  let IMG_C = viewer.imageryLayers.addImageryProvider(new Cesium.TiandituImageryProvider({
                //     mapStyle: Cesium.TiandituMapsStyle.TER_C,
                //     token: 'xx'
                // }))
                // IMG_C.show = true;

                viewer.imageryLayers.addImageryProvider(new Cesium.TiandituImageryProvider({
                    mapStyle: Cesium.TiandituMapsStyle.CIA_C,//天地图全球中文注记服务(经纬度)
                    token: 'xxx' //由天地图官网申请的密钥
                }))
  • 原生对接
// 叠加影像服务
                var imgMap = new Cesium.UrlTemplateImageryProvider({
                    url: tdtUrl + 'DataServer?T=img_w&x={x}&y={y}&l={z}&tk=' + token,
                    subdomains: subdomains,
                    tilingScheme: new Cesium.WebMercatorTilingScheme(),
                    maximumLevel: 22
                });
                viewer.imageryLayers.addImageryProvider(imgMap);
  • 绘制面
ttMaplayer.entities.add({
                    position: Cesium.Cartesian3.fromDegrees(lon, lat, height),
                    ellipse: {
                        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                        disableDepthTestDistance: 99000000,
                        outlineColor: Cesium.Color.YELLOW.withAlpha(0.5),
                        outline: true,
                        outlineWidth: 2,
                        semiMinorAxis: 5000.0,
                        semiMajorAxis: 5000.0,
                        fill: false,
                    }
                });
  • 绘制矩形
let east = points[0].split(','),west = points[1].split(',');
          layer.entities.add({
            type:"marker",
            name: item.name,
            _obj:item,
            position: Cesium.Cartesian3.fromDegrees(parseFloat((+east[0]+(+west[0]))/2), parseFloat((+west[1]+(+east[1]))/2)),
            rectangle: {
                    coordinates: Cesium.Rectangle.fromDegrees(+east[0], +east[1],+west[0], +west[1]),
                    outlineColor:Cesium.Color.RED,
                    outlineWidth:24,
                    fill:true,
                    material: Cesium.Color.BLUE.withAlpha(0.6),
                    outline:true
                }
            })
  • 绘制线段(可以设置线段宽度和材质)
 _t.appendLayer.entities.add({
      polyline: {
        positions: new Cesium.CallbackProperty(function() {
          return _t.routeList
        }, false),
        width: 5,
        material: Cesium.Color.RED,
        depthFailMaterial: Cesium.Color.RED,
        clampToGround: true
      }
    })
  • 参数调节
let Options = function () {
            this.contrast = 128;
            this.brightness = -0.3;
            this.delta = 1;
            this.gamma = 3.5;
            this.enabled = false;
            this.highDynamicRange = true;
            this.shadows = false;
        }
        let option = new Options();
        let gui = new dat.GUI();
        gui.__closeButton.innerHTML = "收缩面板";

        let bloom = viewer.scene.postProcessStages.bloom;

        gui.add(option, 'highDynamicRange').name("高动态范围").onChange(function (value) {
            viewer.scene.highDynamicRange = value;
        })
        gui.add(option, 'gamma', 0, 5).name("伽马亮度").onChange(function (value) {
            viewer.scene.gamma = value;
        })

        gui.add(option, 'enabled').name("启用模糊").onChange(function (value) {
            bloom.enabled = value;
        })
        gui.add(option, 'contrast', -128, 128).name("对比度").onChange(function (value) {
            bloom.uniforms.contrast = value;
        })
        gui.add(option, 'brightness', -2, 2).name("光泽亮度").onChange(function (value) {
            bloom.uniforms.brightness = value;
        })
        gui.add(option, 'delta', -5, 5).name("因子(delta)").onChange(function (value) {
            bloom.uniforms.delta = value;
        })

        gui.add(option, 'shadows').name("启用阴影").onChange(function (value) {
            viewer.shadows = value;
        })
        $('.dg.ac').css('top', '10%');

事件

  • 鼠标左键点击事件

    let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas), _self = this;
                  let ellipsoid = viewer.scene.globe.ellipsoid;
                  //点击地图视频标志窗口弹窗
                  handler.setInputAction(async e => {
                      let lng, lat, height
                      var cartesian = viewer.scene.pickPosition(e.position);
                      //地图点位查询
                      let pick = viewer.scene.pick(e.position);
                      if (Cesium.defined(pick) && pick.id && pick.id.type === "marker") {
                  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  • 鼠标移入事件
-  //鼠标移入事件
                handler.setInputAction(async movement => {
                    let lng, lat, height;
                    if (viewer.scene.mode !== Cesium.SceneMode.MORPHING) {
                        let pick = viewer.scene.pick(movement.endPosition);
                        if (Cesium.defined(pick) && pick.id)
                    }
                }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

鼠标移除事件

 rectHandler && rectHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
                rectHandler && rectHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
                rectHandler && rectHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP);

弹框(生成弹框和弹框移动)

生成:
dom节点

<poiDetail ref="poiRef"></poiDetail>
positionPopUp(c) {
                this.tempPostion = c;
                var x = c.x - 290;
                var y = c.y - 250
                this.boxStyle = `left:${x}px;top:${y}px`
            },
            destroy() {
                this.options = {};
                this.hide();
            },
            hide() {
                this.getActionFlg = false;
                this.visible = false;
                this.showPlayer = false;
                this.tempPostion = null;
            }
  • js方式控制dom节点
 _self.$refs.poiRef.open({
                                position: changedC,
                                item: _self.pickValue,
                                removeHandler: () => {
                                    _self.removeHandler()
                                }
                            })
  • 移动:postRender监听位置移动改变坐标
    viewer.scene.postRender.addEventListener(function () {
    })

轨迹

(需要事先规划哈轨迹路线,然后再根据cesium时间滚轮进行播放)

var viewer = null,
  entifyMap = {
    car: {
      entityFly: null,
      primiayLayer: null
    },
    wrj: {
      entityFly: null,
      primiayLayer: null
    }
  }
import { carList, DroneList } from './routerJson.js'
var routeList = null
export default {
  data() {
    return {}
  },
  mounted() {
   
  },
  methods: {
    collectPoint(position) {
      var cartesian = viewer.scene.globe.pick(viewer.camera.getPickRay(position), viewer.scene)
      routeList.push(cartesian) // 存储每次踩点的位置
      viewer.entities.add({
        polyline: {
          positions: new Cesium.CallbackProperty(function() {
            return routeList
          }, false),
          width: 5,
          material: Cesium.Color.RED,
          depthFailMaterial: Cesium.Color.RED,
          clampToGround: true
        }
      })
    },
    defineRoute(viewerInstance, type) {
      let _t = this
      viewer = viewerInstance
      
      // this.drawLine();
      // return
      // this.changeView();
      this.type = type
      this.clearRoute()
      routeList = this.type=='car'?carList:DroneList;
      if (entifyMap[type].entityFly) return
      this.addRouterLine()
      this.rollbackRoute()
      this.addMouseMove()
    },
    addMouseMove() {
      var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
      handler.setInputAction(function(movement) {
        viewer.trackedEntity = null
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    },
    rollbackRoute() {
      var start = Cesium.JulianDate.fromDate(new Date(), new Cesium.JulianDate()) // 开始时间
      var stop = Cesium.JulianDate.addSeconds(start, 100, new Cesium.JulianDate()) // 结束时间
      viewer.clock.startTime = start.clone()
      viewer.clock.stopTime = stop.clone()
      viewer.clock.currentTime = start.clone()
      viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
      viewer.clock.multiplier = 1

      // viewer.timeline.zoomTo(start, stop)
      function computeCircularTrack() {
        var property = new Cesium.SampledPositionProperty()
        for (var i = 0; i < routeList.length; i++) {
          var time = Cesium.JulianDate.addSeconds(start, (i * 100) / (routeList.length - 1), new Cesium.JulianDate())
          var position = routeList[i]
          property.addSample(time, position)
        }
        return property
      }
      var position = computeCircularTrack()
      entifyMap[this.type].entityFly = viewer.entities.add({
        availability: new Cesium.TimeIntervalCollection([
          new Cesium.TimeInterval({
            start: start,
            stop: stop
          })
        ]),
        position: position,
        orientation: new Cesium.VelocityOrientationProperty(position),
        // model: {
        //   uri: this.type == 'car' ? '/biz/car.gltf' : '/biz/Drone.gltf', // 加载模型
        //   minimumPixelSize: 64 // 指定模型大小
        // },
        billboard: {
            image: this.type == 'car' ? '/biz/type/ydxlc.png' : '/biz/type/wrj.png',
            scale: 1,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            width: 47,
            height: 59
        },
        path: {
          show: false, // 显示轨迹
          resolution: 1,
          material: new Cesium.PolylineOutlineMaterialProperty({
            color: Cesium.Color.fromAlpha(Cesium.Color.LIGHTSKYBLUE, 0.5),
            outlineWidth: 1,
            outlineColor: Cesium.Color.red
          }),
          width: 5
        }
      })

      // 指定轨迹插值算法
      entifyMap[this.type].entityFly.position.setInterpolationOptions({
        interpolationDegree: 1,
        interpolationAlgorithm: Cesium.LinearApproximation
      })
      viewer.trackedEntity = entifyMap[this.type].entityFly
    },
    track() {
      var center = entityFly.position.getValue(viewer.clock.currentTime)
      var orientation = entityFly.orientation.getValue(viewer.clock.currentTime)
      var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center)
      transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation), center)
      viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(-100.0, 0, 50))
    },
    //切换视角
    changeView(flag) {
      if (flag) {
        viewer.clock.onTick.removeEventListener(this.track)
        viewer.trackedEntity = entityFly
      } else {
        viewer.clock.onTick.addEventListener(this.track)
        viewer.trackedEntity = null
      }
    },
    //清除路线
    clearRoute(typ) {
      var type = typ || this.type,entityFly = entifyMap[type].entityFly,primiayLayer = entifyMap[type].primiayLayer
      entityFly && viewer.entities.remove(entityFly)
      primiayLayer && viewer.scene.primitives.remove(primiayLayer)
      entifyMap[type].entityFly = null
      entifyMap[type].primiayLayer = null
      // this.changeView();
    },
    //添加轨迹
    addRouterLine() {
      var instance = new Cesium.GeometryInstance({
        geometry: new Cesium.GroundPolylineGeometry({
          width: 5,
          positions: routeList
        }),
        attributes: {}
      })

      const materialOpts = {
        fabric: {
          type: 'PolylineDash',
          uniforms: {
            color: {
              red: 1,
              green: 1,
              blue: 0,
              alpha: 1
            },
            gapColor: {
              red: 1,
              green: 1,
              blue: 1,
              alpha: 1
            },
            dashLength: 50
          }
        }
      }
      entifyMap[this.type].primiayLayer = new Cesium.GroundPolylinePrimitive({
        asynchronous: false,
        geometryInstances: instance,
        appearance: new Cesium.PolylineMaterialAppearance({
          material: new Cesium.Material(materialOpts)
        })
      })
      viewer.scene.primitives.add(entifyMap[this.type].primiayLayer)
    },
    //绘制轨迹线
    drawLine() {
      let _t = this
      viewer.screenSpaceEventHandler.setInputAction(function(clickEvent) {
        _t.collectPoint(clickEvent.position)
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

      viewer.screenSpaceEventHandler.setInputAction(function(moveEvent) {
        if (routeList.length >= 2) {
          routeList.pop()
          _t.collectPoint(moveEvent.endPosition)
        } else if (routeList.length == 1) {
          _t.collectPoint(moveEvent.endPosition)
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

      viewer.screenSpaceEventHandler.setInputAction(function(clickEvent) {
        routeList.pop()
        _t.collectPoint(clickEvent.position)
        viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
        viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
        viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    }
  }
}

### 流线图
主要是定义材质和数学抛物线位置计算
image.png

/**
 * 飞机纹理流动图
 *
 * @author zhangti
 * @version v1
 *
 */

var cesiumFlyPath = null
var originHeight = 0
export const CesiumFlyPath = function() {
  cesiumFlyPath = this
  this._PolylineTrailLinkMaterialProperty = null
}

CesiumFlyPath.prototype.init = function(param) {
  if (null === param || undefined === param) return
  var t = this
  for (var key in param) {
    t[key] = param[key]
  }

  this.config()
}

CesiumFlyPath.prototype.config = function() {
  var cesiumFlyPath = this
  //绘制位置在地形上
  cesiumFlyPath.viewer.scene.globe.depthTestAgainstTerrain = false
  //取消双击事件
  cesiumFlyPath.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
    Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
  )
  //定义流动纹理对象
  Cesium.PolylineTrailLinkMaterialProperty = PolylineTrailLinkMaterialProperty
  Cesium.Material.PolylineTrailLinkType = 'PolylineTrailLink'
  Cesium.Material.PolylineTrailLinkImage = '/biz/fly.png'
  //着色器
  Cesium.Material.PolylineTrailLinkSource =
    'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
                                                   {\n\
                                                        czm_material material = czm_getDefaultMaterial(materialInput);\n\
                                                        vec2 st = materialInput.st;\n\
                                                        vec4 colorImage = texture2D(image, vec2(fract(st.s - time), st.t));\n\
                                                        material.alpha = colorImage.a * color.a;\n\
                                                        material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\
                                                        return material;\n\
                                                    }'

  //实例化流动纹理
  cesiumFlyPath._PolylineTrailLinkMaterialProperty = new Cesium.PolylineTrailLinkMaterialProperty(
    cesiumFlyPath.color,
    cesiumFlyPath.duration
  )
  Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailLinkType, {
    fabric: {
      type: Cesium.Material.PolylineTrailLinkType,
      uniforms: {
        color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
        image: Cesium.Material.PolylineTrailLinkImage,
        time: 0
      },
      source: Cesium.Material.PolylineTrailLinkSource
    },
    translucent: function(material) {
      return true
    }
  })
}

CesiumFlyPath.prototype.parabolaEquation = function(options, resultOut) {
  var _cesiumFlyPath = this
  //方程 y=-(4h/L^2)*x^2+h h:顶点高度 L:横纵间距较大者
  var h = options.height && options.height > 5000 ? options.height : 5000
  var L =
    Math.abs(options.pt1.lon - options.pt2.lon) > Math.abs(options.pt1.lat - options.pt2.lat)
      ? Math.abs(options.pt1.lon - options.pt2.lon)
      : Math.abs(options.pt1.lat - options.pt2.lat)
  var num = options.num && options.num > 50 ? options.num : 50
  var result = []
  var dlt = L / num
  if (Math.abs(options.pt1.lon - options.pt2.lon) > Math.abs(options.pt1.lat - options.pt2.lat)) {
    //以lon为基准
    var delLat = (options.pt2.lat - options.pt1.lat) / num
    if (options.pt1.lon - options.pt2.lon > 0) {
      dlt = -dlt
    }
    for (var i = 0; i < num; i++) {
      var tempH = h - (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * h) / Math.pow(L, 2)
      var lon = options.pt1.lon + dlt * i
      var lat = options.pt1.lat + delLat * i
      result.push([lon, lat, tempH + originHeight + 1000])
    }
  } else {
    //以lat为基准
    var delLon = (options.pt2.lon - options.pt1.lon) / num
    if (options.pt1.lat - options.pt2.lat > 0) {
      dlt = -dlt
    }
    for (var i = 0; i < num; i++) {
      var tempH = h - (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * h) / Math.pow(L, 2)
      var lon = options.pt1.lon + delLon * i
      var lat = options.pt1.lat + dlt * i
      result.push([lon, lat, tempH + originHeight + 1000])
    }
  }
  // let cartographic = Cesium.Cartographic.fromDegrees(options.pt2.lon, options.pt2.lat);
  // let distHeight = _cesiumFlyPath.viewer.scene.globe.getHeight(cartographic)
    result.push([options.pt2.lon, options.pt2.lat, 1000])
  if (resultOut != undefined) {
    resultOut = result
  }
  return result
}
//默认
CesiumFlyPath.prototype.drawDefault = function(data) {
  var _cesiumFlyPath = this,
    center = data.center,
    // lon = center.lon,
    // lat = center.lat,
    // zoom = data.zoom,
    cities = data.cities
  // v = data.v
  //设置homebutton的位置
  // Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(lon - 1, lat - 1, lon + 1, lat + 1)
  //设置初始位置
  // _cesiumFlyPath.viewer.camera.setView({
  //   destination: Cesium.Cartesian3.fromDegrees(lon, lat, zoom)
  // })
  //生成流动纹理
  let cartographic = Cesium.Cartographic.fromDegrees(center.lon, center.lat)
  originHeight = _cesiumFlyPath.viewer.scene.globe.getHeight(cartographic)
  for (var j = 0; j < cities.length; j++) {
    var points = cesiumFlyPath.parabolaEquation({
      pt1: center,
      pt2: cities[j],
      height: _cesiumFlyPath.height,
      num: cities.length
    })
    var pointArr = []

    for (var i = 0; i < points.length; i++) {
      pointArr.push(points[i][0], points[i][1], points[i][2])
    }
    _cesiumFlyPath.viewer.entities.add({
      name: 'PolylineTrailLink' + j,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(pointArr),
        width: 2,
        //流动纹理
        material: cesiumFlyPath._PolylineTrailLinkMaterialProperty
      }
    })
  }
  // //原点
  // let cartographic = Cesium.Cartographic.fromDegrees(lon, lat);
  // let height = _cesiumFlyPath.viewer.scene.globe.getHeight(cartographic);
  // _cesiumFlyPath.viewer.entities.add({
  //   position: Cesium.Cartesian3.fromDegrees(lon, lat, height),
  //   point: {
  //     pixelSize: 1,
  //     color: v.c
  //   }
  // })

  //目标点
  // for (var i = 0; i < cities.length; i++) {
  //   let cartographic = Cesium.Cartographic.fromDegrees(cities[i].lon, cities[i].lat);
  //   let height = _cesiumFlyPath.viewer.scene.globe.getHeight(cartographic);
  //   _cesiumFlyPath.viewer.entities.add({
  //     position: Cesium.Cartesian3.fromDegrees(cities[i].lon, cities[i].lat, height),
  //     billboard: {
  //       image: !this.showDestPic?"/biz/type/point.png":"",
  //       scale: 0.5,
  //       horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
  //       verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
  //       width: 47,
  //       height: 59
  //    },
  //     // point: {
  //     //   pixelSize: 1,
  //     //   color: v.c2
  //     // }
  //   })
  // }
}

CesiumFlyPath.prototype.build = function(param) {
  var t = this
  switch (param.handleType) {
    case 'default': {
      t.drawDefault(param)
      break
    }
  }
}

CesiumFlyPath.prototype.clear = function() {
  try {
    this.viewer && this.viewer.entities && this.viewer.entities.removeAll()
  } catch (error) {}
}

/*
 流纹纹理线
 color 颜色
 duration 持续时间 毫秒
*/

var PolylineTrailLinkMaterialProperty = null
PolylineTrailLinkMaterialProperty = function(color, duration) {
  this._definitionChanged = new Cesium.Event()
  this._color = undefined
  this._colorSubscription = undefined
  this.color = color
  this.duration = duration
  this._time = new Date().getTime()
}
//在cesium中 定义 PolylineTrailLinkMaterialProperty
Cesium.defineProperties(PolylineTrailLinkMaterialProperty.prototype, {
  isConstant: {
    get: function() {
      return false
    }
  },
  definitionChanged: {
    get: function() {
      return this._definitionChanged
    }
  },
  color: Cesium.createPropertyDescriptor('color')
})
PolylineTrailLinkMaterialProperty.prototype.getType = function(time) {
  return 'PolylineTrailLink'
}
PolylineTrailLinkMaterialProperty.prototype.getValue = function(time, result) {
  if (!Cesium.defined(result)) {
    result = {}
  }
  result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color)
  result.image = Cesium.Material.PolylineTrailLinkImage
  result.time = ((new Date().getTime() - this._time) % this.duration) / this.duration
  return result
}
PolylineTrailLinkMaterialProperty.prototype.equals = function(other) {
  return (
    this === other || (other instanceof PolylineTrailLinkMaterialProperty && Property.equals(this._color, other._color))
  )
}

下雪

image.png

export default class Snow{

    constructor(v){
        this.collection = v.scene.postProcessStages;
        this._snow = new Cesium.PostProcessStage({
            name: 'czm_snow',
            fragmentShader: this.getFS()
        });
        this.collection.add(this._snow);
        v.scene.skyAtmosphere.hueShift = -0.8;
        v.scene.skyAtmosphere.saturationShift = -0.7;
        v.scene.skyAtmosphere.brightnessShift = -0.33;
        v.scene.fog.density = 0.001;
        v.scene.fog.minimumBrightness = 0.8;
    }
    getFS(){
        return "uniform sampler2D colorTexture;\n\
        varying vec2 v_textureCoordinates;\n\
        \n\
            float snow(vec2 uv,float scale)\n\
            {\n\
                float time = czm_frameNumber / 60.0;\n\
                float w=smoothstep(1.,0.,-uv.y*(scale/10.));if(w<.1)return 0.;\n\
                uv+=time/scale;uv.y+=time*2./scale;uv.x+=sin(uv.y+time*.5)/scale;\n\
                uv*=scale;vec2 s=floor(uv),f=fract(uv),p;float k=3.,d;\n\
                p=.5+.35*sin(11.*fract(sin((s+p+scale)*mat2(7,3,6,5))*5.))-f;d=length(p);k=min(d,k);\n\
                k=smoothstep(0.,k,sin(f.x+f.y)*0.01);\n\
                return k*w;\n\
            }\n\
        \n\
            void main(void){\n\
                vec2 resolution = czm_viewport.zw;\n\
                vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);\n\
                vec3 finalColor=vec3(0);\n\
                float c = 0.0;\n\
                c+=snow(uv,30.)*.0;\n\
                c+=snow(uv,20.)*.0;\n\
                c+=snow(uv,15.)*.0;\n\
                c+=snow(uv,10.);\n\
                c+=snow(uv,8.);\n\
            c+=snow(uv,6.);\n\
                c+=snow(uv,5.);\n\
                finalColor=(vec3(c)); \n\
                gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(finalColor,1), 0.5); \n\
        \n\
            }\n\
        ";
    }
    remove(){
        this._snow.destroy();
    }
}

基本工具箱:放大、缩小,定位、画线、全屏

 resetMap() {
                let { x, y, z } = window.globalConfig.map.center;
                this.mapCenter = {
                    destination: {
                        x: x,
                        y: y,
                        z: z,
                    },
                };
                this.viewer.camera.flyTo(this.mapCenter, 5000);
            },
            zoomIn() {
                var viewer = this.viewer;
                let cameraPos = viewer.camera.position;
                // 获取当前坐标系标准
                let ellipsoid = viewer.scene.globe.ellipsoid;

                // 根据坐标系标准,将笛卡尔坐标转换为地理坐标
                let cartographic = ellipsoid.cartesianToCartographic(cameraPos);

                // 获取镜头的高度
                let height = cartographic.height;
                viewer.camera.zoomIn(height / 3);
            },
            zoomOut() {
                var viewer = this.viewer;
                let cameraPos = viewer.camera.position;
                // 获取当前坐标系标准
                let ellipsoid = viewer.scene.globe.ellipsoid;
                // 根据坐标系标准,将笛卡尔坐标转换为地理坐标
                let cartographic = ellipsoid.cartesianToCartographic(cameraPos);
                // 获取镜头的高度
                let height = cartographic.height;
                viewer.camera.zoomOut(height * 1.2);
            },
            screenSet() {
                this.screen = !this.screen;
                if (this.screen) {
                    Cesium.Fullscreen.requestFullscreen(document.getElementById("maps"))
                } else {
                    Cesium.Fullscreen.exitFullscreen()
                }

            },

#### 相关链接:
bigMap kml和geojson转换
在线图层处理
常用的地图json下载和svg下载

[Ceisum文档比官网快](http://cesium.xin/cesium/cn/Documentation1.62/Viewer.html?classFilter=viewer)

github代码:https://github.com/holidaying/Cesium/tree/master

阅读 659

技术博客,人生所思
技术,技术,就是热爱技术。

thinking、doing、do better、do much better than today。exchange 、sharing、improve as quickly as ...

1.2k 声望
81 粉丝
0 条评论
你知道吗?

thinking、doing、do better、do much better than today。exchange 、sharing、improve as quickly as ...

1.2k 声望
81 粉丝
文章目录
宣传栏