- 編輯器:webstorm
- 服務(wù):node.js npm
- CesiumJS: Cesium-v1.9.1
- vue v2.9.6
- 順便丟一個感覺挺實用的cesium中文文檔
一、功能
繪制點線面
點擊按鈕切換模式薛窥,鼠標(biāo)拖拽地圖移動落追,在相應(yīng)模式下單擊右鍵結(jié)束繪制
-
點模式
點擊“繪制點”按鈕后在地圖內(nèi)單擊鼠標(biāo)左鍵遭顶,在地圖上添加一個點柿汛,單擊右鍵結(jié)束畫點
-
線模式
點擊“繪制線”按鈕后單擊鼠標(biāo)左鍵在地圖上添加一個點并開始畫線悟民,單擊右鍵結(jié)束畫線
-
面模式
點擊“繪制面”按鈕后單擊鼠標(biāo)左鍵在地圖上添加一個點并開始畫線丸卷,需要至少三個點以形成面挺举,單擊鼠標(biāo)右鍵結(jié)束畫線
-
清空繪制
點擊按鈕后刪除所有繪制對象
二弱恒、 實現(xiàn)
環(huán)境搭建參照同文集下vue+cesium環(huán)境搭建
1. 初始化場景
參照同文集下vueCesium構(gòu)建航班軌跡文件添加token辨萍,進行cesium初始化
不過因為窗口顯示的是野外,只想簡單實現(xiàn)功能的話并不用加OSM Building(網(wǎng)速不行的話也同理(比如我
此處借鑒官方示例返弹,利用camera的lookAt方法令鏡頭初始化在火山口(分瘦?)上方而不是顯示初始化地球
在初始化場景的時候還可以通過賦值true/false來選擇是否顯示窗口小部件
infoBox: 信息框
selectionIndicator: 選擇指示框
navigation: 導(dǎo)航插件
animation: 動畫控制部件,左下角儀表盤
shouldAnimate: 當(dāng)動畫控件出現(xiàn)琉苇,用來控制通過旋轉(zhuǎn)控件調(diào)整動畫速度
timeline: 時間軸控件
baseLayerPicker: 圖層選擇器
geocoder: 查詢定位按鈕
homeButton: 主頁按鈕
sceneModePicker: 地圖以3D/2D模式顯示
navigationHelpButton: 導(dǎo)航欄幫助按鈕
具體代碼
methods: {
// 初始化
Init () {
// 引入個人token,這里填自己在Cesium Ion的token
Cesium.Ion.defaultAccessToken = 'your_token'
// 設(shè)置取景器
this.viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(),
selectionIndicator: false, // 不顯示指示器小部件
infoBox: false, // 不顯示信息框
sceneModePicker: false, // 不顯示模式切換選項
baseLayerPicker: false, // 不顯示圖層選擇器
navigationHelpButton: false // 不顯示導(dǎo)航欄幫助按鈕
})
// 若瀏覽器不支持pickPosition嘲玫,顯示報錯信息
if (!this.viewer.scene.pickPositionSupported) {
window.alert('This browser does not support pickPosition.')
}
// 載入OSM建筑物,網(wǎng)速慢的話干脆注掉
// const osmBuildings = this.viewer.scene.primitives.add(Cesium.createOsmBuildings()) // eslint-disable-line no-unused-vars
// 初始化鏡頭
this.viewer.camera.lookAt(
Cesium.Cartesian3.fromDegrees(-122.2058, 46.1955, 1000.0),
new Cesium.Cartesian3(5000.0, 5000.0, 5000.0)
) this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
},
}
2. 添加選擇界面
結(jié)構(gòu):一個內(nèi)嵌頁面組件并扇,上部分是選擇按鈕去团,下部分是操作提示
功能:點擊按鈕后相應(yīng)事件有所相應(yīng),按鈕響應(yīng)鼠標(biāo)點擊事件
具體HTML代碼:
<template>
<div id="app">
<div id="cesiumContainer"></div>
<div class="btnContainer">
<button @click="draw('Point')">繪制點</button>
<button @click="draw('Polyline')">繪制線</button>
<button @click="draw('Polygon')">繪制面</button>
<button @click="clearAllDrawn()">清空繪制</button>
<div class="tip">
<p>點擊“繪制點”按鈕后在場景內(nèi)單擊鼠標(biāo)左鍵繪制點穷蛹。</p>
<p>點擊“繪制圖”按鈕后在場景內(nèi)單擊鼠標(biāo)左鍵繪制線土陪,單擊鼠標(biāo)右鍵結(jié)束繪制。</p>
<p>點擊“繪制面”按鈕后在場景內(nèi)單擊鼠標(biāo)左鍵繪制面肴熏,單擊鼠標(biāo)右鍵結(jié)束繪制鬼雀。</p>
<p>點擊“清空繪制”按鈕刪除所有繪制對象。</p>
<p>剩下的我慢慢寫</p>
</div>
</div>
</div>
</template>
具體CSS樣式:
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#app,#cesiumContainer {
font-family: "Avenir", Helvetica, Arial, sans-serif;
width: 100%;
height: 100%;
overflow: hidden;
}
.btnContainer {
position: absolute;
left: 15px;
top: 80px;
padding: 10px 15px;
/*添加圓角邊框*/
border-radius: 5px;
border: 1px solid rgba(128,128,128, 0.5);
color: #ffffff;
background: rgba(0, 0, 0,0.4);
box-shadow: 0 4px 8px rgb(128 128 128 / 50%);
max-width: 300px;
}
button {
background: transparent;
border: 1px solid #00d0ffb8;
color: white;
padding: 7px 9px;
border-radius: 3px;
/*鼠標(biāo)光標(biāo)變?yōu)槭中?/
cursor: pointer;
}
.tip p{
margin: 2px 0px;
padding: 5px 1px;
}
</style>
3. 實現(xiàn)功能
- 數(shù)據(jù)初始化
<script>
...,
export default {
name: 'xxx',
data () {
return {
viewer: undefined,
tempEntities: []
}
}
}
</script>
- 實現(xiàn)根據(jù)指定類型繪制對象
/* 根據(jù)類型繪制對象
* @param type point polyline polygon */
draw (type) {
let that = this
let viewer = this.viewer
let tempEntities = this.tempEntities
let position = []
let tempPoints = []
// 開啟深度檢測
viewer.scene.globe.depthTestAgainstTerrain = true
// 創(chuàng)建場景的HTML canvas元素
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
switch (type) {
// 繪制點
case 'Point':
// 監(jiān)聽鼠標(biāo)左鍵 左鍵單擊開始繪制
handler.setInputAction(function (movement) {
// 從相機位置創(chuàng)建一條射線蛙吏,這條射線通過世界中movement.position像素所在的坐標(biāo)
let ray = viewer.camera.getPickRay(movement.position)
// 找到射線與渲染的地球表面之間的交點源哩。射線必須以世界坐標(biāo)給出。
position = viewer.scene.globe.pick(ray, viewer.scene)
// 畫出交點
let point = that.drawPoint(position)
// 將其添加到tempEntities數(shù)組的末尾
tempEntities.push(point)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 左鍵雙擊或右鍵單擊時停止繪制
handler.setInputAction(function () {
// 停止監(jiān)聽 關(guān)閉事件句柄
handler.destroy()
handler = null
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
handler.setInputAction(function () {
handler.destroy()
handler = null
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
break
// 繪制線
case 'Polyline':
// 監(jiān)聽鼠標(biāo)移動
handler.setInputAction(function (movement) {
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 左鍵單擊開始畫線
handler.setInputAction(function (click) {
// 獲取位置信息
let ray = viewer.camera.getPickRay(click.position)
position = viewer.scene.globe.pick(ray, viewer.scene)
tempPoints.push(position) // 記錄點位
let tempLength = tempPoints.length // 記錄點數(shù)
// 調(diào)用繪制點的接口
let point = that.drawPoint(tempPoints[tempPoints.length - 1])
tempEntities.push(point)
// 存在超過一個點時
if (tempLength > 1) {
// 繪制線
let pointline = that.drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
tempEntities.push(pointline) // 保存記錄
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 右鍵單擊結(jié)束畫線
handler.setInputAction(function (click) {
tempPoints = [] // 清空點位記錄
handler.destroy()
handler = null
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
break
// 繪制面
case 'Polygon':
// 監(jiān)聽鼠標(biāo)移動
handler.setInputAction(function (movement) {
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 左鍵單擊開始畫線
handler.setInputAction(function (click) {
// 獲取位置信息
let ray = viewer.camera.getPickRay(click.position)
position = viewer.scene.globe.pick(ray, viewer.scene)
tempPoints.push(position) // 記錄點位
let tempLength = tempPoints.length // 記錄點數(shù)
// 調(diào)用繪制點的接口
let point = that.drawPoint(tempPoints[tempPoints.length - 1])
tempEntities.push(point)
// 存在超過一個點時
if (tempLength > 1) {
// 繪制線
let pointline = that.drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
tempEntities.push(pointline) // 保存記錄
that.drawPolygon(tempPoints)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 右鍵單擊結(jié)束畫面
handler.setInputAction(function (click) {
// 選擇一個橢球或地圖
let cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
if (cartesian) {
let tempLength = tempPoints.length
if (tempLength < 3) {
alert('閉合操作需要至少3個點嗷')
} else {
// 閉合最后一條線
let pointline = that.drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
tempEntities.push(pointline)
that.drawPolygon(tempPoints)
tempEntities.push(tempPoints)
handler.destroy()
handler = null
}
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
break
}
}
- 具體的繪制方法(本質(zhì)上就是添加實體
// 繪制函數(shù)
drawPoint (position) {
let viewer = this.viewer
// 本質(zhì)上就是添加一個點的實體
return viewer.entities.add({
name: '點幾何對象',
position: position,
point: {
color: Cesium.Color.WHEAT,
pixelSize: 5,
outlineWidth: 3,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 規(guī)定貼地
}
})
},
drawPolyline (positions) {
let viewer = this.viewer
if (positions.length < 1) return
return viewer.entities.add({
name: '線幾何對象',
polyline: {
positions: positions,
width: 5.0,
material: new Cesium.PolylineGlowMaterialProperty({
// eslint-disable-next-line new-cap
color: Cesium.Color.GOLD
}),
depthFailmaterial: new Cesium.PolylineGlowMaterialProperty({
// eslint-disable-next-line new-cap
color: Cesium.Color.GOLD
}),
clampToGround: true
}
})
},
drawPolygon (positions) {
let viewer = this.viewer
if (positions.length < 2) return
return viewer.entities.add({
name: '面幾何對象',
polygon: {
hierarchy: positions,
// eslint-disable-next-line new-cap
material: new Cesium.ColorMaterialProperty(
Cesium.Color.WHITE.withAlpha(0.4)
)
}
})
}
- 清除繪制
思路是把數(shù)據(jù)都還原成初始值鸦做,把實體都注銷
/* 清除實體 */
clearAllDrawn () {
let viewer = this.viewer
this.tempEntities = []
viewer.entities.removeAll()
}
4. 完整核心代碼
<script>
import * as Cesium from 'cesium/Cesium'
import * as widgets from 'cesium/Widgets/widgets.css'
export default {
name: 'App',
data () {
return {
viewer: undefined,
tempEntities: []
}
},
mounted () {
this.Init()
},
methods: {
// 初始化
Init () {
// 引入個人token
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkYmJkNWQ3Mi0zOGVkLTQ5N2YtYTBmMy0wMDAyODZiMDMyZWYiLCJpZCI6ODQ2NzQsImlhdCI6MTY0NjQ0NTYxNX0.XkHX3rdysM4uUe5VTKDVEV3W2An33zyh4qAkFUac2fk'
// 設(shè)置取景器
this.viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(),
selectionIndicator: false, // 不顯示指示器小部件
infoBox: false, // 不顯示信息框
sceneModePicker: false, // 不顯示模式切換選項
baseLayerPicker: false,
navigationHelpButton: false,
animation: false,
shouldAnimate: false,
timeline: false,
geocoder: false,
homeButton: false
})
// 若瀏覽器不支持pickPosition励烦,顯示報錯信息
if (!this.viewer.scene.pickPositionSupported) {
window.alert('This browser does not support pickPosition.')
}
// 載入OSM建筑物
// const osmBuildings = this.viewer.scene.primitives.add(Cesium.createOsmBuildings()) // eslint-disable-line no-unused-vars
// 初始化鏡頭
this.viewer.camera.lookAt(
Cesium.Cartesian3.fromDegrees(-122.2058, 46.1955, 1000.0),
new Cesium.Cartesian3(5000.0, 5000.0, 5000.0)
)
this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
},
// 繪制函數(shù)
drawPoint (position) {
let viewer = this.viewer
// 本質(zhì)上就是添加一個點的實體
return viewer.entities.add({
name: '點幾何對象',
position: position,
point: {
color: Cesium.Color.WHEAT,
pixelSize: 5,
outlineWidth: 3,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 規(guī)定貼地
}
})
},
drawPolyline (positions) {
let viewer = this.viewer
if (positions.length < 1) return
return viewer.entities.add({
name: '線幾何對象',
polyline: {
positions: positions,
width: 5.0,
material: new Cesium.PolylineGlowMaterialProperty({
// eslint-disable-next-line new-cap
color: Cesium.Color.GOLD
}),
depthFailmaterial: new Cesium.PolylineGlowMaterialProperty({
// eslint-disable-next-line new-cap
color: Cesium.Color.GOLD
}),
clampToGround: true
}
})
},
drawPolygon (positions) {
let viewer = this.viewer
if (positions.length < 2) return
return viewer.entities.add({
name: '面幾何對象',
polygon: {
hierarchy: positions,
// eslint-disable-next-line new-cap
material: new Cesium.ColorMaterialProperty(
Cesium.Color.WHITE.withAlpha(0.4)
)
}
})
},
/* 清除實體 */
clearAllDrawn () {
let viewer = this.viewer
this.tempEntities = []
viewer.entities.removeAll()
},
created () {
},
/* 根據(jù)類型繪制對象
* @param type point polyline polygon */
draw (type) {
let that = this
let viewer = this.viewer
let tempEntities = this.tempEntities
let position = []
let tempPoints = []
// 開啟深度檢測
viewer.scene.globe.depthTestAgainstTerrain = true
// 創(chuàng)建場景的HTML canvas元素
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
switch (type) {
// 繪制點
case 'Point':
// 監(jiān)聽鼠標(biāo)左鍵 左鍵單擊開始繪制
handler.setInputAction(function (movement) {
// 從相機位置創(chuàng)建一條射線,這條射線通過世界中movement.position像素所在的坐標(biāo)
let ray = viewer.camera.getPickRay(movement.position)
// 找到射線與渲染的地球表面之間的交點泼诱。射線必須以世界坐標(biāo)給出坛掠。
position = viewer.scene.globe.pick(ray, viewer.scene)
// 畫出交點
let point = that.drawPoint(position)
// 將其添加到tempEntities數(shù)組的末尾
tempEntities.push(point)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 左鍵雙擊或右鍵單擊時停止繪制
handler.setInputAction(function () {
// 停止監(jiān)聽 關(guān)閉事件句柄
handler.destroy()
handler = null
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
handler.setInputAction(function () {
handler.destroy()
handler = null
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
break
// 繪制線
case 'Polyline':
// 監(jiān)聽鼠標(biāo)移動
handler.setInputAction(function (movement) {
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 左鍵單擊開始畫線
handler.setInputAction(function (click) {
// 獲取位置信息
let ray = viewer.camera.getPickRay(click.position)
position = viewer.scene.globe.pick(ray, viewer.scene)
tempPoints.push(position) // 記錄點位
let tempLength = tempPoints.length // 記錄點數(shù)
// 調(diào)用繪制點的接口
let point = that.drawPoint(tempPoints[tempPoints.length - 1])
tempEntities.push(point)
// 存在超過一個點時
if (tempLength > 1) {
// 繪制線
let pointline = that.drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
tempEntities.push(pointline) // 保存記錄
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 右鍵單擊結(jié)束畫線
handler.setInputAction(function (click) {
tempPoints = [] // 清空點位記錄
handler.destroy()
handler = null
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
break
// 繪制面
case 'Polygon':
// 監(jiān)聽鼠標(biāo)移動
handler.setInputAction(function (movement) {
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 左鍵單擊開始畫線
handler.setInputAction(function (click) {
// 獲取位置信息
let ray = viewer.camera.getPickRay(click.position)
position = viewer.scene.globe.pick(ray, viewer.scene)
tempPoints.push(position) // 記錄點位
let tempLength = tempPoints.length // 記錄點數(shù)
// 調(diào)用繪制點的接口
let point = that.drawPoint(tempPoints[tempPoints.length - 1])
tempEntities.push(point)
// 存在超過一個點時
if (tempLength > 1) {
// 繪制線
let pointline = that.drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
tempEntities.push(pointline) // 保存記錄
that.drawPolygon(tempPoints)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 右鍵單擊結(jié)束畫面
handler.setInputAction(function (click) {
// 選擇一個橢球或地圖
let cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
if (cartesian) {
let tempLength = tempPoints.length
if (tempLength < 3) {
alert('閉合操作需要至少3個點嗷')
} else {
// 閉合最后一條線
let pointline = that.drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
tempEntities.push(pointline)
that.drawPolygon(tempPoints)
tempEntities.push(tempPoints)
handler.destroy()
handler = null
}
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
break
}
}
}
}
</script>
三、 問題
-
問題:提示
Cannot read property 'draw' of undefined
應(yīng)對:這里是
this
指向出了問題,出這個問題的時候沒有先在draw (type)
方法里let that = this
然后再在case
里let point = that.drawPoint(position)
屉栓,而是直接this.drawPoint(position)
了舷蒲,所以要加上let that = this