使用Cesium动态绘制点、线、面、圆、矩形

将以下代码复制到https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/?src=Drawing%20on%20Terrain.html查看Demo。

var activeShapePoints = [];
var activeShape;
var floatingPoint;

//查看器
var viewer = new Cesium.Viewer('cesiumContainer', {
    selectionIndicator: false,
    infoBox: false,
    // 注释时相当于使用默认地形,解开注释相当于使用全球地形
    terrainProvider: Cesium.createWorldTerrain()
});

var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);

//双击鼠标左键清除默认事件
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))
            }
        });
    } else if (drawingMode === 'circle') {
        //当positionData为数组时绘制最终图,如果为function则绘制动态图
        var value = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData;
        //var start = activeShapePoints[0];
        //var end = activeShapePoints[activeShapePoints.length - 1];
        //var r = Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
        //r = r ? r : r + 1;
        shape = viewer.entities.add({
            position: activeShapePoints[0],
            name: 'Blue translucent, rotated, and extruded ellipse with outline',
            type:'Selection tool',
            ellipse: {
                semiMinorAxis: new Cesium.CallbackProperty(function () {
                    //半径 两点间距离
                    var r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math.pow(value[0].y - value[value.length - 1].y, 2));
                    return r ? r : r + 1;
                }, false),
                semiMajorAxis: new Cesium.CallbackProperty(function () {
                    var r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math.pow(value[0].y - value[value.length - 1].y, 2));
                    return r ? r : r + 1;
                }, false),
                material: Cesium.Color.BLUE.withAlpha(0.5),
                outline: true
            }
        });
    } else if (drawingMode === 'rectangle') {
        //当positionData为数组时绘制最终图,如果为function则绘制动态图
        var arr = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData;
        shape = viewer.entities.add({
            name: 'Blue translucent, rotated, and extruded ellipse with outline',
            rectangle : {
                coordinates :  new Cesium.CallbackProperty(function () {
                    var obj=Cesium.Rectangle.fromCartesianArray(arr);
                    //if(obj.west==obj.east){ obj.east+=0.000001};
                    //if(obj.south==obj.north){obj.north+=0.000001};
                    return obj;
                }, false),
                material : Cesium.Color.RED.withAlpha(0.5)
            }
        });
    }
    return shape;
}
//鼠标左键
handler.setInputAction(function (event) {
    // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
    // we get the correct point when mousing over terrain.
    var earthPosition = viewer.scene.pickPosition(event.position);
    // `earthPosition` will be undefined if our mouse is not over the globe.
    if (Cesium.defined(earthPosition)) {
        if (activeShapePoints.length === 0) {
            floatingPoint = createPoint(earthPosition);
            activeShapePoints.push(earthPosition);
            var dynamicPositions = new Cesium.CallbackProperty(function () {
	            if (drawingMode === 'polygon') {
	              return new Cesium.PolygonHierarchy(activeShapePoints);
	             }
                return activeShapePoints;
            }, false);
            activeShape = drawShape(dynamicPositions);//绘制动态图
        }
        activeShapePoints.push(earthPosition);
        createPoint(earthPosition);
    }
}, 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);
        }
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

// Redraw the shape so it's not dynamic and remove the dynamic shape.
function terminateShape() {
    activeShapePoints.pop();//去除最后一个动态点
    if(activeShapePoints.length){
       drawShape(activeShapePoints);//绘制最终图
    }
    viewer.entities.remove(floatingPoint);//去除动态点图形(当前鼠标点)
    viewer.entities.remove(activeShape);//去除动态图形
    floatingPoint = undefined;
    activeShape = undefined;
    activeShapePoints = [];
}

handler.setInputAction(function (event) {
    terminateShape();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

var options = [{
    text: 'Draw Lines',
    onselect: function () {
        terminateShape();
        drawingMode = 'line';
    }
}, {
    text: 'Draw Polygons',
    onselect: function () {
        terminateShape();
        drawingMode = 'polygon';
    }
}, {
    text: 'Draw Circle',
    onselect: function () {
        terminateShape();
        drawingMode = 'circle';
    }
}, {
    text: 'Draw Rectangle',
    onselect: function () {
        terminateShape();
        drawingMode = 'rectangle';
    }
}];

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);

最后说下Sandcastle这个,这个是一个简单的组件库,在Cesium中Apps/Sandcastle这个文件夹下,本地可以引入Apps/Sandcastle/Sandcastle-header.js这个文件就可以用Sandcastle了,线上可以引用
<script src=“https://cesiumjs.org/releases/1.59/Apps/Sandcastle/Sandcastle-header.js”>但是还是自己写个好些。。

还有就是有线上引用的话,体验会很差,尤其网不好的同志。会导致画完后线段会没叠到地图上,解决办法就是要不下载cesium本地引用,要不就等一会就好了。1.59、1.60版本需要 access token了,需要去官网注册token,需要设置token否则地图不能正常显示,1.62我试没这个token地图还正常显示。(注意以下代码只在1.62及以下版本适用,其他版本没试过,可能会报错)

还有评论区的小伙伴提的鼠标指针和点不重合的问题depthTestAgainstTerrain 设为true试试。

viewer.scene.globe.depthTestAgainstTerrain = true;//开启地形深度检测
Cesium.Ion.defaultAccessToken = 'your_access_token';

最后完整的本地测试代码在这:新建个html文件copy进去就可以用了。

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- Use correct character set. -->
    <meta charset="utf-8">
    <!-- Tell IE to use the latest, best version. -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
    <meta name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
     <title>Hello World!</title>
    <!-- 本地 -->
    <!-- <script src="../Build/Cesium/Cesium.js"></script>
    <script src="../Apps/Sandcastle/Sandcastle-header.js"></script>
    <link rel="stylesheet" type="text/css" href="../Build/Cesium/Widgets/widgets.css" />  -->
    
    <!-- 线上 -->
    <script src="https://cesiumjs.org/releases/1.62/Build/Cesium/Cesium.js"></script>
    <script src="https://cesiumjs.org/releases/1.62/Apps/Sandcastle/Sandcastle-header.js"></script>
    <link href="https://cesiumjs.org/releases/1.62/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>

<body>
      <div id="cesiumContainer"></div>
      <div id="toolbar" style="margin: 5px;padding: 2px 5px;position: absolute;top:50px"></div>
      <script>
        var activeShapePoints = [];
        var activeShape;
        var floatingPoint;
        //Cesium.Ion.defaultAccessToken = 'your_access_token';
        //查看器
        var viewer = new Cesium.Viewer('cesiumContainer', {
            selectionIndicator: false,
            infoBox: false,
            // 注释时相当于使用默认地形,解开注释相当于使用全球地形
            terrainProvider: Cesium.createWorldTerrain()
        });

        var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);

        //双击鼠标左键清除默认事件
        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))
                    }
                });
            } else if (drawingMode === 'circle') {
                //当positionData为数组时绘制最终图,如果为function则绘制动态图
                var value = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData;
                //var start = activeShapePoints[0];
                //var end = activeShapePoints[activeShapePoints.length - 1];
                //var r = Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
                //r = r ? r : r + 1;
                shape = viewer.entities.add({
                    position: activeShapePoints[0],
                    name: 'Blue translucent, rotated, and extruded ellipse with outline',
                    type: 'Selection tool',
                    ellipse: {
                        semiMinorAxis: new Cesium.CallbackProperty(function () {
                            //半径 两点间距离
                            var r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math
                                .pow(value[0].y - value[value.length - 1].y, 2));
                            return r ? r : r + 1;
                        }, false),
                        semiMajorAxis: new Cesium.CallbackProperty(function () {
                            var r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math
                                .pow(value[0].y - value[value.length - 1].y, 2));
                            return r ? r : r + 1;
                        }, false),
                        material: Cesium.Color.BLUE.withAlpha(0.5),
                        outline: true
                    }
                });
            } else if (drawingMode === 'rectangle') {
                //当positionData为数组时绘制最终图,如果为function则绘制动态图
                var arr = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData;
                shape = viewer.entities.add({
                    name: 'Blue translucent, rotated, and extruded ellipse with outline',
                    rectangle: {
                        coordinates: new Cesium.CallbackProperty(function () {
                            var obj = Cesium.Rectangle.fromCartesianArray(arr);
                            //if(obj.west==obj.east){ obj.east+=0.000001};
                            //if(obj.south==obj.north){obj.north+=0.000001};
                            return obj;
                        }, false),
                        material: Cesium.Color.RED.withAlpha(0.5)
                    }
                });
            }
            return shape;
        }
        //鼠标左键
        handler.setInputAction(function (event) {
            // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
            // we get the correct point when mousing over terrain.
            // scene.pickPosition只有在开启地形深度检测,且不使用默认地形时是准确的。
            var earthPosition = viewer.scene.pickPosition(event.position);
            // `earthPosition` will be undefined if our mouse is not over the globe.
            if (Cesium.defined(earthPosition)) {
                if (activeShapePoints.length === 0) {
                    floatingPoint = createPoint(earthPosition);
                    activeShapePoints.push(earthPosition);
                    var dynamicPositions = new Cesium.CallbackProperty(function () {
	                    if (drawingMode === 'polygon') {
			              return new Cesium.PolygonHierarchy(activeShapePoints);
			             }
                        return activeShapePoints;
                    }, false);
                    activeShape = drawShape(dynamicPositions); //绘制动态图
                }
                activeShapePoints.push(earthPosition);
                createPoint(earthPosition);
            }
        }, 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);
                }
            }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

        // Redraw the shape so it's not dynamic and remove the dynamic shape.
        function terminateShape() {
            activeShapePoints.pop(); //去除最后一个动态点
            if (activeShapePoints.length) {
                drawShape(activeShapePoints); //绘制最终图
            }
            viewer.entities.remove(floatingPoint); //去除动态点图形(当前鼠标点)
            viewer.entities.remove(activeShape); //去除动态图形
            floatingPoint = undefined;
            activeShape = undefined;
            activeShapePoints = [];
        }

        handler.setInputAction(function (event) {
            terminateShape();
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

        var options = [{
            text: 'Draw Lines',
            onselect: function () {
                terminateShape();
                drawingMode = 'line';
            }
        }, {
            text: 'Draw Polygons',
            onselect: function () {
                terminateShape();
                drawingMode = 'polygon';
            }
        }, {
            text: 'Draw Circle',
            onselect: function () {
                terminateShape();
                drawingMode = 'circle';
            }
        }, {
            text: 'Draw Rectangle',
            onselect: function () {
                terminateShape();
                drawingMode = 'rectangle';
            }
        }];

        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);
        viewer.scene.globe.depthTestAgainstTerrain = true;//开启地形深度检测,如果鼠标指针和点不重合,这个选项设置为true试试。
    </script>
</body>

</html>

参考 https://github.com/K-UTIL/cesiumjs-demo/blob/master/Source/demo.js
https://blog.csdn.net/weixin_33774883/article/details/87495638
Cesium的拾取问题总结:https://zhuanlan.zhihu.com/p/44767866
Cesium4种获取鼠标点击位置:https://blog.csdn.net/weitaming1/article/details/95067688

  • 27
    点赞
  • 131
    收藏
    觉得还不错? 一键收藏
  • 38
    评论
要实现cesium动态绘制矩形,可以使用Cesium的Primitive API和MouseEvents。具体步骤如下: 1. 创建矩形entity并添加到场景中。 ``` var entity = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), material: Cesium.Color.RED.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.BLACK } }); ``` 2. 获取鼠标左键按下和移动事件,并更新矩形的坐标。 ``` var startPosition; var mouseHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); mouseHandler.setInputAction(function(movement) { startPosition = movement.position; }, Cesium.ScreenSpaceEventType.LEFT_DOWN); mouseHandler.setInputAction(function(movement) { if (Cesium.defined(startPosition)) { var endPosition = movement.position; var startCartesian = viewer.scene.camera.pickEllipsoid(startPosition, viewer.scene.globe.ellipsoid); var endCartesian = viewer.scene.camera.pickEllipsoid(endPosition, viewer.scene.globe.ellipsoid); if (Cesium.defined(startCartesian) && Cesium.defined(endCartesian)) { var startCartographic = Cesium.Cartographic.fromCartesian(startCartesian); var endCartographic = Cesium.Cartographic.fromCartesian(endCartesian); var west = Math.min(startCartographic.longitude, endCartographic.longitude); var east = Math.max(startCartographic.longitude, endCartographic.longitude); var south = Math.min(startCartographic.latitude, endCartographic.latitude); var north = Math.max(startCartographic.latitude, endCartographic.latitude); entity.rectangle.coordinates = Cesium.Rectangle.fromDegrees(west, south, east, north); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); ``` 3. 获取鼠标左键松开事件,结束矩形绘制。 ``` mouseHandler.setInputAction(function(movement) { startPosition = undefined; }, Cesium.ScreenSpaceEventType.LEFT_UP); ``` 这样,当用户按下鼠标左键并移动时,就可以动态绘制矩形

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值