vue + cesium开发(4) 绘制图形
阅读原文时间:2023年07月11日阅读:2

在官方例子中每个图形都是一个entity,官方例子提供了显示正方形、圆形、锥形、图片等多种案例!

// 初始花
var viewer = new Cesium.Viewer("cesiumContainer");
// 创建蓝色entity
var blueBox = viewer.entities.add({ // 添加到图形实体
  // 名称
  name: "Blue box",
  // 位置 笛卡尔
  position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
  // 形状,可以是盒子 线段 椎体等,当前是盒子
  box: {
    // 设置框的长度、宽度和高度 笛卡尔单位
    dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
    // 颜色 还可以设置边框、阴影等
    material: Cesium.Color.BLUE,
  },
});

// 创建红色entity
var redBox = viewer.entities.add({
  name: "Red box with black outline",
  position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
  box: {
    dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
    material: Cesium.Color.RED.withAlpha(0.5),
    outline: true,
    outlineColor: Cesium.Color.BLACK,
  },
});

// 创建透明entity
var outlineOnly = viewer.entities.add({
  name: "Yellow box outline",
  position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0),
  box: {
    dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
    fill: false,
    outline: true,
    outlineColor: Cesium.Color.YELLOW,
  },
});

viewer.zoomTo(viewer.entities);

此外还可以通过加载czml文件来进行显示,其它例子也可通过 https://sandcastle.cesium.com/?src=Box.html&label=All 进行查看!

但是,这些例子都是根据固定的位置和形状进行显示的,如果我们要自己进行手动绘制呢?官方依然提供了一个例子:

该实例提供了手动绘制线段与多边形的方法,代码如下:

var viewer = new Cesium.Viewer("cesiumContainer", {
    selectionIndicator: false,
    infoBox: false,
    /**
     * 开启世界图形,防止图形错位
     * 如果不开启则使用:
     * 几何图形要依附于模型必须开启depthTestAgainstTerrain
     * viewer.scene.globe.depthTestAgainstTerrain = true
     * */
    terrainProvider: Cesium.createWorldTerrain(),
  });
  // 防止双击放大球体
  viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
    Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
  );
  // 创建一个点
  function createPoint(worldPosition) {
    var point = viewer.entities.add({
      position: worldPosition,
      point: {
        color: Cesium.Color.WHITE,
        // 大小
        pixelSize: 5,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
    });
    return point;
  }
  var drawingMode = "line";
  // 绘制
  function drawShape(positionData) {
    var shape;
    if (drawingMode === "line") {
      shape = viewer.entities.add({
          // 线段
        polyline: {
          positions: positionData,
          clampToGround: true,
          width: 3,
        },
      });
    } else if (drawingMode === "polygon") {
      // 多边形
      shape = viewer.entities.add({
        polygon: {
          hierarchy: positionData,
          material: new Cesium.ColorMaterialProperty(
            Cesium.Color.WHITE.withAlpha(0.7)
          ),
        },
      });
    }
    return shape;
  }
  // 所有活动点的实体
  var activeShapePoints = [];
  // 绘制图形
  var activeShape;
  // 第一个活动点
  var floatingPoint;
  // 创建鼠标事件
  var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
  handler.setInputAction(function (event) {
    // 获取鼠标当前位置 viewer.scene.pickPosition 将位置转化为笛卡尔单位
    var earthPosition = viewer.scene.pickPosition(event.position);
    if (Cesium.defined(earthPosition)) {
      if (activeShapePoints.length === 0) {
        // 创建第一个点
        floatingPoint = createPoint(earthPosition);
        activeShapePoints.push(earthPosition);
        // 最重要的一步,绘制过程中图形会动态跟着鼠标移动
        // CallbackProperty返回一个回调函数 当activeShapePoints改变时会触发
        // 不管activeShapePoints是增加还是删除都会动态改变图形的形状
        // 在绘制结束必须重置activeShapePoints = [] 不然 CallbackProperty 一直处于回调中,严重消耗性能
        var dynamicPositions = new Cesium.CallbackProperty(function () {
          if (drawingMode === "polygon") {
            // 多边形的position需要用 PolygonHierarchy进行转化
            return new Cesium.PolygonHierarchy(activeShapePoints);
          }
          return activeShapePoints;
        }, false);
        activeShape = drawShape(dynamicPositions);
      }
      activeShapePoints.push(earthPosition);
      createPoint(earthPosition);
    }
    // 鼠标左键点击事件 LEFT_CLICK
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  handler.setInputAction(function (event) {
      // 判断是否存在
    if (Cesium.defined(floatingPoint)) {
      var newPosition = viewer.scene.pickPosition(event.endPosition);
      if (Cesium.defined(newPosition)) {
        // 动态改变活动点的位置与鼠标当前位置保持一致
        floatingPoint.position.setValue(newPosition);
        activeShapePoints.pop();
        activeShapePoints.push(newPosition);
      }
    }
    // 鼠标左键移动事件 MOUSE_MOVE
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  // 重新绘制形状,使其不是动态的,然后删除动态形状.
  function terminateShape() {
    // 删除最后一个点
    activeShapePoints.pop();
    // 绘制完整的图形
    drawShape(activeShapePoints);
    // 删除创建的第一个点和处于活动状态的实体
    viewer.entities.remove(floatingPoint);
    viewer.entities.remove(activeShape);
    // 格式化
    floatingPoint = undefined;
    activeShape = undefined;
    activeShapePoints = [];
  }
  // 结束绘制
  handler.setInputAction(function (event) {
    terminateShape();
    // 鼠标右键点击事件 RIGHT_CLICK
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

  // Sandcastle 百度解决,不用也行,只是在cesium上挂载组件
  var options = [
    {
      text: "Draw Lines",
      onselect: function () {
        if (!Cesium.Entity.supportsPolylinesOnTerrain(viewer.scene)) {
          window.alert(
            "This browser does not support polylines on terrain."
          );
        }

        terminateShape();
        drawingMode = "line";
      },
    },
    {
      text: "Draw Polygons",
      onselect: function () {
        terminateShape();
        drawingMode = "polygon";
      },
    },
  ];

  Sandcastle.addToolbarMenu(options);
  // Zoom in to an area with mountains
  viewer.camera.lookAt(
    Cesium.Cartesian3.fromDegrees(-122.2058, 46.1955, 1000.0),
    new Cesium.Cartesian3(5000.0, 5000.0, 5000.0)
  );
  viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);

下面是自己封装的一个绘制多边形的代码:DrawPolygon.js

点击查看代码

/*
绘制面
 */
import * as Cesium from 'cesium'
import * as turf from '@turf/turf'
import Entity from './Entity'

const LEFT_CLICK = Cesium.ScreenSpaceEventType.LEFT_CLICK
const RIGHT_CLICK = Cesium.ScreenSpaceEventType.RIGHT_CLICK
const MOUSE_MOVE = Cesium.ScreenSpaceEventType.MOUSE_MOVE
const LEFT_DOUBLE_CLICK = Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK

// 绘制面
export default class DaChDraw {
    // 初始化
    constructor(viewer = null, options = { singleMode: false }) {
        if (!viewer) {
            throw new Error('请传入cesium实例!')
        }
        this.viewer = viewer
        // 当前面所有点
        this._position = []
        // 最后一个活动点
        this._positionLast = null
        // 第一次绘制的图形
        this._shape = null
        // 绘制的所有实体
        this._entityList = []
        // 通过加载geojson显示的面
        this._polygonJson = []
        // 是否显示面积
        this._isShowArea = false
        // 通过加载geojson显示的图形
        this._geoMap = new Map()
        // 绘制的图形
        this._drawMap = new Map()
        this.entity = new Entity(viewer)
        // 测量
        this._resultTip = null
        // 测量所保存的实体
        this._resultTipArr = []
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas)
        const _serf = this
        // 是否开启单例模式,默认关闭 开启后在多个页面实例化都取到相同的DaChDraw 实例
        _serf.singleMode = null
        if (options.singleMode) {
            if (!DaChDraw.singleMode) {
                DaChDraw.singleMode = _serf
            }
            return DaChDraw.singleMode
        }
    }
    // 结束
    destroy() {
        this._position = []
        this._positionLast = null
        this._shape = null
        this._entityList = []
    }
    // 开始绘制
    startDraw(showArea = this._isShowArea) {
        const _serf = this
        _serf._isShowArea = showArea
        // 鼠标点击
        _serf.handler.setInputAction(function(event) {
            // 获取当前点击坐标
            let earthPosition = _serf.viewer.scene.pickPosition(event.position)
            if (Cesium.defined(earthPosition)) {
                if (_serf._position.length === 0) {
                    // 创建点击的第一个点
                    _serf._positionLast = _serf.entity.createPoint(earthPosition)
                    _serf._position.push(earthPosition)
                    var dynamicPositions = new Cesium.CallbackProperty(function() {
                        // return new Cesium.PolygonHierarchy(_serf._position)
                        return _serf._position
                    }, false)
                    _serf._shape = _serf.entity.createLine(dynamicPositions)
                    _serf._entityList.push(_serf._positionLast)
                    _serf._entityList.push(_serf._shape)
                }
                _serf._position.push(earthPosition)
                const pot = _serf.entity.createPoint(earthPosition)
                _serf._entityList.push(pot)
            }
        }, LEFT_CLICK)
        // 鼠标移动
        this.handler.setInputAction(function(event) {
            if (Cesium.defined(_serf._positionLast)) {
                // 如果已经存在了一个点,说明当前处于绘制状态
                // 获取移动后的最后一个位置 pickPosition获取笛卡尔坐标
                let newPosition = _serf.viewer.scene.pickPosition(event.endPosition)
                if (Cesium.defined(newPosition)) {
                    _serf._positionLast.position.setValue(newPosition)
                    _serf._position.pop()
                    _serf._position.push(newPosition)
                }
            }
        }, MOUSE_MOVE)
        // 鼠标双击绘制完成
        _serf.handler.setInputAction(function(event) {
            console.log(_serf._position)
            if (_serf._position.length <= 4) {
                _serf.breakDraw()
            } else {
                _serf.finishDraw()
            }
        }, LEFT_DOUBLE_CLICK)
        // 鼠标右键结束绘制
        _serf.handler.setInputAction(function(event) {
            _serf.breakDraw()
        }, RIGHT_CLICK)
    }
    // 绘制中断
    breakDraw() {
        const _serf = this
        _serf._entityList.forEach((entity) => {
            _serf.entity.remove(entity)
        })
        // 移除鼠标监听
        this.handler.removeInputAction(LEFT_CLICK)
        this.handler.removeInputAction(MOUSE_MOVE)
        this.handler.removeInputAction(RIGHT_CLICK)
        this.handler.removeInputAction(LEFT_DOUBLE_CLICK)
        _serf.destroy()
    }
    // 绘制结束
    finishDraw() {
        const _serf = this
        _serf.entity.remove(_serf._positionLast)
        _serf.entity.remove(_serf._shape)
        _serf._position.pop()
        _serf._position.unshift(_serf._position[_serf._position.length - 1])
        // _serf._polygonLast = _serf.entity.createPolygon(_serf._position)
        _serf._polygonLast = _serf.entity.createLine(_serf._position)
        const position = _serf.coordinates(
            _serf._position,
            _serf._position,
            'Polygon'
        )
        // 绘制图形转geosjson
        let geoJson = turf.polygon([position])
        console.log(JSON.stringify(geoJson))
        // 绘制完成后显示面积
        if (_serf._isShowArea) {
            let area = (turf.area(obj) / 1000000.0).toFixed(4) + '平方公里'
            _serf.entity.createLabel(
                area,
                _serf._position[_serf._position.length - 1]
            )
        }
        const { _id: id } = _serf._polygonLast
        const polyObj = {
            id,
            geoJson,
        }
        this._drawMap.set(id, polyObj)
        // 去掉所有绘制的点
        _serf._entityList.forEach((entity) => {
            _serf.entity.remove(entity)
        })
        this.destroy()
    }
    cartesian2Degrees(cartesian) {
        const ellipsoid =
            this.viewer.scene.globe.ellipsoid || Cesium.Ellipsoid.WGS84
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian, ellipsoid)
        let lat = Cesium.Math.toDegrees(cartographic.latitude)
        let lon = Cesium.Math.toDegrees(cartographic.longitude)
        let height = cartographic.height
        return {
            lat,
            lon,
            height,
        }
    }
    coordinates(position, positions, type) {
        if (position instanceof Cesium.Cartesian3) {
            const coor = this.cartesian2Degrees(position)
            return [coor.lon, coor.lat, coor.height]
        } else if (positions instanceof Array) {
            const pts = []
            for (let p of positions) {
                const c = this.cartesian2Degrees(p)
                pts.push([c.lon, c.lat, c.height])
            }
            if (type === 'Polygon') {
                return pts
            } else {
                return [pts]
            }
        }
    }

    // 加载geojson显示图形
    getDraw(feat, style = {}) {
        let positions = []
        const coordinates = feat.geometry.coordinates[0]
        for (let c of coordinates) {
            positions.push({
                lon: c[0],
                lat: c[1],
                height: c[2],
            })
        }
        positions = positions.map((_) => {
            return Cesium.Cartesian3.fromDegrees(_.lon, _.lat, _.height)
        })
        return this.entity.createPolygon(positions, style)
    }

} 

Entity.js

点击查看代码

// 定义实体对象
import * as Cesium from 'cesium'
export default class Entitys {
    constructor(core) {
        this.entitys = core.entities
    }
    // 新增
    add(entity) {
        return this.entitys.add(entity)
    }
    // 删除
    remove(entity) {
        this.entitys.remove(entity)
    }
    // 移除所有
    removeAll() {
        this.entitys.removeAll()
    }
    // 创建实体类
    create() {
        return new Cesium.Entity()
    }
    // 根据ID获取实体类
    withIdGainEntity(id) {
        return this.entitys.getById(id)
    }
    getPoint() {
        return new Cesium.PointGraphics({
            pixelSize: 5,
            color: Cesium.Color.BLUE,
            outlineColor: Cesium.Color.WHITE,
            outlineWidth: 1,
        })
    }
    getLine(positions, color, width = 1) {
        return new Cesium.PolylineGraphics({
            show: true,
            positions: positions,
            material: color,
            width,
            clampToGround: true,
        })
    }
    getPolygon(position) {
        return new Cesium.PolygonGraphics({
            show: true,
            hierarchy: position,
            material: Cesium.Color.RED.withAlpha(0.5),
        })
    }
    // 创建点
    createPoint(position, label = null, point = true, billboard = false) {
        let entity = this.create()
        entity.position = position
        if (point) entity.point = this.getPoint()
        if (label) entity.label = this.getLabel(label)
        return this.add(entity)
    }
    // 创建线
    createLine(positions, oid = '', color = Cesium.Color.BLUE) {
        let entity = this.create()
        entity.position = positions
        entity.polyline = this.getLine(positions, color)
        entity.oid = oid
        return this.add(entity)
    }
    // 创建面
    createPolygon(positions) {
        const entity = this.create()
        entity.polygon = this.getPolygon(positions)
        return this.add(entity)
    }
    // 创建label
    createLabel(text, positions) {
        let entity = this.create()
        entity.label = this.getLabel(text)
        entity.position = positions
        return this.add(entity)
    }
    getLabel(text, offset) {
        return new Cesium.LabelGraphics({
            //文字标签
            text: text,
            font: '16px sans-serif',
            fillColor: Cesium.Color.GOLD,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            showBackground: true,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: offset == undefined ? new Cesium.Cartesian2(10, 30) : offset,
        })
    }
} 

TRANSLATE with x

English

Arabic

Hebrew

Polish

Bulgarian

Hindi

Portuguese

Catalan

Hmong Daw

Romanian

Chinese Simplified

Hungarian

Russian

Chinese Traditional

Indonesian

Slovak

Czech

Italian

Slovenian

Danish

Japanese

Spanish

Dutch

Klingon

Swedish

English

Korean

Thai

Estonian

Latvian

Turkish

Finnish

Lithuanian

Ukrainian

French

Malay

Urdu

German

Maltese

Vietnamese

Greek

Norwegian

Welsh

Haitian Creole

Persian

 

TRANSLATE with

COPY THE URL BELOW

Back

EMBED THE SNIPPET BELOW IN YOUR SITE

Enable collaborative features and customize widget: Bing Webmaster Portal

Back

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章