Cesium 测距测区域面积

<!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, maximum-scale=1, minimum-scale=1, user-scalable=no" />
    <title>Cesium示例集--测量平面面积</title>
    <script type="text/javascript" src="./cesium/Cesium.js"></script>
    <script type="text/javascript" src="./libs/turf.min.js"></script>
    <link rel="stylesheet" href="./cesium/Widgets/widgets.css">
    <style type="text/css">
        html,
        body {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            overflow: hidden;
        }

        .cesium-container {
            width: 100%;
            height: 100%;
            position: relative;
        }

        .opt-bar {
            position: absolute;
            top: 20px;
            left: 20px;
            background: rgba(0, 0, 0, .8);
            padding: 5px 10px;
            border-radius: 2px;

            >a {
                font-size: 14px;
                color: #00e7ff;
                cursor: pointer;
                margin: 0 10px;
            }
        }
    </style>
</head>

<body onload="load()">
    <div id="cesiumContainer" class="cesium-container"></div>
    <div class="opt-bar">
        <a onclick="startEdit()">测量平面面积</a>
        <a onclick="clearEdit()">清除</a>
    </div>
    <div id="toolTip" style="position: absolute;font-size: 12px;background: rgba(0,0,0,.8);color:#fff;padding: 3px 5px;"
        style="display: none;"></div>

    <script>
        function getMapExtent () {
            let camera = viewer.scene.camera;
            let pos = {
                position: camera.position,
                heading: camera.heading,
                pitch: camera.pitch,
                roll: camera.roll,
            };
            console.log('屏幕当前范围:', pos);
        }

        var handler, viewer;
        var labels = [], movePush = false, positions = [], floatLabel = null, polyline = null, polygon = null, controlPoints = [];
        var tooltip = document.getElementById("toolTip");

        function load () {

            viewer = new Cesium.Viewer("cesiumContainer", {
                animation: false,//是否创建动画小器件,左下角仪表
                fullscreenButton: false,//是否显示全屏按钮
                // geocoder: false,//是否显示geocoder小器件,右上角查询按钮
                // homeButton: false,//是否显示Home按钮
                infoBox: false,//是否显示信息框
                // sceneModePicker: false,//是否显示3D/2D选择器
                // scene3DOnly: false,//如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
                selectionIndicator: false,//是否显示选取指示器组件
                timeline: false,//是否显示时间轴
                // navigationHelpButton: false,//是否显示右上角的帮助按钮
                baselLayerPicker: false,// 将图层选择的控件关掉,才能添加其他影像数据
                shadows: false,//是否显示背影
                baseLayerPicker: false,//是否显示图层选择器
                imageryProvider: new Cesium.UrlTemplateImageryProvider({
                    url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png'
                })
            });
            //去除版权信息
            viewer._cesiumWidget._creditContainer.style.display = "none";

            //屏蔽Cesium的默认双击追踪选中entity行为
            viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
                Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
            );

            //默认开启地形
            // viewer.terrainProvider = Cesium.createWorldTerrain();

            var pos = {
                "position": {
                    "x": -2463425.8997346475,
                    "y": 4873855.487729879,
                    "z": 3288016.4618711653
                },
                "heading": 0.1341636770247039,
                "pitch": -0.817714806133921,
                "roll": 0.00001433107210147
            };
            viewer.camera.flyTo({
                destination: new Cesium.Cartesian3(
                    pos.position.x,
                    pos.position.y,
                    pos.position.z
                ),
                orientation: {
                    heading: pos.heading,
                    pitch: pos.pitch,
                    roll: pos.roll,
                },
            });

        }

        function clearEdit () {
            positions = [];
            if (polyline) {
                viewer.entities.remove(polyline);
                polyline = null;
            }
            if (polygon) {
                viewer.entities.remove(polygon);
                polygon = null;
            }
            labels = [];
            for (var ind = 0; ind < controlPoints.length; ind++) {
                viewer.entities.remove(controlPoints[ind]);
            }
            controlPoints = [];
            if (floatLabel) {
                viewer.entities.remove(floatLabel);
                floatLabel = null;
            }
            floatLabel = null;
            if (handler) {
                handler.destroy();
                handler = null;
            }
            movePush = false;
            viewer.scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
            viewer.trackedEntity = undefined;
        }

        function startEdit () {
            clearEdit();
            tooltip.style.display = "block";

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

            //左键单击,开始绘制
            handler.setInputAction(function (evt) {
                // tooltip.style.display = "none";

                var cartesian = getCatesian3FromPX(evt.position, viewer).cartesian;
                if (!cartesian) return;
                if (movePush) {
                    positions.pop();
                    movePush = false;
                }
                var point = createPoint(cartesian.clone());
                point.wz = positions.length; // 和坐标点关联
                controlPoints.push(point);
                positions.push(cartesian);

            }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

            //鼠标移动
            handler.setInputAction(function (evt) {
                tooltip.style.left = evt.endPosition.x + 40 + "px";
                tooltip.style.top = evt.endPosition.y + 30 + "px";
                if (positions.length < 1) {
                    tooltip.innerHTML = '<p>单击开始绘制</p>';
                    return;
                }
                tooltip.innerHTML = '<p>双击结束,右键取消上一步</p>';

                var cartesian = getCatesian3FromPX(evt.endPosition, viewer).cartesian;
                if (!cartesian) return;



                if (positions.length >= 1) {
                    if (!movePush) {
                        positions.push(cartesian);
                        movePush = true;
                    } else {
                        positions[positions.length - 1] = cartesian;
                    }
                    if (positions.length == 2) {
                        if (!Cesium.defined(polyline)) {
                            polyline = createPolyline();
                        }
                    }
                    if (positions.length == 3) {
                        if (!Cesium.defined(polygon)) {
                            polygon = createPolygon();
                            polygon.isFilter = true;
                            polygon.objId = Number((new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0));
                        }
                        if (!floatLabel) {
                            floatLabel = createLabel(cartesian, "", {
                                style: Cesium.LabelStyle.FILL,
                                showBackground: true,
                                backgroundColor: Cesium.Color.fromCssColorString('#303336'),
                                pixelOffset: new Cesium.Cartesian2(0, -50)
                            });
                            floatLabel.label.heightReference = 1;
                        }
                    }
                    if (polygon) {
                        var areaCenter = getAreaAndCenter(positions)
                        var area = areaCenter.area;
                        var center = areaCenter.center;

                        var text = formateArea(area);
                        floatLabel.label.text = `平面面积:${text}`;
                        floatLabel.area = area;
                        if (center) floatLabel.position.setValue(center);
                        floatLabel.show = true;
                    }

                }

            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

            //右键取消上一步
            handler.setInputAction(function (evt) {
                if (!polyline && !polygon) return;
                if (positions.length <= 2) return; // 默认第一个不给删除
                positions.splice(positions.length - 2, 1);
                viewer.entities.remove(controlPoints.pop());  // 移除最后一个

                if (positions.length == 2) {
                    if (polygon) {
                        viewer.entities.remove(polygon);
                        polygon = null;
                        if (polyline) polyline.show = true;
                    }
                    floatLabel.show = false;
                }
                if (positions.length == 1) {
                    if (polyline) {
                        viewer.entities.remove(polyline);
                        polyline = null;
                    }
                    tooltip.innerHTML = '<p>单击开始测量</p>';
                    tooltip.style.left = evt.endPosition.x + 40 + "px";
                    tooltip.style.top = evt.endPosition.y + 30 + "px";
                    movePush = false;
                    positions = [];
                }
                if (positions.length > 2) {
                    var areaCenter = getAreaAndCenter(positions);
                    var area = areaCenter.area;
                    var center = areaCenter.center;
                    var text = formateArea(area);
                    floatLabel.label.text = `平面面积:${text}`;
                    if (center) floatLabel.position.setValue(center);
                    floatLabel.area = area;
                    floatLabel.show = true;
                }


            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

            //左键双击完成绘制
            handler.setInputAction(function (evt) {
                if (!polygon) return;

                tooltip.style.display = "none";

                positions.pop();
                viewer.entities.remove(controlPoints.pop()); // 移除最后一个
                movePush = false;

                viewer.scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
                viewer.trackedEntity = undefined;
                var areaCenter = getAreaAndCenter(positions)
                var area = areaCenter.area;
                var center = areaCenter.center;
                var text = formateArea(area);
                floatLabel.label.text = `平面面积:${text}`;
                floatLabel.area = area;
                if (center) floatLabel.position.setValue(center);

                if (handler) {
                    handler.destroy();
                    handler = null;
                }

            }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
        }


        function createPoint (position) {
            if (!position) return;

            return this.viewer.entities.add({
                position: position,
                point: {
                    pixelSize: 6,
                    color: Cesium.Color.RED,
                    outlineWidth: 1,
                    outlineColor: Cesium.Color.WHITE,
                    disableDepthTestDistance: Number.POSITIVE_INFINITY
                },
                show: false
            });
        }

        function createPolyline () {
            var ent = viewer.entities.add({
                polyline: {
                    positions: new Cesium.CallbackProperty(function () {
                        var linePositions = positions.concat([positions[0]]);
                        return linePositions
                    }, false),
                    material: Cesium.Color.RED,
                    width: 2
                }
            });
            return ent;
        }

        function createPolygon () {
            var polygon = viewer.entities.add({
                polygon: new Cesium.PolygonGraphics({
                    hierarchy: new Cesium.CallbackProperty(function () {
                        return new Cesium.PolygonHierarchy(positions);
                    }, false),
                    material: Cesium.Color.RED.withAlpha(0.4),
                    heightReference: Cesium.HeightReference.NONE,
                    perPositionHeight: true
                }),

            });
            return polygon;
        }

        function getAreaAndCenter (positions, height) {
            if (!positions || positions.length < 1) return;
            var cartographics = [];
            var turfPoints = [];
            for (var i = 0; i < positions.length; i++) {
                var cartesian3 = positions[i];
                var cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
                cartographics.push([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)]);
                turfPoints.push(turf.point([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)]));
            }
            if (!cartographics.length) return;
            cartographics = cartographics.concat([cartographics[0]]);
            var polygon = turf.polygon([cartographics]);
            var area = turf.area(polygon);
            //获取当前范围的中心点
            var features = turf.featureCollection(turfPoints);
            var turfCenter = turf.center(features);
            var center = turfCenter.geometry.coordinates;
            let centerNum = height ? Cesium.Cartesian3.fromDegrees(center[0], center[1], height) : Cesium.Cartesian3.fromDegrees(center[0], center[1]);

            return {
                area: area,
                center: centerNum
            };
        }

        function formateArea (val) {
            if (val == undefined) return;
            let dwStr = '';
            if (Number(val) > 1000000) {
                dwStr += (Number(val) / 1000000).toFixed(2) + "km²";
            } else {
                dwStr += Number(val).toFixed(2) + "m²";
            }
            return dwStr;
        }

        function createLabel (c, text, params) {
            if (!c) return;
            return viewer.entities.add({
                position: c,
                label: {
                    text: text || "",
                    font: '14px Helvetica',
                    showBackground: params ? params.showBackground : false,
                    backgroundColor: params ? params.backgroundColor : Cesium.Color.WHITE,
                    backgroundPadding: new Cesium.Cartesian2(10, 8),
                    fillColor: params ? params.fillColor : Cesium.Color.WHITE,
                    outlineColor: params ? params.outlineColor : Cesium.Color.BLACK,
                    outlineWidth: 2,
                    disableDepthTestDistance: Number.POSITIVE_INFINITY,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    pixelOffset: params ? params.pixelOffset : new Cesium.Cartesian2(0, -20)
                }
            });
        }

        function getCatesian3FromPX (px, viewer) {
            var picks = viewer.scene.drillPick(px);
            viewer.scene.render();
            var cartesian;
            var isOn3dtiles = 'no';
            for (var i = 0; i < picks.length; i++) {
                if ((picks[i] && picks[i].primitive) && picks[i].primitive instanceof Cesium.Cesium3DTileset) { //模型上拾取
                    isOn3dtiles = 'yes';
                    break;
                }
            }
            if (isOn3dtiles == 'yes') {
                cartesian = viewer.scene.pickPosition(px);
            } else {
                var ray = viewer.camera.getPickRay(px);
                if (!ray) return null;
                cartesian = viewer.scene.globe.pick(ray, viewer.scene);
            }
            return { cartesian: cartesian, isOn3dtiles: isOn3dtiles };
        }

    </script>
</body>

</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, maximum-scale=1, minimum-scale=1, user-scalable=no" />
    <title>Cesium示例集--测量平面面积</title>
    <script type="text/javascript" src="./cesium/Cesium.js"></script>
    <script type="text/javascript" src="./libs/turf.min.js"></script>
    <link rel="stylesheet" href="./cesium/Widgets/widgets.css">
    <style type="text/css">
        html,
        body {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            overflow: hidden;
            user-select: none;
        }

        .cesium-container {
            /* margin-top: 200px; */
            width: 100%;
            height: 100%;
            position: relative;
        }

        .opt-bar {
            position: absolute;
            top: 20px;
            left: 20px;
            background: rgba(0, 0, 0, .8);
            padding: 5px 10px;
            border-radius: 2px;

            >a {
                font-size: 14px;
                color: #00e7ff;
                cursor: pointer;
                margin: 0 10px;
            }
        }

        #toolTip {
            /* background-color: #00e7ff!important; */
        }

        /* 添加CSS过渡动画 */
        .measure-tooltip {
            transition: opacity 0.3s, transform 0.3s;
            pointer-events: none;
            max-width: 300px;
            background: rgba(40, 40, 40, 0.9) !important;
            border-radius: 4px;
            padding: 8px 12px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
        }
    </style>
</head>

<body>
    <div id="cesiumContainer" class="cesium-container"></div>
    <div class="opt-bar">
        <a onclick="startEdit()">测量平面面积</a>
        <a onclick="clearEdit()">清除</a>
    </div>
    <!-- <div id="toolTip" style="position: absolute;font-size: 12px;background: rgba(0,0,0,.8);color:#fff;padding: 3px 5px;"
        style="display: none;"></div> -->
    <script>

        class CesiumPopupClass {
            constructor(viewer, options) {
                this.viewer = viewer
                this.position = options.position;
                this.options = this.extend({}, options);
                var popupContainer = document.createElement("div");
                popupContainer.classList.add('popup');
                var popupInner = options.content;
                popupContainer.innerHTML = popupInner;
                popupContainer.style.display = 'none';
                viewer.cesiumWidget.container.appendChild(popupContainer);
                popupContainer.style.cssText = "display: none;position: absolute;left: -100;top: -100;z-index:9999;";

                this.popupContainer = popupContainer;

                // 初始化  
                this.init();
            }
            init() {
                if (this.position) {
                    this.popupContainer.style.display = 'block'
                    this.renderListener = this.viewer.scene.postRender.addEventListener(this.render, this)
                }
            }
            updateContent(newContent) {
                if (this.popupContainer) {
                    this.popupContainer.innerHTML = newContent;
                }
            }
            render() {
                var ellipsoid = this.viewer.scene.globe.ellipsoid;
                var geometry = Cesium.Cartesian3.fromDegrees(
                    this.position[0],
                    this.position[1],
                    this.position[2] ? this.position[2] : 0,
                    ellipsoid
                );

                if (!geometry) return
                var position = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, geometry)
                if (!position) {
                    return
                }
                if (this.popupContainer) {
                    this.popupContainer.style.left = position.x - this.popupContainer.offsetWidth / 2 + 'px'
                    this.popupContainer.style.top = position.y - this.popupContainer.offsetHeight - 10 + 'px'
                }
            }
            remove() {
                if (this.popupContainer) {
                    this.popupContainer.parentNode.removeChild(this.popupContainer)
                    this.popupContainer = null
                }

                if (this.renderListener) {
                    this.renderListener()
                    this.renderListener = null
                }

                if (this.viewer) {
                    this.viewer = null
                }
            }
            extend(obj, obj2) {
                for (var k in obj2) {
                    obj[k] = obj2[k];
                }
                return obj;
            }
        }

        let viewer = new Cesium.Viewer("cesiumContainer", {
            animation: false,//是否创建动画小器件,左下角仪表
            fullscreenButton: false,//是否显示全屏按钮
            // geocoder: false,//是否显示geocoder小器件,右上角查询按钮
            // homeButton: false,//是否显示Home按钮
            infoBox: false,//是否显示信息框
            // sceneModePicker: false,//是否显示3D/2D选择器
            // scene3DOnly: false,//如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
            selectionIndicator: false,//是否显示选取指示器组件
            timeline: false,//是否显示时间轴
            // navigationHelpButton: false,//是否显示右上角的帮助按钮
            baselLayerPicker: false,// 将图层选择的控件关掉,才能添加其他影像数据
            shadows: false,//是否显示背影
            baseLayerPicker: false,//是否显示图层选择器
            imageryProvider: new Cesium.UrlTemplateImageryProvider({
                url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png'
            })
        });
        if (Cesium.FeatureDetection.supportsImageRenderingPixelated()) {
            //判断是否支持图像渲染像素化处理
            viewer.resolutionScale = window.devicePixelRatio;
        }
        //开启抗锯齿
        viewer.scene.fxaa = true;
        viewer.scene.postProcessStages.fxaa.enabled = true;
        //去除版权信息
        viewer._cesiumWidget._creditContainer.style.display = "none";

        //屏蔽Cesium的默认双击追踪选中entity行为
        viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
            Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
        );
        //默认开启地形
        // viewer.terrainProvider = Cesium.createWorldTerrain();

        var pos = {
            "position": {
                "x": -2463425.8997346475,
                "y": 4873855.487729879,
                "z": 3288016.4618711653
            },
            "heading": 0.1341636770247039,
            "pitch": -0.817714806133921,
            "roll": 0.00001433107210147
        };
        viewer.camera.flyTo({
            destination: new Cesium.Cartesian3(
                pos.position.x,
                pos.position.y,
                pos.position.z
            ),
            orientation: {
                heading: pos.heading,
                pitch: pos.pitch,
                roll: pos.roll,
            },
        });



        class AreaDraw {
            constructor(viewer, id = Date.now()) {
                this.viewer = viewer;
                this.polyLineHeight = 0.2
                this.handler = null;
                this.positions = [];
                this.polyline = null;
                this.polygon = null;
                this.controlPoints = [];
                this.floatLabelAreaShow = false;
                this.floatLabel = null;// 面积
                this.movePush = false;
                this.tooltip = null;
                this.id = id;
                this.popDiv = null
                this.rect = this.viewer.canvas.getBoundingClientRect();
                this.pointStyle = {
                    pixelSize: 6,
                    color: Cesium.Color.fromCssColorString("rgba(255,0,0,1)"),
                    outlineWidth: 1,
                    outlineColor: Cesium.Color.fromCssColorString("rgba(255,255,255,1)"),
                }
                this.polylineStyle = {
                    width: 4,
                    material: Cesium.Color.fromCssColorString("rgba(255,255,0,1)"),
                }
                this.polygonStyle = {
                    material: Cesium.Color.fromCssColorString("rgba(0,255,255,0.4)"),
                }
            }
            startEdit(callback) {
                // 创建一个 div 元素
                let toolTip = document.createElement("div");
                this.tooltip = toolTip
                // 设置 div 的 ID
                toolTip.id = "toolTip";

                // 设置 div 的样式
                toolTip.style.position = "absolute";
                toolTip.style.fontSize = "14px";
                toolTip.style.background = "rgba(255,255,255,.8)";
                toolTip.style.color = "#000000";
                toolTip.style.padding = "3px 5px";
                toolTip.style.display = "none"; // 初始隐藏
                // 将该 div 插入到页面中(例如插入到 body 中)
                document.body.appendChild(toolTip);
                toolTip.style.maxWidth = "200px";
                this.tooltip.style.display = "block";
                this.tooltip.style.zIndex = "9999";
                this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);

                //左键单击,开始绘制
                this.handler.setInputAction((evt) => {
                    // tooltip.style.display = "none";

                    var cartesian = this.getCatesian3FromPX(evt.position, this.viewer).cartesian;
                    if (!cartesian) return;
                    if (this.movePush) {
                        this.positions.pop();
                        this.movePush = false;
                    }
                    var point = this.createPoint(cartesian.clone());
                    point.wz = this.positions.length; // 和坐标点关联
                    this.controlPoints.push(point);
                    this.positions.push(cartesian);

                }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

                //鼠标移动
                this.handler.setInputAction((evt) => {

                    var rect = this.rect;
                    this.tooltip.style.left = rect.left + evt.endPosition.x + 40 + "px";
                    this.tooltip.style.top = rect.top + evt.endPosition.y + 30 + "px";
                    if (this.positions.length < 1) {
                        this.tooltip.innerHTML = '<div>单击开始绘制</div>';
                        return;
                    }
                    this.tooltip.innerHTML = `<div style='color:#2525F5;font-weight: 700;'>正在绘制中:</div>
                        <div>单击确定点位,双击结束当前绘制,右键取消上一步</div>`;

                    var cartesian = this.getCatesian3FromPX(evt.endPosition, this.viewer).cartesian;
                    if (!cartesian) return;



                    if (this.positions.length >= 1) {
                        if (!this.movePush) {
                            this.positions.push(cartesian);
                            this.movePush = true;
                        } else {
                            this.positions[this.positions.length - 1] = cartesian;
                        }
                        if (this.positions.length == 2) {
                            if (!Cesium.defined(this.polyline)) {
                                this.polyline = this.createPolyline();
                            }
                        }
                        if (this.positions.length == 3) {
                            if (!Cesium.defined(this.polygon)) {
                                this.polygon = this.createPolygon();
                                this.polygon.isFilter = true;
                                this.polygon.objId = Number((new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0));
                            }
                            if (this.floatLabelAreaShow && !this.floatLabel) {
                                this.floatLabel = this.createLabel(cartesian, "", {
                                    style: Cesium.LabelStyle.FILL,
                                    showBackground: true,
                                    backgroundColor: Cesium.Color.fromCssColorString('#303336'),
                                    pixelOffset: new Cesium.Cartesian2(0, -50)
                                });
                                this.floatLabel.label.heightReference = 1;
                            }
                        }
                        if (this.floatLabelAreaShow && this.polygon) {
                            var areaCenter = this.getAreaAndCenter(this.positions)
                            var area = areaCenter.area;
                            var center = areaCenter.center;

                            var text = this.formateArea(area);
                            this.floatLabel.label.text = `平面面积:${text}`;
                            this.floatLabel.area = area;
                            if (center) this.floatLabel.position.setValue(center);
                            this.floatLabel.show = true;
                        }

                    }

                }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);



                //右键取消上一步
                this.handler.setInputAction((evt) => {
                    if (!this.polyline && !this.polygon) return;
                    if (this.positions.length <= 2) return; // 默认第一个不给删除
                    this.positions.splice(this.positions.length - 2, 1);
                    this.viewer.entities.remove(this.controlPoints.pop());  // 移除最后一个

                    if (this.positions.length == 2) {
                        if (this.polygon) {
                            this.viewer.entities.remove(this.polygon);
                            this.polygon = null;
                            if (this.polyline) this.polyline.show = true;
                        }
                        if (this.floatLabelAreaShow) {
                            this.floatLabel.show = false;
                        }

                    }
                    if (this.positions.length == 1) {
                        if (this.polyline) {
                            this.viewer.entities.remove(this.polyline);
                            this.polyline = null;
                        }
                        var rect = this.rect;
                        this.tooltip.innerHTML = '<div>单击开始测量</div>';
                        this.tooltip.style.left = rect.left + evt.endPosition.x + 40 + "px";
                        this.tooltip.style.top = rect.top + evt.endPosition.y + 30 + "px";
                        this.movePush = false;
                        this.positions = [];
                    }
                    if (this.floatLabelAreaShow && this.positions.length > 2) {
                        var areaCenter = this.getAreaAndCenter(this.positions);
                        var area = areaCenter.area;
                        var center = areaCenter.center;
                        var text = this.formateArea(area);
                        this.floatLabel.label.text = `平面面积:${text}`;
                        if (center) this.floatLabel.position.setValue(center);
                        this.floatLabel.area = area;
                        this.floatLabel.show = true;
                    }


                }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

                //左键双击完成绘制
                this.handler.setInputAction((evt) => {

                    // if (!this.polygon) return;

                    if (this.tooltip) {
                        this.tooltip.parentNode.removeChild(this.tooltip);
                        // document.body.removeChild(this.tooltip);
                        this.tooltip = null;
                    }
                    this.positions.pop();
                    this.viewer.entities.remove(this.controlPoints.pop()); // 移除最后一个
                    this.movePush = false;

                    // this.viewer.scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
                    // this.viewer.trackedEntity = undefined;
                    if (this.floatLabelAreaShow) {
                        var areaCenter = this.getAreaAndCenter(this.positions)
                        var area = areaCenter.area;
                        var center = areaCenter.center;
                        var text = this.formateArea(area);
                        this.floatLabel.label.text = `平面面积:${text}`;
                        this.floatLabel.area = area;
                        if (center) this.floatLabel.position.setValue(center);
                    }
                    if (this.polyline) {
                        this.polyline.show = false;
                    }
                    if (this.polygon) {
                        this.addpop()
                    }
                    if (this.handler) {
                        this.handler.destroy();
                        this.handler = null;
                        typeof callback === 'function' && callback(this.positions)
                    }
                }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)


            }
            addpop() {
                let cartographic = Cesium.Cartographic.fromCartesian(this.positions[this.positions.length - 1]);
                let longitude = Cesium.Math.toDegrees(cartographic.longitude); // 经度 (从 -180 到 180)
                let latitude = Cesium.Math.toDegrees(cartographic.latitude); // 纬度 (从 -90 到 90)
                let popId = "id" + Number((new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0));
                this.popDiv = new CesiumPopupClass(this.viewer, {
                    position: [longitude, latitude],
                    content: `<div class="popup-titleCss" id="${popId}" style="
                              position: absolute;
                              top: 10px;
                              right: 10px;
                              background-color: #FFFFFF;
                              color: #ff0000;
                              font-size: 15px;
                              font-weight: bold;
                              width: 20px;
                              height: 20px;
                              border-radius: 50%;
                              display: flex;
                              justify-content: center;
                              align-items: center;
                              box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.2);
                              cursor: pointer;
                              border: 2px solid red;
                              transition: all 0.3s ease;">
                              X
                            </div>`

                })


                document.querySelector(`#${popId}`).addEventListener("click", () => {
                    this.popDiv.remove()
                    this.clearEdit()
                })
            }
            clearEdit() {
                if (!this.viewer) {
                    return
                }
                if (this.popDiv) {
                    this.popDiv.remove();
                    this.popDiv = null
                }
                if (this.tooltip) {
                    document.body.removeChild(this.tooltip);
                    this.tooltip = null;
                }
                this.positions = [];
                if (this.polyline) {
                    this.viewer.entities.remove(this.polyline);
                    this.polyline = null;
                }
                if (this.polygon) {
                    this.viewer.entities.remove(this.polygon);
                    this.polygon = null;
                }
                for (var ind = 0; ind < this.controlPoints.length; ind++) {
                    this.viewer.entities.remove(this.controlPoints[ind]);
                    this.controlPoints[ind] = null;
                }
                this.controlPoints = [];
                if (this.floatLabelAreaShow) {
                    if (this.floatLabel) {
                        this.viewer.entities.remove(this.floatLabel);
                        this.floatLabel = null;
                    }
                    this.floatLabel = null;
                }

                if (this.handler) {
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
                    this.handler.destroy();
                    this.handler = null;
                }
                this.movePush = false;
                // this.viewer.scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
                // this.viewer.trackedEntity = undefined;
                this.rect = null
                this.viewer = null
                for (let key in this.pointStyle) {
                    if (this.pointStyle.hasOwnProperty(key)) {
                        delete this.pointStyle[key];
                    }
                }
                for (let key in this.polylineStyle) {
                    if (this.polylineStyle.hasOwnProperty(key)) {
                        delete this.polylineStyle[key];
                    }
                }
                for (let key in this.polygonStyle) {
                    if (this.polygonStyle.hasOwnProperty(key)) {
                        delete this.polygonStyle[key];
                    }
                }
                this.id = null
                this.pointStyle = null
                this.polylineStyle = null
                this.polygonStyle = null
                console.log("clearEdit---------------");

            }


            createPoint(position) {
                if (!position) return;

                return this.viewer.entities.add({
                    position: position,
                    point: {
                        pixelSize: this.pointStyle.pixelSize,
                        color: this.pointStyle.color,
                        outlineWidth: this.pointStyle.outlineWidth,
                        outlineColor: this.pointStyle.outlineColor,
                        disableDepthTestDistance: Number.POSITIVE_INFINITY
                    },
                    show: false
                });
            }

            createPolyline() {
                var ent = this.viewer.entities.add({
                    id: 'polylineDraw_' + this.id,
                    polyline: {
                        positions: new Cesium.CallbackProperty(() => {
                            var linePositions = this.positions.concat([this.positions[0]]);
                            return linePositions
                        }, false),
                        material: this.polylineStyle.material,
                        disableDepthTestDistance: Number.POSITIVE_INFINITY,
                        width: this.polylineStyle.width,
                    }
                });
                return ent;
            }

            createPolygon() {
                var polygon = this.viewer.entities.add({
                    id: 'polygonDraw_' + this.id,
                    polygon: new Cesium.PolygonGraphics({
                        hierarchy: new Cesium.CallbackProperty(() => {
                            return new Cesium.PolygonHierarchy(this.positions);
                        }, false),
                        material: this.polygonStyle.material,
                        heightReference: Cesium.HeightReference.NONE,
                        perPositionHeight: true
                    }),

                });
                return polygon;
            }

            getAreaAndCenter(positions, height) {
                if (!positions || positions.length < 1) return;
                var cartographics = [];
                var turfPoints = [];
                for (var i = 0; i < positions.length; i++) {
                    var cartesian3 = positions[i];
                    var cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
                    cartographics.push([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)]);
                    turfPoints.push(turf.point([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)]));
                }
                if (!cartographics.length) return;
                cartographics = cartographics.concat([cartographics[0]]);
                var polygon = turf.polygon([cartographics]);
                var area = turf.area(polygon);
                //获取当前范围的中心点
                var features = turf.featureCollection(turfPoints);
                var turfCenter = turf.center(features);
                var center = turfCenter.geometry.coordinates;
                let centerNum = height ? Cesium.Cartesian3.fromDegrees(center[0], center[1], height) : Cesium.Cartesian3.fromDegrees(center[0], center[1]);

                return {
                    area: area,
                    center: centerNum
                };
            }

            formateArea(val) {
                if (val == undefined) return;
                let dwStr = '';
                if (Number(val) > 1000000) {
                    dwStr += (Number(val) / 1000000).toFixed(2) + "km²";
                } else {
                    dwStr += Number(val).toFixed(2) + "m²";
                }
                return dwStr;
            }

            createLabel(c, text, params) {
                if (!c) return;
                return this.viewer.entities.add({
                    position: c,
                    label: {
                        text: text || "",
                        font: '14px Helvetica',
                        showBackground: params ? params.showBackground : false,
                        backgroundColor: params ? params.backgroundColor : Cesium.Color.WHITE,
                        backgroundPadding: new Cesium.Cartesian2(10, 8),
                        fillColor: params ? params.fillColor : Cesium.Color.WHITE,
                        outlineColor: params ? params.outlineColor : Cesium.Color.BLACK,
                        outlineWidth: 2,
                        disableDepthTestDistance: Number.POSITIVE_INFINITY,
                        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                        pixelOffset: params ? params.pixelOffset : new Cesium.Cartesian2(0, -20)
                    }
                });
            }

            getCatesian3FromPX(px, viewer) {
                // this.viewer.scene.render();
                var cartesian;
                var isOn3dtiles = 'no';
                var ray = this.viewer.camera.getPickRay(px);
                if (!ray) return null;
                cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);

                if (this.polyLineHeight) {
                    // 计算当前坐标点的法线方向
                    let ellipsoid = this.viewer.scene.globe.ellipsoid;
                    let normal = ellipsoid.geodeticSurfaceNormal(cartesian);

                    // 增加 2 米的高度:沿法线方向偏移
                    let offset = this.polyLineHeight;  // 增加的高度(单位:米)
                    let newCartesain = Cesium.Cartesian3.add(cartesian, Cesium.Cartesian3.multiplyByScalar(normal, offset, new Cesium.Cartesian3()), new Cesium.Cartesian3());
                    return { cartesian: newCartesain, isOn3dtiles: isOn3dtiles };
                } else {
                    return { cartesian: cartesian, isOn3dtiles: isOn3dtiles };
                }

            }


        }


        class AreaManager {
            constructor(viewer, fn) {
                this.viewer = viewer;
                this.idItem = null;
                this.areaList = [];
                this.handler = null
                this.fn = typeof fn == 'function' ? fn : null
                this.startEditFlag = false
                // this.drawArea = this.startEdit()
            }
            startEditManage(callback) {
                if (this.startEditFlag) return
                this.startEditFlag = true
                this.areaList.forEach(e => {
                    if (e.area.viewer && e.area.polyline) {
                        e.area.polyline.show = false
                    }
                })

                let id = Date.now()
                this.idItem = id

                this.areaList.push({
                    id: id,
                    area: new AreaDraw(this.viewer, id)
                })
                this.cancelHander()
                console.log(this.areaList.length, 'this.areaList.length');
                this.areaList[this.areaList.length - 1].area.startEdit((e) => {
                    console.log("完成");
                    this.startEditFlag = false
                    console.log(this.areaList, 'this.areaList');
                    this.AddLeftClick()
                    let resPosition = e.map(e => this.cartesianToLatLon(e))
                    typeof callback === 'function' && callback(resPosition)
                });
                this.drawArea = this.areaList[this.areaList.length - 1].area
                return this.areaList[this.areaList.length - 1].area
            }
            clearEditAll() {

                // 单个清除
                // let areaItem =  areaList.find(e=>e.id == idItem)
                // console.log(areaItem.area,'area');

                // areaItem.area.clearEdit();
                // areaItem.area = null
                // areaList.splice(areaList.findIndex(e=>e.id == idItem),1)

                this.areaList.forEach(e => {
                    e.area.clearEdit();
                    e.area = null;
                    e = null
                })
                this.fn = null
                this.areaList = null
                this.cancelHander()
                this.viewer = null
                this.startEditFlag = false
            }

            AddLeftClick() {
                this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
                this.handler.setInputAction((evt) => {
                    // 获取点击位置的实体
                    var pickedObject = this.viewer.scene.pick(evt.position);
                    if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id)) {
                        let list = pickedObject.id.id.split('_');
                        if (list[0] == 'polygonDraw') {
                            this.areaList.forEach(e => {
                                if (e.area.viewer) {
                                    if (String(e.id) === list[1]) {
                                        e.area.polyline.show = true
                                        console.log(e.area.positions, 'e.area.positions');
                                        let p = e.area.positions.map(e1 => {
                                            let result = this.cartesianToLatLon(e1);
                                            return result
                                        })
                                        if (this.fn) {
                                            this.fn(p)
                                        }
                                        console.log(p, 'e.area.positions');
                                    } else {
                                        e.area.polyline.show = false
                                    }
                                }
                            })
                        }
                    }

                }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
            }

            cancelHander() {
                if (this.handler) {
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
                    this.handler.destroy();
                    this.handler = null;
                }
            }
            /**
            * 将笛卡尔坐标转换为经纬度坐标
            * @param {Cesium.Cartesian3} cartesian - 笛卡尔坐标
            * @param {Cesium.Ellipsoid} [ellipsoid=Cesium.Ellipsoid.WGS84] - 参考椭球体,默认为 WGS84
            * @returns {Object} 包含经度和纬度的对象,单位为度
            */
            cartesianToLatLon(cartesian, ellipsoid = Cesium.Ellipsoid.WGS84) {
                if (!Cesium.defined(cartesian)) {
                    throw new Error('cartesian 参数未定义');
                }

                var cartographic = ellipsoid.cartesianToCartographic(cartesian);
                if (!Cesium.defined(cartographic)) {
                    throw new Error('无法将笛卡尔坐标转换为地理坐标');
                }

                var longitude = Cesium.Math.toDegrees(cartographic.longitude);
                var latitude = Cesium.Math.toDegrees(cartographic.latitude);
                var height = cartographic.height;

                return {
                    longitude: longitude,
                    latitude: latitude,
                    height: height
                };
            }
        }






        let m

        function startEdit() {
            if (!m) {
                m = new AreaManager(viewer, (e) => {
                    console.log(e, 'eee点击事件回调');
                });
            }

            m.startEditManage((e) => {
                console.log(e, 'drawArea完成事件回调')
            });
            // m.drawArea.polylineStyle.material = Cesium.Color.RED.withAlpha(0.5);
            // m.drawArea.floatLabelAreaShow = true
        }
        function clearEdit() {
            console.log(m, 'm');
            if (m) {
                m.clearEditAll()
                m = null
            }

        }

    </script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值