vue + cesium: 绘制点线面 方法封装(draw.js)

374 阅读1分钟
/*
* 说明:   绘制点线面 方法封装
*/

import * as Cesium from "cesium/Cesium.js";
import { pickEllipsoidCartesian3ToLonLatHeight,  pickPositionCartesian3ToLonLatHeight} from './transform'
import {$Params} from "./params";
import Vue from 'vue'
var DRAW_TYPE = {
    Point: 'Point',
    PolyLine: 'PolyLine',
    Polygon: 'Polygon',
    Marker: 'Marker',
    Circle: 'Circle',
    Box: 'Box',
};


/**
 * 绘制线面
 * @type {ConstructDraw}
 */
export const $Draw = (
    function () {
        var viewer;
        var handler;
        var drawingMode;  //绘制类型
        var imgUrl;  //绘制Marker图标
        var tipOverlay; //指示框
        var is_click = false;  //是否点击来判断显示指示框文字
        var editEntities = [];  //编辑实体
        var isExitEditDialog = false; //是否退出编辑弹框
        var activeShape;   //绘制的形状
        var floatingPoint;   //牵引的浮动点
        let positions = [];  //坐标点
        function ConstructDraw() {
            viewer = Vue.prototype.$MyCesium.viewer;
            return {
                draw: (options) => draw(options),  //绘制
                remove: () => removeEntity()  //移除当前绘制的实体、解绑当前的鼠标事件
            }

        }
        function draw(options) {
            handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
            drawingMode = options.drawingMode;
            imgUrl = options.imgUrl || ""
            tipOverlay = document.createElement('div');
            tipOverlay.style.display = "block";
            viewer.container.appendChild(tipOverlay);
            isExitEditDialog = true
            switch (options.drawingMode) {
                case DRAW_TYPE.Point:
                case DRAW_TYPE.Marker:
                    drawPoint(options.drawingMode);
                    break;
                case DRAW_TYPE.PolyLine:
                case DRAW_TYPE.Polygon:
                    drawGraphics(options.drawingMode);
                    break;
                case DRAW_TYPE.Box: 
                    drawBox(options.drawingMode)
                case DRAW_TYPE.Circle: 
                    drawCircle(options.drawingMode)
                default:
                    break;
            }
        }
        function removeEntity() {
            terminateShape(true)
        }
        // 绘制点、广告牌
        function drawPoint(type) {
            let submitParams = [];
            let dom = document.getElementsByTagName("body")[0]
            is_click = true
            if(!isExitEditDialog) return
            //鼠标左键
            console.log('isExitEditDialog 绘制点、广告牌', isExitEditDialog)
            handler.setInputAction(event => {
                is_click = false
                let {cartesian, lonlat} = pickEllipsoidCartesian3ToLonLatHeight(viewer, event.position)
                console.log('lonlat', lonlat)
                if (Cesium.defined(cartesian)) {
                    dom.style.cursor = 'crosshair'
                    if(positions.length == 0) {
                        positions.push(cartesian);
                        submitParams.push(lonlat);
                        activeShape = drawShape(drawingMode, cartesian)
                        editEntities.push(activeShape)
                        Vue.prototype.$Bus.$emit("setLocation", submitParams, type)
                    }
                }
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
            //鼠标移动
            handler.setInputAction(event => {
                if (submitParams.length > 0) handleTipOverlay(event.endPosition)
            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
            handler.setInputAction(event => {
                terminateShape()
            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
            handler.setInputAction(event => {
                terminateShape(true)
            }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
        }
        // 绘制线面
        function drawGraphics(type) {
            let dom = document.getElementsByTagName("body")[0];
            let submitParams = []; //提交参数
            is_click = true
            console.log('isExitEditDialog', isExitEditDialog)
            if(!isExitEditDialog) return
            //鼠标左键
            handler.setInputAction(event => {
                is_click = false
                let {cartesian, lonlat} = pickEllipsoidCartesian3ToLonLatHeight(viewer, event.position)
                if (Cesium.defined(cartesian)) {
                    dom.style.cursor = 'crosshair'
                    if (positions.length === 0) {
                        if (!Cesium.defined(cartesian)) {
                            return
                        }
                        floatingPoint = drawShape('Point', cartesian)
                        editEntities.push(floatingPoint)
                        positions.push(cartesian);
                        var dynamicPositions = new Cesium.CallbackProperty(function () {
                            if (drawingMode === 'Polygon') {
                                return new Cesium.PolygonHierarchy(positions);
                            }
                            return positions
                        }, false);
                        activeShape = drawShape(drawingMode, dynamicPositions);//绘制动态图
                        editEntities.push(activeShape)
                    }
                    positions.push(cartesian);
                    let pointEntity = drawShape('Point', cartesian)
                    submitParams.push(lonlat)
                    console.log('submitParams', submitParams)
                    Vue.prototype.$Bus.$emit("setLocation", submitParams, type)
                    editEntities.push(pointEntity)
                }
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
            //鼠标移动
            handler.setInputAction(event => {
                // console.log(viewer.camera.position,
                //     viewer.camera.heading,
                //     viewer.camera.pitch,
                //     viewer.camera.roll,
                //     viewer.camera,
                //     'views'
                //     )
                if (Cesium.defined(floatingPoint)) {
                    let {cartesian, lonlat} = pickEllipsoidCartesian3ToLonLatHeight(viewer, event.endPosition)
                    if (Cesium.defined(cartesian)) {
                        floatingPoint.position.setValue(cartesian);
                        positions.pop();
                        positions.push(cartesian);
                    }
                    handleTipOverlay(event.endPosition)
                }
            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

            handler.setInputAction(event => {
                positions.pop();//去除最后一个动态点
                terminateShape()
            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
            handler.setInputAction(event => {
                terminateShape(true)
            }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
        }
        // 绘制矩形
        function drawBox(type) {
            
        }
        // 绘制圆形
        function drawCircle(type) {
            /**实体的唯一标注 */
            let id = null
            /**圆半径 */
            let radius = 0
            /**圆心 */
            let lngLat = []
            handler.setInputAction((click) => {
                id = new Date().getTime()
                let cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
                let cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic())
                let lng = Cesium.Math.toDegrees(cartographic.longitude)
                let lat = Cesium.Math.toDegrees(cartographic.latitude)
                lngLat = [lng, lat]
                let entity = viewer.entities.add({
                    position: new Cesium.CallbackProperty(function () { return new Cesium.Cartesian3.fromDegrees(...lngLat, 0) }, false),
                    name: 'circle',
                    id: id,
                    ellipse: {
                        height: 0,
                        outline: true,
                        material: new Cesium.Color.fromCssColorString("#FFD700").withAlpha(.2),
                        // outlineColor: this.config.borderColor,
                        // outlineWidth: this.config.borderWidth
                    }
                })
                entity.ellipse.semiMajorAxis = new Cesium.CallbackProperty(function () { return radius }, false)
                entity.ellipse.semiMinorAxis = new Cesium.CallbackProperty(function () { return radius }, false)
    
                if (lngLat) {
                    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
                }
                handler.setInputAction((move) => {
                    let cartesian2 = viewer.camera.pickEllipsoid(move.endPosition, viewer.scene.globe.ellipsoid)
                    radius = Cesium.Cartesian3.distance(cartesian, cartesian2)
                }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    
            handler.setInputAction(() => {
                Vue.prototype.$Bus.$emit("setLocation", {center: lngLat, radius: radius}, type)
                editEntities.push({ id: id, center: lngLat, radius: radius })
                handler.destroy();
            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
        }
        // 绘制形状
        function drawShape(drawingMode, position) {
            var shape;
            let defaultDrawStyle = $Params[drawingMode + 'Style']
            if(drawingMode === 'Point') {
                shape = viewer.entities.add(new Cesium.Entity({
                    position: position,
                    point: defaultDrawStyle,
                    type: drawingMode,
                }));
            } else if(drawingMode === 'Marker') {
                let markerStyle = defaultDrawStyle
                if(imgUrl) markerStyle = {...defaultDrawStyle, ...{image: imgUrl}}
                shape = viewer.entities.add(new Cesium.Entity({
                    position: position,
                    billboard: markerStyle,
                    type: drawingMode
                }));
            }
            else if (drawingMode === 'PolyLine') {
                let polylineStyle = {...defaultDrawStyle, ...{positions: position}}
                shape = viewer.entities.add({
                    polyline: polylineStyle,
                    type: drawingMode,
                    material: new Cesium.PolylineGlowMaterialProperty({
                        color: new Cesium.Color.fromCssColorString('#000'),
                    }), // 颜色
                    depthFailMaterial: new Cesium.PolylineGlowMaterialProperty({
                        color: new Cesium.Color.fromCssColorString('#ccc'),
                    }),						// 被地形覆盖的虚线颜色
                    clampToGround: true,	// 是否贴和地型

                });
            }
            else if (drawingMode === 'Polygon') {
                let polygonStyle = {...defaultDrawStyle, ...{hierarchy: position}}
                shape = viewer.entities.add({
                    type: drawingMode,
                    polygon: polygonStyle,
                    // 面颜色
                    material: new Cesium.Color.fromCssColorString("#FFD700").withAlpha(.2),
                
                });
            }

            return shape;
        }
        
        // 清空
        function terminateShape(bool) {
            //鼠标形状回复默认
            let dom = document.getElementsByTagName("body")[0]
            dom.style.cursor = 'default'
            //指示框移除
            if(tipOverlay) viewer.container.removeChild(tipOverlay);
            tipOverlay = undefined
            is_click = false
            //解除事件
            if(handler) {
                handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
                handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
                handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
                handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
            }
            //移除实体
            viewer.entities.remove(floatingPoint);//去除动态点图形(当前鼠标点)
            floatingPoint = undefined;
            if(bool) {  //双击清楚实体、右键保留实体
                positions = [];
                activeShape = undefined;
                viewer.entities.remove(activeShape);//去除动态图形
                Vue.prototype.$Bus.$emit("setLocation", false);
                // store.state.user.currentActiveTool = false;
                isExitEditDialog = false;
                if(editEntities && editEntities.length > 0) editEntities.forEach(item => viewer.entities.remove(item));
                editEntities = [];
            }
        }
        function handleTipOverlay(endPosition) {
            if(!tipOverlay) return
            tipOverlay.style.position = 'absolute';
            tipOverlay.style.color = '#fff';
            tipOverlay.style.bottom = '0';

            tipOverlay.style.left = '0';

            tipOverlay.style['pointer-events'] = 'none';

            tipOverlay.style.padding = '4px';
            tipOverlay.style.width = '10rem';
            tipOverlay.style.height = '2.4rem';
            tipOverlay.style.fontSize = '0.14rem';
            tipOverlay.style.backgroundColor = 'black';
            tipOverlay.style.display = 'block';
            if (is_click) {
                tipOverlay.textContent = "请单击鼠标左键开始绘制";
            } else {
                tipOverlay.textContent = "请单击鼠标右键结束绘制,双击清除绘制";
            }
            tipOverlay.style.bottom = viewer.canvas.clientHeight - endPosition.y + 'px';
            tipOverlay.style.left = endPosition.x + 'px';
        }
        return ConstructDraw;
    })()