Cesium學習筆記10——通過WFS服務實現交互式屬性查詢

1.功能說明:

  鼠標繪製多邊形進行查詢,通過多邊形範圍,調用Geoserver發佈的WFS服務,查詢相交的地圖要素,將返回結果高亮顯示。

  單擊高亮顯示的要素,顯示要素的屬性信息。

2.網頁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" />
    <meta name="description" content="Draw point on terrain with mouse clicks.">
    <meta name="cesium-sandcastle-labels" content="Showcases">
    <title>WFS屬性查詢</title>
    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    <script type="text/javascript" src="Sandcastle-header.js"></script>
    <script type="module" src="load-cesium-es6.js"></script>
    <script src="./Build/CesiumUnminified/Cesium.js"></script>
    <script>window.CESIUM_BASE_URL = "./Build/CesiumUnminified/";</script>
  </head>
  <body  class="sandcastle-loading"  data-sandcastle-bucket="bucket-requirejs.html">
    <style>
    @import url(bucket.css);
        html,
        body,
        #cesiumContainer {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
        }
    </style>
    <div id="cesiumContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar">
      <table class="infoPanel">
        <tbody>
          <tr>
            <td>左鍵單擊繪製點,右擊結束線矩形框繪製。</td>
          </tr>
        </tbody>
      </table>
    </div>
    <div id="infowindow" style="position:absolute;top:10px;right:10px;z-index:999;background:rgb(18, 100, 138);width:200px;height:50px;font-size:13px;display:none;line-height:25px;"></div>
    <script src="./code.js"> </script>
</body>
</html>

3.編寫的code.js代碼:

Cesium.Ion.defaultAccessToken='你的Token';
window.startup = async function (Cesium) {
    'use strict';
    //增加視圖區
    const viewer = new Cesium.Viewer("cesiumContainer", {
        geocoder: false,
        homeButton: true,
        sceneModePicker: false,
        fullscreenButton: false,
        vrButton: false,
        baseLayerPicker: false,
        infoBox: false,
        selectionIndicator: false,
        animation: false,
        timeline: false,
        shouldAnimate: true,
        navigationHelpButton: false,
        navigationInstructionsInitiallyVisible: false,
        terrainProvider: Cesium.createWorldTerrain(),
        imageryProvider: new Cesium.UrlTemplateImageryProvider({
            //url: 'http://mt0.google.cn/vt/lyrs=t,r&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}',
            //url: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
            url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
            //tilingScheme : new Cesium.GeographicTilingScheme(),
            credit: ''
        }),
    });
    //繪製geojson圖層樣式
    var geoJsonStyle = {
        stroke: Cesium.Color.YELLOW,
        strokeWidth: 3,
        fill: Cesium.Color.YELLOW.withAlpha(0.1)
      };
    var geoserverUrl = 'http://127.0.0.1:8180/geoserver/NtuWrokspace';
    viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
        );
        function createPoint(worldPosition) {
            const point = viewer.entities.add({
                position: worldPosition,
                point: {
                color: Cesium.Color.RED,
                pixelSize: 5,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                },
            });
            return point;
        }
        let drawingMode = "polygon";
        function drawShape(positionData) {
            let shape;
            if (drawingMode === "rectangle") {
               
            } else if (drawingMode === "polygon") {
                shape = viewer.entities.add({
                polygon: {
                    hierarchy: positionData,
                    material: new Cesium.ColorMaterialProperty(
                    Cesium.Color.RED.withAlpha(0.7)
                    ),
                },
                }); 
            }
            return shape;
        }
         /*空間查詢圖層
        *@method queryByPolygon
        *@param polygon 空間範圍
        *@param typeName 圖層名稱
        *@return null
        */
        function queryByPolygon(polygon, typeName, callback){
            var filter =
            '<Filter xmlns="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml">';
            /*filter += '<And>';*/
            filter += '<Intersects>';
            filter += '<PropertyName>the_geom</PropertyName>';
            filter += '<gml:Polygon>';
            filter += '<gml:outerBoundaryIs>';
            filter += '<gml:LinearRing>';
            filter += '<gml:coordinates>' + polygon + '</gml:coordinates>';
            filter += '</gml:LinearRing>';
            filter += '</gml:outerBoundaryIs>';
            filter += '</gml:Polygon>';
            filter += '</Intersects>';
            /*filter += '<PropertyIsLike wildCard="*" singleChar="#" escapeChar="!">';
            filter += '<PropertyName>map_num</PropertyName>';
            filter += '<Literal>*201911_440114*</Literal>';
            filter += '</PropertyIsLike>'; */
            /*filter += '</And>';*/
            filter += '</Filter>';
            var urlString = geoserverUrl + '/ows';
            var param = {
            service: 'WFS',
            version: '1.0.0',
            request: 'GetFeature',
            typeName: typeName,
            outputFormat: 'application/json',
            filter: filter
            };
            var geojsonUrl = urlString + getParamString(param, urlString);
            $.ajax({
                url: geojsonUrl,
                async: true,
                type:'GET',
                dataType: 'json',
                success(result) {
                    callback(result);
                },
                error(err) {
                    console.log(err);
                }
            })
        }

        function getParamString(obj, existingUrl, uppercase){
            var params = [];
            for (var i in obj) {
                params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
            }
            return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');    
        }
        /*
        * 圖層空間查詢回調函數
        */
        function callbackLastQueryWFSService(data){
            console.log('data',data);
            if(data && data.features.length>0){
            clearGeojsonLayer();
            loadGeojsonLayer(data);
            }
        }
        /*
        * 繪製圖形函數
        */
        function loadGeojsonLayer(geojson){
            var promise = Cesium.GeoJsonDataSource.load(geojson,geoJsonStyle);
            promise.then(function(dataSource) {
                viewer.dataSources.add(dataSource);
                viewer.zoomTo(dataSource);
            }).otherwise(function(error){
                //Display any errrors encountered while loading.
                window.alert(error);
            });
        }
        /*
        * 清空繪製圖形函數
        */
        function clearGeojsonLayer(){
            viewer.dataSources.removeAll();
        }

        function clearMap(){
            clearGeojsonLayer();
        }

        function getExtentByPoints(points) {
            if (points) {
                // 指定世界範圍
                let lonMin = 180;
                let lonMax = -180;
                let latMin = 90;
                let latMax = -180;
                points.forEach(function (point) {
                    const longitude = point[0];
                    const latitude = point[1];
                    // 計算邊界
                    lonMin = longitude < lonMin ? longitude : lonMin;
                    latMin = latitude < latMin ? latitude : latMin;
                    lonMax = longitude > lonMax ? longitude : lonMax;
                    latMax = latitude > latMax ? latitude : latMax;
                });
                const xRange = lonMax - lonMin ? lonMax - lonMin : 1;
                const yRange = latMax - latMin ? latMax - latMin : 1;
                // 返回數據
                return [lonMin - xRange / 10, latMin - yRange / 10, lonMax + xRange / 10, latMax + yRange / 10];
            }
            return [-180,-90,180,90];
        }
        /**
         * @todo 弧度座標轉經緯度座標
         * @param {Cartographic} cartographic - 弧度座標
         * @return {Object} - {longitude: x, latitude: y, height: h} - 返回經緯度
         */
        function cartographicToDegrees(cartographic) {
            const result = {};
            result.longitude = Cesium.Math.toDegrees(cartographic.longitude);
            result.latitude = Cesium.Math.toDegrees(cartographic.latitude);
            if (cartographic.height > 0) {
                result.height = cartographic.height;
            }
            return result;
        }
        /**
         * @todo 獲取 Cartesian3 四至範圍
         * @param {Cartesian3} cartesian3s - 世界座標對象
         * @return {*[]}
         */
        function getExtentByCartesian3(cartesian3s) {

            if(cartesian3s instanceof Array && cartesian3s.length>0){
                const points = [];
                for (let i = 0; i < cartesian3s.length; i++) {
                    const cartesian3 = cartesian3s[i];
                    // 將 cartesian3 轉爲經緯度數組
                    
                const cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
                const point = cartographicToDegrees(cartographic);
                    points.push([point.longitude,point.latitude]);
                }
                return getExtentByPoints(points);
            }
        }

        let activeShapePoints = [];
        let activeShape;
        let floatingPoint;
        //窗口事件句柄
        const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
        handler.setInputAction(function (event) {
        const ray = viewer.camera.getPickRay(event.position);//根據鼠標點擊座標和相機座標構建射線
        const earthPosition = viewer.scene.globe.pick(ray, viewer.scene);//射線與球面求交,在地面的交點
        // `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);
                const 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)) {
            const ray = viewer.camera.getPickRay(event.endPosition);
            const newPosition = viewer.scene.globe.pick(ray, viewer.scene);
            if (Cesium.defined(newPosition)) {
            floatingPoint.position.setValue(newPosition);
            activeShapePoints.pop();
            activeShapePoints.push(newPosition);
            }
        }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);//鼠標移動
        //移除臨時繪製圖像.
        function terminateShape() {
            activeShapePoints.pop();
           // drawShape(activeShapePoints);
            viewer.entities.remove(floatingPoint);
            viewer.entities.remove(activeShape);
            floatingPoint = undefined;
            activeShape = undefined;
            activeShapePoints = [];
        }
        handler.setInputAction(function (event) {    
            var polygon = drawShape(activeShapePoints);
            //polygon.setVisible(false);
            var extent =getExtentByCartesian3(activeShapePoints);   
            viewer.entities.remove(polygon);
            terminateShape();
            drawingMode = "unknown";
            if(extent && extent.length>0){
                     //構造polygon 
                     polygon = '';
                     polygon += extent[0] + ',' + extent[1] + ' ' ;
                     polygon += extent[2] + ',' + extent[1] + ' ' ;
                     polygon += extent[2] + ',' + extent[3] + ' ' ;
                     polygon += extent[0] + ',' + extent[3] + ' ' ;
                     polygon += extent[0] + ',' + extent[1] + ' ' ;
           }
           console.log('polygon',polygon);
           if(polygon){
               queryByPolygon(polygon,'NtuWrokspace:省界_region',callbackLastQueryWFSService);
            }
            
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);//鼠標右鍵


    var highlightFace = null;
    viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
         var pickedFeature = viewer.scene.pick(movement.position);
         console.log('pickedFeature',pickedFeature);
         if(pickedFeature){
             //判斷之前是否有高亮面存在
             if (highlightFace) {
                 highlightFace.material = highlightFace.material0;
             }
             if(pickedFeature.id.polygon.material){
                 pickedFeature.id.polygon.material0 = pickedFeature.id.polygon.material;
                 pickedFeature.id.polygon.material = Cesium.Color.DEEPSKYBLUE.withAlpha(0.8);
                 highlightFace = pickedFeature.id.polygon;
                 console.log('properties',pickedFeature.id.properties);
                //氣泡窗口顯示
                var content =
                    "<div>"+
                    "<span>圖斑編號:</span><span>"+pickedFeature.id.properties.CODE+"</span></br>"+
                    "<span>圖斑描述::</span><span>"+pickedFeature.id.properties.NAME+"</span></br>"+
                    "</div>";
                $("#infowindow").show();
                $("#infowindow").empty();
                $("#infowindow").append(content);
             }
         }
         else{
            if (highlightFace) {
                 highlightFace.material = highlightFace.material0;
            }
            $("#infowindow").hide();
         }
     }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    Sandcastle.addDefaultToolbarButton("框選查詢", function () {
        terminateShape();
        drawingMode = "polygon";
    });
      
      //Example 2: Load with basic styling options.
    Sandcastle.addToolbarButton("點選查詢", function () {
        clearMap();
        drawingMode = "unknown";
    });

    Sandcastle.reset = function () {
        viewer.dataSources.removeAll();
      
        //Set the camera to a US centered tilted view and switch back to moving in world coordinates.
        viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(115.0, 45.0),
          new Cesium.Cartesian3(0.0, -4790000.0, 3930000.0)
        );
        viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
    };
      //Sandcastle_End
    Sandcastle.finishedLoading();

};
if (typeof Cesium !== 'undefined') {
    window.startupCalled = true;
    window.startup(Cesium).catch((error) => {
      "use strict";
      console.error(error);
    });
}

   

4.效果如下:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章