前言:
cesium 加载矢量地图后,在三维模式下会平铺在地面上,我们配好的标注也会变形,非常影响效果。如下图所示:加载的arcgis 矢量服务后。
需求:
我们想要加载普通的矢量服务后也要有三维的效果,点图标是立起来的,标注是三维始终面向用户的,面和线是可以在地形上的。
看下渲染的三维效果:
思路:
针对arcgis mapserver :
1、获取屏幕范围
2、获取屏幕范围内的要素点
3、重新渲染
其中第二点可以调用它的服务 query 接口 ,找到一个mapserver ,点进去具体的server ,拉到最下面有个query 点进去,然后在where 一栏中 输入 1 = 1 ,看下地址栏参数,这个页面右上角有help 也可以看下帮助手册。
代码实现:
今天心情不错,直接贴源码吧。提前祝大家新年快乐~~~
<!--加载arcgis server mapserver 矢量-->
<template>
<div class="box">
<div class="map-tool">
<el-button @click="rendererArcisMapserver">开启渲染</el-button>
</div>
<div id="mapContainter"></div>
</div>
</template>
<script>
import * as Cesium from 'cesium';
import "cesium/widgets.css";
import {car3ToDegress} from '@/moudules/common/commonUtils'
import LayerApi from "@/api/layers/LayerApi";
import {markerPoint} from "@/moudules/config/symbolConfig";
var viewer = null;
var arcgisLayer = null;
var billboardC = null;
var labelC = null;
export default {
name: "statrMapbackup",
data() {
return {
url: 'http://server.mars3d.cn/arcgis/rest/services/mars/hfghss/MapServer',
}
},
mounted() {
this.initMap();
},
methods: {
initMap() {
Cesium.Ion.defaultAccessToken = this.CesiumToken;
//初始化视图
viewer = new Cesium.Viewer(
"mapContainter",
{
// animation:false
selectionIndicator: false,//是否创建选择指示符小部件,也就是在选择实体时实体本身会出现一个绿色方块。如果设置为false,则不创建选择指示符小部件
timeline: false,//时间轴,默认值 true
infoBox: false,//显示信息框
imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
url: 'http://{s}.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=' + this.tdtToken,
layer: 'img',
style: 'default',
format: 'tiles',
tileMatrixSetID: 'w',
subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
credit: new Cesium.Credit('天地图影像'),
maximumLevel: 21
}),
terrainProvider: new Cesium.CesiumTerrainProvider({
url: Cesium.IonResource.fromAssetId(1),
requestVertexNormals: true,//顶点法线效果
requestWaterMask: true,//水效果
})
}
)
// 显示帧率
viewer.scene.debugShowFramesPerSecond = true;
//正常加载
this.addArcgisLayer();
},
addArcgisLayer() {
arcgisLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: this.url,
rectangle: new Cesium.Rectangle.fromDegrees(
116.86790296682878,
31.594039369049813,
117.55673693657434,
32.10242163337958
)
}),
);
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(117.28, 31.86, 1000000)
});
},
//先获取屏幕区域,再获取区域内要素点,最后渲染
rendererArcisMapserver() {
viewer.scene.globe.depthTestAgainstTerrain = true;
viewer.camera.moveEnd.addEventListener(() => {
let bounds = this.getCurrentBounds();
// console.log(bounds)
let p = {
'f': 'json',
'geometry': bounds,
'geometryType': 'esriGeometryEnvelope',
'spatialRel': 'esriSpatialRelIntersects',//相交
"returnGeometry": "true",
"outFields": "*"
}
let url = this.url + '/1/query';
LayerApi.arcgisQuery(url, p).then((res) => {
if (res.data.features && res.data.features.length > 0) {
this.clearLast();
console.log(res.data.features)
res.data.features.forEach((item) => {
let g = item.geometry;
this.addMarkerPoint(g.x, g.y, item.attributes['设施类型'])
})
}
})
})
},
getCurrentBounds() {
let bounds = [];
let car3_lt = viewer.scene.globe.pick(viewer.camera.getPickRay(new Cesium.Cartesian2(0, 0)), viewer.scene);
let car3_rb = viewer.scene.globe.pick(viewer.camera.getPickRay(new Cesium.Cartesian2(viewer.scene.canvas.width, viewer.scene.canvas.height)), viewer.scene);
if (!car3_lt) return;
if (!car3_rb) return;
let degrees_lt = car3ToDegress(car3_lt);
let degress_rb = car3ToDegress(car3_rb);
bounds = {
"xmin": degrees_lt[0],
"ymin": degress_rb[1],
"xmax": degress_rb[0],
"ymax": degrees_lt[1],
};
return bounds;
},
clearLast() {
if (billboardC) {
billboardC.removeAll();
} else {
billboardC = viewer.scene.primitives.add(
new Cesium.BillboardCollection({
scene: viewer.scene
})
);
}
if (labelC) {
labelC.removeAll();
} else {
labelC = viewer.scene.primitives.add(
new Cesium.LabelCollection({
scene: viewer.scene
})
)
}
},
addMarkerPoint(lng, lat, val) {
//添加billboard
billboardC.add({
position: Cesium.Cartesian3.fromDegrees(lng, lat, 5),
...markerPoint.billBoard
});
labelC.add({
position: Cesium.Cartesian3.fromDegrees(lng, lat, 5),
text: val,
...markerPoint.label
})
},
},
components: {}
}
</script>
<style scoped>
html,
#mapContainter {
width: 100%;
height: 98vh;
}
</style>
markerPoint 配置:
/**
* @Description: 符号集合
* @author MrKuang
* @VX k792794653
* @date 2022/8/22 0022
*/
import * as Cesium from "cesium";
/**
* 点图片+点标签
* @type {{label: {fillColor: Color, outlineWidth: number, verticalOrigin: VerticalOrigin.BOTTOM, showBackground: boolean, outlineColor: module:cesium.Color, horizontalOrigin: HorizontalOrigin.LEFT, style: LabelStyle.FILL_AND_OUTLINE, pixelOffset: module:cesium.Cartesian2, font: string}, billBoard: {image: *, verticalOrigin: VerticalOrigin.BOTTOM, width: number, heightReference: HeightReference.RELATIVE_TO_GROUND, height: number}}}
*/
const markerPoint ={
billBoard:{
image:require('@/assets/billboard.png'),
verticalOrigin:Cesium.VerticalOrigin.BOTTOM,
heightReference:Cesium.HeightReference.RELATIVE_TO_GROUND,
height:40,
width:35,
},
label:{
font : '18px sans-serif',
fillColor:Cesium.Color.WHITE,
outlineColor : new Cesium.Color(0 / 255, 229 / 255, 255 / 255, 0.8),
outlineWidth : 0.5,
style:Cesium.LabelStyle.FILL_AND_OUTLINE,
showBackground:false,
pixelOffset:new Cesium.Cartesian2(-20,-40),//像素偏移
horizontalOrigin:Cesium.HorizontalOrigin.LEFT,//相对于对象的原点的水平位置
verticalOrigin:Cesium.VerticalOrigin.BOTTOM,//相对于对象的原点的垂直位置
}
}
export {
markerPoint
}
car3ToDegress 方法:
export const car3ToDegress=(v)=>{
let c = Cesium.Cartographic.fromCartesian(v);
let d1 = Cesium.Math.toDegrees(c.longitude);
let d2 = Cesium.Math.toDegrees(c.latitude);
return [d1,d2];
}
LayerApi.arcgisQuery 是我自己封装的get 请求,一个参数 是url ,另个参数 是params ,代码里有, 你自己根据ajax 或者 axios 去请求都行
哦了~~~