vue + cesium開發(4) 繪制圖形


在官方例子中每個圖形都是一個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,
		})
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM