效果图
方法一:使用插件
cesium_measure.js
下载地址:https://github.com/zhangti0708/cesium-measure/blob/master/src/cesium-measure.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Widgets/widgets.css">
<title>测距&面积</title>
</head>
<style>
.btn {
z-index: 999;
width: 100px;
height: 30px;
background-color: #fff;
position: absolute;
top: 30px;
right: 40px;
line-height: 30px;
text-align: center;
user-select: none;
}
.change {
z-index: 999;
width: 100px;
height: 30px;
position: absolute;
top: 30px;
right: 40px;
line-height: 30px;
text-align: center;
color: #fff;
background-color: #007acc;
user-select: none;
}
.pointInfo {
z-index: 999;
position: absolute;
/* top: 50%;
left: 50%;
transform: translate(-50%, -50%); */
width: 80px;
height: 40px;
background-color: #fff;
}
</style>
<body style="margin: 0;">
<div id="app">
<div class="pointInfo" v-show="open" ref="pointinfo" id="point">
</div>
<div :class="change?'btn':'change'" @click="signPlace(window.viewer)">
{{change?"测距":"测面积"}}
</div>
<div id="mapcontainer"></div>
</div>
</body>
<script src="../js/cesium_measure.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
plane: [], //存面实例
pointId: 0,
change: true,
open: false,
openimg: false,
labelname: '',
objpoint: {},
imgs: [
"../img/0.png",
"../img/1.png",
"../img/2.png",
],
urlimg: "../img/0.png",
point: [], //测距的点
arr: [], //存放划线的点
measure: null
},
methods: {
initMap() {
var viewer = new Cesium.Viewer('mapcontainer', {
animation: false, //是否显示动画控件
shouldAnimate: true,
homeButton: false, //是否显示Home按钮
fullscreenButton: true, //是否显示全屏按钮
baseLayerPicker: false, //是否显示图层选择控件
geocoder: false, //是否显示地名查找控件
timeline: false, //是否显示时间线控件
sceneModePicker: false, //是否显示投影方式控件
navigationHelpButton: false, //是否显示帮助信息控件
requestRenderMode: false, //启用请求渲染模式
scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存
sceneMode: 3, //初始场景模式 1 2D模式 2 2D循环模式 3 3D模式 Cesium.SceneMode
selectionIndicator: false,
skyAtmosphere: false,
infoBox: false
});
viewer._cesiumWidget._creditContainer.style.display = "none";
this.measure = new Cesium.Measure(viewer);
return viewer
},
mapFlyTo(viewer) {
viewer.camera.flyTo({
destination: new Cesium.Cartesian3.fromDegrees(132.02294829, 53.323929, 180000),
duration: 3
})
},
signPlace(viewer) {
if (this.change) {
this.change = false;
this.measure.drawLineMeasureGraphics({
clampToGround: true,
callback: () => {},
});
} else {
this.change = true;
this.measure.drawAreaMeasureGraphics({
clampToGround: true,
callback: (e) => {}
});
}
},
},
mounted() {
window.viewer = this.initMap();
this.mapFlyTo(window.viewer);
// this.mapEvent(window.viewer)
}
})
</script>
</html>
方法二:自己实现
测面积没实现 ,可以参考方法一插件里的实现方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Widgets/widgets.css">
<title>测距&面积</title>
</head>
<style>
.btn {
z-index: 999;
width: 100px;
height: 30px;
background-color: #fff;
position: absolute;
top: 30px;
right: 40px;
line-height: 30px;
text-align: center;
user-select: none;
}
.change {
z-index: 999;
width: 100px;
height: 30px;
position: absolute;
top: 30px;
right: 40px;
line-height: 30px;
text-align: center;
color: #fff;
background-color: #007acc;
user-select: none;
}
.pointInfo {
z-index: 999;
position: absolute;
/* top: 50%;
left: 50%;
transform: translate(-50%, -50%); */
width: 80px;
height: 40px;
background-color: #fff;
}
</style>
<body style="margin: 0;">
<div id="app">
<div class="pointInfo" v-show="open" ref="pointinfo" id="point">
</div>
<div :class="change?'btn':'change'" @click="signPlace(window.viewer)">
{{change?"测距":"测面积"}}
</div>
<div id="mapcontainer"></div>
</div>
</body>
<script src="../js/cesium_measure.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
plane: [], //存面实例
pointId: 0,
change: true,
open: false,
openimg: false,
labelname: '',
objpoint: {},
imgs: [
"../img/0.png",
"../img/1.png",
"../img/2.png",
],
urlimg: "../img/0.png",
point: [], //测距的点
arr: [], //存放划线的点
measure: null,
timeline: null
},
methods: {
drawLineMeasureGraphics(viewer) {
window.that = this
var draw = new Cesium.CustomDataSource('measureLayer')
viewer.dataSources.add(draw)
var positions = [],
positions_mian = [],
polygon = new Cesium.PolygonHierarchy(),
_lineEntity = new Cesium.Entity(),
$this = this,
lineObj,
_handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
// left
_handlers.setInputAction((movement) => {
var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
// console.log("cli" + cartesian);
var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());
var lat = Cesium.Math.toDegrees(cartographic.latitude);
var lng = Cesium.Math.toDegrees(cartographic.longitude);
var height = cartographic.height;
var objpoint = {
longitude: lng,
latitude: lat
}
this.point.push(cartesian)
if (this.point.length > 1) {
var distance = this.disTance(this.point)
this.labelname = distance;
// this.creatLine(this.arr, viewer)
}
if (cartesian && cartesian.x) {
if (positions.length == 0) {
positions.push(cartesian.clone());
}
this.addpoint(objpoint, viewer)
positions.push(cartesian);
// 测距
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
_handlers.setInputAction((movement) => {
// console.log(positions);
var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
if (positions.length >= 2) {
if (cartesian && cartesian.x) {
positions.pop();
positions.push(cartesian);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// right
_handlers.setInputAction((movement) => {
_handlers.destroy()
_handlers = null
let cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());
var lat = Cesium.Math.toDegrees(cartographic.latitude);
var lng = Cesium.Math.toDegrees(cartographic.longitude);
var height = cartographic.height;
var objpoint = {
longitude: lng,
latitude: lat
}
this.addpoint(objpoint, viewer)
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
_lineEntity.polyline = {
width: 5,
material: Cesium.Color.BLUE.withAlpha(0.8),
clampToGround: false
}
_lineEntity.polyline.positions = new Cesium.CallbackProperty(function() {
return positions
}, false)
lineObj = draw.entities.add(_lineEntity)
},
// 测面
drawplane(viewer) {
var draw = new Cesium.CustomDataSource('measureLayer1')
viewer.dataSources.add(draw)
var positions = [],
polygon = new Cesium.PolygonHierarchy(),
_polygonEntity = new Cesium.Entity(),
polyObj = null,
_label = '',
_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
// left
_handler.setInputAction((movement) => {
var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
if (cartesian && cartesian.x) {
if (positions.length == 0) {
polygon.positions.push(cartesian.clone())
positions.push(cartesian.clone());
}
positions.push(cartesian.clone());
polygon.positions.push(cartesian.clone())
// var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());
var lat = Cesium.Math.toDegrees(cartographic.latitude);
var lng = Cesium.Math.toDegrees(cartographic.longitude);
var height = cartographic.height;
var objpoint = {
longitude: lng,
latitude: lat
}
this.addpoint(objpoint, viewer)
if (!polyObj) {
_polygonEntity.polyline = {
width: 3,
material: Cesium.Color.BLUE.withAlpha(0.8),
clampToGround: false
}
_polygonEntity.polyline.positions = new Cesium.CallbackProperty(function() {
return positions
}, false)
_polygonEntity.polygon = {
hierarchy: new Cesium.CallbackProperty(function() {
return polygon
}, false),
material: Cesium.Color.WHITE.withAlpha(0.8),
clampToGround: false
}
polyObj = draw.entities.add(_polygonEntity)
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// mouse
_handler.setInputAction((movement) => {
var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
// var cartesian = $this._viewer.scene.camera.pickEllipsoid(movement.endPosition, $this._viewer.scene.globe.ellipsoid);
if (positions.length >= 2) {
if (cartesian && cartesian.x) {
positions.pop()
positions.push(cartesian);
polygon.positions.pop()
polygon.positions.push(cartesian);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// right
_handler.setInputAction((movement) => {
let cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
_handler.destroy();
positions.push(positions[0]);
// let cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());
var lat = Cesium.Math.toDegrees(cartographic.latitude);
var lng = Cesium.Math.toDegrees(cartographic.longitude);
var height = cartographic.height;
var objpoint = {
longitude: lng,
latitude: lat
}
this.addpoint(objpoint, viewer)
// if (typeof options.callback === 'function') {
// options.callback($this.transformCartesianArrayToWGS84Array(positions), polyObj);
// }
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
},
initMap() {
var viewer = new Cesium.Viewer('mapcontainer', {
animation: false, //是否显示动画控件
shouldAnimate: true,
homeButton: false, //是否显示Home按钮
fullscreenButton: true, //是否显示全屏按钮
baseLayerPicker: false, //是否显示图层选择控件
geocoder: false, //是否显示地名查找控件
timeline: false, //是否显示时间线控件
sceneModePicker: false, //是否显示投影方式控件
navigationHelpButton: false, //是否显示帮助信息控件
requestRenderMode: false, //启用请求渲染模式
scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存
sceneMode: 3, //初始场景模式 1 2D模式 2 2D循环模式 3 3D模式 Cesium.SceneMode
selectionIndicator: false,
skyAtmosphere: false,
infoBox: false
});
viewer._cesiumWidget._creditContainer.style.display = "none";
this.measure = new Cesium.Measure(viewer);
return viewer
},
mapFlyTo(viewer) {
viewer.camera.flyTo({
destination: new Cesium.Cartesian3.fromDegrees(132.02294829, 53.323929, 180000),
duration: 3
})
},
signPlace(viewer) {
viewer.screenSpaceEventHandler.destroy()
this.point = [];
this.labelname = ""
if (this.change) {
this.change = false;
this.drawLineMeasureGraphics(viewer)
} else {
this.change = true;
this.drawplane(viewer)
}
},
// 两点距离
//positions 包含两个点的数组
disTance(positions) {
var distance = 0;
for (var i = 0; i < positions.length - 1; i++) {
var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
// console.log(point1cartographic, point2cartographic);
var geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
var s = geodesic.surfaceDistance;
distance = distance + s;
}
return distance.toFixed(0);
},
/**
* 计算一组坐标组成多边形的面积
* @param {*} positions
*/
getPositionsArea: function(positions) {
let result = 0
if (positions) {
let h = 0
let ellipsoid = Cesium.Ellipsoid.WGS84
positions.push(positions[0])
for (let i = 1; i < positions.length; i++) {
let oel = ellipsoid.cartographicToCartesian(
this.transformWGS84ToCartographic(positions[i - 1])
)
let el = ellipsoid.cartographicToCartesian(
this.transformWGS84ToCartographic(positions[i])
)
h += oel.x * el.y - el.x * oel.y
}
result = Math.abs(h).toFixed(2)
}
return result
},
// 添加点
//添加图标点
addpoint(pointData, viewer) {
var billboards = viewer.scene.primitives.add(new Cesium.BillboardCollection());
window.billboards = billboards;
var labels = viewer.scene.primitives.add(new Cesium.LabelCollection());
window.labels = labels
position = Cesium.Cartesian3.fromDegrees(pointData.longitude, pointData.latitude,
0);
billboards.add({
id: this.pointId,
position: position,
image: this.urlimg,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
});
labels.add({
show: !this.change,
position: position,
text: this.labelname,
id: this.pointId,
font: '10px',
pixelOffset: new Cesium.Cartesian2(-20, -30),
})
this.pointId++;
},
//面
creatplane(polylineData, viewer) {
var entit = this.plane[0]
this.plane = [];
viewer.entities.remove(entit);
var polyon = viewer.entities.add({
polygon: {
// 获取指定属性(positions,holes(图形内需要挖空的区域))
hierarchy: {
positions: Cesium.Cartesian3.fromDegreesArray(polylineData)
},
// 边框
outline: true,
// 边框颜色
outlineColor: Cesium.Color.WHITE,
// 边框尺寸
outlineWidth: 2,
// 填充的颜色,withAlpha透明度
material: Cesium.Color.GREEN.withAlpha(0.5),
// 是否被提供的材质填充
fill: true,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(1000, 10000000),
// 是否显示
show: true,
// 顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。
zIndex: 10
}
})
this.plane.push(polyon)
},
mapEvent(viewer) {
// var mapEvent = new Cesium.ScreenSpaceEventHandler(cesiumScene.canvas);
viewer.screenSpaceEventHandler.setInputAction((click) => {
var pick = viewer.scene.pick(click.endPosition);
if (pick && typeof(pick.id) == "number") {
document.body.style = "cursor: pointer;";
this.infobox(viewer.scene, viewer)
} else {
document.body.style = "cursor: default;";
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
},
//弹框位置
htmlFixed(cesiumView, htmlOverlay, lng, lat) {
const domHeight = htmlOverlay.offsetHeight; // DOM的高度
const domWidth = htmlOverlay.offsetWidth; // DOM的宽度
const heightOffset = 20; // Y轴偏移量
const widthOffset = -9; // X轴偏移量
const scratch = new Cesium.Cartesian2();
cesiumView.scene.preRender.addEventListener(function() {
var las = lat - 0.0009;
let position = Cesium.Cartesian3.fromDegrees(
lng, las, 2);
let canvasPosition = cesiumView.scene
.cartesianToCanvasCoordinates(position,
scratch);
if (Cesium.defined(canvasPosition)) {
htmlOverlay.style.top = canvasPosition.y -
domHeight -
heightOffset + 'px';
htmlOverlay.style.left = canvasPosition.x -
domWidth / 2 -
widthOffset + 'px';
}
});
},
},
mounted() {
window.viewer = this.initMap();
this.mapFlyTo(window.viewer);
// this.mapEvent(window.viewer)
}
})
</script>
</html>