博主又开新系列啦!!!毕业前学了3个月的postgresql+geoserver+leaflet准备工作后大展拳脚,事实证明我还是太年轻啊,因为我学的一个也没用到,因为公司项目以三维为主,于是我又开始了Vue+Cesium从入门到放弃之路,相比二维,三维平台还不是很成熟,很多在二维下很容易实现的功能在三维下可以需要从头写起,话不多说,先上图。
PS:以下功能都是Cesium结合Vue实现的,如果不懂Vue语法可以在理解起来有点困难。
功能:添加一个注记,允许用户输入注记信息。
添加标记应该是GIS常用的一个功能,但是Cesium并没有很好的实现这个功能,Cesium有一个Entry类,可以用来在地图上创建一个实体,包括后面的点线面都要用这个类实现(当然也有其它办法),这个的参数有billboard,point、polyline、polygon、label,分别用来创建广告牌(Cesium中的叫法,就是用图片在图上添加一个标记)、点、线、面、文字。
思路:Cesium有添加一个图片(注记)的功能(billboard),也有添加文字的功能(label),但并没有给注记添加文字信息的功能,所以要实现这个功能就要把billboard和labe合成一个组件。具体:
实现过程:marker.vue
1.设计模板,需要一个文本框和一个按钮
<template>
<div id="markerContainer">
<div id="msg1" :style="{left:scenePos.x+30+'px',top:scenePos.y+'px'}" v-show="isShow">
<input id="msg" type="text" placeholder="标记名称" @keyup.enter="update" v-model="msg" ref="msg_input" v-focus class="form-control"/>
div>
<div id='submit1' :style="{left:scenePos.x+180+'px',top:scenePos.y+'px'}" v-show="isShow">
<input type="button" name="nameSave" class="btn btn-primary" id='submit' @click="update" value="ok" />
div>
<div id="menu" v-show="menuShow" oncontextmenu="return false">
<div><a href="#" @click="edit">编 辑a>div>
<div><a href="#" @click="drop">删 除a>div>
div>
<div id="tooltip" :style="{left:tipPos.x-100+'px',top:tipPos.y-90+'px'}" v-show="tipShow">
<span>名称:{{curText}}span><br/>
<span>纬度:{{curLat}}span><br/>
<span>经度:{{curLon}}span><br/>
<div class="arrow">div>
div>
div>
template>
2.功能实现
import Cesium from 'cesium/Cesium'
import Bus from '@/js/Bus'
export default {
data() {
return {
msg:'',
tipPos:{x:0,y:0},
viewer:'',
scenePos:'',
isShow:false,
billboards:'',
labels:'',
selectedObj:'',
menuShow:false,
tipShow:true,
curIndex:null,
isDrawing:true,
curLat:0,
curLon:0,
curText:''
}
},
computed:{
handler(){
return new Cesium.ScreenSpaceEventHandler(this.viewer.canvas)
}
},
directives:{
focus(el){
el.focus()
}
},
mounted(){
const _this=this
_this.viewer=new Cesium.Viewer('cesiumContainer')
Bus.$on('drawingStop',_this.stopDrawing)
Bus.$on('markerViewerInit',_this.init)
Bus.$on('markerViewerDestroy',_this.destroy)
},
methods: {
init(){
const _this=this
// _this.isShow=true
_this.handler.setInputAction(evt=>{
// _this.menuShow=false
const e = window.event,//event|| window.event,
target = e.target || e.srcElement;
if(!_this.isDrawing){
return
}
//如果点击的对象是地球,添加一个marker
if(target&&target.tagName=='CANVAS'&&target.parentElement.className=='cesium-widget'){
_this.scenePos=evt.position
_this.add()
_this.msg=''
// _this.$refs.msg_input.focus()
}else {
}
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
//将billboard和label分别存储在数组中
_this.billboards=_this.viewer.scene.primitives.add(new Cesium.BillboardCollection())
_this.labels=_this.viewer.scene.primitives.add(new Cesium.LabelCollection())
},
add() {
const _this=this
_this.isShow=true
_this.tipShow=false
_this.billboards.add({
id:'marker%d' % _this.billboards.length,
position: _this.viewer.scene.globe.pick(_this.viewer.camera.getPickRay(_this.scenePos),_this.viewer.scene),
image:'static/images/pin.png'//marker的图片,可以任意替换
})
_this.labels.add({
position:_this.viewer.scene.globe.pick(_this.viewer.camera.getPickRay(_this.scenePos),_this.viewer.scene),
id:'marker_label%d' % _this.billboards.length,
text:'',
font: '24px sans-serif',
fillColor: Cesium.Color.BLACK,
outlineWidth: 5,
outlineColor: Cesium.Color.WHITE,
pixelOffset: new Cesium.Cartesian2(20, 20),
style: Cesium.LabelStyle.FILL_AND_OUTLINE
})
},
update:function(){
if(this.curIndex==undefined){
this.curIndex=this.labels.length-1
}
this.labels.get(this.curIndex).text=this.msg
this.isShow=false
this.msg=''
this.curIndex=undefined
},
destroy(){
this.handler.destroy()
this.labels.destroy()
this.billboards.destroy()
}
}
}
</script>
3.样式
<style>
style>
4.调用
在你的主页面引入刚才写的marker组件
<template>
<markerViewer></markerViewer>
</template>
<script>
import markerViewer from 'marker'
import Bus from '@/js/Bus'
export default {
data() {
return {
}
},
components:{markerViewer},//引用自己写的组件
methods: {},
mounted() {
Bus.$emit('markerViewerInit')//初始化
}
</script>
5.Bus.js
import Vue from 'vue'
export default new Vue()
6.总结
到这里添加一个标记的功能就基本完成了,图片中的单击显示标记信息和右键菜单的代码我并没有贴出来,因为代码量太大影响阅读,对此功能有需求的可以联系博主。
时间有限,今天就写到这里吧,下次再写绘点线面。。。。。
=================== 4.16更新分割线=================
今天我打算写简单一点,时间有限,直接上代码
const viewer = new Cesium.Viewer('cesiumContainer');
const handler=new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
let drawMode='line'
let activePoints=[]
let floatPoint,dynamicShape
handler.setInputAction(function (e) {
const wp=viewer.scene.globe.pick(viewer.camera.getPickRay(e.position),viewer.scene)
if(Cesium.defined(wp)){
activePoints.push(wp)
//下面这个if中的代码用于创建一个临时多边形(线)多边形的开关跟随鼠标的位置变化,
if(!Cesium.defined(floatPoint)){
floatPoint=new Cesium.CallbackProperty(function () {
return activePoints
})
activePoints.push(wp)
dynamicShape=drawShape(floatPoint)
}
}
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
handler.setInputAction(function (e) {
const wp=viewer.scene.globe.pick(viewer.camera.getPickRay(e.endPosition),viewer.scene)
if(Cesium.defined(wp)){
if(activePoints.length>1){
activePoints.pop()
activePoints.push(wp)
}
}
},Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handler.setInputAction(function (e) {
drawShape(activePoints)
activePoints=[]
floatPoint=null
},Cesium.ScreenSpaceEventType.RIGHT_CLICK)
function drawShape(position) {
console.log(position)
const entity=drawMode=='line'?
viewer.entities.add({
polyline:{
positions:position,
width:3,
material: new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.8)),
clampToGround: true
}
}):
viewer.entities.add({
polygon:{
hierarchy:position,
material: new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.3)),
//material: new Cesium.ColorMaterialProperty(new Cesium.Color(205, 139, 14, 1)),
outline: true,
outlineColor: Cesium.Color.BLACK,
outlineWidth:3
}
})
return entity
//viewer.entities.add(entity)
}
以上。有问题请留言。
-------------------------------我又来更新啦------------------------------
最近把这个功能完善了一下,增加了编辑和删除功能,下面是效果图
修改后的代码我上传到了github,地址https://github.com/xtfge/vue-cesium-draw,有兴趣的请自己下载。
2020.3.3更新
Github被墙了,更新码云地址