arcgis api for js - 图上标绘及测量

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>draw38_3.21</title>
    <!--此代码进行到,要实现绘图界面。-->
    <!--<link rel="stylesheet" href="https://js.arcgis.com/3.21/dijit/themes/claro/claro.css">-->
    <!--<link rel="stylesheet" href="https://js.arcgis.com/3.21/esri/css/esri.css">-->
    <!--<script src="https://js.arcgis.com/3.21/"></script>-->
    <!--<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>-->

    <!--上下两个接口都行。-->
    <link rel="stylesheet" href="https://js.arcgis.com/3.26/dijit/themes/nihilo/nihilo.css">
    <link rel="stylesheet" href="https://js.arcgis.com/3.26/esri/css/esri.css">
    <script src="https://js.arcgis.com/3.26/"></script>

    <style>
        html, body, #map {
            height: 100%; width: 100%; margin: 0; padding: 0;
        }
        #search {
            z-index: 20;
            height: 35px;
            width: 300px;
            position: absolute;
            top: 10px;
            left: 0;
            right: 0;
            margin: auto;
        }
        #drawOperations {
            z-index: 20;
            position: absolute;
            top: 60px;
            left: 5px;
            color: #444;
            width: 320px;
            overflow: auto;
            font-family: 仿宋体;
            border: solid 1px #4A92E7;
            border-radius: 4px;
            background-color: #fff;
        }
        /*#info button {*/
            /*width: 30px;*/
            /*height:30px;*/
            /*line-height:30px;*/
            /*text-align: center;*/
            /*background-color: #fff;*/
            /*padding: 2px;*/
            /*margin: 4px;*/
            /*cursor: pointer;*/
            /*border-radius: 3px;*/
            /*border: 1px solid*/
        /*}*/
        /*#info button:hover {*/
            /*border: 1px solid #1e90ff;*/
        /*}*/
        #drawOperations img{
            width:40px;
            margin:4px;
        }
        #drawOperations div{
            padding:4px 4px 0px 4px;
        }
    </style>
    <!--导入该js才可以添加多行文本。-->
    <script src="js/esri.symbol.MultiLineTextSymbol.js"></script>
    <script>
        require([
            "esri/config",
            "esri/tasks/GeometryService",
            "esri/tasks/LengthsParameters",
            "esri/tasks/AreasAndLengthsParameters",
            "esri/symbols/TextSymbol", "esri/Color", "esri/symbols/Font",
            "esri/map",
            "esri/layers/ArcGISTiledMapServiceLayer",
            "esri/layers/ArcGISDynamicMapServiceLayer",
            "dojo/_base/connect",
            "esri/dijit/BasemapToggle",
            "esri/toolbars/draw",
            "esri/geometry/Point", "esri/geometry/Polyline", "esri/geometry/Polygon",
            "esri/dijit/Search",
            "dijit/registry",
            "esri/dijit/Scalebar",
            "esri/symbols/SimpleMarkerSymbol",
            "esri/symbols/SimpleLineSymbol",
            "esri/symbols/SimpleFillSymbol",
            "esri/symbols/PictureMarkerSymbol",
            "esri/symbols/CartographicLineSymbol",
            "esri/symbols/PictureFillSymbol",
            "esri/geometry/Extent",
            "esri/SpatialReference",
            "esri/geometry/mathUtils",
            "esri/geometry/ScreenPoint",
            "esri/toolbars/edit",
            "dijit/Menu",
            "dijit/MenuItem",
            "dijit/MenuSeparator",
            "esri/graphic",
            "esri/layers/GraphicsLayer",
            "esri/dijit/Popup",
            "esri/dijit/PopupTemplate",
            "esri/InfoTemplate",
            "dojo/dom-construct",
            "dojo/dom",
            "dojo/on",
            "dojo/domReady!"
        ], function(
            esriConfig, GeometryService, LengthsParameters, AreasAndLengthsParameters,
            TextSymbol, Color, Font,
            Map,  ArcGISTiledMapServiceLayer, ArcGISDynamicMapServiceLayer,
            connect, BasemapToggle, Draw, Point, Polyline, Polygon, Search, registry, Scalebar,
            SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol,
            PictureMarkerSymbol, CartographicLineSymbol, PictureFillSymbol,
            Extent, SpatialReference, mathUtils, ScreenPoint, Edit, Menu, MenuItem,
            MenuSeparator,
            Graphic, GraphicsLayer, Popup, PopupTemplate, InfoTemplate,
            domConstruct,dom, on
        ) {
            //量算
            function doMeasure(geometry) {
                let symbol;
                measureGeometry = geometry;
                draw.deactivate();
                switch (geometry.type) {
                    case "point":
                        symbol = new SimpleMarkerSymbol();
                        break;
                    case "polyline":
                        symbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0, 0, 0]), 5);
                        break;
                    case "polygon":
                        symbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NONE, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DASHDOT, new dojo.Color([255, 0, 0]), 2), new dojo.Color([255, 255, 0, 0.25]));
                        break;
                }
                //设置样式
                const graphic = new Graphic(geometry, symbol);

                map.infoWindow.hide();

                graphicsLayer.add(graphic);
                //进行投影转换,完成后调用projectComplete
                MeasureGeometry(geometry);
            }

            //投影转换完成后调用方法
            function MeasureGeometry(geometry) {
                // 如果为点类型,就测量经纬度。
                if(geometry.type == "point"){
                    outputLongitudeLatitude(geometry.x, geometry.y);
                }
                // 如果为线类型就进行lengths距离测算
                else if (geometry.type == "polyline") {
                    const lengthParams = new LengthsParameters();
                    lengthParams.polylines = [geometry];
                    lengthParams.lengthUnit = GeometryService.UNIT_METER;
                    lengthParams.geodesic = true;
                    lengthParams.polylines[0].spatialReference = new SpatialReference(4326);
                    geometryService.lengths(lengthParams);
                    dojo.connect(geometryService, "onLengthsComplete", outputDistance);
                }
                // 如果为面类型,需要先进行simplify操作再进行面积测算
                else if (geometry.type == "polygon") {
                    const areasAndLengthParams = new AreasAndLengthsParameters();
                    areasAndLengthParams.lengthUnit = GeometryService.UNIT_METER;
                    areasAndLengthParams.areaUnit = GeometryService.UNIT_SQUARE_METERS;
                    this.outSR = new SpatialReference({wkid: 102113});
                    geometryService.project([geometry], this.outSR, function (geometry) {
                        geometryService.simplify(geometry, function (simplifiedGeometries) {
                            // 此处把各特征点的经纬度,转换成了坐标系中的实际坐标,
                            // 单位即上边规定的单位。
                            // console.log('simplifiedGeometries:', simplifiedGeometries);
                            areasAndLengthParams.polygons = simplifiedGeometries;
                            areasAndLengthParams.polygons[0].spatialReference = new SpatialReference(102113);
                            geometryService.areasAndLengths(areasAndLengthParams);
                        });
                    });
                    dojo.connect(geometryService, "onAreasAndLengthsComplete", outputAreaAndLength);
                }

            }
            
            // 显示经纬度。
            function outputLongitudeLatitude(lon, lat) {
                const curPos = new Point(lon, lat, map.spatialReference);
                let textSymbol =  new TextSymbol(
                    "经度:" + lon.toFixed(3) + "\n纬度:" + lat.toFixed(3)
                ).setColor(new Color([182,0,0])).setFont(
                    new Font("14pt").setWeight(Font.WEIGHT_BOLD)
                ).setHorizontalAlignment("left").setVerticalAlignment('middle');
                graphicsLayer.add(new Graphic(curPos, textSymbol));
            }

            //显示测量距离
            function outputDistance(result) {
                const curX = measureGeometry.paths[0][measureGeometry.paths[0].length - 1][0];
                const curY = measureGeometry.paths[0][measureGeometry.paths[0].length - 1][1];
                const curPos = new Point(curX, curY, map.spatialReference);
                let len = parseInt(result.lengths[0]);
                let textSymbol;
                if(len <= 10000){
                    textSymbol =  new TextSymbol(
                        "长度:" + len + "米"
                    );

                }
                else{
                    textSymbol =  new TextSymbol(
                        "长度:" + len / 1000 + "千米"
                    );
                }
                let textSymbol2 = textSymbol.setColor(new Color([182,0,0])).setFont(
                    new Font("14pt").setWeight(Font.WEIGHT_BOLD)
                ).setHorizontalAlignment("left").setVerticalAlignment('middle');
                graphicsLayer.add(new Graphic(curPos, textSymbol2));
            }

            // 显示测量面积,周长。
            function outputAreaAndLength(result) {
                const center = measureGeometry.getCentroid();  //获取查询区域的中心点
                let area = parseInt(result.areas[0]);
                let len = parseInt(result.lengths[0]);
                let area2, len2;
                if(len > 10000){
                    len2 = len / 1000
                }
                if(area > 1000000){
                    area2 = (area / 1000000).toFixed(3);
                }
                let textSymbol;
                if(area2 && len2){
                    textSymbol =  new TextSymbol(
                        "面积:" + area2 + "平方千米\n" +
                        "周长:" + len2 + "千米"
                    );

                }
                else if(area2){
                    textSymbol =  new TextSymbol(
                        "面积:" + area2 + "平方千米\n" +
                        "周长:" + len + "米"
                    );

                }
                else if(len2){
                    textSymbol =  new TextSymbol(
                        "面积:" + area + "平方米\n" +
                        "周长:" + len2 + "千米"
                    );

                }
                else{
                    textSymbol =  new TextSymbol(
                        "面积:" + area + "平方米\n" +
                        "周长:" + len + "米"
                    );

                }
                let textSymbol2 = textSymbol.setColor(new Color([182,0,0])).setFont(
                    new Font("14pt").setWeight(Font.WEIGHT_BOLD)
                ).setHorizontalAlignment("left").setVerticalAlignment('middle');
                graphicsLayer.add(new Graphic(center, textSymbol2));
            }


            // 添加图形
            function addGraphic(event) {
                // 使绘图工具无效。
                // draw.deactivate();
                // 启用地图导航.
                map.enableMapNavigation();
                let symbol;
                if ( event.geometry.type === "point" || event.geometry.type === "multipoint") {
                    symbol = markerSymbol;
                    // symbol = textSymbol;
                }
                else if ( event.geometry.type === "line" || event.geometry.type === "polyline") {
                    symbol = lineSymbol;
                }
                else {
                    symbol = fillSymbol;
                }

                const measureOrNot = document.getElementById("measure").checked;
                // 绘制并测量
                if(measureOrNot){
                    // 后边的代码,不能处理extent类型的面积长度测量,
                    // 所以此处需特殊处理。
                    // 即,把extent类型的数据结构,重构成polygon类型的数据结构,即可。
                    if(event.geometry.type == "extent"){
                        let center = event.geometry.getCenter();
                        // console.log('center:', center);
                        const polygonJson = {
                            "rings": [[
                                [event.geometry.xmin, event.geometry.ymax],
                                [event.geometry.xmax, event.geometry.ymax],
                                [event.geometry.xmax, event.geometry.ymin],
                                [event.geometry.xmin, event.geometry.ymin],
                                [event.geometry.xmin, event.geometry.ymax]
                            ]],
                            "spatialReference": {"wkid": 4326},
                            "cache": {
                                "geoShape": "polygon",
                                "_centroid": center,
                                "_extent": {
                                    "xmin": event.geometry.xmin,
                                    "ymin": event.geometry.ymin,
                                    "xmax": event.geometry.xmax,
                                    "ymax": event.geometry.ymax,
                                    "spatialReference": event.geometry.spatialReference
                                },
                                "_partwise": null,

                            }
                        };
                        const polygon = new Polygon(polygonJson);
                        polygon.setCacheValue("geoShape", polygon.type);
                        doMeasure(polygon);
                    }
                    else {
                        event.geometry.setCacheValue("geoShape", event.geometry.type);
                        doMeasure(event.geometry);
                    }
                }
                // 只绘制不测量
                else {
                    event.geometry.setCacheValue("geoShape", event.geometry.type);
                    graphicsLayer.add(new Graphic(event.geometry, symbol));
                }

            }


            //初始化工具栏
            function initToolbar() {
                // 创建绘图工具。
                // showTooltips,默认为true。
                draw = new Draw(map, { showTooltips: true });
                // 绘图工具监听画完事件。
                // console.log('graphicsLayer:', graphicsLayer);
                draw.on("draw-end", addGraphic);
                // undo_redo_arr,用于存储 操作撤消恢复事件时 的图形对象。
                undo_redo_arr = [];
                // clear_arr,用于存储清除操作,清除的所有图形对象。
                let clear_arr = [];
                let len_undo_redo, len_clear, len_graphics;
                let textAdd;
                // 绘图工具监听 绘制选项。
                on(dom.byId("drawOptions"), "click", function(event){
                    // 没有事件的元素。
                    if (event.target.id === "drawOptions" ) {
                        return;
                    }
                    const tool = event.target.id.toLowerCase();
                    // 禁用地图导航。
                    map.disableMapNavigation();
                    // 绘图工具激活相应的绘图功能。
                    draw.activate(tool);
                    if(textAdd){
                        textAdd.remove();
                    }
                });
                // 监听撤消事件。
                on(dom.byId("undo"), "click", function(event) {
                    // 每单击一次按钮,就更新一遍各个数组的长度。
                    len_clear = clear_arr.length;
                    len_graphics = graphicsLayer.graphics.length;
                    // 撤消 清除事件。
                    if(len_graphics == 0 && len_clear != 0){
                        // 前提:视图中没图形,清除数组有图形,才能撤消清除操作。
                        for(let i=0;i<len_clear;i++){
                            graphicsLayer.add(clear_arr.pop());
                        }
                    }
                    // 撤消单个图形(多点绘制的是多个点,撤消的话一同撤消。)
                    else if(len_graphics != 0){
                        // 前提:视图中有图形,才能撤消绘制的单个图形。
                        let graphic_pop = graphicsLayer.graphics.pop();
                        // remove的两个参数,第一个是要移除的图形,第二个是该图形对应的html元素节点。
                        graphicsLayer.remove(graphic_pop, graphic_pop.getNode());
                        undo_redo_arr.push(graphic_pop);
                        // console.log('undo_redo_arr:', undo_redo_arr);
                    }
                });
                // 监听恢复事件。
                on(dom.byId("redo"), "click", function (event) {
                    // 每单击一次恢复按钮,就更新一遍undo_redo_arr数组的长度。
                    len_undo_redo = undo_redo_arr.length;
                    // 恢复,是相对于撤消而言的。即,只能恢复撤消的图形。
                    if(len_undo_redo != 0){
                        // 前提是 undo_redo_arr数组不为空,才有图形可恢复。
                        graphicsLayer.add(undo_redo_arr.pop());
                    }
                });
                // 监听清除事件。
                on(dom.byId("clearAll"), "click", function (event) {
                    // 清除视图中所有图形 事件。
                    len_graphics = graphicsLayer.graphics.length;
                    for(let i=0;i<len_graphics;i++){
                        let graphic_pop = graphicsLayer.graphics.pop();
                        clear_arr.push(graphicsLayer.remove(graphic_pop, graphic_pop.getNode()));
                    }
                });
                // 监听停止标绘事件。
                on(dom.byId("stop"), "click", function (event) {
                    draw.deactivate();
                    if(textAdd){
                        textAdd.remove();
                    }
                });
                // 监听添加文字事件。
                on(dom.byId("text"), "click", function (event) {
                    // console.log('text');
                    draw.deactivate();
                    textAdd = map.on("click", function(event) {
                        // console.log('event:', event);
                        graphicsLayer.add(
                            new Graphic(event.mapPoint, new TextSymbol("Multi-Line \n Text"), {})
                        );
                    });
                });
            }

            //创建右键菜单
            function createGraphicsMenu(){
                ctxMenuForGraphics = new Menu({});
                // 在graphicsLayer图层里的元素,重叠时,也有上下之分。
                // 即,重叠的元素,哪个在上边,哪个在下边。
                //当鼠标在graphicsLayer图层的图形上方时绑定该图形的点击事件
                let selected;
                graphicsLayer.on("mouse-over", function(event) {
                    selected = event.graphic;
                    // 右键菜单绑定dom节点。不绑定则“删除”标签不弹出。
                    // event.graphic.getDojoShape().getNode(), 指的就是图形对应的html方式的表达。
                    ctxMenuForGraphics.bindDomNode(event.graphic.getNode());
                });
                //当鼠标移出graphicsLayer图层的图形上方时取消绑定该图形的点击事件
                graphicsLayer.on("mouse-out", function(event) {
                    ctxMenuForGraphics.unBindDomNode(event.graphic.getNode());
                });
                ctxMenuForGraphics.addChild(new MenuItem({
                    label: "删除",
                    // 此处的onClick是在“删除”标签上的onClick。
                    onClick: function () {
                        undo_redo_arr.push(graphicsLayer.remove(selected));
                    }
                }));
            }

            // 主函数。
            function main() {
                // 创建popup弹出层
                const popup = new Popup(null, domConstruct.create("div"));
                // 地图
                map = new Map("map", {
                    slider:false,
                    center: [121.47003707885744, 31.24853148977224],
                    zoom: 7,
                    infoWindow: popup, // 信息窗口,弹窗。
                    extent: new Extent(
                        -122.68,45.53,-122.45,45.60,
                        new SpatialReference({wkid:4326 })
                    ) // 猜测:显示的区域。
                });
                // 添加地图图层
                const mapServiceURL = "https://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";
                map.addLayer(new ArcGISTiledMapServiceLayer(mapServiceURL));
                //初始化比例尺
                const scalebar = new Scalebar({
                    map: map,
                    attachTo: "bottom-left",
                    scalebarUnit: "dual",
                });
                //显示比例尺
                scalebar.show();
                // 创建图层
                graphicsLayer = new GraphicsLayer({id: "draw"});
                map.addLayer(graphicsLayer);
                // 给地图添加事件。
                map.on("load", initToolbar);
                // 创建右键菜单。
                createGraphicsMenu();
                //启动右键菜单
                ctxMenuForGraphics.startup();
                //点击地图响应
                map.on("click", function(event) {
                    //点击空白处隐藏popup
                    if(event.graphic == undefined){
                        popup.hide();
                    }
                    // mapPoint = event.mapPoint;
                });

                // 搜索框
                const search = new Search({
                    map: map,
                    graphicsLayer: graphicsLayer,
                }, "search");
                search.startup();

                // 弹出框信息
                graphicsLayer.on("click",  function(event) {
                    let details;
                    if(event.graphic.geometry.getCacheValue("geoShape") == "polygon"){
                        // const details = '图形: ' + event.graphic.geometry.cache.geoShape + '<br>';
                        details = '图形类型: ' + event.graphic.geometry.getCacheValue("geoShape") + '<br>' +
                        '图形长度:'  + event.graphic.geometry.getCacheValue("长度") + '<br>' +
                        '图形面积:'  + event.graphic.geometry.getCacheValue("面积");
                    }
                    else if(event.graphic.geometry.getCacheValue("geoShape") == "polyline"){
                        details = '图形类型: ' + event.graphic.geometry.getCacheValue("geoShape") + '<br>' +
                            '图形长度:'  + event.graphic.geometry.getCacheValue("长度");
                    }
                    else if(event.graphic.geometry.getCacheValue("geoShape") == "point"){
                        details = '图形类型: ' + event.graphic.geometry.getCacheValue("geoShape") + '<br>' +
                            '经度:'  + event.graphic.geometry.getCacheValue("经度") + '<br>' +
                            '纬度:'  + event.graphic.geometry.getCacheValue("纬度");
                    }
                    popup.setTitle('图形信息');  // 弹窗标题
                    popup.setContent(details);  // 弹窗内容
                    popup.show(event.mapPoint);  // 弹窗展示及其位置
                });

                // textSymbol =  new TextSymbol("Hello World").setColor(
                //     new Color([128,0,0])).setAlign(Font.ALIGN_START).setAngle(45).setFont(
                //     new Font("12pt").setWeight(Font.WEIGHT_BOLD)) ;
                //用来展示点的symbol
                //链式调用更有性能优势。
                markerSymbol = new SimpleMarkerSymbol().setSize(10).setColor(
                    new Color("#00FFFF")).setStyle(SimpleMarkerSymbol.STYLE_SQUARE);
                // 用来展示线的symbol
                lineSymbol = new CartographicLineSymbol(
                    CartographicLineSymbol.STYLE_SOLID, // 线的样式,实线。
                    new Color([255, 0, 0]), 4,  // 颜色 线宽
                    CartographicLineSymbol.CAP_ROUND,  // 两头圆角
                    CartographicLineSymbol.JOIN_MITER, // 连接处尖角
                    5 // 最大斜接长度。斜接长度指的是在两条线交汇处内角和外角之间的距离。
                    // 如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示。
                );
                //用来展示面的symbol
                fillSymbol = new SimpleFillSymbol(
                    SimpleFillSymbol.STYLE_SOLID, // 实心
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID, // 实线
                        new Color('#fff'), // 边/线的颜色
                        1 // 边的宽度
                    ),
                    new Color([0, 255, 0, 0.2]) // 填充的颜色及透明度
                );
                // console.log('markerSymbol:', markerSymbol);
                // console.log('lineSymbol:', lineSymbol);
                // console.log('fillSymbol:', fillSymbol);
            }

            let map, graphicsLayer, draw, ctxMenuForGraphics;
            let measureGeometry, undo_redo_arr;
            let textSymbol, markerSymbol,lineSymbol,fillSymbol;

            const geometryServiceUrl="http://10.254.11.41:6080/arcgis/rest/services/Utilities/Geometry/GeometryServer";
            esriConfig.defaults.io.proxyUrl = "/proxy/";
            esriConfig.defaults.io.alwaysUseProxy = false;
            const geometryService = new GeometryService(geometryServiceUrl);
            // esriConfig.defaults.geometryService = new GeometryService(geometryServiceUrl);

            main();
        });
    </script>
</head>

<body class="claro" style="font-size: 0.75em;">
    <!--绘图菜单。-->
    <div id="drawOperations">
        <div align="left">绘图选项</div>
        <div id="drawOptions">
            <img id="Point" src="../images/multipoint.png">
            <img id="Line" src="../images/line.png">
            <img id="Polyline" src="../images/polyline.png">
            <img id="FreehandPolyline" src="../images/freehand_polyline.png">
            <img id="Triangle" src="../images/triangel.png">
            <img id="Extent" src="../images/rectangle.png">
            <img id="Circle" src="../images/circle.png">
            <img id="Ellipse" src="../images/ellipse.png">
            <img id="Polygon" src="../images/polygon.png">
            <img id="FreehandPolygon" src="../images/freehand_ploygon.png">
        </div>
        <div>添加文字</div>
        <img id="text" src="../images/text.png">
        <div><input id="measure" type="checkbox">绘制并测量</div>
        <button id="stop">停止标绘</button>
        <button id="undo">撤消</button>
        <button id="redo">恢复</button>
        <button id="clearAll" >清除</button>
    </div>
    <!--搜索框。-->
    <div id="search"></div>
    <!--地图显示区。-->
    <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">
    </div>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/weixin_42193179/article/details/83963209